diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml index 62803d3919e50f38bbede449a85e32ff422f90e6..963223f4d95e9d2e65cc3106cfeb8d50d4a3a56f 100644 --- a/.forgejo/workflows/ci.yaml +++ b/.forgejo/workflows/ci.yaml @@ -93,7 +93,7 @@ jobs: fetch-depth: 0 - name: Build and Test run: sh ci/aarch64-macos-debug.sh - timeout-minutes: 180 + timeout-minutes: 240 aarch64-macos-release: runs-on: [self-hosted, aarch64-macos] steps: @@ -157,7 +157,7 @@ jobs: fetch-depth: 0 - name: Build and Test run: sh ci/riscv64-linux-debug.sh - timeout-minutes: 720 + timeout-minutes: 840 riscv64-linux-release: if: github.event_name != 'pull_request' runs-on: [self-hosted, riscv64-linux] diff --git a/.gitattributes b/.gitattributes index b9cb5340b1a941e1d897dab5240b0f820de611dd..8abf9c1f5e1a4108f0bcb7c44be0d3269007aef3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -11,6 +11,7 @@ lib/std/compress/lzma/testdata/** binary lib/std/compress/xz/testdata/** binary lib/std/crypto/codecs/asn1/der/testdata/** binary lib/std/tar/testdata/** binary +lib/std/zip/testdata/** binary src/Package/Fetch/testdata/** binary src/Package/Fetch/git/testdata/** binary diff --git a/.mailmap b/.mailmap index e91a8c6c1a4482c099a1c06530f25a1e90550e6a..811ce2b2e7cc998e305320396eca63789ad24ad7 100644 --- a/.mailmap +++ b/.mailmap @@ -108,3 +108,6 @@ saurabh saurabh xEgoist <101279047+xEgoist@users.noreply.github.com> zenith391 <39484230+zenith391@users.noreply.github.com> +xtex +xtex +xtex diff --git a/CMakeLists.txt b/CMakeLists.txt index f40634b7e20ab9b8f8ea1fc9cda5ac5978a93e30..3211a15d4ddeeb9fe0ffa834482aa4e8ad486621 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -342,7 +342,7 @@ set(ZIG_STAGE2_SOURCES src/Package/Module.zig src/RangeSet.zig src/Sema.zig - src/Sema/bitcast.zig + src/Sema/reinterpret.zig src/Sema/comptime_ptr_access.zig src/Sema/type_resolution.zig src/Type.zig @@ -678,10 +678,8 @@ set(BUILD_ZIG2_ARGS -femit-bin="${ZIG2_C_SOURCE}" -target "${ZIG_HOST_TARGET_TRIPLE}" --dep "build_options" - --dep "aro" "-Mroot=src/main.zig" "-Mbuild_options=${ZIG_CONFIG_ZIG_OUT}" - "-Maro=lib/compiler/aro/aro.zig" ) add_custom_command( diff --git a/bootstrap.c b/bootstrap.c index bc7ba46ed72a0f2221b89d423f9f63185abc2341..50297f34fdc429cdc75f1f338c4a9cd7d5aea5ab 100644 --- a/bootstrap.c +++ b/bootstrap.c @@ -202,10 +202,8 @@ int main(int argc, char **argv) { "--name", "zig2", "-femit-bin=zig2.c", "-target", host_triple, "--dep", "build_options", - "--dep", "aro", "-Mroot=src/main.zig", "-Mbuild_options=config.zig", - "-Maro=lib/compiler/aro/aro.zig", NULL, }; print_and_run(child_argv); diff --git a/build.zig b/build.zig index c914d0f161f818a493d933c77dba7884258a4921..ebf163bf5c136a61ecad9120c75c4215cdd8345e 100644 --- a/build.zig +++ b/build.zig @@ -70,6 +70,23 @@ pub fn build(b: *std.Build) !void { b.getInstallStep().dependOn(&install_std_docs.step); } + const update_cpu_features = b.addExecutable(.{ + .name = "update-cpu-features", + .root_module = b.createModule(.{ + .root_source_file = b.path("tools/update_cpu_features.zig"), + .target = b.graph.host, + .imports = &.{.{ + .name = "spirv_spec", + .module = b.createModule(.{ + .root_source_file = b.path("src/codegen/spirv/spec.zig"), + .target = b.graph.host, + }), + }}, + }), + }); + const run_update_cpu_features = b.addRunArtifact(update_cpu_features); + run_update_cpu_features.addPassthruArgs(); + if (flat) { b.installFile("LICENSE", "LICENSE"); b.installFile("README.md", "README.md"); @@ -85,6 +102,9 @@ pub fn build(b: *std.Build) !void { docs_step.dependOn(langref_step); docs_step.dependOn(std_docs_step); + const update_cpu_features_step = b.step("update-cpu-features", "Update CPU Features"); + update_cpu_features_step.dependOn(&run_update_cpu_features.step); + const no_matrix = b.option(bool, "no-matrix", "Limit test matrix to exactly one target configuration") orelse false; const fuzz_only = b.option(bool, "fuzz-only", "Limit test matrix to one target suitable for fuzzing") orelse false; const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false; @@ -142,24 +162,9 @@ pub fn build(b: *std.Build) !void { .install_dir = if (flat) .prefix else .lib, .install_subdir = if (flat) "lib" else "zig", .exclude_extensions = &[_][]const u8{ - // exclude files from lib/std/compress/testdata - ".gz", - ".z.0", - ".z.9", - ".zst.3", - ".zst.19", - "rfc1951.txt", - "rfc1952.txt", - "rfc8478.txt", // exclude files from lib/std/compress/flate/testdata ".expect", - ".expect-noinput", - ".golden", ".input", - "compress-e.txt", - "compress-gettysburg.txt", - "compress-pi.txt", - "rfc1951.txt", // exclude files from lib/std/compress/lzma/testdata ".lzma", // exclude files from lib/std/compress/xz/testdata @@ -168,6 +173,8 @@ pub fn build(b: *std.Build) !void { ".tzif", // exclude files from lib/std/tar/testdata ".tar", + // exclude files from lib/std/zip/testdata + ".zip", // others "README.md", }, @@ -216,7 +223,6 @@ pub fn build(b: *std.Build) !void { const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); exe.use_llvm = use_llvm; - exe.use_lld = use_llvm; if (no_bin) { b.getInstallStep().dependOn(&exe.step); @@ -250,7 +256,6 @@ pub fn build(b: *std.Build) !void { 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; - const enable_link_snapshots = b.option(bool, "link-snapshot", "Whether to enable linker state snapshots") orelse false; const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git."); const version_slice = if (opt_version_string) |version| version else v: { @@ -366,7 +371,6 @@ pub fn build(b: *std.Build) !void { exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions); exe_options.addOption(bool, "enable_logging", enable_logging); - exe_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots); exe_options.addOption(bool, "enable_tracy", tracy != null); exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); @@ -623,6 +627,15 @@ pub fn build(b: *std.Build) !void { .skip_llvm = skip_llvm, .max_rss = 3_300_000_000, })); + test_step.dependOn(tests.addLinkTests(b, .{ + .test_target_filters = test_target_filters, + .test_filters = test_filters, + .optimize_modes = optimize_modes, + .skip_non_native = skip_non_native, + .skip_windows = skip_windows, + .skip_llvm = skip_llvm, + .max_rss = 100_000_000, + })); test_step.dependOn(tests.addStackTraceTests(b, test_filters, skip_non_native)); test_step.dependOn(tests.addErrorTraceTests(b, test_filters, optimize_modes, skip_non_native)); test_step.dependOn(tests.addCliTests(b)); @@ -662,6 +675,26 @@ pub fn build(b: *std.Build) !void { update_mingw_step.dependOn(&b.addFail("The -Dmingw-src=... option is required for this step").step); } + const check_mingw_step = b.step("check-mingw", "Checks for mingw preprocessor regressions"); + const mingw_preprocessor_mod = b.createModule(.{ + .root_source_file = b.path("src/libs/mingw/Preprocessor.zig"), + .target = target, + }); + + const check_mingw_exe = b.addExecutable(.{ + .name = "check_mingw", + .root_module = b.createModule(.{ + .target = b.graph.host, + .root_source_file = b.path("tools/check_mingw.zig"), + .imports = &.{ + .{ .name = "preprocessor", .module = mingw_preprocessor_mod }, + }, + }), + }); + const check_mingw_run = b.addRunArtifact(check_mingw_exe); + check_mingw_run.addDirectoryArg(b.path("lib/libc/mingw")); + check_mingw_step.dependOn(&check_mingw_run.step); + const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases"); try tests.addIncrementalTests(b, test_incremental_step, test_filters); if (!skip_test_incremental) test_step.dependOn(test_incremental_step); @@ -698,7 +731,6 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { exe_options.addOption(std.SemanticVersion, "semver", semver); exe_options.addOption(bool, "enable_debug_extensions", false); exe_options.addOption(bool, "enable_logging", false); - exe_options.addOption(bool, "enable_link_snapshots", false); exe_options.addOption(bool, "enable_tracy", false); exe_options.addOption(bool, "enable_tracy_callstack", false); exe_options.addOption(bool, "enable_tracy_allocation", false); @@ -764,12 +796,6 @@ fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Modu .valgrind = options.valgrind, }); - const aro_mod = b.createModule(.{ - .root_source_file = b.path("lib/compiler/aro/aro.zig"), - }); - - compiler_mod.addImport("aro", aro_mod); - return compiler_mod; } diff --git a/ci/aarch64-freebsd-debug.sh b/ci/aarch64-freebsd-debug.sh index a4cdc95d92961889301003d9176cc20a10029d5a..f84a683771b456066ce5c7997b12bae71aac27bb 100755 --- a/ci/aarch64-freebsd-debug.sh +++ b/ci/aarch64-freebsd-debug.sh @@ -46,7 +46,7 @@ stage3-debug/bin/zig build test docs \ -Dskip-non-native \ --search-prefix "$PREFIX" \ --zig-lib-dir "$PWD/../lib" \ - --test-timeout 2m + --test-timeout 4m stage3-debug/bin/zig build \ --prefix stage4-debug \ diff --git a/ci/aarch64-freebsd-release.sh b/ci/aarch64-freebsd-release.sh index 9d99e6e515911dfb7d9756d32ce08a0d1d1201f7..e008d4ee81fb11bdeac967f93965d7bffb754c5d 100755 --- a/ci/aarch64-freebsd-release.sh +++ b/ci/aarch64-freebsd-release.sh @@ -46,7 +46,7 @@ stage3-release/bin/zig build test docs \ -Dskip-non-native \ --search-prefix "$PREFIX" \ --zig-lib-dir "$PWD/../lib" \ - --test-timeout 2m + --test-timeout 4m # Ensure that stage3 and stage4 are byte-for-byte identical. stage3-release/bin/zig build \ diff --git a/ci/x86_64-linux-debug-llvm.sh b/ci/x86_64-linux-debug-llvm.sh index 8036ca4ab27031c324d3c604d75d75647ef23f3f..3ec4cf0738a24af69c0198e53eefc4268e9e7319 100755 --- a/ci/x86_64-linux-debug-llvm.sh +++ b/ci/x86_64-linux-debug-llvm.sh @@ -11,7 +11,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.17.0-dev.203+073889523" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" -export PATH="$HOME/deps/wasmtime-v44.0.0-x86_64-linux:$HOME/deps/qemu-linux-x86_64-11.0.1/bin:$HOME/local/bin:$PATH" +export PATH="$HOME/deps/wasmtime-v46.0.1-x86_64-linux:$HOME/deps/qemu-linux-x86_64-11.0.1/bin:$HOME/local/bin:$PATH" # Override the cache directories because they won't actually help other CI runs # which will be testing alternate versions of zig, and ultimately would just @@ -51,7 +51,7 @@ stage3-debug/bin/zig build \ stage3-debug/bin/zig build test docs \ --maxrss ${ZSF_MAX_RSS:-0} \ -Dlldb=$HOME/deps/lldb-zig/Debug-7c1090fd46/bin/lldb \ - -Dlibc-test-path=$HOME/deps/libc-test-f2bac77 \ + -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \ -fqemu \ --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \ -fwasmtime \ diff --git a/ci/x86_64-linux-debug.sh b/ci/x86_64-linux-debug.sh index 68a3468381086b8eae635eefc1f09ef7f190fbb3..040fd17723babb49607d83c130e8791c7aa610c0 100755 --- a/ci/x86_64-linux-debug.sh +++ b/ci/x86_64-linux-debug.sh @@ -11,7 +11,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.17.0-dev.203+073889523" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" -export PATH="$HOME/deps/wasmtime-v44.0.0-x86_64-linux:$HOME/deps/qemu-linux-x86_64-11.0.1/bin:$HOME/local/bin:$PATH" +export PATH="$HOME/deps/wasmtime-v46.0.1-x86_64-linux:$HOME/deps/qemu-linux-x86_64-11.0.1/bin:$HOME/local/bin:$PATH" # Override the cache directories because they won't actually help other CI runs # which will be testing alternate versions of zig, and ultimately would just diff --git a/ci/x86_64-linux-release.sh b/ci/x86_64-linux-release.sh index 4753a1dd61123f3e7ffb3b63d8023e092b375ae2..a0dd4770f5a91537fbc13bef025eb6a9ae477941 100755 --- a/ci/x86_64-linux-release.sh +++ b/ci/x86_64-linux-release.sh @@ -11,7 +11,7 @@ CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.17.0-dev.203+073889523" PREFIX="$HOME/deps/$CACHE_BASENAME" ZIG="$PREFIX/bin/zig" -export PATH="$HOME/deps/wasmtime-v44.0.0-x86_64-linux:$HOME/deps/qemu-linux-x86_64-11.0.1/bin:$HOME/local/bin:$PATH" +export PATH="$HOME/deps/wasmtime-v46.0.1-x86_64-linux:$HOME/deps/qemu-linux-x86_64-11.0.1/bin:$HOME/local/bin:$PATH" # Override the cache directories because they won't actually help other CI runs # which will be testing alternate versions of zig, and ultimately would just @@ -59,7 +59,7 @@ stage3-release/bin/zig build \ stage3-release/bin/zig build test docs \ --maxrss ${ZSF_MAX_RSS:-0} \ -Dlldb=$HOME/deps/lldb-zig/Release-7c1090fd46/bin/lldb \ - -Dlibc-test-path=$HOME/deps/libc-test-f2bac77 \ + -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \ -fqemu \ --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \ -fwasmtime \ diff --git a/doc/langref.html.in b/doc/langref.html.in index 9b178fae44ef0634c2714d7f8618b1a208e62000..123ef1e2edad916ca00f45644dcc5f4f0352b009 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -315,7 +315,7 @@ 0.9.1 | 0.10.1 | 0.11.0 | - 0.12.0 | + 0.12.1 | 0.13.0 | 0.14.1 | 0.15.2 | @@ -1955,7 +1955,7 @@ or TODO talk about C ABI interop
TODO consider suggesting std.MultiArrayList

- {#see_also|@splat|@shuffle|@select|@reduce#} + {#see_also|@splat|@shuffle|@select|@reduce|Slicing by Length#} {#header_open|Relationship with Arrays#}

Vectors and {#link|Arrays#} each have a well-defined bit layout @@ -2150,6 +2150,24 @@ or {#see_also|Pointers|for|Arrays#} + {#header_open|Slicing by Length#} +

Even though Zig only has syntax for slicing based on start and end indices, by slicing twice, + one can express a slice by length operation.

+

The pattern {#syntax#}[a .. a + b]{#endsyntax#} is always better expressed + {#syntax#}[a..][0..b]{#endsyntax#} because:

+
    +
  • Slices are represented in memory as a pointer and length. Despite + syntactically appearing as twice the work, it is actually one less + subtraction in machine code.
  • +
  • If {#syntax#}a{#endsyntax#} is known at runtime and + {#syntax#}b{#endsyntax#} is known at {#link|comptime#}, the former + results in a slice but the latter results in a single-item + {#link|pointer|Pointers#} to an {#link|array|Arrays#}, a generally more + safe type because the length is compile-time known.
  • +
+ {#code|slicing_by_length.zig#} + {#header_close#} + {#header_open|Sentinel-Terminated Slices#}

The syntax {#syntax#}[:x]T{#endsyntax#} is a slice which has a runtime-known length @@ -5792,6 +5810,50 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val

Returns an {#link|enum#} type with the properties specified by the arguments.

{#header_close#} + {#header_open|@SpirvType#} +
{#syntax#}@SpirvType(comptime options: std.lang.Type.Spirv) type{#endsyntax#}
+

+ Returns a SPIR-V type with the properties specified by the arguments. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TagSPIR-V EquivalentDescription
.samplerOpTypeSamplerAn opaque sampler
.imageOpTypeImageAn opaque image
.sampled_imageOpTypeSampledImageAn opaque image combined with a sampler
.runtime_arrayOpTypeRuntimeArray + An array whose length is determined at runtime. + The resulting type supports indexing and exposes a {#syntax#}.len{#endsyntax#} field. + It may only appear as the last field of an {#link|extern struct#}. +
+
+ {#header_close#} + {#header_open|@typeInfo#}
{#syntax#}@typeInfo(comptime T: type) std.lang.Type{#endsyntax#}

@@ -8035,7 +8097,7 @@ PrefixTypeOp / ArrayTypeStart SuffixOp - <- LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET + <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET / DOT IDENTIFIER / DOTASTERISK / DOTQUESTIONMARK @@ -8193,7 +8255,7 @@ BUILTINIDENTIFIER <- '@'[A-Za-z_][A-Za-z0-9_]* skip AMPERSAND <- '&' ![=] skip AMPERSANDEQUAL <- '&=' skip -ASTERISK <- '*' ![*%=|] skip +ASTERISK <- '*' ![%=|] skip ASTERISKEQUAL <- '*=' skip ASTERISKPERCENT <- '*%' ![=] skip ASTERISKPERCENTEQUAL <- '*%=' skip diff --git a/doc/langref/destructuring_mixed.zig b/doc/langref/destructuring_mixed.zig index d2bef4388b7a25b20cd464b357683d2195567a6e..d75157c8cc465996edd167001039d872fadf17b8 100644 --- a/doc/langref/destructuring_mixed.zig +++ b/doc/langref/destructuring_mixed.zig @@ -15,7 +15,7 @@ pub fn main() void { // You can use _ to throw away unwanted values. _, x, _ = tuple; - print("x = {}", .{x}); + print("x = {}\n", .{x}); } // exe=succeed diff --git a/doc/langref/slicing_by_length.zig b/doc/langref/slicing_by_length.zig new file mode 100644 index 0000000000000000000000000000000000000000..abb7d9394fd3978f694e9a58796a65926584e087 --- /dev/null +++ b/doc/langref/slicing_by_length.zig @@ -0,0 +1,12 @@ +const expectEqual = @import("std").testing.expectEqual; + +test "example" { + var array = [_]i32{ 1, 2, 3, 4 }; + var runtime_start: usize = 1; + _ = &runtime_start; + const length = 2; + const array_ptr_len = array[runtime_start..][0..length]; + try expectEqual(*[length]i32, @TypeOf(array_ptr_len)); +} + +// test diff --git a/doc/langref/test_basic_slices.zig b/doc/langref/test_basic_slices.zig index 28013148352eba7c5b9e6c0849e778c1ebc0b5ed..d627b7d0a6c1347ccebbf2f773de59630c91d063 100644 --- a/doc/langref/test_basic_slices.zig +++ b/doc/langref/test_basic_slices.zig @@ -21,15 +21,6 @@ test "basic slices" { const array_ptr = array[0..array.len]; try expectEqual(*[array.len]i32, @TypeOf(array_ptr)); - // You can perform a slice-by-length by slicing twice. This allows the compiler - // to perform some optimisations like recognising a comptime-known length when - // the start position is only known at runtime. - var runtime_start: usize = 1; - _ = &runtime_start; - const length = 2; - const array_ptr_len = array[runtime_start..][0..length]; - try expectEqual(*[length]i32, @TypeOf(array_ptr_len)); - // Using the address-of operator on a slice gives a single-item pointer. try expectEqual(*i32, @TypeOf(&slice[0])); // Using the `ptr` field gives a many-item pointer. diff --git a/doc/langref/test_packed_structs.zig b/doc/langref/test_packed_structs.zig index 7e46f852a0a5cfda15a4432d5d3f8ebd710f315f..1fe918eefa23500a409d6228fbe789768de21564 100644 --- a/doc/langref/test_packed_structs.zig +++ b/doc/langref/test_packed_structs.zig @@ -26,16 +26,8 @@ fn doTheTest() !void { try expectEqual(0x1, divided.quarter4); const ordered: [2]u8 = @bitCast(full); - switch (native_endian) { - .big => { - try expectEqual(0x12, ordered[0]); - try expectEqual(0x34, ordered[1]); - }, - .little => { - try expectEqual(0x34, ordered[0]); - try expectEqual(0x12, ordered[1]); - }, - } + try expectEqual(0x34, ordered[0]); + try expectEqual(0x12, ordered[1]); } // test diff --git a/doc/langref/test_pointer_casting.zig b/doc/langref/test_pointer_casting.zig index 0a3fde2efe6675c1d142f97ccc67ffdce56bee22..f3de7ca48645626635220db9e300d69a48a62cd0 100644 --- a/doc/langref/test_pointer_casting.zig +++ b/doc/langref/test_pointer_casting.zig @@ -1,18 +1,22 @@ const std = @import("std"); +const native_endian = @import("builtin").target.cpu.arch.endian(); const expectEqual = std.testing.expectEqual; test "pointer casting" { - const bytes align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12 }; + const bytes: [4]u8 align(@alignOf(u32)) = .{ 0x10, 0x20, 0x30, 0x40 }; const u32_ptr: *const u32 = @ptrCast(&bytes); - try expectEqual(0x12121212, u32_ptr.*); - // Even this example is contrived - there are better ways to do the above than - // pointer casting. For example, using a slice narrowing cast: - const u32_value = std.mem.bytesAsSlice(u32, bytes[0..])[0]; - try expectEqual(0x12121212, u32_value); + // Because we directly reinterpreted bytes of memory, the `u32` value we + // load from `u32_ptr` depends on the target endian: + switch (native_endian) { + .little => try expectEqual(0x40302010, u32_ptr.*), + .big => try expectEqual(0x10203040, u32_ptr.*), + } - // And even another way, the most straightforward way to do it: - try expectEqual(0x12121212, @as(u32, @bitCast(bytes))); + // To instead reinterpret the logical bit representation of `bytes` with no + // dependency on the target endian, use `@bitCast`, which always places + // earlier array elements into less-significant bits: + try expectEqual(0x40302010, @as(u32, @bitCast(bytes))); } test "pointer child type" { diff --git a/lib/build-web/fuzz.zig b/lib/build-web/fuzz.zig index e8753702020c1e41e5326cf6ab54911fa61f0cd0..3f9d692169e04b620e3f9368242b49c72a49ee92 100644 --- a/lib/build-web/fuzz.zig +++ b/lib/build-web/fuzz.zig @@ -22,7 +22,7 @@ pub fn sourceIndexMessage(msg_bytes: []u8) error{OutOfMemory}!void { js.requestSources(); const Header = abi.fuzz.SourceIndexHeader; - const header: Header = @bitCast(msg_bytes[0..@sizeOf(Header)].*); + const header: *align(1) const Header = @ptrCast(msg_bytes[0..@sizeOf(Header)]); const directories_start = @sizeOf(Header); const directories_end = directories_start + header.directories_len * @sizeOf(Coverage.String); @@ -81,7 +81,7 @@ pub fn coverageUpdateMessage(msg_bytes: []u8) error{OutOfMemory}!void { var entry_points: std.ArrayList(SourceLocationIndex) = .empty; pub fn entryPointsMessage(msg_bytes: []u8) error{OutOfMemory}!void { - const header: abi.fuzz.EntryPointHeader = @bitCast(msg_bytes[0..@sizeOf(abi.fuzz.EntryPointHeader)].*); + const header: *align(1) const abi.fuzz.EntryPointHeader = @ptrCast(msg_bytes[0..@sizeOf(abi.fuzz.EntryPointHeader)]); const slis: []align(1) const SourceLocationIndex = @ptrCast(msg_bytes[@sizeOf(abi.fuzz.EntryPointHeader)..]); assert(slis.len == header.locsLen()); try entry_points.resize(gpa, slis.len); @@ -285,10 +285,10 @@ fn updateStats() error{OutOfMemory}!void { , .{ hdr.n_runs, hdr.unique_runs, - @as(f64, @floatFromInt(hdr.unique_runs)) / @as(f64, @floatFromInt(hdr.n_runs)), + @as(f64, @floatFromInt(hdr.unique_runs)) / @as(f64, @floatFromInt(hdr.n_runs)) * 100, covered_src_locs, total_src_locs, - @as(f64, @floatFromInt(covered_src_locs)) / @as(f64, @floatFromInt(total_src_locs)), + @as(f64, @floatFromInt(covered_src_locs)) / @as(f64, @floatFromInt(total_src_locs)) * 100, avg_speed, }); defer gpa.free(html); diff --git a/lib/c/math.zig b/lib/c/math.zig index fe6832f55b783f243436abcf47169295c8c2c014..b1ff37c04e0f454024a0e5e45590cecb34bb0df1 100644 --- a/lib/c/math.zig +++ b/lib/c/math.zig @@ -37,6 +37,7 @@ comptime { symbol(&hypotf, "hypotf"); symbol(&hypotl, "hypotl"); symbol(&lrintl, "lrintl"); + symbol(&lroundl, "lroundl"); symbol(&modfl, "modfl"); symbol(&rintl, "rintl"); } @@ -76,6 +77,8 @@ comptime { symbol(&log1pf, "log1pf"); symbol(&lrint, "lrint"); symbol(&lrintf, "lrintf"); + symbol(&lround, "lround"); + symbol(&lroundf, "lroundf"); symbol(&modf, "modf"); symbol(&nan, "nan"); symbol(&nanf, "nanf"); @@ -278,6 +281,18 @@ fn lrintl(x: c_longdouble) callconv(.c) c_long { return @trunc(rintl(x)); } +fn lround(x: f64) callconv(.c) c_long { + return @round(x); +} + +fn lroundf(x: f32) callconv(.c) c_long { + return @round(x); +} + +fn lroundl(x: c_longdouble) callconv(.c) c_long { + return @round(x); +} + fn modfGeneric(comptime T: type, x: T, iptr: *T) T { if (math.isNegativeInf(x)) { iptr.* = -math.inf(T); diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index cd3e43d332b2acb21ac76a8828d9426aba9a60d5..c31ba826d00a25807284c75e2209388d5e17b4d7 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -49,7 +49,7 @@ web_server: if (!builtin.single_threaded) ?WebServer else ?noreturn, /// Allocated into `gpa`. memory_blocked_steps: std.ArrayList(Configuration.Step.Index), /// Allocated into `gpa`. -step_stack: std.AutoArrayHashMapUnmanaged(Configuration.Step.Index, void), +step_stack: std.array_hash_map.Auto(Configuration.Step.Index, void), pkg_config: PkgConfig, error_style: ErrorStyle, @@ -481,7 +481,7 @@ pub fn main(init: process.Init.Minimal) !void { // maker process fails or crashes and it's helpful to be able to repeat // execution of the command line or otherwise inspect the configuration file. const c = &configuration; - var top_level_steps: std.StringArrayHashMapUnmanaged(Configuration.Step.Index) = .empty; + var top_level_steps: std.array_hash_map.String(Configuration.Step.Index) = .empty; for (configuration.steps, 0..) |*conf_step, step_index_usize| { if (conf_step.owner != .root) continue; const step_index: Configuration.Step.Index = @enumFromInt(step_index_usize); @@ -1217,7 +1217,7 @@ fn printTreeStep( step_index: Configuration.Step.Index, stderr: Io.Terminal, parent_node: *PrintNode, - step_stack: *std.AutoArrayHashMapUnmanaged(Configuration.Step.Index, void), + step_stack: *std.array_hash_map.Auto(Configuration.Step.Index, void), ) !void { const writer = stderr.writer; const first = step_stack.swapRemove(step_index); @@ -1502,7 +1502,7 @@ fn printChildNodePrefix(stderr: Io.Terminal) !void { fn constructGraphAndCheckForDependencyLoop( maker: *Maker, step_index: Configuration.Step.Index, - step_stack: *std.AutoArrayHashMapUnmanaged(Configuration.Step.Index, void), + step_stack: *std.array_hash_map.Auto(Configuration.Step.Index, void), rand: std.Random, ) error{ DependencyLoopDetected, OutOfMemory }!void { const c = &maker.scanned_config.configuration; diff --git a/lib/compiler/Maker/Fuzz.zig b/lib/compiler/Maker/Fuzz.zig index 2160befc08df2fb7f896d0f37b522e838cf7d331..44c3ccd2705799819cf189ae28053ddc9dce3583 100644 --- a/lib/compiler/Maker/Fuzz.zig +++ b/lib/compiler/Maker/Fuzz.zig @@ -27,7 +27,7 @@ prog_node: std.Progress.Node, /// Protects `coverage_files`. coverage_mutex: Io.Mutex, -coverage_files: std.AutoArrayHashMapUnmanaged(u64, CoverageMap), +coverage_files: std.array_hash_map.Auto(u64, CoverageMap), queue_mutex: Io.Mutex, queue_cond: Io.Condition, @@ -273,7 +273,7 @@ pub fn serveSourcesTar(fuzz: *Fuzz, req: *std.http.Server.Request) !void { defer arena_state.deinit(); const arena = arena_state.allocator(); - const DedupTable = std.ArrayHashMapUnmanaged(Build.Cache.Path, void, Build.Cache.Path.TableAdapter, false); + const DedupTable = std.array_hash_map.Custom(Build.Cache.Path, void, Build.Cache.Path.TableAdapter, false); var dedup_table: DedupTable = .empty; defer dedup_table.deinit(gpa); diff --git a/lib/compiler/Maker/ScannedConfig.zig b/lib/compiler/Maker/ScannedConfig.zig index c1e1ff18a90ba79e2331eae052deb4db61e5d164..e52e26279c19eee4b955ea0d6deba574bca47abe 100644 --- a/lib/compiler/Maker/ScannedConfig.zig +++ b/lib/compiler/Maker/ScannedConfig.zig @@ -8,7 +8,7 @@ const Serializer = std.zon.Serializer; const Graph = @import("Graph.zig"); configuration: Configuration, -top_level_steps: std.StringArrayHashMapUnmanaged(Configuration.Step.Index), +top_level_steps: std.array_hash_map.String(Configuration.Step.Index), path: []const u8, pub fn print(sc: *const ScannedConfig, w: *Writer) Writer.Error!void { @@ -324,7 +324,7 @@ pub fn printUsage(sc: *const ScannedConfig, graph: *Graph, w: *Writer) !void { \\ '--webui' when no limit is specified. \\ --time-report Force full rebuild and provide detailed information on \\ compilation time of Zig source code (implies '--webui') - \\ -fincremental Enable incremental compilation + \\ -fincremental Enable incremental compilation \\ -fno-incremental Disable incremental compilation \\ \\Package Management Options: diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig index 6a6f5c1cf3718c2dce6c957283e528d7b0844ac4..40d82db57f6afbacc468e038f5c1e9f1487f15d9 100644 --- a/lib/compiler/Maker/Step.zig +++ b/lib/compiler/Maker/Step.zig @@ -180,7 +180,7 @@ pub const Inputs = struct { .table = .{}, }; - pub const Table = std.ArrayHashMapUnmanaged(Path, Files, Path.TableAdapter, false); + pub const Table = std.array_hash_map.Custom(Path, Files, Path.TableAdapter, false); /// The special file name "." means any changes inside the directory. pub const Files = std.ArrayList([]const u8); diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig index 99b9374ef98678462ba6441cccb0481ccd8d8b32..69dae4610f8a10f70d25316da2a4bfec6234d63a 100644 --- a/lib/compiler/Maker/Step/Compile.zig +++ b/lib/compiler/Maker/Step/Compile.zig @@ -45,12 +45,14 @@ pub fn make( try lowerZigArgs(arena, compile, compile_index, maker, progress_node, &argv, false); + const incremental = conf_comp.flags4.incremental.toBool() orelse graph.incremental == true; + const maybe_output_dir = Step.evalZigProcess( compile_index, maker, argv.items, progress_node, - (graph.incremental == true) and (maker.watch or maker.web_server != null), + incremental and (maker.watch or maker.web_server != null), ) catch |err| switch (err) { error.NeedCompileErrorCheck => { try checkCompileErrors(arena, maker, compile_index); @@ -119,9 +121,9 @@ fn updateGeneratedFile( /// List of importable modules in a compilation's module graph, including /// the root module. The root module is guaranteed to be first. -const ModuleList = std.AutoArrayHashMapUnmanaged(Configuration.Module.Index, Configuration.String); +const ModuleList = std.array_hash_map.Auto(Configuration.Module.Index, Configuration.String); /// Keyed on the first key in the module list. -pub const ModuleGraph = std.ArrayHashMapUnmanaged(ModuleList, void, ModuleListContext, false); +pub const ModuleGraph = std.array_hash_map.Custom(ModuleList, void, ModuleListContext, false); const ModuleListContext = struct { pub fn eql(ctx: @This(), a: ModuleList, b: ModuleList) bool { @@ -221,8 +223,8 @@ fn lowerZigArgs( // module, along with any C compiler arguments that need to be passed // to the compiler for each module individually as reported by // pkg-config. - var seen_system_libs: std.AutoArrayHashMapUnmanaged(Configuration.String, []const []const u8) = .empty; - var frameworks: std.AutoArrayHashMapUnmanaged(Configuration.String, Configuration.Module.Framework.Flags) = .empty; + var seen_system_libs: std.array_hash_map.Auto(Configuration.String, []const []const u8) = .empty; + var frameworks: std.array_hash_map.Auto(Configuration.String, Configuration.Module.Framework.Flags) = .empty; var module_graph: ModuleGraph = .empty; var prev_has_cflags = false; @@ -767,18 +769,6 @@ fn lowerZigArgs( try zig_args.append(gpa, if (enabled) "--enable-new-dtags" else "--disable-new-dtags"); } - if (conf_comp.flags3.kind == .@"test" and conf_comp.exec_cmd_args.slice.len != 0) { - for (conf_comp.exec_cmd_args.slice) |cmd_arg| { - try zig_args.ensureUnusedCapacity(gpa, 2); - if (cmd_arg.slice(conf)) |arg| { - zig_args.appendAssumeCapacity("--test-cmd"); - zig_args.appendAssumeCapacity(arg); - } else { - zig_args.appendAssumeCapacity("--test-cmd-bin"); - } - } - } - if (graph.sysroot) |sysroot| try zig_args.appendSlice(gpa, &.{ "--sysroot", sysroot }); // -I and -L arguments that appear after the last --mod argument apply to all modules. @@ -861,7 +851,7 @@ fn lowerZigArgs( "--error-limit", try allocPrint(arena, "{d}", .{err_limit}), }; - try addFlag(gpa, zig_args, "incremental", graph.incremental); + try addFlag(gpa, zig_args, "incremental", conf_comp.flags4.incremental.toBool() orelse graph.incremental); try zig_args.append(gpa, "--listen=-"); @@ -984,6 +974,11 @@ fn addFlag(gpa: Allocator, args: *std.ArrayList([]const u8), comptime name: []co try args.append(gpa, if (cond) "-f" ++ name else "-fno-" ++ name); } +fn addArchFlag(gpa: Allocator, args: *std.ArrayList([]const u8), comptime name: []const u8, opt: ?bool) !void { + const cond = opt orelse return; + try args.append(gpa, if (cond) "-m" ++ name else "-mno-" ++ name); +} + fn checkCompileErrors(arena: Allocator, maker: *Maker, step_index: Configuration.Step.Index) Step.ExtendedMakeError!void { const step = maker.stepByIndex(step_index); const conf = &maker.scanned_config.configuration; @@ -1121,8 +1116,8 @@ fn moduleNeedsCliArg(mod: *const Configuration.Module, conf: *const Configuratio } const CliNamedModules = struct { - modules: std.AutoArrayHashMapUnmanaged(Configuration.Module.Index, void), - names: std.StringArrayHashMapUnmanaged(void), + modules: std.array_hash_map.Auto(Configuration.Module.Index, void), + names: std.array_hash_map.String(void), /// Traverse the whole dependency graph and give every module a unique /// name, ideally one named after what it's called somewhere in the graph. @@ -1172,7 +1167,7 @@ pub fn getCompileDependencies( start: Configuration.Step.Index, chase_dynamic: bool, ) ![]const Configuration.Step.Index { - var compiles: std.AutoArrayHashMapUnmanaged(Configuration.Step.Index, void) = .empty; + var compiles: std.array_hash_map.Auto(Configuration.Step.Index, void) = .empty; var compiles_i: usize = 0; try compiles.putNoClobber(arena, start, {}); @@ -1249,9 +1244,9 @@ fn appendModuleFlags( try addFlag(gpa, zig_args, "fuzz", m.flags.fuzz.toBool()); try addFlag(gpa, zig_args, "valgrind", m.flags2.valgrind.toBool()); try addFlag(gpa, zig_args, "PIC", m.flags2.pic.toBool()); - try addFlag(gpa, zig_args, "red-zone", m.flags2.red_zone.toBool()); try addFlag(gpa, zig_args, "no-builtin", m.flags2.no_builtin.toBool()); + try addArchFlag(gpa, zig_args, "red-zone", m.flags2.red_zone.toBool()); { try zig_args.ensureUnusedCapacity(gpa, 6); diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index 8b30753ecacc8b25c016286f6b110c13ed6f318c..9ca0b0071ef85554d51f6e2ee328f7bd93d29760 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -65,6 +65,12 @@ 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); + man.hash.addBytes(try cwd_path.toString(arena)); + } + man.hash.add(graph.fuzzing); man.hash.add(conf_run.flags.color); man.hash.add(conf_run.flags.disable_zig_progress); @@ -87,8 +93,9 @@ pub fn make( const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{ - prefix, try convertPathArg(arena, run_index, maker, file_path), suffix, + prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix, })); + man.hash.add(arg.flags.make_absolute); man.hash.addBytesZ(prefix); man.hash.addBytesZ(suffix); _ = try man.addFilePath(file_path, null); @@ -98,9 +105,10 @@ pub fn make( const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); const resolved_arg = try mem.concat(arena, u8, &.{ - prefix, try convertPathArg(arena, run_index, maker, file_path), suffix, + prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix, }); argv_list.appendAssumeCapacity(resolved_arg); + man.hash.add(arg.flags.make_absolute); man.hash.addBytes(resolved_arg); }, .file_content => { @@ -142,9 +150,12 @@ pub fn make( const file_path = producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?).*; argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{ - prefix, try convertPathArg(arena, run_index, maker, file_path), suffix, + prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix, })); + man.hash.add(arg.flags.make_absolute); + man.hash.addBytesZ(prefix); + man.hash.addBytesZ(suffix); _ = try man.addFilePath(file_path, null); }, .output_file, .output_directory => { @@ -152,6 +163,7 @@ pub fn make( const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; const basename = arg.basename.value.?.slice(conf); + man.hash.add(arg.flags.make_absolute); man.hash.addBytesZ(prefix); man.hash.addBytesZ(basename); man.hash.addBytesZ(suffix); @@ -181,7 +193,7 @@ pub fn make( man.hash.add(conf_run.flags.test_runner_mode); if (conf_run.flags.test_runner_mode) { - const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }); + const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false); try argv_list.ensureUnusedCapacity(gpa, 3); argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string})); @@ -1552,7 +1564,7 @@ pub fn rerunInFuzzMode( const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{ - prefix, try convertPathArg(arena, run_index, maker, file_path), suffix, + prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix, })); }, .path_directory => { @@ -1560,7 +1572,7 @@ pub fn rerunInFuzzMode( const suffix = if (arg.suffix.value) |p| p.slice(conf) else ""; const file_path = try maker.resolveLazyPathIndex(arena, arg.path.value.?, run_index); const resolved_arg = try mem.concat(arena, u8, &.{ - prefix, try convertPathArg(arena, run_index, maker, file_path), suffix, + prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix, }); argv_list.appendAssumeCapacity(resolved_arg); }, @@ -1602,7 +1614,7 @@ pub fn rerunInFuzzMode( producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?).*; argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{ - prefix, try convertPathArg(arena, run_index, maker, file_path), suffix, + prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix, })); }, .output_file => unreachable, @@ -1612,7 +1624,7 @@ pub fn rerunInFuzzMode( } if (conf_run.flags.test_runner_mode) { - const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }); + const cache_dir_string = try convertPathArg(arena, run_index, maker, .{ .root_dir = cache_root }, false); try argv_list.ensureUnusedCapacity(gpa, 3); argv_list.appendAssumeCapacity(try allocPrint(arena, "--cache-dir={s}", .{cache_dir_string})); @@ -1688,7 +1700,7 @@ fn populateGeneratedPathsCreateDirs( maker.generatedPath(arg.generated.value.?).* = generated_path; - const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path); + const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path, arg.flags.make_absolute); argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix }); } } @@ -1906,9 +1918,15 @@ fn runCommand( }, .wasmtime => |bin_name| { if (graph.enable_wasmtime) { - try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len); + try interp_argv.ensureUnusedCapacity(arena, 3 + argv.len + conf_run.preopen_names.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); + 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 allocPrint(arena, "--dir={f}::{s}", .{ path, name.slice(conf) })); + } // Wasmtime doeesn't inherit environment variables from the parent process // by default. '-S inherit-env' was added in Wasmtime version 20. interp_argv.appendAssumeCapacity("-Sinherit-env"); @@ -2100,6 +2118,67 @@ fn runCommand( }); } } + const snapshots: []const ?struct { + path: Cache.Path, + result: enum { stderr, stdout }, + } = &.{ + if (conf_run.expect_stderr_snapshot.value) |path| .{ + .path = try maker.resolveLazyPathIndex(arena, path, run_index), + .result = .stderr, + } else null, + if (conf_run.expect_stdout_snapshot.value) |path| .{ + .path = try maker.resolveLazyPathIndex(arena, path, run_index), + .result = .stdout, + } else null, + }; + for (snapshots) |opt_snapshot| { + const snapshot = opt_snapshot orelse continue; + + const file = snapshot.path.root_dir.handle.openFile(io, snapshot.path.sub_path, .{}) catch |err| + return step.fail(maker, "unable to open snapshot file {f}: {t}", .{ snapshot.path, err }); + defer file.close(io); + + var file_reader = file.reader(io, &.{}); + const snapshot_contents = file_reader.interface.allocRemaining(gpa, .unlimited) catch |err| + return step.fail(maker, "unable to read snapshot file {f}: {t}", .{ snapshot.path, err }); + defer gpa.free(snapshot_contents); + + const result = switch (snapshot.result) { + .stderr => generic_result.stderr.?, + .stdout => generic_result.stdout.?, + }; + if (std.mem.findDiff(u8, snapshot_contents, result)) |diff_index| { + var diff_line_number: usize = 1; + + for (snapshot_contents[0..diff_index]) |value| { + if (value == '\n') diff_line_number += 1; + } + + return step.fail(maker, + \\ + \\========= snapshot file: ========= + \\{f} + \\========= contained: ============= + \\{s} + \\========= {t} output was: ======== + \\{s} + \\================================== + \\first difference on line {d}: + \\expected: + \\{f} + \\found: + \\{f} + , .{ + snapshot.path, + snapshot_contents, + snapshot.result, + result, + diff_line_number, + fmtSnapshotIndicatorLine(snapshot_contents, diff_index), + fmtSnapshotIndicatorLine(result, diff_index), + }); + } + } }, else => { // On failure, report captured stderr like normal standard error output. @@ -2113,6 +2192,38 @@ fn runCommand( } } +const FmtIndicatorLine = struct { + buf: []const u8, + index: usize, +}; + +fn fmtSnapshotIndicatorLine(buf: []const u8, index: usize) std.fmt.Alt( + FmtIndicatorLine, + snapshotIndicatorLine, +) { + return .{ .data = .{ .buf = buf, .index = index } }; +} + +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| + line_begin + 1 + else + 0; + const line_end_index = if (std.mem.findScalar(u8, line.buf[line.index..], '\n')) |line_end| + (line.index + line_end) + else + line.buf.len; + + try w.writeAll(line.buf[line_begin_index..line_end_index]); + try w.writeByte('\n'); + try w.splatByteAll(' ', line_end_index - line_begin_index); + try w.writeByte('\n'); + if (line.index >= line.buf.len) + try w.writeAll("^ (end of file)") + else + try w.print("^ ('\\x{x:0>2}')\n", .{line.buf[line.index]}); +} + const EvalGenericResult = struct { term: process.Child.Term, stdout: ?[]const u8, @@ -2195,6 +2306,7 @@ fn spawnChildAndCollect( }; if (conf_run.flags.stdio == .zig_test) { + try setColorEnvironmentVariables(&conf_run, environ_map, graph.stderr_mode.?); const started: Io.Clock.Timestamp = .now(io, .awake); const result = evalZigTest(run, run_index, maker, progress_node, spawn_options, fuzz_context) catch |err| switch (err) { error.Canceled => |e| return e, @@ -2283,18 +2395,29 @@ fn setColorEnvironmentVariables( } fn checksContainStdout(conf_run: *const Configuration.Step.Run) bool { - return conf_run.expect_stdout_exact.value != null or conf_run.expect_stdout_match.slice.len != 0; + return conf_run.expect_stdout_exact.value != null or + conf_run.expect_stdout_match.slice.len != 0 or + conf_run.expect_stdout_snapshot.value != null; } fn checksContainStderr(conf_run: *const Configuration.Step.Run) bool { - return conf_run.expect_stderr_exact.value != null or conf_run.expect_stderr_match.slice.len != 0; + return conf_run.expect_stderr_exact.value != null or + conf_run.expect_stderr_match.slice.len != 0 or + conf_run.expect_stderr_snapshot.value != null; } -/// If `path` is cwd-relative, make it relative to the cwd of the child instead. +/// If `path` is absolute, return it unchanged. If `make_absolute` is true, make it absolute. +/// Otherwise, make it relative to the cwd of the child. /// -/// Whenever a path is included in the argv of a child, it should be put through this function first -/// to make sure the child doesn't see paths relative to a cwd other than its own. -fn convertPathArg(arena: Allocator, run_index: Configuration.Step.Index, maker: *Maker, path: Path) ![]const u8 { +/// Whenever a path is included in the argv of a child, it should be put through this function +/// first. +fn convertPathArg( + arena: Allocator, + run_index: Configuration.Step.Index, + maker: *Maker, + path: Path, + make_absolute: bool, +) ![]const u8 { const conf = &maker.scanned_config.configuration; const conf_step = run_index.ptr(conf); const conf_run = conf_step.extended.get(conf.extra).run; @@ -2305,6 +2428,11 @@ fn convertPathArg(arena: Allocator, run_index: Configuration.Step.Index, maker: // Absolute paths don't need changing. return path_str; } + + if (make_absolute) { + return Dir.path.join(arena, &.{ graph.cache.cwd, path_str }); + } + const child_cwd_rel: []const u8 = rel: { const child_lazy_cwd = conf_run.cwd.value orelse break :rel path_str; const child_cwd = try maker.resolveLazyPathIndexAbs(arena, child_lazy_cwd, run_index); diff --git a/lib/compiler/Maker/Step/TranslateC.zig b/lib/compiler/Maker/Step/TranslateC.zig index d9bbd6ad4cb2b20deaf3da3f74cc56409a491598..11b30e89b6ec6a677e04df4622bee15a3a4c0bd2 100644 --- a/lib/compiler/Maker/Step/TranslateC.zig +++ b/lib/compiler/Maker/Step/TranslateC.zig @@ -66,7 +66,7 @@ pub fn make( var prev_search_strategy: std.Build.Module.SystemLib.SearchStrategy = .paths_first; var prev_preferred_link_mode: std.builtin.LinkMode = .dynamic; - var seen_system_libs: std.AutoArrayHashMapUnmanaged(Configuration.String, []const []const u8) = .empty; + var seen_system_libs: std.array_hash_map.Auto(Configuration.String, []const []const u8) = .empty; for (conf_tc.system_libs.slice) |system_lib_index| { const system_lib = system_lib_index.get(conf); diff --git a/lib/compiler/Maker/Watch.zig b/lib/compiler/Maker/Watch.zig index 603b9c911d696ad94f0ea5d250df07236cec78d6..fb8bca122804d0ba963f3827e29f38d69b40444e 100644 --- a/lib/compiler/Maker/Watch.zig +++ b/lib/compiler/Maker/Watch.zig @@ -27,11 +27,11 @@ pub const have_impl = Os != void; /// interested in noticing changes to. /// /// Value is generation. -const DirTable = std.ArrayHashMapUnmanaged(Cache.Path, void, Cache.Path.TableAdapter, false); +const DirTable = std.array_hash_map.Custom(Cache.Path, void, Cache.Path.TableAdapter, false); /// Special key of "." means any changes in this directory trigger the steps. -const ReactionSet = std.StringArrayHashMapUnmanaged(StepSet); -const StepSet = std.AutoArrayHashMapUnmanaged(Configuration.Step.Index, Generation); +const ReactionSet = std.array_hash_map.String(StepSet); +const StepSet = std.array_hash_map.Auto(Configuration.Step.Index, Generation); const Generation = u8; @@ -46,10 +46,10 @@ const Os = switch (builtin.os.tag) { handle_table: HandleTable, /// fanotify file descriptors are keyed by mount id since marks /// are limited to a single filesystem. - poll_fds: std.AutoArrayHashMapUnmanaged(MountId, posix.pollfd), + poll_fds: std.array_hash_map.Auto(MountId, posix.pollfd), const MountId = i32; - const HandleTable = std.ArrayHashMapUnmanaged(FileHandle, struct { mount_id: MountId, reaction_set: ReactionSet }, FileHandle.Adapter, false); + const HandleTable = std.array_hash_map.Custom(FileHandle, struct { mount_id: MountId, reaction_set: ReactionSet }, FileHandle.Adapter, false); const fan_mask: std.os.linux.fanotify.MarkMask = .{ .CLOSE_WRITE = true, @@ -314,7 +314,7 @@ const Os = switch (builtin.os.tag) { const windows = std.os.windows; /// Keyed differently but indexes correspond 1:1 with `dir_table`. - handle_table: std.ArrayHashMapUnmanaged(*Directory, void, Directory.TableAdapter, false), + handle_table: std.array_hash_map.Custom(*Directory, void, Directory.TableAdapter, false), ready_dirs: std.DoublyLinkedList, const FileId = struct { diff --git a/lib/compiler/aro/aro/Compilation.zig b/lib/compiler/aro/aro/Compilation.zig index 978bbcffc8ea121ebbcdfd7bda6c9dfcd24e636d..f1dc72ae86c5f15611e77cbdbf69a28339d2b275 100644 --- a/lib/compiler/aro/aro/Compilation.zig +++ b/lib/compiler/aro/aro/Compilation.zig @@ -140,7 +140,7 @@ io: Io, cwd: std.Io.Dir, diagnostics: *Diagnostics, -sources: std.StringArrayHashMapUnmanaged(Source) = .empty, +sources: std.array_hash_map.String(Source) = .empty, source_aliases: std.ArrayList(Source) = .empty, /// Allocated into `gpa`, but keys are externally managed. search_path: std.ArrayList(Include) = .empty, @@ -159,7 +159,7 @@ builtins: Builtins = .{}, string_interner: StringInterner = .{}, interner: Interner = .{}, type_store: TypeStore = .{}, -pragma_handlers: std.StringArrayHashMapUnmanaged(*Pragma) = .empty, +pragma_handlers: std.array_hash_map.String(*Pragma) = .empty, /// If this is not null, the directory containing the specified Source will be searched for includes /// Used by MS extensions which allow searching for includes relative to the directory of the main source file. ms_cwd_source_id: ?Source.Id = null, diff --git a/lib/compiler/aro/aro/DepFile.zig b/lib/compiler/aro/aro/DepFile.zig index a8f8d7cbaebe944adff461abadd38d3396fbf117..ba8d5c92b58e7d403544cc2a020e5420add2d979 100644 --- a/lib/compiler/aro/aro/DepFile.zig +++ b/lib/compiler/aro/aro/DepFile.zig @@ -6,7 +6,7 @@ pub const Format = enum { make, nmake }; const DepFile = @This(); target: []const u8, -deps: std.StringArrayHashMapUnmanaged(void) = .empty, +deps: std.array_hash_map.String(void) = .empty, format: Format, pub fn deinit(d: *DepFile, gpa: Allocator) void { diff --git a/lib/compiler/aro/aro/Preprocessor.zig b/lib/compiler/aro/aro/Preprocessor.zig index 6b52492e7d9a09a1650c7ffdf27cd6ffd09cdad4..2018da7bd023d347fdedccfadf029a25140b4054 100644 --- a/lib/compiler/aro/aro/Preprocessor.zig +++ b/lib/compiler/aro/aro/Preprocessor.zig @@ -23,7 +23,7 @@ const Tree = @import("Tree.zig"); const Token = Tree.Token; const TokenWithExpansionLocs = Tree.TokenWithExpansionLocs; -const DefineMap = std.StringArrayHashMapUnmanaged(Macro); +const DefineMap = std.array_hash_map.String(Macro); const RawTokenList = std.ArrayList(RawToken); const max_include_depth = 200; diff --git a/lib/compiler/aro/aro/StringInterner.zig b/lib/compiler/aro/aro/StringInterner.zig index e22ec23a467f20fcba6184628fc9ddddbb45a626..021bd3f602438587c91d8db63de450ba58098d65 100644 --- a/lib/compiler/aro/aro/StringInterner.zig +++ b/lib/compiler/aro/aro/StringInterner.zig @@ -19,7 +19,7 @@ pub const StringId = enum(u32) { } }; -table: std.StringArrayHashMapUnmanaged(void) = .empty, +table: std.array_hash_map.String(void) = .empty, pub fn deinit(si: *StringInterner, allocator: mem.Allocator) void { si.table.deinit(allocator); diff --git a/lib/compiler/aro/backend/Interner.zig b/lib/compiler/aro/backend/Interner.zig index 027c411d637cf35c2534dd8f8b22128ac927cbbe..6a7fe6fd0772d478ac9ff0d30cbeb7064819cee8 100644 --- a/lib/compiler/aro/backend/Interner.zig +++ b/lib/compiler/aro/backend/Interner.zig @@ -8,7 +8,7 @@ const Limb = std.math.big.Limb; const Interner = @This(); -map: std.AutoArrayHashMapUnmanaged(void, void) = .empty, +map: std.array_hash_map.Auto(void, void) = .empty, items: std.MultiArrayList(struct { tag: Tag, data: u32, diff --git a/lib/compiler/aro/backend/Ir.zig b/lib/compiler/aro/backend/Ir.zig index ae4fa2a6d30fb4910b9409f0f11b6acf1256cdec..f35eca40f7af811593b8a4161ad8d575f44609ce 100644 --- a/lib/compiler/aro/backend/Ir.zig +++ b/lib/compiler/aro/backend/Ir.zig @@ -7,7 +7,7 @@ const Object = @import("Object.zig"); const Ir = @This(); interner: *Interner, -decls: std.StringArrayHashMapUnmanaged(Decl), +decls: std.array_hash_map.String(Decl), pub const Decl = struct { instructions: std.MultiArrayList(Inst), @@ -26,7 +26,7 @@ pub const Builder = struct { arena: std.heap.ArenaAllocator, interner: *Interner, - decls: std.StringArrayHashMapUnmanaged(Decl) = .empty, + decls: std.array_hash_map.String(Decl) = .empty, instructions: std.MultiArrayList(Ir.Inst) = .empty, body: std.ArrayList(Ref) = .empty, alloc_count: u32 = 0, @@ -181,7 +181,7 @@ pub const Renderer = struct { ir: *const Ir, errors: ErrorList = .{}, - pub const ErrorList = std.StringArrayHashMapUnmanaged([]const u8); + pub const ErrorList = std.array_hash_map.String([]const u8); pub const Error = Allocator.Error || error{LowerFail}; @@ -380,7 +380,7 @@ const REF = std.Io.Terminal.Color.bright_blue; const LITERAL = std.Io.Terminal.Color.bright_green; const ATTRIBUTE = std.Io.Terminal.Color.bright_yellow; -const RefMap = std.AutoArrayHashMapUnmanaged(Ref, void); +const RefMap = std.array_hash_map.Auto(Ref, void); pub const DumpError = std.Io.Terminal.SetColorError || std.mem.Allocator.Error; diff --git a/lib/compiler/configurer.zig b/lib/compiler/configurer.zig index cdd86f87d4ae8f5fb8fb770424b6da7a5e810a5a..f044dc311945d20b330d472553ad5dded0d3138f 100644 --- a/lib/compiler/configurer.zig +++ b/lib/compiler/configurer.zig @@ -160,10 +160,10 @@ pub fn main(init: process.Init.Minimal) !void { const Serialize = struct { arena: Allocator, wc: *Configuration.Wip, - module_map: std.AutoArrayHashMapUnmanaged(*std.Build.Module, Configuration.Module.Index) = .empty, - package_map: std.AutoArrayHashMapUnmanaged(*std.Build, Configuration.Package.Index) = .empty, + 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, /// Index corresponds to `Configuration.steps` index. - step_map: std.AutoArrayHashMapUnmanaged(*Step, void) = .empty, + step_map: std.array_hash_map.Auto(*Step, void) = .empty, fn builderToPackage(s: *Serialize, b: *std.Build) !Configuration.Package.Index { if (b.pkg_hash.len == 0) return .root; @@ -312,15 +312,16 @@ const Serialize = struct { .flags = .{ .tag = .artifact, .prefix = a.prefix.len != 0, - .suffix = false, + .suffix = a.suffix.len != 0, .basename = false, .path = false, .producer = true, .generated = false, .dep_file = false, + .make_absolute = a.make_absolute, }, .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null }, - .suffix = .{ .value = null }, + .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null }, .basename = .{ .value = null }, .path = .{ .value = null }, .producer = .{ .value = stepIndex(s, &a.artifact.step) }, @@ -330,15 +331,16 @@ const Serialize = struct { .flags = .{ .tag = .path_file, .prefix = a.prefix.len != 0, - .suffix = false, + .suffix = a.suffix.len != 0, .basename = false, .path = true, .producer = false, .generated = false, .dep_file = false, + .make_absolute = a.make_absolute, }, .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null }, - .suffix = .{ .value = null }, + .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null }, .basename = .{ .value = null }, .path = .{ .value = try addLazyPath(s, a.lazy_path) }, .producer = .{ .value = null }, @@ -354,6 +356,7 @@ const Serialize = struct { .producer = false, .generated = false, .dep_file = false, + .make_absolute = a.make_absolute, }, .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null }, .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null }, @@ -366,15 +369,16 @@ const Serialize = struct { .flags = .{ .tag = .file_content, .prefix = a.prefix.len != 0, - .suffix = false, + .suffix = a.suffix.len != 0, .basename = false, .path = true, .producer = false, .generated = false, .dep_file = false, + .make_absolute = false, }, .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null }, - .suffix = .{ .value = null }, + .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null }, .basename = .{ .value = null }, .path = .{ .value = try addLazyPath(s, a.lazy_path) }, .producer = .{ .value = null }, @@ -390,6 +394,7 @@ const Serialize = struct { .producer = false, .generated = false, .dep_file = false, + .make_absolute = false, }, .prefix = .{ .value = try wc.addString(a) }, .suffix = .{ .value = null }, @@ -402,15 +407,16 @@ const Serialize = struct { .flags = .{ .tag = .output_file, .prefix = a.prefix.len != 0, - .suffix = false, + .suffix = a.suffix.len != 0, .basename = a.basename.len != 0, .path = false, .producer = false, .generated = true, .dep_file = tag == .output_file_dep, + .make_absolute = a.make_absolute, }, .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null }, - .suffix = .{ .value = null }, + .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null }, .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null }, .path = .{ .value = null }, .producer = .{ .value = null }, @@ -420,15 +426,16 @@ const Serialize = struct { .flags = .{ .tag = .output_directory, .prefix = a.prefix.len != 0, - .suffix = false, + .suffix = a.suffix.len != 0, .basename = a.basename.len != 0, .path = false, .producer = false, .generated = true, .dep_file = false, + .make_absolute = a.make_absolute, }, .prefix = .{ .value = if (a.prefix.len != 0) try wc.addString(a.prefix) else null }, - .suffix = .{ .value = null }, + .suffix = .{ .value = if (a.suffix.len != 0) try wc.addString(a.suffix) else null }, .basename = .{ .value = if (a.basename.len != 0) try wc.addString(a.basename) else null }, .path = .{ .value = null }, .producer = .{ .value = null }, @@ -444,6 +451,7 @@ const Serialize = struct { .producer = false, .generated = false, .dep_file = false, + .make_absolute = false, }, .prefix = .{ .value = null }, .suffix = .{ .value = null }, @@ -668,7 +676,6 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { }, .compile => e: { const c: *Step.Compile = @fieldParentPtr("step", step); - const exec_cmd_args: []const ?[]const u8 = c.exec_cmd_args orelse &.{}; const installed_headers: []u32 = try arena.alloc(u32, c.installed_headers.items.len); for (installed_headers, c.installed_headers.items) |*dst, src| switch (src) { .file => |file| { @@ -695,7 +702,6 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { break :e try wc.addExtraErased(Configuration.Step.Compile, .{ .flags = .{ .filters_len = c.filters.len != 0, - .exec_cmd_args_len = exec_cmd_args.len != 0, .installed_headers_len = installed_headers.len != 0, .force_undefined_symbols_len = c.force_undefined_symbols.entries.len != 0, @@ -797,6 +803,7 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { .generated_llvm_bc = c.generated_llvm_bc != .none, .generated_llvm_ir = c.generated_llvm_ir != .none, .generated_h = c.generated_h != .none, + .incremental = .init(c.incremental), }, .root_module = try s.addModule(c.root_module), .root_name = try wc.addString(c.name), @@ -828,7 +835,6 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { .none, .fast, .uuid, .sha1, .md5 => null, } else null }, .filters = .{ .slice = try s.initStringList(c.filters) }, - .exec_cmd_args = .{ .slice = try s.initOptionalStringList(exec_cmd_args) }, .installed_headers = .initErased(installed_headers), .force_undefined_symbols = .{ .slice = try s.initStringList(c.force_undefined_symbols.keys()) }, .expect_errors = .{ .u = if (c.expect_errors) |x| switch (x) { @@ -1005,6 +1011,8 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { status: Configuration.Step.Run.ExpectTermStatus, value: u32, } = null; + var expect_stderr_snapshot: ?Configuration.LazyPath.Index = null; + var expect_stdout_snapshot: ?Configuration.LazyPath.Index = null; switch (run.stdio) { .check => |checks| for (checks.items) |check| switch (check) { .expect_stderr_exact => |bytes| expect_stderr_exact = try wc.addBytes(bytes), @@ -1021,6 +1029,8 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { .stopped => |x| .{ .status = .stopped, .value = @intFromEnum(x) }, .unknown => |x| .{ .status = .unknown, .value = x }, }, + .expect_stderr_snapshot => |path| expect_stderr_snapshot = try s.addLazyPath(path), + .expect_stdout_snapshot => |path| expect_stdout_snapshot = try s.addLazyPath(path), }, else => {}, } @@ -1060,17 +1070,21 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { .expect_stdout_match = expect_stdout_match.items.len != 0, .expect_term = expect_term != null, .expect_term_status = if (expect_term) |t| t.status else .exited, + .expect_stderr_snapshot = expect_stderr_snapshot != null, + .expect_stdout_snapshot = expect_stdout_snapshot != null, }, .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()) }, .captured_stdout = .{ .value = if (run.captured_stdout) |cs| .{ - .basename = try wc.addString(cs.output.basename), - .generated_file = cs.output.generated_file, + .basename = try wc.addString(cs.basename), + .generated_file = cs.generated_file, } else null }, .captured_stderr = .{ .value = if (run.captured_stderr) |cs| .{ - .basename = try wc.addString(cs.output.basename), - .generated_file = cs.output.generated_file, + .basename = try wc.addString(cs.basename), + .generated_file = cs.generated_file, } else null }, .environ_map = .{ .value = try s.addEnvironMap(run.environ_map) }, .expect_term_value = .{ .value = if (expect_term) |t| t.value else null }, @@ -1080,6 +1094,8 @@ fn serialize(b: *std.Build, wc: *Configuration.Wip, writer: *Io.Writer) !void { .expect_stdout_exact = .{ .value = if (expect_stdout_exact) |bytes| bytes else null }, .expect_stderr_match = .{ .slice = expect_stderr_match.items }, .expect_stdout_match = .{ .slice = expect_stdout_match.items }, + .expect_stderr_snapshot = .{ .value = expect_stderr_snapshot orelse null }, + .expect_stdout_snapshot = .{ .value = expect_stdout_snapshot orelse null }, .stdin = .{ .u = switch (run.stdin) { .none => .none, .bytes => |bytes| .{ .bytes = try wc.addBytes(bytes) }, diff --git a/lib/compiler/objdump.zig b/lib/compiler/objdump.zig index d2af9c09c6e6e344794d0aaaa26f45efc2ce5d4c..c3f6f5e8a7a444862b1396427fcf589805725942 100644 --- a/lib/compiler/objdump.zig +++ b/lib/compiler/objdump.zig @@ -4,19 +4,149 @@ const fatal = std.process.fatal; const mem = std.mem; const assert = std.debug.assert; +const builtin = @import("builtin"); +const native_endian = builtin.cpu.arch.endian(); + var stdout_buffer: [4000]u8 = undefined; +const Options = struct { + exports: bool, + exports_sort: bool, + file_headers: bool, + imports: bool, + input_path: []const u8, + member_filters: []const []const u8 = &.{}, + member_headers: bool, + elements: std.enums.EnumArray(Element, bool), + redact: std.enums.EnumArray(FieldKind, bool), + relocs: bool, + section_filters: []const []const u8 = &.{}, + section_headers: bool, + symbol_filters: []const []const u8 = &.{}, + strings: bool, + symbols: bool, + tls: bool, + + // Coff-specific + linker_member: ?std.coff.ArchiveMemberHeader.Kind, +}; + +const FieldKind = enum { + va, + rva, + ord, + size, +}; + +const Element = enum { + @"file-type", + @"header-name", + @"member-path", + newlines, + @"table-header", +}; + pub fn main(init: std.process.Init) !void { const io = init.io; const args = try init.minimal.args.toSlice(init.arena.allocator()); + const arena = init.arena.allocator(); - var opt_input_path: ?[]const u8 = null; var i: usize = 1; + + var opt_exports: ?bool = null; + var opt_exports_sort: ?bool = null; + var opt_file_headers: ?bool = null; + var opt_imports: ?bool = null; + var opt_input_path: ?[]const u8 = null; + var opt_linker_member: ?std.coff.ArchiveMemberHeader.Kind = null; + var opt_member_headers: ?bool = null; + var any_elements = false; + var elements: ?@FieldType(Options, "elements") = null; + var redact: @FieldType(Options, "redact") = .initFill(false); + var opt_relocs: ?bool = null; + var opt_section_headers: ?bool = null; + var opt_strings: ?bool = null; + var opt_symbols: ?bool = null; + var opt_tls: ?bool = null; + var section_filters: std.ArrayList([]const u8) = .empty; + var symbol_filters: std.ArrayList([]const u8) = .empty; + var member_filters: std.ArrayList([]const u8) = .empty; while (i < args.len) : (i += 1) { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { return Io.File.stdout().writeStreamingAll(io, usage); + } else if (mem.eql(u8, arg, "--all-headers")) { + opt_file_headers = true; + opt_linker_member = .second_linker; + opt_member_headers = true; + opt_section_headers = true; + opt_symbols = true; + opt_relocs = true; + } else if (mem.startsWith(u8, arg, "--exports")) { + opt_exports = true; + opt_linker_member = .second_linker; + if (mem.eql(u8, arg["--exports".len..], "=sort")) + opt_exports_sort = true; + } else if (mem.eql(u8, arg, "--file-headers")) { + opt_file_headers = true; + } else if (mem.eql(u8, arg, "--imports")) { + opt_imports = true; + } else if (mem.startsWith(u8, arg, "--linker-member")) { + if (mem.eql(u8, arg["--linker-member".len..], "=1")) + opt_linker_member = .first_linker + else if (mem.eql(u8, arg["--linker-member".len..], "=longnames")) + opt_linker_member = .longnames + else + opt_linker_member = .second_linker; + } else if (mem.eql(u8, arg, "--member-headers")) { + opt_member_headers = true; + } else if (mem.startsWith(u8, arg, "--elements=")) { + any_elements = true; + var split = std.mem.splitScalar(u8, arg["--elements=".len..], ','); + while (split.next()) |element| { + const kind, const add = if (element.len > 0 and element[0] == '-') + .{ element[1..], false } + else + .{ element, true }; + + if (elements == null) elements = .initFill(false); + if (std.meta.stringToEnum(Element, kind)) |format_kind| { + elements.?.set(format_kind, add); + } else if (std.mem.eql(u8, kind, "all")) { + elements.? = .initFill(add); + } else { + fatal("unrecognized element: '{s}'", .{kind}); + } + } + } else if (mem.startsWith(u8, arg, "--only-member=")) { + (try member_filters.addOne(arena)).* = try arena.dupe(u8, arg["--only-member=".len..]); + } else if (mem.startsWith(u8, arg, "--only-section=")) { + (try section_filters.addOne(arena)).* = try arena.dupe(u8, arg["--only-section=".len..]); + } else if (mem.startsWith(u8, arg, "--only-symbol=")) { + (try symbol_filters.addOne(arena)).* = try arena.dupe(u8, arg["--only-symbol=".len..]); + } else if (mem.startsWith(u8, arg, "--redact=")) { + const kind = arg["--redact=".len..]; + if (std.meta.stringToEnum(FieldKind, kind)) |field_kind| { + redact.set(field_kind, true); + } else if (std.mem.eql(u8, kind, "all")) { + redact = .initFill(true); + } else { + fatal("unrecognized redaction kind: {s}", .{kind}); + } + } else if (mem.eql(u8, arg, "--relocs")) { + opt_relocs = true; + } else if (mem.eql(u8, arg, "--section-headers")) { + opt_section_headers = true; + } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--snapshot")) { + elements = .initFill(false); + redact = .initFill(true); + } else if (mem.eql(u8, arg, "--strings")) { + opt_strings = true; + } else if (mem.eql(u8, arg, "--symbols")) { + opt_symbols = true; + } else if (mem.eql(u8, arg, "--tls")) { + opt_tls = true; } else { fatal("unrecognized argument: {s}", .{arg}); } @@ -27,42 +157,134 @@ pub fn main(init: std.process.Init) !void { } } - const input_path = opt_input_path orelse fatal("missing input file path positional argument", .{}); + const opts: Options = .{ + .input_path = opt_input_path orelse fatal("missing input file path positional argument", .{}), + .exports = opt_exports orelse false, + .exports_sort = opt_exports_sort orelse false, + .file_headers = opt_file_headers orelse false, + .imports = opt_imports orelse false, + .linker_member = opt_linker_member, + .member_filters = member_filters.items, + .member_headers = opt_member_headers orelse false, + .elements = elements orelse .initFill(true), + .redact = redact, + .relocs = opt_relocs orelse false, + .section_filters = section_filters.items, + .section_headers = opt_section_headers orelse false, + .strings = opt_strings orelse false, + .symbol_filters = symbol_filters.items, + .symbols = opt_symbols orelse false, + .tls = opt_tls orelse false, + }; - var file = std.Io.Dir.cwd().openFile(io, input_path, .{}) catch |err| - fatal("failed to open {s}: {t}", .{ input_path, err }); + var file = std.Io.Dir.cwd().openFile(io, opts.input_path, .{}) catch |err| + fatal("failed to open {s}: {t}", .{ opts.input_path, err }); defer file.close(io); - var buffer: [4000]u8 = undefined; + var buffer: [4096]u8 = undefined; var file_reader = file.reader(io, &buffer); var stdout_writer = std.Io.File.stdout().writerStreaming(io, &stdout_buffer); - dump(&file_reader.interface, &stdout_writer.interface) catch |err| switch (err) { + + const ctx: DumpContext = .{ + .gpa = init.gpa, + .opts = &opts, + .fr = &file_reader, + .w = &stdout_writer.interface, + }; + + dump(&ctx) catch |err| switch (err) { error.ReadFailed => return file_reader.err.?, error.WriteFailed => return stdout_writer.err.?, - error.UnknownFile => fatal("unrecognized file: {s}", .{input_path}), + error.UnknownFile => fatal("unrecognized file: {s}", .{opts.input_path}), + error.ParseFailure => {}, else => |e| return e, }; try stdout_writer.flush(); } -fn dump(r: *Io.Reader, w: *Io.Writer) !void { +fn dump(d: *const DumpContext) !void { + const r = &d.fr.interface; try r.fill(4); elf: { if (!mem.eql(u8, r.buffered()[0..4], std.elf.MAGIC)) break :elf; - return elf.dump(r, w); + return elf.dump(r, d.w); } macho: { if (mem.readInt(u32, r.buffered()[0..4], .little) != std.macho.MH_MAGIC_64) break :macho; - return macho.dump(r, w); + return macho.dump(r, d.w); } wasm: { comptime assert(std.wasm.magic.len == 4); if (!mem.eql(u8, r.buffered()[0..4], &std.wasm.magic)) break :wasm; - return wasm.dump(r, w); + return wasm.dump(r, d.w); + } + coff: { + const ext = std.fs.path.extension(d.opts.input_path); + const basename = std.fs.path.basename(d.opts.input_path); + if (std.mem.eql(u8, ext, ".exe") or std.mem.eql(u8, ext, ".dll")) { + if (!mem.eql(u8, r.buffered()[0..2], "MZ")) break :coff; + try r.discardAll(std.coff.pe_pointer_offset); + const sig_offset = try r.takeInt(u32, .little); + try d.fr.seekTo(sig_offset); + const sig = try r.take(4); + + if (!std.mem.eql(u8, sig, std.coff.pe_signature)) { + try d.w.print("invalid PE signature: {x}", .{sig}); + return error.ParseFailure; + } + + if (d.element(.@"file-type")) { + try d.w.print("{s}: PE/COFF image\n\n", .{basename}); + if (d.element(.newlines)) try d.w.writeByte('\n'); + } + + return coff.dumpObject(d, true, basename); + } else if (std.mem.eql(u8, ext, ".lib")) { + r.fill(std.coff.archive_signature.len) catch break :coff; + if (!mem.eql(u8, r.buffered()[0..std.coff.archive_signature.len], std.coff.archive_signature)) break :coff; + if (d.element(.@"file-type")) { + try d.w.print("{s}: COFF archive\n", .{basename}); + if (d.element(.newlines)) try d.w.writeByte('\n'); + } + + return coff.dumpArchive(d); + } else if (std.mem.eql(u8, ext, ".obj")) { + if (d.element(.@"file-type")) { + try d.w.print("{s}: COFF object\n", .{basename}); + if (d.element(.newlines)) try d.w.writeByte('\n'); + } + + return coff.dumpObject(d, false, basename); + } } return error.UnknownFile; } +const DumpContext = struct { + gpa: std.mem.Allocator, + opts: *const Options, + fr: *Io.File.Reader, + w: *Io.Writer, + + fn element(self: *const DumpContext, e: Element) bool { + return self.opts.elements.get(e); + } + + fn redacted(self: *const DumpContext, opt_kind: ?FieldKind) bool { + const kind = opt_kind orelse return false; + return self.opts.redact.get(kind); + } + + fn failParse( + ctx: *const DumpContext, + comptime fmt: []const u8, + args: anytype, + ) noreturn { + std.log.err("error parsing '{s}'", .{std.fs.path.basename(ctx.opts.input_path)}); + fatal(fmt, args); + } +}; + const elf = struct { fn dump(r: *Io.Reader, w: *Io.Writer) !void { _ = r; @@ -84,10 +306,1478 @@ const wasm = struct { } }; +const coff = struct { + const DIRECTORY_ENTRY = std.coff.IMAGE.DIRECTORY_ENTRY; + + const Section = struct { + header: std.coff.SectionHeader, + name: []const u8, + + fn rvaFileOffset(section: *const Section, rva: u32) !u32 { + if (rva < section.header.virtual_address or + rva >= section.header.virtual_address + section.header.size_of_raw_data) + return error.OutOfBounds; + + return section.header.pointer_to_raw_data + (rva - section.header.virtual_address); + } + }; + + const ArchiveHeader = struct { + name: []const u8, + date: u40, + user_id: u20, + group_id: u20, + file_mode: u24, + size: u34, + + pub fn fromRaw(d: *const DumpContext, raw_header: *const std.coff.ArchiveMemberHeader, opt_longnames: ?[]const u8) @This() { + const name = raw_header.parseName(opt_longnames) catch |err| switch (err) { + error.BadName => d.failParse("malformed member name: '{s}'", .{&raw_header.name}), + error.NoLongNames => d.failParse("member uses a long name, but there was no longnames member", .{}), + }; + + return .{ + .name = name, + .date = raw_header.parseDate() catch |err| + d.failParse("unable to parse date '{s}' in member '{s}': {t}", .{ raw_header.date, name, err }), + .user_id = raw_header.parseUserId() catch |err| + d.failParse("unable to parse user_id '{s}' in member '{s}': {t}", .{ raw_header.user_id, name, err }), + .group_id = raw_header.parseGroupId() catch |err| + d.failParse("unable to parse group_id '{s}' in member '{s}': {t}", .{ raw_header.group_id, name, err }), + .file_mode = raw_header.parseFileMode() catch |err| + d.failParse("unable to parse file_mode '{s}' in member '{s}': {t}", .{ raw_header.file_mode, name, err }), + .size = raw_header.parseSize() catch |err| + d.failParse("unable to parse size '{s}' in member '{s}': {t}", .{ raw_header.size, name, err }), + }; + } + }; + + fn dumpArchive(d: *const DumpContext) !void { + const gpa = d.gpa; + const fr = d.fr; + const w = d.w; + + const r = &fr.interface; + r.toss(std.coff.archive_signature.len); + + const Member = struct { + offset: u32, + order: ?u32, + }; + + var members: std.ArrayList(Member) = .empty; + defer members.deinit(gpa); + var symbol_member_indices: std.ArrayList(u32) = .empty; + defer symbol_member_indices.deinit(gpa); + + var opt_expected_kind: ?std.coff.ArchiveMemberHeader.Kind = .first_linker; + var opt_longnames: ?[]const u8 = null; + defer if (opt_longnames) |l| gpa.free(l); + + var pos = fr.logicalPos(); + const size = try fr.getSize(); + while (pos < size) : (pos = fr.logicalPos()) { + if ((pos & 1) != 0) try r.discardAll(1); + const raw_header = try r.takeStruct(std.coff.ArchiveMemberHeader, .little); + const header: ArchiveHeader = .fromRaw(d, &raw_header, opt_longnames); + + if (!std.mem.eql(u8, &raw_header.end_of_header, std.coff.archive_end_of_header)) + return d.failParse("malformed end-of-header field in member '{s}': {x}", .{ header.name, raw_header.end_of_header }); + + const dump_header = + (d.opts.member_headers and filterMatches(d.opts.member_filters, header.name)) or + (d.opts.linker_member == opt_expected_kind); + + if (dump_header) + try dumpArchiveHeader(d, &header, @intCast(pos)); + + const member_end = fr.logicalPos() + header.size; + if (member_end > size) + return d.failParse("out-of-bounds length 0x{x} in member '{s}'", .{ header.size, header.name }); + + if (opt_expected_kind) |expected_kind| switch (expected_kind) { + .first_linker => { + if (!std.mem.eql(u8, header.name, "/")) + return d.failParse("expected first linker member, found '{s}'", .{header.name}); + + const num_symbols = try r.takeInt(u32, .big); + if (dump_header) + try w.print( + \\{t: >16} type + \\ | {d} symbols + \\ + , .{ expected_kind, num_symbols }); + + if (d.opts.linker_member == .first_linker) { + if (d.element(.@"table-header")) + try w.writeAll( + \\ + \\Archive symbols: + \\& Member Symbol + \\ + ); + + const offsets = try r.readAlloc(gpa, num_symbols * 4); + defer gpa.free(offsets); + + for (0..num_symbols) |symbol_i| { + const symbol = r.takeDelimiter(0) catch |err| + return d.failParse("unable to read first linker member string table: {t}", .{err}); + + if (!filterMatches(d.opts.symbol_filters, symbol.?)) + continue; + + const offset = std.mem.readInt(u32, offsets[symbol_i * 4 ..][0..4], .big); + try w.print("{f} {s}\n", .{ + fmtIntField(d, offset, .{ .kind = .va }), + symbol.?, + }); + } + } + if (dump_header and d.element(.newlines)) try w.writeByte('\n'); + + try fr.seekTo(member_end); + opt_expected_kind = .second_linker; + continue; + }, + .second_linker => { + if (!std.mem.eql(u8, header.name, "/")) + return d.failParse("expected second linker member, found '{s}'", .{header.name}); + + const num_members = try r.takeInt(u32, .little); + pos = fr.logicalPos(); + if (pos + num_members * @sizeOf(u32) > member_end) + return d.failParse("invalid member count 0x{x} in second linker member", .{num_members}); + + try members.ensureTotalCapacity(gpa, num_members); + for (0..num_members) |_| + members.addOneAssumeCapacity().* = .{ + .offset = try r.takeInt(u32, .little), + .order = null, + }; + + const num_symbols = try r.takeInt(u32, .little); + pos = fr.logicalPos(); + if (pos + num_symbols * @sizeOf(u16) > member_end) + return d.failParse("invalid symbol count 0x{x} in second linker member", .{num_symbols}); + + if (dump_header) + try w.print( + \\{t: >16} type + \\ | {f} symbols + \\ | {f} members + \\ + , .{ + expected_kind, + fmtIntField(d, num_symbols, .{ .kind = .size, .width = .auto }), + fmtIntField(d, num_members, .{ .kind = .size, .width = .auto }), + }); + + try symbol_member_indices.ensureTotalCapacity(gpa, num_symbols); + for (0..num_symbols) |order| { + const index = (try r.takeInt(u16, .little)) - 1; + if (index >= members.items.len) + return d.failParse("invalid member index 0x{x} in seconds linker member indices array", .{index}); + + symbol_member_indices.addOneAssumeCapacity().* = index; + + if (members.items[index].order == null) + members.items[index].order = @intCast(order); + } + + if (d.opts.exports and d.opts.exports_sort) { + std.sort.pdq(Member, members.items, {}, struct { + fn lessThan(ctx: void, lhs: Member, rhs: Member) bool { + _ = ctx; + if (lhs.order == null and rhs.order == null) + return lhs.offset < rhs.offset + else if (lhs.order) |lhs_order| + return if (rhs.order) |rhs_order| lhs_order < rhs_order else false + else if (rhs.order) |rhs_order| + return if (lhs.order) |lhs_order| lhs_order < rhs_order else true + else + unreachable; + } + }.lessThan); + } + + if (d.opts.linker_member == .second_linker) { + if (d.element(.@"table-header")) + try w.writeAll( + \\ + \\Archive Symbols: + \\& Member Symbol + \\ + ); + + pos = fr.logicalPos(); + var symbol_i: u32 = 0; + while (pos < member_end and symbol_i < num_symbols) : ({ + pos = fr.logicalPos(); + symbol_i += 1; + }) { + const symbol_name = if (r.takeDelimiter(0) catch |err| switch (err) { + error.StreamTooLong => null, + else => |e| return e, + }) |n| n else return d.failParse("unterminated string found in second linker member", .{}); + + if (!filterMatches(d.opts.symbol_filters, symbol_name)) + continue; + + try w.print("{f} {s}\n", .{ + fmtIntField( + d, + members.items[symbol_member_indices.items[symbol_i]].offset, + .{ .kind = .va }, + ), + symbol_name, + }); + } + + if (symbol_i != num_symbols) + return d.failParse( + " expected {d} entries in second linker member string table, but found {d}", + .{ num_symbols, symbol_i }, + ); + } + + if (d.element(.newlines)) try w.writeByte('\n'); + try fr.seekTo(member_end); + opt_expected_kind = .longnames; + continue; + }, + .longnames => { + // This member is optional + if (std.mem.eql(u8, header.name, "//")) { + opt_longnames = try r.readAlloc(gpa, header.size); + if (dump_header) + try w.print("{t: >16} type\n", .{expected_kind}); + + if (d.opts.linker_member == .longnames) { + if (d.element(.@"table-header")) + try w.print( + \\ + \\Longnames (0x{x} bytes): + \\ + , .{opt_longnames.?.len}); + + var lr = Io.Reader.fixed(opt_longnames.?); + while (try lr.takeDelimiter(0)) |str| { + try w.writeAll(str); + try w.writeByte('\n'); + } + } + + if (d.element(.newlines)) try w.writeByte('\n'); + } + + opt_expected_kind = null; + break; + }, + else => unreachable, + }; + } + + if (opt_expected_kind) |expected_kind| switch (expected_kind) { + .first_linker => d.failParse("missing first linker member", .{}), + .second_linker => d.failParse("missing second linker member", .{}), + else => {}, + }; + + for (members.items, 0..) |member, member_i| { + fr.seekTo(member.offset) catch |err| + d.failParse("unable to read member {d} at offset 0x{x}: {t}", .{ member_i, member.offset, err }); + + const raw_header = try r.takeStruct(std.coff.ArchiveMemberHeader, .little); + const header: ArchiveHeader = .fromRaw(d, &raw_header, opt_longnames); + if (!filterMatches(d.opts.member_filters, header.name)) continue; + + const member_sig = try r.peek(4); + const machine: std.coff.IMAGE.FILE.MACHINE = + @enumFromInt(std.mem.readInt(u16, member_sig[0..2], .little)); + const sig = std.mem.readInt(u16, member_sig[2..4], .little); + + const is_imp_lib = machine == std.coff.IMAGE.FILE.MACHINE.UNKNOWN and sig == 0xffff; + if (d.opts.member_headers) + try dumpArchiveHeader(d, &header, member.offset); + + if (d.opts.member_headers or (d.opts.exports and is_imp_lib)) { + if (is_imp_lib) { + const imp_header = try r.takeStruct(std.coff.ImportHeader, .little); + const sym_name = (try r.takeDelimiter(0)).?; + const imp_dll = (try r.takeDelimiter(0)).?; + + if (!filterMatches(d.opts.symbol_filters, sym_name)) + continue; + + if (d.element(.@"header-name")) + try w.writeAll("\nImport header:\n"); + + try dumpHeader(d, std.coff.ImportHeader, &imp_header, struct { + pub fn sig1(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {} + pub fn sig2(_: *const DumpContext, _: *const std.coff.ImportHeader) !void {} + pub fn types(id: *const DumpContext, h: *const std.coff.ImportHeader) !void { + try id.w.print( + \\{t: >16} import_type + \\{t: >16} name_type + \\ + , .{ h.types.type, h.types.name_type }); + } + }); + + const imp_name = imp_name: switch (imp_header.types.name_type) { + .NAME_NOPREFIX, + .NAME_UNDECORATE, + => |tag| { + var imp_name = std.mem.trimStart(u8, sym_name, "?@_"); + if (tag == .NAME_UNDECORATE) + imp_name = std.mem.sliceTo(imp_name, '@'); + break :imp_name imp_name; + }, + else => sym_name, + }; + + try w.print( + \\ symbol name | {s} + \\ import name | {s} + \\ dll | {s} + \\ + , .{ + sym_name, + imp_name, + imp_dll, + }); + } else { + try w.writeAll(" COFF object type\n"); + } + if (d.element(.newlines)) try w.writeByte('\n'); + } + + if (is_imp_lib) continue; + if (d.opts.section_headers or + d.opts.file_headers or + d.opts.relocs or + d.opts.strings or + d.opts.symbols) + { + const member_name = if (d.element(.@"member-path")) + header.name + else + std.fs.path.basename(header.name); + + if (d.element(.@"file-type")) { + try w.print("{s}({s}): COFF object\n", .{ + std.fs.path.basename(d.opts.input_path), + member_name, + }); + if (d.element(.newlines)) try w.writeByte('\n'); + } + try dumpObject(d, false, member_name); + } + } + } + + fn dumpObject( + d: *const DumpContext, + is_image: bool, + obj_name: []const u8, + ) !void { + const gpa = d.gpa; + const fr = d.fr; + const w = d.w; + + const file_location = fr.logicalPos(); + const r = &fr.interface; + const header = r.takeStruct(std.coff.Header, .little) catch |err| + return d.failParse("unable to read COFF header: {t}", .{err}); + + if (d.opts.file_headers) { + if (d.element(.@"header-name")) try w.writeAll("COFF Header:\n"); + try dumpHeader(d, std.coff.Header, &header, struct {}); + if (d.element(.newlines)) try w.writeByte('\n'); + } + + switch (header.machine) { + _ => return d.failParse("unknown machine type: {x}", .{header.machine}), + else => {}, + } + + var known_dirs: [DIRECTORY_ENTRY.len]std.coff.ImageDataDirectory = undefined; + const needs_data_dirs = + d.opts.exports or + d.opts.imports or + d.opts.tls; + + const ImageInfo = struct { + data_dirs: []const std.coff.ImageDataDirectory, + magic: std.coff.OptionalHeader.Magic, + image_base: u64, + }; + + const image_info: ?ImageInfo = if (header.size_of_optional_header > 0) image_info: { + if (!d.opts.file_headers and !needs_data_dirs) { + try fr.seekBy(header.size_of_optional_header); + break :image_info null; + } + + if (d.opts.file_headers and d.element(.@"header-name")) + try w.writeAll("COFF Optional Header:\n"); + + const magic: std.coff.OptionalHeader.Magic = @enumFromInt(try r.peekInt(u16, .little)); + const num_directory_entries, const image_base = switch (magic) { + inline .PE32, .@"PE32+" => |v| num_data_dirs: { + const OptionalHeader = if (v == .PE32) + std.coff.OptionalHeader.PE32 + else + std.coff.OptionalHeader.@"PE32+"; + + const optional_header = r.takeStruct(OptionalHeader, .little) catch |err| + return d.failParse("unable to read optional header: {t}", .{err}); + + if (d.opts.file_headers) { + try dumpHeader(d, OptionalHeader, &optional_header, struct { + pub fn base_of_code(id: *const DumpContext, h: *const std.coff.OptionalHeader) !void { + const base = @as(*const OptionalHeader, @ptrCast(@alignCast(h))).image_base; + try dumpRvaField(id, @src().fn_name, h.base_of_code, base); + } + + pub fn address_of_entry_point(id: *const DumpContext, h: *const std.coff.OptionalHeader) !void { + const base = @as(*const OptionalHeader, @ptrCast(@alignCast(h))).image_base; + try dumpRvaField(id, @src().fn_name, h.base_of_code, base); + } + + pub fn major_linker_version(id: *const DumpContext, h: *const std.coff.OptionalHeader) !void { + try dumpVersionField(id.w, "linker_version", h.major_linker_version, h.minor_linker_version); + } + pub fn minor_linker_version(_: *const DumpContext, _: *const std.coff.OptionalHeader) !void {} + + pub fn major_operating_system_version(id: *const DumpContext, h: *const OptionalHeader) !void { + try dumpVersionField( + id.w, + "operating_system_version", + h.major_operating_system_version, + h.minor_operating_system_version, + ); + } + pub fn minor_operating_system_version(_: *const DumpContext, _: *const OptionalHeader) !void {} + + pub fn major_image_version(id: *const DumpContext, h: *const OptionalHeader) !void { + try dumpVersionField(id.w, "image_version", h.major_image_version, h.minor_image_version); + } + pub fn minor_image_version(_: *const DumpContext, _: *const OptionalHeader) !void {} + + pub fn major_subsystem_version(id: *const DumpContext, h: *const OptionalHeader) !void { + try dumpVersionField(id.w, "subsystem_version", h.major_subsystem_version, h.minor_subsystem_version); + } + pub fn minor_subsystem_version(_: *const DumpContext, _: *const OptionalHeader) !void {} + }); + if (d.element(.newlines)) try w.writeByte('\n'); + } + + break :num_data_dirs .{ + optional_header.number_of_rva_and_sizes, + optional_header.image_base, + }; + }, + else => return d.failParse("invalid optional header magic number: {x}", .{magic}), + }; + + if (d.opts.file_headers and d.element(.@"header-name")) + try w.writeAll("Data Directories:\n"); + + for (0..num_directory_entries) |dir_i| { + const dir = r.takeStruct(std.coff.ImageDataDirectory, .little) catch |err| + return d.failParse("unable to read data directory {x}: {t}", .{ dir_i, err }); + + if (dir_i < known_dirs.len) + known_dirs[dir_i] = dir; + + if (d.opts.file_headers) + try w.print( + "{x: >16} {x: >8} {t}\n", + .{ dir.virtual_address, dir.size, @as(DIRECTORY_ENTRY, @enumFromInt(dir_i)) }, + ); + } + if (d.opts.file_headers and d.element(.newlines)) try w.writeByte('\n'); + + break :image_info .{ + .data_dirs = known_dirs[0..@min(known_dirs.len, num_directory_entries)], + .magic = magic, + .image_base = image_base, + }; + } else if (is_image) { + return d.failParse("image did not contain an optional header", .{}); + } else null; + + // Section names in images don't use the string table, as they must fit inline in the header + const load_string_table = (d.opts.strings or !is_image) and header.pointer_to_symbol_table > 0; + const string_table = if (load_string_table) string_table: { + const pos = fr.logicalPos(); + fr.seekTo(file_location + header.pointer_to_symbol_table + header.number_of_symbols * std.coff.Symbol.sizeOf()) catch |err| + return d.failParse("unable to seek to string table: {t}", .{err}); + + const string_table_len = r.peekInt(u32, .little) catch |err| + return d.failParse("unable to read string table length: {t}", .{err}); + + const table = r.readAlloc(gpa, string_table_len) catch |err| + return d.failParse("unable to read string table: {t}", .{err}); + + try fr.seekTo(pos); + break :string_table table; + } else &.{}; + defer gpa.free(string_table); + + if (d.opts.strings) { + if (d.element(.@"table-header")) + try w.print( + \\String Table (0x{x} bytes): + \\ + , .{string_table.len}); + + var sr = Io.Reader.fixed(string_table[@sizeOf(u32)..]); + while (try sr.takeDelimiter(0)) |str| { + try w.writeAll(str); + try w.writeByte('\n'); + } + + if (d.element(.newlines)) try w.writeByte('\n'); + } + + var sections: std.ArrayList(Section) = .empty; + defer sections.deinit(gpa); + var sections_with_data: u16 = 0; + + const load_sections = + d.opts.section_headers or + d.opts.symbols or + d.opts.relocs or + needs_data_dirs; + + if (load_sections) { + if (d.opts.section_headers and d.element(.@"table-header")) + try w.print( + \\Sections in '{s}': + \\Num Name RVA Virt Size Data Size & Data & Relocs & Lines # Relocs # Lines Flags + \\ + , .{obj_name}); + + try sections.resize(gpa, header.number_of_sections); + for (sections.items, 0..) |*section, section_i| { + section.header = r.takeStruct(std.coff.SectionHeader, .little) catch |err| + return d.failParse("unable to read section header {x}: {t}", .{ section_i, err }); + section.name = headerName(§ion.header.name, string_table) catch |err| switch (err) { + error.Overflow, + error.InvalidCharacter, + => return d.failParse("unable to parse section name offset '{s}': {t}", .{ + section.name, + err, + }), + error.OutOfBounds => return d.failParse("section name offset '{s}' was out of bounds (>= {x})", .{ + section.name, + string_table.len, + }), + }; + + sections_with_data += @intFromBool(section.header.size_of_raw_data > 0); + if (d.opts.section_headers) { + if (!filterMatches(d.opts.section_filters, section.name)) continue; + const raw_name = std.mem.sliceTo(§ion.header.name, 0); + try w.print( + "{x: >3} {s: <8} {f} {f} {f} {f} {f} {f} {f} {f} {x:0>8} |", + .{ + section_i + 1, + raw_name, + fmtIntField(d, section.header.virtual_address, .{ .kind = .va }), + fmtIntField(d, section.header.virtual_size, .{ .kind = .size, .width = .{ .explicit = 9 } }), + fmtIntField(d, section.header.size_of_raw_data, .{ .kind = .size, .width = .{ .explicit = 9 } }), + fmtIntField(d, section.header.pointer_to_raw_data, .{ .kind = .va }), + fmtIntField(d, section.header.pointer_to_relocations, .{ .kind = .va }), + fmtIntField(d, section.header.pointer_to_linenumbers, .{ .kind = .va }), + fmtIntField(d, section.header.number_of_relocations, .{ .kind = .va }), + fmtIntField(d, section.header.number_of_linenumbers, .{ .kind = .va }), + @as(u32, @bitCast(section.header.flags)), + }, + ); + + try dumpFlags(w, "{s}", std.coff.SectionHeader.Flags, §ion.header.flags, 1); + if (section.name.len > 8) + try w.print("\n | {s}", .{section.name}); + + try w.writeByte('\n'); + } + } + + if (d.opts.section_headers and d.element(.newlines)) try w.writeByte('\n'); + } + + var symbols: std.ArrayList(struct { + name: []const u8, + section_number: std.coff.SectionNumber, + }) = .empty; + defer symbols.deinit(gpa); + + var name_arena: std.heap.ArenaAllocator = .init(gpa); + defer name_arena.deinit(); + + if (d.opts.relocs) + try symbols.ensureUnusedCapacity(gpa, header.number_of_symbols); + + if (d.opts.symbols or d.opts.relocs) { + if (header.pointer_to_symbol_table > 0) { + fr.seekTo(file_location + header.pointer_to_symbol_table) catch |err| + return d.failParse("unable to seek to symbol table: {t}", .{err}); + + if (d.opts.symbols and d.element(.@"table-header")) + try w.print( + \\Symbols in '{s}': + \\ Ord Value Sect Type Storage Name + \\ + , .{obj_name}); + + const symbol_size = std.coff.Symbol.sizeOf(); + var symbol_i: u32 = 0; + while (symbol_i < header.number_of_symbols) { + var symbol: std.coff.Symbol = undefined; + const symbol_bytes = r.take(symbol_size) catch |err| + return d.failParse("unable to read symbol {x}: {t}", .{ symbol_i, err }); + + @memcpy(std.mem.asBytes(&symbol)[0..symbol_size], symbol_bytes); + if (native_endian != .little) + std.mem.byteSwapAllFields(std.coff.Symbol, &symbol); + + const aux_symbols = if (symbol.number_of_aux_symbols > 0) + try r.take(symbol_size * symbol.number_of_aux_symbols) + else + &.{}; + defer symbol_i += symbol.number_of_aux_symbols + 1; + + const name = if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: { + const index = std.mem.readInt(u32, symbol.name[4..], .little); + if (index >= string_table.len) + return d.failParse("invalid name offset for symbol {x} ({x} >= {x})", .{ + symbol_i, + index, + string_table.len, + }); + break :name std.mem.sliceTo(string_table[index..], 0); + } else try name_arena.allocator().dupe(u8, std.mem.sliceTo(&symbol.name, 0)); + + if (d.opts.relocs) + symbols.appendNTimesAssumeCapacity(.{ + .name = name, + .section_number = symbol.section_number, + }, 1 + symbol.number_of_aux_symbols); + + if (!d.opts.symbols or !filterMatches(d.opts.symbol_filters, name)) + continue; + + try w.print("{f} {x:0>8} ", .{ + fmtIntField(d, @as(u16, @intCast(symbol_i)), .{ .kind = .ord }), + symbol.value, + }); + try switch (symbol.section_number) { + .UNDEFINED => w.writeAll("UNDEF"), + .ABSOLUTE => w.writeAll(" ABS"), + .DEBUG => w.writeAll("DEBUG"), + else => |v| { + const backing = @intFromEnum(v); + const fmt = "{x: >5}"; + if (backing >= 0) + try w.print(fmt, .{@as(u15, @intCast(backing))}) + else + try w.print(fmt, .{backing}); + }, + }; + + try w.print("{t: >5}", .{symbol.type.base_type}); + if (switch (symbol.type.complex_type) { + .NULL => " ", + .POINTER => "* ", + .FUNCTION => "()", + .ARRAY => "[]", + else => null, + }) |suffix| try w.writeAll(suffix) else try w.print("{x}", .{symbol.type.complex_type}); + + try w.print("{t: >16} | {s}\n", .{ symbol.storage_class, name }); + + for (0..symbol.number_of_aux_symbols) |aux_i| { + _ = aux_i; + try w.writeAll(" |"); + + if (symbol.storage_class == .EXTERNAL and + symbol.type == std.coff.SymType{ + .complex_type = .FUNCTION, + .base_type = .NULL, + } and + @intFromEnum(symbol.section_number) > 0) + { + try w.writeAll("TODO function aux symbol"); + } else if (symbol.type == std.coff.SymType{ + .complex_type = .FUNCTION, + .base_type = .NULL, + } and + (std.mem.eql(u8, name, ".bf") or std.mem.eql(u8, name, ".ef"))) + { + try w.writeAll("TODO bf / ef aux symbol"); + } else if (symbol.storage_class == .WEAK_EXTERNAL and symbol.section_number == .UNDEFINED) { + if (symbol.value != 0) + return d.failParse( + "invalid value 0x{x} for weak external symbol 0x{x}", + .{ symbol.value, symbol_i }, + ); + + var weak_external: std.coff.WeakExternalDefinition = undefined; + @memcpy(std.mem.asBytes(&weak_external)[0..symbol_size], aux_symbols[0..symbol_size]); + if (native_endian != .little) + std.mem.byteSwapAllFields(std.coff.WeakExternalDefinition, &weak_external); + + if (weak_external.tag_index >= header.number_of_symbols) + return d.failParse( + "invalid tag_index 0x{x} for weak external symbol 0x{x}", + .{ weak_external.tag_index, symbol_i }, + ); + + if (d.redacted(.ord)) + try w.print(" Weak External [falls back to relative ordinal {x:0>8} via {t}]", .{ + @as(i64, weak_external.tag_index) - symbol_i, + weak_external.flag, + }) + else + try w.print(" Weak External [falls back to ordinal {x:0>8} via {t}]", .{ + weak_external.tag_index, + weak_external.flag, + }); + } else if (symbol.storage_class == .FILE) { + if (!std.mem.eql(u8, name, ".file")) { + try w.print(" !! unexpected symbol name '{s}' for file symbol 0x{x}", .{ name, symbol_i }); + continue; + } + + const filename = std.mem.sliceTo(aux_symbols, 0); + try w.print(" File '{s}'", .{filename}); + break; + } else if (symbol.storage_class == .STATIC and + symbol.type == std.coff.SymType{ + .complex_type = .NULL, + .base_type = .NULL, + } and + symbol.value == 0 and + switch (symbol.section_number) { + .UNDEFINED, .DEBUG, .ABSOLUTE => false, + else => |sn| @intFromEnum(sn) > 0, + }) + { + const section_i: u15 = @intCast(@intFromEnum(symbol.section_number) - 1); + try w.writeAll(" Section "); + + if (section_i >= sections.items.len) { + try w.print(" !! invalid section number: {x}", .{section_i}); + continue; + } + + var section_def: std.coff.SectionDefinition = undefined; + @memcpy(std.mem.asBytes(§ion_def)[0..symbol_size], aux_symbols[0..symbol_size]); + if (native_endian != .little) + std.mem.byteSwapAllFields(std.coff.SectionDefinition, §ion_def); + + const section = §ions.items[section_i]; + if (section_def.number_of_relocations != section.header.number_of_relocations) { + try w.print( + " !! relocation count did not match section header: {d} vs {d}", + .{ section_def.number_of_relocations, section.header.number_of_relocations }, + ); + continue; + } + + if (section_def.number_of_linenumbers != section.header.number_of_linenumbers) { + try w.print( + " !! line number count did not match section header: {d} vs {d}", + .{ section_def.number_of_linenumbers, section.header.number_of_linenumbers }, + ); + continue; + } + + try w.print(" [size {f} chksum {x:0>8} relocs {x:0>4} lines {x:0>4}]", .{ + fmtIntField(d, section_def.length, .{ .kind = .size, .zero_fill = true }), + section_def.checksum, + section_def.number_of_relocations, + section_def.number_of_linenumbers, + }); + + switch (section_def.selection) { + .NONE => {}, + else => |selection| { + try w.print(" COMDAT({t}", .{selection}); + if (selection == .ASSOCIATIVE) + try w.print("->{x}", .{section_def.number}); + try w.writeAll(")"); + }, + } + } + + try w.writeByte('\n'); + } + } + + if (d.opts.symbols and d.element(.newlines)) try w.writeByte('\n'); + } else if (d.opts.symbols) { + try w.writeAll("No symbol table found\n"); + } + } + + if (d.opts.relocs) { + const relocation_size = std.coff.Relocation.sizeOf(); + + for (sections.items, 0..) |section, section_i| { + if (section.header.pointer_to_relocations == 0) continue; + + if (d.element(.@"table-header")) + try w.print( + \\Relocs for section {x} '{s}' in {s}: + \\ Offset Type Symbol -> Sect Name + \\ + , .{ section_i + 1, section.name, obj_name }); + + fr.seekTo(file_location + section.header.pointer_to_relocations) catch |err| + return d.failParse("unable to seek to section {x} relocation table: {t}", .{ section_i + 1, err }); + + for (0..section.header.number_of_relocations) |reloc_i| { + var reloc: std.coff.Relocation = undefined; + @memcpy(std.mem.asBytes(&reloc)[0..relocation_size], try r.take(relocation_size)); + if (native_endian != .little) + std.mem.byteSwapAllFields(std.coff.Relocation, &reloc); + + const sym = &symbols.items[reloc.symbol_table_index]; + if (!filterMatches(d.opts.symbol_filters, sym.name)) + continue; + + try w.print("{f} ", .{ + fmtIntField(d, reloc.virtual_address, .{ .kind = .va, .zero_fill = true }), + }); + switch (header.machine) { + _ => unreachable, + inline else => |m| switch (m.RelocationType()) { + void => try w.writeAll("(unknown arch)"), + else => |RelocationType| try w.print( + "{t: <17} ", + .{@as(RelocationType, @enumFromInt(reloc.type))}, + ), + }, + } + + if (reloc.symbol_table_index >= symbols.items.len) + return d.failParse( + "reloc {x} in section {x} has out-of-bounds symbol index {x}", + .{ reloc_i, section_i + 1, reloc.symbol_table_index }, + ); + + try w.print("{f} {f} | {s}\n", .{ + fmtIntField(d, reloc.symbol_table_index, .{ .kind = .ord }), + fmtSectionNumber(sym.section_number), + sym.name, + }); + } + if (d.element(.newlines)) try w.writeByte('\n'); + } + } + + // Sections indices with raw data, sorted by RVA + const rva_index = if (needs_data_dirs) rva_index: { + const rva_index = try gpa.alloc(u16, sections_with_data); + var indices_i: u16 = 0; + for (sections.items, 0..) |*section, i| { + if (section.header.size_of_raw_data == 0) continue; + rva_index[indices_i] = @intCast(i); + indices_i += 1; + } + + const Context = struct { + indices: []u16, + sections: []const Section, + + pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { + return ctx.sections[ctx.indices[lhs]].header.virtual_address < + ctx.sections[ctx.indices[rhs]].header.virtual_address; + } + + pub fn swap(ctx: @This(), lhs: usize, rhs: usize) void { + std.mem.swap(u16, &ctx.indices[lhs], &ctx.indices[rhs]); + } + }; + + std.sort.pdqContext(0, rva_index.len, Context{ + .indices = rva_index, + .sections = sections.items, + }); + + break :rva_index rva_index; + } else &.{}; + defer gpa.free(rva_index); + + if (d.opts.exports) exports: { + if (try seekToDataDirectory( + d, + rva_index, + sections.items, + (image_info orelse { + try w.writeAll("COFF objects do not contain an export data directory"); + break :exports; + }).data_dirs, + .EXPORT, + )) |section_index| { + const export_dir = r.takeStruct(std.coff.ExportDirectoryTable, .little) catch |err| + return d.failParse("unable to read export directory: {t}", .{err}); + + try w.print("Export directory:\n", .{}); + try dumpHeader(d, std.coff.ExportDirectoryTable, &export_dir, struct { + pub fn major_version(id: *const DumpContext, h: *const std.coff.ExportDirectoryTable) !void { + try dumpVersionField(id.w, "version", h.major_version, h.minor_version); + } + pub fn minor_version(_: *const DumpContext, _: *const std.coff.ExportDirectoryTable) !void {} + }); + + const section = sections.items[section_index]; + const name_loc = section.rvaFileOffset(export_dir.name_rva) catch + return d.failParse( + "export name rva 0x{x} was not within the export section", + .{export_dir.name_rva}, + ); + + const eat_loc = section.rvaFileOffset(export_dir.export_address_table_rva) catch + return d.failParse( + "export address table rva 0x{x} was not within the export section", + .{export_dir.export_address_table_rva}, + ); + + const name_pointer_loc = section.rvaFileOffset(export_dir.name_pointer_table_rva) catch + return d.failParse( + "export name pointer table rva 0x{x} was not within the export section", + .{export_dir.name_pointer_table_rva}, + ); + + const ord_loc = section.rvaFileOffset(export_dir.ordinal_table_rva) catch + return d.failParse( + "export ordinal table rva 0x{x} was not within the export section", + .{export_dir.ordinal_table_rva}, + ); + + // All the variable length fields should be contained within this directory. + // Read it entirely to avoid needing to seek per-name when iterating. + const dir = image_info.?.data_dirs[@intFromEnum(DIRECTORY_ENTRY.EXPORT)]; + const dir_end_rva = dir.virtual_address + dir.size; + const dir_loc = fr.logicalPos(); + const dir_slice = try r.readAlloc(gpa, dir.size); + defer gpa.free(dir_slice); + + const dll_name = std.mem.sliceTo(dir_slice[name_loc - dir_loc ..], 0); + if (d.element(.@"table-header")) + try w.print( + \\ + \\Exports from {s}: + \\ Ord Hint RVA Name + \\ + , .{dll_name}); + + const name_pointers = dir_slice[name_pointer_loc - dir_loc ..][0 .. export_dir.number_of_names * @sizeOf(u32)]; + const ords = dir_slice[ord_loc - dir_loc ..][0 .. export_dir.number_of_names * @sizeOf(u16)]; + const addrs = dir_slice[eat_loc - dir_loc ..][0 .. export_dir.number_of_entries * @sizeOf(u32)]; + const name_rva_to_offset = dir.virtual_address + @sizeOf(std.coff.ExportDirectoryTable); + for (0..export_dir.number_of_names) |name_i| { + const name_rva = std.mem.readInt(u32, name_pointers[name_i * @sizeOf(u32) ..][0..@sizeOf(u32)], .little); + const name = std.mem.sliceTo(dir_slice[name_rva - name_rva_to_offset ..], 0); + if (!filterMatches(d.opts.symbol_filters, name)) + continue; + + const ord = std.mem.readInt(u16, ords[name_i * @sizeOf(u16) ..][0..@sizeOf(u16)], .little); + const addr = std.mem.readInt(u32, addrs[@as(u32, ord) * @sizeOf(u32) ..][0..@sizeOf(u32)], .little); + + try w.print("{f} {f} ", .{ + fmtIntField(d, @as(u16, @intCast(export_dir.ordinal_base + ord)), .{ .kind = .ord }), + fmtIntField(d, @as(u16, @intCast(name_i)), .{ .kind = .ord }), + }); + const is_forwarder = addr >= dir.virtual_address and addr < dir_end_rva; + if (is_forwarder) { + try w.writeAll("forwards"); + } else { + try w.print("{f}", .{fmtIntField(d, addr, .{ .kind = .rva })}); + } + + try w.print(" | {s}", .{name}); + if (is_forwarder) + try w.print(" -> {s}", .{std.mem.sliceTo(dir_slice[addr - name_rva_to_offset ..], 0)}); + try w.writeByte('\n'); + } + } + } + + if (d.opts.imports) imports: { + if (try seekToDataDirectory( + d, + rva_index, + sections.items, + (image_info orelse { + try w.writeAll("COFF objects do not contain an import data directory"); + break :imports; + }).data_dirs, + .IMPORT, + )) |_| { + const Entry = std.coff.ImportDirectoryEntry; + var directory_entries: std.ArrayList(Entry) = .empty; + defer directory_entries.deinit(gpa); + while (true) { + const entry = r.takeStruct(Entry, .little) catch |err| + return d.failParse( + "unable to read import directory entry {x}: {t}", + .{ directory_entries.items.len, err }, + ); + + if (std.mem.allEqual(u8, std.mem.asBytes(&entry), 0)) break; + (try directory_entries.addOne(gpa)).* = entry; + } + + for (directory_entries.items) |entry| { + const name_section = sectionContainingRva( + rva_index, + sections.items, + entry.name_rva, + ) orelse + return d.failParse( + "import directory entry name rva 0x{x} was not found in any section", + .{entry.name_rva}, + ); + + const name_loc = sections.items[name_section].rvaFileOffset( + entry.name_rva, + ) catch unreachable; + fr.seekTo(name_loc) catch |err| + return d.failParse( + "unable to seek to import directory entry name at 0x{x}: {t}", + .{ name_loc, err }, + ); + + const dll_name = (try r.takeDelimiter(0)).?; + + if (d.element(.@"header-name")) + try w.print("Import table entry for {s}:\n", .{dll_name}); + try dumpHeader(d, Entry, &entry, struct {}); + + if (d.element(.@"table-header")) + try w.print( + \\ + \\ Ord Hint Name + \\ + , .{}); + + const ilt_section = sectionContainingRva( + rva_index, + sections.items, + entry.import_lookup_table_rva, + ) orelse + return d.failParse( + "import directory entry ilt rva 0x{x} was not found in any section", + .{entry.import_lookup_table_rva}, + ); + + const ilt_loc = sections.items[ilt_section].rvaFileOffset( + entry.import_lookup_table_rva, + ) catch unreachable; + fr.seekTo(ilt_loc) catch |err| + return d.failParse( + "unable to seek to import directory ilt at 0x{x}: {t}", + .{ ilt_loc, err }, + ); + + switch (image_info.?.magic) { + _ => try w.writeAll("(unknown magic)"), + inline else => |m| { + const TableEntry = std.coff.ImportLookupTableEntry(m); + const null_entry: TableEntry = @bitCast(@as(@typeInfo(TableEntry).@"struct".backing_integer.?, 0)); + + var ilt_entries: std.ArrayList(TableEntry) = .empty; + defer ilt_entries.deinit(gpa); + while (true) { + const table_entry = r.takeStruct(TableEntry, .little) catch |err| + return d.failParse( + "unable to read ilt entry {s}:{x}: {t}", + .{ dll_name, ilt_entries.items.len, err }, + ); + if (table_entry == null_entry) break; + (try ilt_entries.addOne(gpa)).* = table_entry; + } + + for (ilt_entries.items, 0..) |ilt_entry, ilt_entry_i| { + if (ilt_entry.is_ordinal) { + try w.print("{x: >4}", .{ilt_entry.payload.ordinal.ordinal}); + } else { + const hint_section = sectionContainingRva( + rva_index, + sections.items, + ilt_entry.payload.hint_name_rva, + ) orelse + return d.failParse( + "import directory ilt entry 0x{x}'s hint rva 0x{x} was not found in any section", + .{ ilt_entry_i, ilt_entry.payload.hint_name_rva }, + ); + + const hint_loc = sections.items[hint_section].rvaFileOffset( + ilt_entry.payload.hint_name_rva, + ) catch unreachable; + fr.seekTo(hint_loc) catch |err| + return d.failParse( + "unable to seek to ilt entry 0x{x}'s hint at 0x{x}: {t}", + .{ ilt_entry_i, hint_loc, err }, + ); + + const hint = r.takeInt(u16, .little) catch |err| + return d.failParse( + "unable to read import directory ilt entry 0x{x}'s hint: {t}", + .{ ilt_entry_i, err }, + ); + + const name = r.takeDelimiter(0) catch |err| + return d.failParse( + "unable to read import directory ilt entry 0x{x}'s name: {t}", + .{ ilt_entry_i, err }, + ); + + try w.print(" {x: >4} | {s}\n", .{ hint, name.? }); + } + } + if (d.element(.newlines)) try w.writeByte('\n'); + }, + } + } + } + } + + if (d.opts.tls) tls: { + if (try seekToDataDirectory( + d, + rva_index, + sections.items, + (image_info orelse { + try w.writeAll("COFF objects do not contain a TLS data directory"); + break :tls; + }).data_dirs, + .TLS, + )) |_| { + switch (image_info.?.magic) { + _ => try w.writeAll("(unknown magic)"), + inline else => |m| { + const TlsDirectoryEntry = std.coff.TlsDirectoryEntry(m); + const tls_entry = r.takeStruct(TlsDirectoryEntry, .little) catch |err| + return d.failParse("unable to read tls directory: {t}", .{err}); + + try w.writeAll("TLS Directory:\n"); + try dumpHeader(d, TlsDirectoryEntry, &tls_entry, struct {}); + + try w.writeAll(" | "); + if (tls_entry.characteristics.alignment == .NONE) { + try w.writeAll("Alignment not specified"); + } else { + try w.print( + "Alignment: {d}", + .{tls_entry.characteristics.alignment.toByteUnits().?}, + ); + } + + try w.writeAll( + \\ + \\ + \\TLS Callbacks: + \\ Address + \\ + ); + + const callbacks_rva: u32 = @intCast(tls_entry.callbacks_va - image_info.?.image_base); + const section_index = sectionContainingRva( + rva_index, + sections.items, + callbacks_rva, + ) orelse + return d.failParse( + "tls callbacks rva 0x{x} was not found in any section", + .{callbacks_rva}, + ); + + const callbacks_loc = sections.items[section_index] + .rvaFileOffset(callbacks_rva) catch unreachable; + + fr.seekTo(callbacks_loc) catch |err| + return d.failParse( + "unable to seek to tls callbacks array at offset 0x{x}: {t}", + .{ callbacks_loc, err }, + ); + + while (true) { + const callback_va = r.takeInt(@FieldType(TlsDirectoryEntry, "callbacks_va"), .little) catch |err| + return d.failParse( + "unable to read tls callbacks array: {t}", + .{err}, + ); + + try w.print("{f}\n", .{fmtIntField(d, callback_va, .{ .kind = .va })}); + if (callback_va == 0) break; + } + if (d.element(.newlines)) try w.writeByte('\n'); + }, + } + } + } + } + + fn seekToDataDirectory( + d: *const DumpContext, + rva_index: []const u16, + sections: []const Section, + data_dirs: []const std.coff.ImageDataDirectory, + entry: DIRECTORY_ENTRY, + ) !?u16 { + if (@intFromEnum(entry) < data_dirs.len) blk: { + const rva = data_dirs[@intFromEnum(entry)].virtual_address; + if (rva == 0) break :blk; + + const section_index = sectionContainingRva(rva_index, sections, rva) orelse + return d.failParse( + "{t} directory rva 0x{x} was not found in any section", + .{ entry, rva }, + ); + + const file_offset = sections[section_index].rvaFileOffset(rva) catch unreachable; + d.fr.seekTo(file_offset) catch |err| + return d.failParse( + "unable to seek to {t} directory at offset 0x{x}: {t}", + .{ entry, file_offset, err }, + ); + + return section_index; + } + + try d.w.print("{t} directory was not present in optional header\n", .{entry}); + return null; + } + + fn sectionContainingRva( + /// Indices into `sections` sorted by rva + indices: []const u16, + sections: []const Section, + rva: u32, + ) ?u16 { + const Context = struct { + rva: u32, + sections: []const Section, + + fn order(ctx: @This(), section_index: u16) std.math.Order { + const h = &ctx.sections[section_index].header; + if (ctx.rva < h.virtual_address) return .lt; + const end = h.virtual_address + h.size_of_raw_data; + if (ctx.rva >= end) return .gt; + return .eq; + } + }; + + const indices_index = std.sort.binarySearch(u16, indices, Context{ + .rva = rva, + .sections = sections, + }, Context.order) orelse return null; + return @intCast(indices[indices_index]); + } + + fn headerName(raw: *const [8]u8, string_table: []const u8) ![]const u8 { + return if (raw[0] == '/') name: { + const name_offset = try std.fmt.parseUnsigned(u24, std.mem.sliceTo(raw[1..], 0), 10); + if (name_offset >= string_table.len) + return error.OutOfBounds; + + break :name std.mem.sliceTo(string_table[name_offset..], 0); + } else std.mem.sliceTo(raw, 0); + } + + fn fmtSectionNumber(section_number: std.coff.SectionNumber) std.fmt.Alt(std.coff.SectionNumber, sectionNumberString) { + return .{ .data = section_number }; + } + + fn sectionNumberString(section_number: std.coff.SectionNumber, w: *std.Io.Writer) std.Io.Writer.Error!void { + try switch (section_number) { + .UNDEFINED => w.writeAll("UNDEF"), + .ABSOLUTE => w.writeAll(" ABS"), + .DEBUG => w.writeAll("DEBUG"), + else => |v| { + const backing = @intFromEnum(v); + const fmt = "{x: >5}"; + if (backing >= 0) + try w.print(fmt, .{@as(u15, @intCast(backing))}) + else + try w.print(fmt, .{backing}); + }, + }; + } + + const FormatIntField = struct { + val: ?u64, + width: ?usize, + zero_fill: bool, + }; + + fn fmtIntField( + d: *const DumpContext, + val: anytype, + params: struct { + kind: ?FieldKind = null, + width: union(enum) { + fit_max, + auto, + explicit: usize, + } = .fit_max, + zero_fill: bool = false, + }, + ) std.fmt.Alt(FormatIntField, intFieldString) { + return .{ + .data = .{ + .val = if (d.redacted(params.kind)) null else val, + .width = switch (params.width) { + .fit_max => @typeInfo(@TypeOf(val)).int.bits / 4, + .auto => null, + .explicit => |w| w, + }, + .zero_fill = params.zero_fill, + }, + }; + } + + fn intFieldString(field: FormatIntField, w: *std.Io.Writer) std.Io.Writer.Error!void { + if (field.val) |val| { + try w.printInt(val, 16, .lower, .{ + .width = field.width, + .alignment = .right, + .fill = if (field.zero_fill) '0' else ' ', + }); + } else try w.splatByteAll('x', field.width orelse 1); + } + + fn dumpFlags(w: *Io.Writer, comptime fmt: []const u8, comptime T: type, flags: *const T, cols: u32) !void { + const s = @typeInfo(T).@"struct"; + inline for (s.field_names, s.field_types) |field_name, field_type| { + if (field_type == bool and @field(flags, field_name)) { + try w.splatByteAll(' ', cols); + try w.print(fmt, .{field_name}); + } + } + } + + fn dumpArchiveHeader(d: *const DumpContext, header: *const ArchiveHeader, pos: u32) !void { + if (d.element(.@"header-name")) + try d.w.print("Archive member at offset 0x{x}: '{s}'\n", .{ pos, header.name }); + try dumpHeader(d, ArchiveHeader, header, struct { + pub fn name(_: *const DumpContext, _: *const ArchiveHeader) !void {} + pub fn file_mode(id: *const DumpContext, h: *const ArchiveHeader) !void { + try id.w.print("{o: >16} file_mode\n", .{h.file_mode}); + } + }); + } + + fn fieldKind(name: []const u8) ?FieldKind { + if (std.mem.endsWith(u8, name, "_rva")) + return .rva; + if (std.mem.endsWith(u8, name, "_va") or + std.mem.endsWith(u8, name, "_address") or + std.mem.startsWith(u8, name, "pointer_")) + return .va; + if (std.mem.startsWith(u8, name, "number_") or + std.mem.startsWith(u8, name, "size")) + return .size; + if (std.mem.startsWith(u8, name, "hint")) + return .ord; + return null; + } + + fn dumpHeader( + d: *const DumpContext, + comptime T: type, + header: *const T, + Custom: type, + ) !void { + const s = @typeInfo(T).@"struct"; + inline for (s.field_names, s.field_types) |field_name, field_type| { + const val = &@field(header, field_name); + if (@hasDecl(Custom, field_name)) { + try @field(Custom, field_name)(d, header); + } else { + switch (@typeInfo(field_type)) { + .int => try d.w.print("{f} {s}\n", .{ fmtIntField(d, val.*, .{ + .kind = comptime fieldKind(field_name), + .width = .{ .explicit = 16 }, + }), field_name }), + .@"enum" => try d.w.print("{x: >16} {s} ({t})\n", .{ val.*, field_name, val.* }), + .@"struct" => |s_field| { + switch (s_field.layout) { + .auto, + .@"extern", + => try dumpHeader(d, field_type, val, Custom), + .@"packed" => { + try d.w.print("{x: >16} {s}\n", .{ @as(s_field.backing_integer.?, @bitCast(val.*)), field_name }); + try dumpFlags(d.w, "| {s}\n", field_type, val, 15); + }, + } + }, + else => unreachable, + } + } + } + } + + fn dumpVersionField(w: *Io.Writer, name: []const u8, major: anytype, minor: anytype) !void { + try w.print("{d: >13}.{x:0<2} {s}\n", .{ major, minor, name }); + } + + fn dumpRvaField(d: *const DumpContext, name: []const u8, rva: u64, base: u64) !void { + try d.w.print("{f} {s} ({f})\n", .{ + fmtIntField(d, rva, .{ .kind = .rva }), + name, + fmtIntField(d, base + rva, .{ .kind = .va }), + }); + } +}; + +fn filterMatches(filters: []const []const u8, val: []const u8) bool { + return for (filters) |filter| { + if (std.mem.containsAtLeast(u8, val, 1, filter)) break true; + } else filters.len == 0; +} + const usage = \\Usage: zig objdump [options] file \\ \\Options: - \\ -h, --help Print this help and exit - \\ + \\ -h, --help Print this help and exit + \\ --all-headers Alias for --file-headers --linker-member=2 --member-headers --section-headers --relocs --symbols + \\ --exports[=sort] Display exported symbols. + \\ In the case of COFF import libraries, displays the symbol list and import headers. + \\ Specify =sort to optionally sort the import headers by symbol name. + \\ --file-headers Display file-format specific headers + \\ --imports Display imported symbols + \\ --linker-member[=1|2|longnames] (Coff) Display contents of the specified archive linker member (default 2) + \\ --member-headers Display archive member headers + \\ --elements=[e1],[e2],-[e3],... Select which formatting elements are displayed. Intended for snapshot testing. + \\ file-type File type summary + \\ header-name Name that precedes a header block + \\ member-path Display full member paths. If removed, only basenames will be used. + \\ newlines Newlines between output sections + \\ table-header Table headers with column names + \\ all (default) All of the above + \\ --only-member=[name] Only consider archive members names that contain [name]. Can be specified multiple times. + \\ --only-section=[name] Only consider section names that contain [name]. Can be specified multiple times. + \\ --only-symbol=[name] Only consider symbol names that contain [name]. Can be specified multiple times. + \\ --redact=[kind] Redact the specified field kind. Intended for snapshot testing. + \\ rva Relative virtual addresses + \\ va Virtual addresses and file offsets + \\ ord Symbol ordinals / hints + \\ size Sizes and lengths + \\ all All of the above + \\ --relocs Display relocations + \\ -s, --snapshot Alias for --redact=all --elements=-all + \\ --section-headers Display section headers + \\ --strings Display string tables + \\ --symbols Display symbol tables + \\ --tls Display TLS information ; diff --git a/lib/compiler/reduce/Walk.zig b/lib/compiler/reduce/Walk.zig index 955eed53259a8bf8802ca8301f35266ade07d37c..1873c23d77f6c08230e69743e5b6db09285284f4 100644 --- a/lib/compiler/reduce/Walk.zig +++ b/lib/compiler/reduce/Walk.zig @@ -44,7 +44,7 @@ pub const Transformation = union(enum) { imported_string: []const u8, /// Identifier names that must be renamed in the inlined code or else /// will cause ambiguous reference errors. - in_scope_names: std.StringArrayHashMapUnmanaged(void), + in_scope_names: std.array_hash_map.String(void), }; }; @@ -723,7 +723,7 @@ fn walkBuiltinCall( try w.transformations.append(.{ .inline_imported_file = .{ .builtin_call_node = call_node, .imported_string = imported_string, - .in_scope_names = try std.StringArrayHashMapUnmanaged(void).init( + .in_scope_names = try std.array_hash_map.String(void).init( w.arena, w.in_scope_names.keys(), &.{}, diff --git a/lib/compiler/resinator/cli.zig b/lib/compiler/resinator/cli.zig index f35e70ce6cccdd726d01426ba8c11216f94b81b1..276b03af412368ac49ba27eeca4d4dff562d5798 100644 --- a/lib/compiler/resinator/cli.zig +++ b/lib/compiler/resinator/cli.zig @@ -15,7 +15,7 @@ pub const usage_string_after_command_name = \\ [options] [--] [] \\ \\The sequence -- can be used to signify when to stop parsing options. - \\This is necessary when the input path begins with a forward slash. + \\This avoids ambiguity when the input path begins with a forward slash. \\ \\Supported option prefixes are /, -, and --, so e.g. /h, -h, and --h all work. \\Drop-in compatible with the Microsoft Resource Compiler. @@ -159,7 +159,7 @@ pub const Options = struct { default_language_id: ?u16 = null, default_code_page: ?SupportedCodePage = null, verbose: bool = false, - symbols: std.StringArrayHashMapUnmanaged(SymbolValue) = .empty, + symbols: std.array_hash_map.String(SymbolValue) = .empty, null_terminate_string_table_strings: bool = false, max_string_literal_codepoints: u15 = lex.default_max_string_literal_codepoints, silent_duplicate_control_ids: bool = false, diff --git a/lib/compiler/resinator/compile.zig b/lib/compiler/resinator/compile.zig index c8c11b58707d7c8a2ae03fea8c5db8424af4b7e8..fc814576ac5e9e86a7510d8ef2542a60078cebfa 100644 --- a/lib/compiler/resinator/compile.zig +++ b/lib/compiler/resinator/compile.zig @@ -2746,7 +2746,7 @@ pub const Compiler = struct { // 1. Any permutation that does not have PRELOAD in it just uses the // default flags. const initial_flags = flags.*; - var flags_set = std.enums.EnumSet(rc.CommonResourceAttributes).empty; + var flags_set: std.enums.EnumSet(rc.CommonResourceAttributes) = .empty; for (tokens) |token| { const attribute = rc.CommonResourceAttributes.map.get(token.slice(source)).?; flags_set.insert(attribute); @@ -2769,7 +2769,7 @@ pub const Compiler = struct { // 3. If none of DISCARDABLE, SHARED, or PURE is specified, then PRELOAD // implies `flags &= ~SHARED` and LOADONCALL implies `flags |= SHARED` const shared_set = comptime blk: { - var set = std.enums.EnumSet(rc.CommonResourceAttributes).empty; + var set: std.enums.EnumSet(rc.CommonResourceAttributes) = .empty; set.insert(.discardable); set.insert(.shared); set.insert(.pure); @@ -3049,7 +3049,7 @@ pub const StringTablesByLanguage = struct { /// when the first STRINGTABLE for the language was defined, and all blocks for a given /// language are written contiguously. /// Using an ArrayHashMap here gives us this property for free. - tables: std.AutoArrayHashMapUnmanaged(res.Language, StringTable) = .empty, + tables: std.array_hash_map.Auto(res.Language, StringTable) = .empty, pub fn deinit(self: *StringTablesByLanguage, allocator: Allocator) void { self.tables.deinit(allocator); @@ -3080,7 +3080,7 @@ pub const StringTable = struct { /// was added to the block (i.e. `STRINGTABLE { 16 "b" 0 "a" }` would then get written /// with block ID 2 (the one with "b") first and block ID 1 (the one with "a") second). /// Using an ArrayHashMap here gives us this property for free. - blocks: std.AutoArrayHashMapUnmanaged(u16, Block) = .empty, + blocks: std.array_hash_map.Auto(u16, Block) = .empty, pub const Block = struct { strings: std.ArrayList(Token) = .empty, diff --git a/lib/compiler/resinator/cvtres.zig b/lib/compiler/resinator/cvtres.zig index 84364cea9fc0199e8ba35cd03301c4f4b1573bd6..52f3a70ca0b4162ae5fc2248c29205b686ce56bb 100644 --- a/lib/compiler/resinator/cvtres.zig +++ b/lib/compiler/resinator/cvtres.zig @@ -383,7 +383,7 @@ pub fn writeCoff( fn writeSymbol(writer: *std.Io.Writer, symbol: std.coff.Symbol) !void { try writer.writeAll(&symbol.name); try writer.writeInt(u32, symbol.value, .little); - try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little); + try writer.writeInt(i16, @intFromEnum(symbol.section_number), .little); try writer.writeInt(u8, @intFromEnum(symbol.type.base_type), .little); try writer.writeInt(u8, @intFromEnum(symbol.type.complex_type), .little); try writer.writeInt(u8, @intFromEnum(symbol.storage_class), .little); @@ -439,9 +439,9 @@ pub const ResourceDataEntry = extern struct { /// type -> name -> language const ResourceTree = struct { - type_to_name_map: std.ArrayHashMapUnmanaged(NameOrOrdinal, NameToLanguageMap, NameOrOrdinalHashContext, true), - rsrc_string_table: std.ArrayHashMapUnmanaged(NameOrOrdinal, void, NameOrOrdinalHashContext, true), - deduplicated_data: std.StringArrayHashMapUnmanaged(u32), + type_to_name_map: std.array_hash_map.Custom(NameOrOrdinal, NameToLanguageMap, NameOrOrdinalHashContext, true), + rsrc_string_table: std.array_hash_map.Custom(NameOrOrdinal, void, NameOrOrdinalHashContext, true), + deduplicated_data: std.array_hash_map.String(u32), data_offsets: std.ArrayList(u32), rsrc02_len: u32, coff_options: CoffOptions, @@ -451,8 +451,8 @@ const ResourceTree = struct { resource: *const Resource, original_index: usize, }; - const LanguageToResourceMap = std.AutoArrayHashMapUnmanaged(Language, RelocatableResource); - const NameToLanguageMap = std.ArrayHashMapUnmanaged(NameOrOrdinal, LanguageToResourceMap, NameOrOrdinalHashContext, true); + const LanguageToResourceMap = std.array_hash_map.Auto(Language, RelocatableResource); + const NameToLanguageMap = std.array_hash_map.Custom(NameOrOrdinal, LanguageToResourceMap, NameOrOrdinalHashContext, true); const NameOrOrdinalHashContext = struct { pub fn hash(self: @This(), v: NameOrOrdinal) u32 { diff --git a/lib/compiler/resinator/source_mapping.zig b/lib/compiler/resinator/source_mapping.zig index 7e3bc88e1da4f68447159ef8dd14fc7d27c8c37d..8ae4a70dd0a4afef5c7f346a864693a9dfc799c5 100644 --- a/lib/compiler/resinator/source_mapping.zig +++ b/lib/compiler/resinator/source_mapping.zig @@ -636,6 +636,10 @@ fn parseFilename(allocator: Allocator, str: []const u8) error{ OutOfMemory, Inva if (escape_val != 0) escape_val = std.math.mul(u8, @as(u8, @intCast(escape_val)), 16) catch return error.InvalidString; escape_val = std.math.add(u8, @as(u8, @intCast(escape_val)), digit) catch return error.InvalidString; escape_len += 1; + if (escape_len == 2) { + filename.appendAssumeCapacity(@intCast(escape_val)); + state = .string; + } }, else => { if (escape_len == 0) return error.InvalidString; @@ -706,6 +710,7 @@ fn testParseFilename(expected: []const u8, input: []const u8) !void { test parseFilename { try testParseFilename("'\"?\\\t\n\r\x11", "\\'\\\"\\?\\\\\\t\\n\\r\\x11"); try testParseFilename("\xABz\x53", "\\xABz\\123"); + try testParseFilename("\xABCDEF", "\\xABCDEF"); try testParseFilename("⚡⚡", "\\u26A1\\U000026A1"); try std.testing.expectError(error.InvalidString, parseFilename(std.testing.allocator, "\"")); try std.testing.expectError(error.InvalidString, parseFilename(std.testing.allocator, "\\")); @@ -713,7 +718,6 @@ test parseFilename { try std.testing.expectError(error.InvalidString, parseFilename(std.testing.allocator, "\\U")); try std.testing.expectError(error.InvalidString, parseFilename(std.testing.allocator, "\\x")); try std.testing.expectError(error.InvalidString, parseFilename(std.testing.allocator, "\\xZZ")); - try std.testing.expectError(error.InvalidString, parseFilename(std.testing.allocator, "\\xABCDEF")); try std.testing.expectError(error.InvalidString, parseFilename(std.testing.allocator, "\\777")); } diff --git a/lib/compiler/translate-c/Scope.zig b/lib/compiler/translate-c/Scope.zig index 9e5f715600179973b8e0394e6a723e5f59ad2ba7..80817634314b1e366a06b7b09e9b0bced31bdf1a 100644 --- a/lib/compiler/translate-c/Scope.zig +++ b/lib/compiler/translate-c/Scope.zig @@ -7,7 +7,7 @@ const Translator = @import("Translator.zig"); const Scope = @This(); -pub const SymbolTable = std.StringArrayHashMapUnmanaged(ast.Node); +pub const SymbolTable = std.array_hash_map.String(ast.Node); pub const AliasList = std.ArrayList(struct { alias: []const u8, name: []const u8, @@ -18,7 +18,7 @@ pub const ContainerMemberFns = struct { container_decl_ptr: *ast.Node, member_fns: std.ArrayList(*ast.Payload.Func) = .empty, }; -pub const ContainerMemberFnsHashMap = std.ArrayHashMapUnmanaged( +pub const ContainerMemberFnsHashMap = std.array_hash_map.Custom( aro.QualType, ContainerMemberFns, struct { @@ -79,7 +79,7 @@ pub const Block = struct { /// will be used. This maps the variable's name to the Discard payload, so that if /// the variable is subsequently referenced we can indicate that the discard should /// be skipped during the intermediate AST -> Zig AST render step. - variable_discards: std.StringArrayHashMapUnmanaged(*ast.Payload.Discard), + variable_discards: std.array_hash_map.String(*ast.Payload.Discard), /// When the block corresponds to a function, keep track of the return type /// so that the return expression can be cast, if necessary @@ -209,7 +209,7 @@ pub const Root = struct { base: Scope, translator: *Translator, sym_table: SymbolTable, - blank_macros: std.StringArrayHashMapUnmanaged(void), + blank_macros: std.array_hash_map.String(void), nodes: std.ArrayList(ast.Node), container_member_fns_map: ContainerMemberFnsHashMap, @@ -267,7 +267,7 @@ pub const Root = struct { const gpa = root.translator.gpa; const arena = root.translator.arena; - var member_names: std.StringArrayHashMapUnmanaged(void) = .empty; + var member_names: std.array_hash_map.String(void) = .empty; defer member_names.deinit(gpa); for (root.container_member_fns_map.keys(), root.container_member_fns_map.values()) |container_qt, members| { // Get the container name diff --git a/lib/compiler/translate-c/Translator.zig b/lib/compiler/translate-c/Translator.zig index 9e27ee5e387dba6f072220bec6f64e3d0105e382..794be9361e530a25fa4da4f40693bf432838cef5 100644 --- a/lib/compiler/translate-c/Translator.zig +++ b/lib/compiler/translate-c/Translator.zig @@ -106,7 +106,7 @@ global_scope: *Scope.Root, mangle_count: u32 = 0, /// Table of declarations for enum, struct, union and typedef types. -type_decls: std.AutoArrayHashMapUnmanaged(Node.Index, []const u8) = .empty, +type_decls: std.array_hash_map.Auto(Node.Index, []const u8) = .empty, /// Table of record decls that have been demoted to opaques. opaque_demotes: std.HashMapUnmanaged(QualType, void, QualTypeHashContext, std.hash_map.default_max_load_percentage) = .empty, /// Table of unnamed enums and records that are child types of typedefs. @@ -123,7 +123,7 @@ anonymous_record_field_names: std.HashMapUnmanaged( /// a list of names that we found by visiting all the top level decls without /// translating them. The other maps are updated as we translate; this one is updated /// up front in a pre-processing step. -global_names: std.StringArrayHashMapUnmanaged(void) = .empty, +global_names: std.array_hash_map.String(void) = .empty, /// This is similar to `global_names`, but contains names which we would /// *like* to use, but do not strictly *have* to if they are unavailable. @@ -132,11 +132,11 @@ global_names: std.StringArrayHashMapUnmanaged(void) = .empty, /// may be mangled. /// This is distinct from `global_names` so we can detect at a type /// declaration whether or not the name is available. -weak_global_names: std.StringArrayHashMapUnmanaged(void) = .empty, +weak_global_names: std.array_hash_map.String(void) = .empty, /// Set of identifiers known to refer to typedef declarations. /// Used when parsing macros. -typedefs: std.StringArrayHashMapUnmanaged(void) = .empty, +typedefs: std.array_hash_map.String(void) = .empty, /// The lhs lval of a compound assignment expression. compound_assign_dummy: ?ZigNode = null, diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index 04370b2fd86f6febda129b81a516173f3f8f6e1d..73bb514565d0ee57ed721b7b366ebea209cff107 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -404,10 +404,6 @@ pub const want_ppc_abi = builtin.cpu.arch.isPowerPC(); pub const want_float_exceptions = !builtin.cpu.arch.isWasm(); -// Libcalls that involve u128 on Windows x86-64 are expected by LLVM to use the -// calling convention of @Vector(2, u64), rather than what's standard. -pub const want_windows_v2u64_abi = builtin.os.tag == .windows and builtin.cpu.arch == .x86_64 and !ofmt_c; - /// This governs whether to use these symbol names for f16/f32 conversions /// rather than the standard names: /// * __gnu_f2h_ieee diff --git a/lib/compiler_rt/divdf3.zig b/lib/compiler_rt/divdf3.zig index 489c556186e2b3c2edd865efc26adcbf16b2e179..3ad767dbf2292d403aa0e2aafbdaf20f80ff9571 100644 --- a/lib/compiler_rt/divdf3.zig +++ b/lib/compiler_rt/divdf3.zig @@ -4,7 +4,7 @@ const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; const wideMultiply = compiler_rt.wideMultiply; @@ -189,14 +189,13 @@ inline fn div(a: f64, b: f64) f64 { const writtenExponent = quotientExponent +% exponentBias; + const round = @intFromBool((residual << 1) >= bSignificand); + if (writtenExponent >= maxExponent) { // If we have overflowed the exponent, return infinity. return @bitCast(infRep | quotientSign); } else if (writtenExponent < 1) { if (writtenExponent == 0) { - // Check whether the rounded result is normal. - const round = @intFromBool((residual << 1) > bSignificand); - // Clear the implicit bit. var absResult = quotient & significandMask; // Round. absResult += round; @@ -205,11 +204,16 @@ inline fn div(a: f64, b: f64) f64 { return @bitCast(absResult | quotientSign); } } - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return @bitCast(quotientSign); + + const roundedQuotient = quotient +% round; + const shiftAmount: u32 = @intCast(1 - writtenExponent); + if (shiftAmount > significandBits + 1) { + return @bitCast(quotientSign); + } + + const denormQuotient = roundedQuotient >> @as(std.math.Log2Int(Z), @intCast(shiftAmount)); + return @bitCast((denormQuotient & significandMask) | quotientSign); } else { - const round = @intFromBool((residual << 1) > bSignificand); // Clear the implicit bit var absResult = quotient & significandMask; // Insert the exponent diff --git a/lib/compiler_rt/divdf3_test.zig b/lib/compiler_rt/divdf3_test.zig index 1524f9833fef3a4eb2022e302ee7d697f32b4797..45de9b27ef794706fc6e0e297f4289be3ae549fc 100644 --- a/lib/compiler_rt/divdf3_test.zig +++ b/lib/compiler_rt/divdf3_test.zig @@ -2,8 +2,15 @@ // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divdf3_test.c +const std = @import("std"); +const math = std.math; +const testing = std.testing; + const __divdf3 = @import("divdf3.zig").__divdf3; -const testing = @import("std").testing; + +const nanRep: u64 = @as(u64, @bitCast(math.nan(f64))); +const infRep: u64 = @as(u64, @bitCast(math.inf(f64))); +const negInfRep: u64 = @as(u64, @bitCast(-math.inf(f64))); fn compareResultD(result: f64, expected: u64) bool { const rep: u64 = @bitCast(result); @@ -12,7 +19,7 @@ fn compareResultD(result: f64, expected: u64) bool { return true; } // test other possible NaN representation(signal NaN) - else if (expected == 0x7ff8000000000000) { + else if (expected == nanRep) { if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) { @@ -32,4 +39,28 @@ test "divdf3" { try test__divdf3(1.0, 3.0, 0x3fd5555555555555); try test__divdf3(4.450147717014403e-308, 2.0, 0x10000000000000); try test__divdf3(1.0, 0x1.fffffffffffffp-1, 0x3ff0000000000001); + + try test__divdf3(math.nan(f64), 1.0, nanRep); + try test__divdf3(1.0, math.nan(f64), nanRep); + + try test__divdf3(math.inf(f64), 1.0, infRep); + try test__divdf3(-math.inf(f64), 1.0, negInfRep); + try test__divdf3(1.0, math.inf(f64), 0x0000000000000000); + try test__divdf3(1.0, -math.inf(f64), 0x8000000000000000); + + try test__divdf3(math.inf(f64), math.inf(f64), nanRep); + try test__divdf3(0.0, 0.0, nanRep); + try test__divdf3(-0.0, 0.0, nanRep); + + try test__divdf3(0.0, 1.0, 0x0000000000000000); + try test__divdf3(-0.0, 1.0, 0x8000000000000000); + try test__divdf3(1.0, 0.0, infRep); + try test__divdf3(1.0, -0.0, negInfRep); + + try test__divdf3(0x1p-1022, 0x1p52, 0x0000000000000001); + try test__divdf3(-0x1p-1022, 0x1p52, 0x8000000000000001); + try test__divdf3(0x1p-1022, -0x1p52, 0x8000000000000001); + + try test__divdf3(1.0, 0x1p1023, 0x0008000000000000); + try test__divdf3(-1.0, 0x1p1023, 0x8008000000000000); } diff --git a/lib/compiler_rt/divsf3.zig b/lib/compiler_rt/divsf3.zig index dc017dbde1fee6973e140a25e9b416f701460459..c0fbcb92b743fff4e12db533d7694210e7ebb0a2 100644 --- a/lib/compiler_rt/divsf3.zig +++ b/lib/compiler_rt/divsf3.zig @@ -5,7 +5,7 @@ const std = @import("std"); const compiler_rt = @import("../compiler_rt.zig"); -const symbol = @import("../compiler_rt.zig").symbol; +const symbol = compiler_rt.symbol; const normalize = compiler_rt.normalize; comptime { @@ -170,14 +170,14 @@ inline fn div(a: f32, b: f32) f32 { const writtenExponent = quotientExponent +% exponentBias; + const round = @intFromBool((residual << 1) >= bSignificand); + if (writtenExponent >= maxExponent) { // If we have overflowed the exponent, return infinity. return @bitCast(infRep | quotientSign); } else if (writtenExponent < 1) { if (writtenExponent == 0) { // Check whether the rounded result is normal. - const round = @intFromBool((residual << 1) > bSignificand); - // Clear the implicit bit. var absResult = quotient & significandMask; // Round. absResult += round; @@ -186,11 +186,16 @@ inline fn div(a: f32, b: f32) f32 { return @bitCast(absResult | quotientSign); } } - // Flush denormals to zero. In the future, it would be nice to add - // code to round them correctly. - return @bitCast(quotientSign); + + const roundedQuotient = quotient +% round; + const shiftAmount: u32 = @intCast(1 - writtenExponent); + if (shiftAmount > significandBits + 1) { + return @bitCast(quotientSign); + } + + const denormQuotient = roundedQuotient >> @as(std.math.Log2Int(Z), @intCast(shiftAmount)); + return @bitCast((denormQuotient & significandMask) | quotientSign); } else { - const round = @intFromBool((residual << 1) > bSignificand); // Clear the implicit bit var absResult = quotient & significandMask; // Insert the exponent diff --git a/lib/compiler_rt/divsf3_test.zig b/lib/compiler_rt/divsf3_test.zig index 1af93bc77c80e2c97020d2dd63b17a421a86293e..c457915e49cd41986f1470b2f868398cfad855e9 100644 --- a/lib/compiler_rt/divsf3_test.zig +++ b/lib/compiler_rt/divsf3_test.zig @@ -2,8 +2,15 @@ // // https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/test/builtins/Unit/divsf3_test.c +const std = @import("std"); +const math = std.math; +const testing = std.testing; + const __divsf3 = @import("divsf3.zig").__divsf3; -const testing = @import("std").testing; + +const nanRep: u32 = @as(u32, @bitCast(math.nan(f32))); +const infRep: u32 = @as(u32, @bitCast(math.inf(f32))); +const negInfRep: u32 = @as(u32, @bitCast(-math.inf(f32))); fn compareResultF(result: f32, expected: u32) bool { const rep: u32 = @bitCast(result); @@ -12,7 +19,7 @@ fn compareResultF(result: f32, expected: u32) bool { return true; } // test other possible NaN representation(signal NaN) - else if (expected == 0x7fc00000) { + else if (expected == nanRep) { if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) { @@ -32,4 +39,28 @@ test "divsf3" { try test__divsf3(1.0, 3.0, 0x3EAAAAAB); try test__divsf3(2.3509887e-38, 2.0, 0x00800000); try test__divsf3(1.0, 0x1.fffffep-1, 0x3f800001); + + try test__divsf3(math.nan(f32), 1.0, nanRep); + try test__divsf3(1.0, math.nan(f32), nanRep); + + try test__divsf3(math.inf(f32), 1.0, infRep); + try test__divsf3(-math.inf(f32), 1.0, negInfRep); + try test__divsf3(1.0, math.inf(f32), 0x00000000); + try test__divsf3(1.0, -math.inf(f32), 0x80000000); + + try test__divsf3(math.inf(f32), math.inf(f32), nanRep); + try test__divsf3(0.0, 0.0, nanRep); + try test__divsf3(-0.0, 0.0, nanRep); + + try test__divsf3(0.0, 1.0, 0x00000000); + try test__divsf3(-0.0, 1.0, 0x80000000); + try test__divsf3(1.0, 0.0, infRep); + try test__divsf3(1.0, -0.0, negInfRep); + + try test__divsf3(0x1p-126, 0x1p23, 0x00000001); + try test__divsf3(-0x1p-126, 0x1p23, 0x80000001); + try test__divsf3(0x1p-126, -0x1p23, 0x80000001); + + try test__divsf3(1.0, 0x1p127, 0x00400000); + try test__divsf3(-1.0, 0x1p127, 0x80400000); } diff --git a/lib/compiler_rt/divtf3_test.zig b/lib/compiler_rt/divtf3_test.zig index 4573d2ed85a6d7581a230ccfe5264de463a57ea6..4d10e5c39d7dc61b1c317364750757148635543d 100644 --- a/lib/compiler_rt/divtf3_test.zig +++ b/lib/compiler_rt/divtf3_test.zig @@ -30,14 +30,19 @@ fn test__divtf3(a: f128, b: f128, expectedHi: u64, expectedLo: u64) !void { } test "divtf3" { - // NaN / any = NaN try test__divtf3(math.nan(f128), 0x1.23456789abcdefp+5, 0x7fff800000000000, 0); - // inf / any(except inf and nan) = inf + try test__divtf3(0x1.23456789abcdefp+5, math.nan(f128), 0x7fff800000000000, 0); try test__divtf3(math.inf(f128), 0x1.23456789abcdefp+5, 0x7fff000000000000, 0); - // inf / inf = nan + try test__divtf3(-math.inf(f128), 0x1.23456789abcdefp+5, 0xffff000000000000, 0); + try test__divtf3(0x1.23456789abcdefp+5, math.inf(f128), 0, 0); + try test__divtf3(0x1.23456789abcdefp+5, -math.inf(f128), 0x8000000000000000, 0); try test__divtf3(math.inf(f128), math.inf(f128), 0x7fff800000000000, 0); - // inf / nan = nan - try test__divtf3(math.inf(f128), math.nan(f128), 0x7fff800000000000, 0); + try test__divtf3(0.0, 0.0, 0x7fff800000000000, 0); + try test__divtf3(-0.0, 0.0, 0x7fff800000000000, 0); + try test__divtf3(0.0, 1.0, 0, 0); + try test__divtf3(-0.0, 1.0, 0x8000000000000000, 0); + try test__divtf3(1.0, 0.0, 0x7fff000000000000, 0); + try test__divtf3(1.0, -0.0, 0xffff000000000000, 0); try test__divtf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.eedcbaba3a94546558237654321fp-1, 0x4004b0b72924d407, 0x0717e84356c6eba2); try test__divtf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50, 0x1.ed2c3ba15935332532287654321fp-9, 0x3fd5b2af3f828c9b, 0x40e51f64cde8b1f2); diff --git a/lib/compiler_rt/divxf3_test.zig b/lib/compiler_rt/divxf3_test.zig index 0aec97b54d07d72c549a5b59f0cfd753807b7507..cb897a1014022d50e8cb93043749b033b56af55d 100644 --- a/lib/compiler_rt/divxf3_test.zig +++ b/lib/compiler_rt/divxf3_test.zig @@ -4,6 +4,10 @@ const testing = std.testing; const __divxf3 = @import("divxf3.zig").__divxf3; +const nanRep: u80 = @as(u80, @bitCast(math.nan(f80))); +const infRep: u80 = @as(u80, @bitCast(math.inf(f80))); +const negInfRep: u80 = @as(u80, @bitCast(-math.inf(f80))); + fn compareResult(result: f80, expected: u80) bool { const rep: u80 = @bitCast(result); @@ -39,14 +43,19 @@ fn test__divxf3(a: f80, b: f80) !void { } test "divxf3" { - // NaN / any = NaN - try expect__divxf3_result(math.nan(f80), 0x1.23456789abcdefp+5, 0x7fffC000000000000000); - // inf / any(except inf and nan) = inf - try expect__divxf3_result(math.inf(f80), 0x1.23456789abcdefp+5, 0x7fff8000000000000000); - // inf / inf = nan - try expect__divxf3_result(math.inf(f80), math.inf(f80), 0x7fffC000000000000000); - // inf / nan = nan - try expect__divxf3_result(math.inf(f80), math.nan(f80), 0x7fffC000000000000000); + try expect__divxf3_result(math.nan(f80), 0x1.23456789abcdefp+5, nanRep); + try expect__divxf3_result(0x1.23456789abcdefp+5, math.nan(f80), nanRep); + try expect__divxf3_result(math.inf(f80), 0x1.23456789abcdefp+5, infRep); + try expect__divxf3_result(-math.inf(f80), 0x1.23456789abcdefp+5, negInfRep); + try expect__divxf3_result(0x1.23456789abcdefp+5, math.inf(f80), 0x0); + try expect__divxf3_result(0x1.23456789abcdefp+5, -math.inf(f80), 0x80000000000000000000); + try expect__divxf3_result(math.inf(f80), math.inf(f80), nanRep); + try expect__divxf3_result(0.0, 0.0, nanRep); + try expect__divxf3_result(-0.0, 0.0, nanRep); + try expect__divxf3_result(0.0, 1.0, 0x0); + try expect__divxf3_result(-0.0, 1.0, 0x80000000000000000000); + try expect__divxf3_result(1.0, 0.0, infRep); + try expect__divxf3_result(1.0, -0.0, negInfRep); try test__divxf3(0x1.a23b45362464523375893ab4cdefp+5, 0x1.eedcbaba3a94546558237654321fp-1); try test__divxf3(0x1.a2b34c56d745382f9abf2c3dfeffp-50, 0x1.ed2c3ba15935332532287654321fp-9); diff --git a/lib/compiler_rt/fixdfti.zig b/lib/compiler_rt/fixdfti.zig index 4717fd7b59f1b17854dfc742b73bfd506c1522fd..ff7434d63da148afc20b22bbfb54d6c1bdd17822 100644 --- a/lib/compiler_rt/fixdfti.zig +++ b/lib/compiler_rt/fixdfti.zig @@ -3,19 +3,9 @@ const intFromFloat = @import("./int_from_float.zig").intFromFloat; const symbol = @import("../compiler_rt.zig").symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixdfti_windows_x86_64, "__fixdfti"); - } else { - symbol(&__fixdfti, "__fixdfti"); - } + symbol(&__fixdfti, "__fixdfti"); } pub fn __fixdfti(a: f64) callconv(.c) i128 { return intFromFloat(i128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixdfti_windows_x86_64(a: f64) callconv(.c) v2u64 { - return @bitCast(intFromFloat(i128, a)); -} diff --git a/lib/compiler_rt/fixsfti.zig b/lib/compiler_rt/fixsfti.zig index 0980012a453eba643ea0af0206d8256bab481990..121eff084d58a00726ed140a0d4f4cacafdce87b 100644 --- a/lib/compiler_rt/fixsfti.zig +++ b/lib/compiler_rt/fixsfti.zig @@ -4,19 +4,9 @@ const symbol = compiler_rt.symbol; const intFromFloat = @import("./int_from_float.zig").intFromFloat; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixsfti_windows_x86_64, "__fixsfti"); - } else { - symbol(&__fixsfti, "__fixsfti"); - } + symbol(&__fixsfti, "__fixsfti"); } pub fn __fixsfti(a: f32) callconv(.c) i128 { return intFromFloat(i128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixsfti_windows_x86_64(a: f32) callconv(.c) v2u64 { - return @bitCast(intFromFloat(i128, a)); -} diff --git a/lib/compiler_rt/fixtfti.zig b/lib/compiler_rt/fixtfti.zig index cb642d61664a2780003a78cc0293f80657b516a5..0aac298ca2c4d0fa3f8d7fd02cf1290f98929c2b 100644 --- a/lib/compiler_rt/fixtfti.zig +++ b/lib/compiler_rt/fixtfti.zig @@ -3,21 +3,11 @@ const intFromFloat = @import("./int_from_float.zig").intFromFloat; const symbol = @import("../compiler_rt.zig").symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixtfti_windows_x86_64, "__fixtfti"); - } else { - if (compiler_rt.want_ppc_abi) - symbol(&__fixtfti, "__fixkfti"); - symbol(&__fixtfti, "__fixtfti"); - } + if (compiler_rt.want_ppc_abi) + symbol(&__fixtfti, "__fixkfti"); + symbol(&__fixtfti, "__fixtfti"); } pub fn __fixtfti(a: f128) callconv(.c) i128 { return intFromFloat(i128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixtfti_windows_x86_64(a: f128) callconv(.c) v2u64 { - return @bitCast(intFromFloat(i128, a)); -} diff --git a/lib/compiler_rt/fixunsdfti.zig b/lib/compiler_rt/fixunsdfti.zig index 95d15ac3138eab9596b375c50814521c4aac5416..1a634baaf5a6da399abaebb3e236ea5c02005ead 100644 --- a/lib/compiler_rt/fixunsdfti.zig +++ b/lib/compiler_rt/fixunsdfti.zig @@ -3,19 +3,9 @@ const symbol = @import("../compiler_rt.zig").symbol; const intFromFloat = @import("./int_from_float.zig").intFromFloat; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixunsdfti_windows_x86_64, "__fixunsdfti"); - } else { - symbol(&__fixunsdfti, "__fixunsdfti"); - } + symbol(&__fixunsdfti, "__fixunsdfti"); } pub fn __fixunsdfti(a: f64) callconv(.c) u128 { return intFromFloat(u128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixunsdfti_windows_x86_64(a: f64) callconv(.c) v2u64 { - return @bitCast(intFromFloat(u128, a)); -} diff --git a/lib/compiler_rt/fixunshfti.zig b/lib/compiler_rt/fixunshfti.zig index a090027196937f25b649dcd6d8e3d589e7cd4083..3dc7a5f99390d05606bb09298651e1d4482e3ab6 100644 --- a/lib/compiler_rt/fixunshfti.zig +++ b/lib/compiler_rt/fixunshfti.zig @@ -3,19 +3,9 @@ const intFromFloat = @import("./int_from_float.zig").intFromFloat; const symbol = @import("../compiler_rt.zig").symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixunshfti_windows_x86_64, "__fixunshfti"); - } else { - symbol(&__fixunshfti, "__fixunshfti"); - } + symbol(&__fixunshfti, "__fixunshfti"); } pub fn __fixunshfti(a: f16) callconv(.c) u128 { return intFromFloat(u128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixunshfti_windows_x86_64(a: f16) callconv(.c) v2u64 { - return @bitCast(intFromFloat(u128, a)); -} diff --git a/lib/compiler_rt/fixunssfti.zig b/lib/compiler_rt/fixunssfti.zig index da46f43d5bc111b53ee317a70a0456d3ea554853..6824afcde4b518642189696a47c0983047dd47c3 100644 --- a/lib/compiler_rt/fixunssfti.zig +++ b/lib/compiler_rt/fixunssfti.zig @@ -4,19 +4,9 @@ const intFromFloat = @import("./int_from_float.zig").intFromFloat; const symbol = @import("../compiler_rt.zig").symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixunssfti_windows_x86_64, "__fixunssfti"); - } else { - symbol(&__fixunssfti, "__fixunssfti"); - } + symbol(&__fixunssfti, "__fixunssfti"); } pub fn __fixunssfti(a: f32) callconv(.c) u128 { return intFromFloat(u128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixunssfti_windows_x86_64(a: f32) callconv(.c) v2u64 { - return @bitCast(intFromFloat(u128, a)); -} diff --git a/lib/compiler_rt/fixunstfti.zig b/lib/compiler_rt/fixunstfti.zig index 81c2a160957c20492c3781353a4042807d7ed0af..78c6b1e8f7b90aa5d90a957920e949bb0aa2cbc0 100644 --- a/lib/compiler_rt/fixunstfti.zig +++ b/lib/compiler_rt/fixunstfti.zig @@ -4,21 +4,11 @@ const symbol = compiler_rt.symbol; const intFromFloat = @import("./int_from_float.zig").intFromFloat; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixunstfti_windows_x86_64, "__fixunstfti"); - } else { - if (compiler_rt.want_ppc_abi) - symbol(&__fixunstfti, "__fixunskfti"); - symbol(&__fixunstfti, "__fixunstfti"); - } + if (compiler_rt.want_ppc_abi) + symbol(&__fixunstfti, "__fixunskfti"); + symbol(&__fixunstfti, "__fixunstfti"); } pub fn __fixunstfti(a: f128) callconv(.c) u128 { return intFromFloat(u128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixunstfti_windows_x86_64(a: f128) callconv(.c) v2u64 { - return @bitCast(intFromFloat(u128, a)); -} diff --git a/lib/compiler_rt/fixunsxfti.zig b/lib/compiler_rt/fixunsxfti.zig index 24296dd416c85377442b95e1dcdea92ed27a96e7..064c1352c9045870c1a984850f71c86fcf6e8e61 100644 --- a/lib/compiler_rt/fixunsxfti.zig +++ b/lib/compiler_rt/fixunsxfti.zig @@ -4,19 +4,9 @@ const symbol = compiler_rt.symbol; const intFromFloat = @import("./int_from_float.zig").intFromFloat; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixunsxfti_windows_x86_64, "__fixunsxfti"); - } else { - symbol(&__fixunsxfti, "__fixunsxfti"); - } + symbol(&__fixunsxfti, "__fixunsxfti"); } pub fn __fixunsxfti(a: f80) callconv(.c) u128 { return intFromFloat(u128, a); } - -const v2u64 = @Vector(2, u64); - -fn __fixunsxfti_windows_x86_64(a: f80) callconv(.c) v2u64 { - return @bitCast(intFromFloat(u128, a)); -} diff --git a/lib/compiler_rt/float_from_int.zig b/lib/compiler_rt/float_from_int.zig index d275e181799b4de5ef87a12933beca8e355af935..548d027accbb674e1ecbaeb77ef01a5491e256bc 100644 --- a/lib/compiler_rt/float_from_int.zig +++ b/lib/compiler_rt/float_from_int.zig @@ -64,10 +64,21 @@ 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 { switch (x.len) { 0 => return 0, - inline 1...4 => |limbs_len| return @floatFromInt(@as( - @Int(signedness, 32 * limbs_len), - @bitCast(x[0..limbs_len].*), - )), + inline 1...4 => |limbs_len| { + const low_to_high: [limbs_len]u32 = switch (@import("builtin").cpu.arch.endian()) { + .little => x[0..limbs_len].*, + .big => switch (limbs_len) { + 1 => .{x[0]}, + 2 => .{ x[1], x[0] }, + 3 => .{ x[2], x[1], x[0] }, + 4 => .{ x[3], x[2], x[1], x[0] }, + else => comptime unreachable, + }, + }; + const I = @Int(signedness, 32 * limbs_len); + const int: I = @bitCast(low_to_high); + return @floatFromInt(int); + }, else => {}, } diff --git a/lib/compiler_rt/floattidf.zig b/lib/compiler_rt/floattidf.zig index 5fd6b4c0f68782935fb6b90713228dabfab7d928..02298705324edcd49b36f69a64c0c78873ecb57b 100644 --- a/lib/compiler_rt/floattidf.zig +++ b/lib/compiler_rt/floattidf.zig @@ -3,17 +3,9 @@ const symbol = @import("../compiler_rt.zig").symbol; const floatFromInt = @import("./float_from_int.zig").floatFromInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floattidf_windows_x86_64, "__floattidf"); - } else { - symbol(&__floattidf, "__floattidf"); - } + symbol(&__floattidf, "__floattidf"); } pub fn __floattidf(a: i128) callconv(.c) f64 { return floatFromInt(f64, a); } - -fn __floattidf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f64 { - return floatFromInt(f64, @as(i128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floattihf.zig b/lib/compiler_rt/floattihf.zig index 643849f48e25ca2735ab813dd152f3b93015fcbf..a751e3142c5b273819199105a6848c0280aee3c5 100644 --- a/lib/compiler_rt/floattihf.zig +++ b/lib/compiler_rt/floattihf.zig @@ -4,17 +4,9 @@ const symbol = compiler_rt.symbol; const floatFromInt = @import("./float_from_int.zig").floatFromInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floattihf_windows_x86_64, "__floattihf"); - } else { - symbol(&__floattihf, "__floattihf"); - } + symbol(&__floattihf, "__floattihf"); } pub fn __floattihf(a: i128) callconv(.c) f16 { return floatFromInt(f16, a); } - -fn __floattihf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f16 { - return floatFromInt(f16, @as(i128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floattisf.zig b/lib/compiler_rt/floattisf.zig index 8926105d2df059bccfdf34bebfcff4277c988504..72af61c6b6805d9bd03e6d215dd300fe7589c21f 100644 --- a/lib/compiler_rt/floattisf.zig +++ b/lib/compiler_rt/floattisf.zig @@ -3,17 +3,9 @@ const floatFromInt = @import("./float_from_int.zig").floatFromInt; const symbol = @import("../compiler_rt.zig").symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floattisf_windows_x86_64, "__floattisf"); - } else { - symbol(&__floattisf, "__floattisf"); - } + symbol(&__floattisf, "__floattisf"); } pub fn __floattisf(a: i128) callconv(.c) f32 { return floatFromInt(f32, a); } - -fn __floattisf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f32 { - return floatFromInt(f32, @as(i128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floattitf.zig b/lib/compiler_rt/floattitf.zig index f8e6ca80e61d65f4c765b94aade334ccd13d1ed1..3e49a68fd56912ebe7573346b6b8aea6b98b91ba 100644 --- a/lib/compiler_rt/floattitf.zig +++ b/lib/compiler_rt/floattitf.zig @@ -3,19 +3,11 @@ const symbol = @import("../compiler_rt.zig").symbol; const floatFromInt = @import("./float_from_int.zig").floatFromInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floattitf_windows_x86_64, "__floattitf"); - } else { - if (compiler_rt.want_ppc_abi) - symbol(&__floattitf, "__floattikf"); - symbol(&__floattitf, "__floattitf"); - } + if (compiler_rt.want_ppc_abi) + symbol(&__floattitf, "__floattikf"); + symbol(&__floattitf, "__floattitf"); } pub fn __floattitf(a: i128) callconv(.c) f128 { return floatFromInt(f128, a); } - -fn __floattitf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f128 { - return floatFromInt(f128, @as(i128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floattixf.zig b/lib/compiler_rt/floattixf.zig index b69b8f9845fa858e5a05133aa4b69a5c11342ca3..be05180795aef517800c15d01c928bab4f7f19a0 100644 --- a/lib/compiler_rt/floattixf.zig +++ b/lib/compiler_rt/floattixf.zig @@ -4,17 +4,9 @@ const symbol = compiler_rt.symbol; const floatFromInt = @import("./float_from_int.zig").floatFromInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floattixf_windows_x86_64, "__floattixf"); - } else { - symbol(&__floattixf, "__floattixf"); - } + symbol(&__floattixf, "__floattixf"); } pub fn __floattixf(a: i128) callconv(.c) f80 { return floatFromInt(f80, a); } - -fn __floattixf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f80 { - return floatFromInt(f80, @as(i128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floatuntidf.zig b/lib/compiler_rt/floatuntidf.zig index 7e08a66b97c4f18a85ec386e4fc8eda16bb972ab..b770457bc4992a5bd6237d832e2ca4c0cbed11e0 100644 --- a/lib/compiler_rt/floatuntidf.zig +++ b/lib/compiler_rt/floatuntidf.zig @@ -3,17 +3,9 @@ const floatFromInt = @import("./float_from_int.zig").floatFromInt; const symbol = @import("../compiler_rt.zig").symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floatuntidf_windows_x86_64, "__floatuntidf"); - } else { - symbol(&__floatuntidf, "__floatuntidf"); - } + symbol(&__floatuntidf, "__floatuntidf"); } pub fn __floatuntidf(a: u128) callconv(.c) f64 { return floatFromInt(f64, a); } - -fn __floatuntidf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f64 { - return floatFromInt(f64, @as(u128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floatuntihf.zig b/lib/compiler_rt/floatuntihf.zig index 5c50f39eaad5be332c32eb5618e8ff8011f660b1..5b4373cb7c496b0acf1a2fe6ef988872b30e8780 100644 --- a/lib/compiler_rt/floatuntihf.zig +++ b/lib/compiler_rt/floatuntihf.zig @@ -3,17 +3,9 @@ const symbol = @import("../compiler_rt.zig").symbol; const floatFromInt = @import("./float_from_int.zig").floatFromInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floatuntihf_windows_x86_64, "__floatuntihf"); - } else { - symbol(&__floatuntihf, "__floatuntihf"); - } + symbol(&__floatuntihf, "__floatuntihf"); } pub fn __floatuntihf(a: u128) callconv(.c) f16 { return floatFromInt(f16, a); } - -fn __floatuntihf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f16 { - return floatFromInt(f16, @as(u128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floatuntisf.zig b/lib/compiler_rt/floatuntisf.zig index 5a15f7c19d9f6906bb1a485d7101976f2297ac40..de9a021476edecfcc26761133c0645d799c677da 100644 --- a/lib/compiler_rt/floatuntisf.zig +++ b/lib/compiler_rt/floatuntisf.zig @@ -4,17 +4,9 @@ const symbol = compiler_rt.symbol; const floatFromInt = @import("./float_from_int.zig").floatFromInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floatuntisf_windows_x86_64, "__floatuntisf"); - } else { - symbol(&__floatuntisf, "__floatuntisf"); - } + symbol(&__floatuntisf, "__floatuntisf"); } pub fn __floatuntisf(a: u128) callconv(.c) f32 { return floatFromInt(f32, a); } - -fn __floatuntisf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f32 { - return floatFromInt(f32, @as(u128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floatuntitf.zig b/lib/compiler_rt/floatuntitf.zig index 6df02c5bef9a6d43c54a82e207446d049a0b84e8..47cd65cc3ff4460d937e0ccd7acabb2455ae704a 100644 --- a/lib/compiler_rt/floatuntitf.zig +++ b/lib/compiler_rt/floatuntitf.zig @@ -3,19 +3,11 @@ const floatFromInt = @import("./float_from_int.zig").floatFromInt; const symbol = @import("../compiler_rt.zig").symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floatuntitf_windows_x86_64, "__floatuntitf"); - } else { - if (compiler_rt.want_ppc_abi) - symbol(&__floatuntitf, "__floatuntikf"); - symbol(&__floatuntitf, "__floatuntitf"); - } + if (compiler_rt.want_ppc_abi) + symbol(&__floatuntitf, "__floatuntikf"); + symbol(&__floatuntitf, "__floatuntitf"); } pub fn __floatuntitf(a: u128) callconv(.c) f128 { return floatFromInt(f128, a); } - -fn __floatuntitf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f128 { - return floatFromInt(f128, @as(u128, @bitCast(a))); -} diff --git a/lib/compiler_rt/floatuntixf.zig b/lib/compiler_rt/floatuntixf.zig index 27e668109fdc4eaf3315dea7e129aa70393782c7..41fb45b3a3a1b8e213c03a4ef5e847feb8d31211 100644 --- a/lib/compiler_rt/floatuntixf.zig +++ b/lib/compiler_rt/floatuntixf.zig @@ -4,17 +4,9 @@ const symbol = compiler_rt.symbol; const floatFromInt = @import("./float_from_int.zig").floatFromInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__floatuntixf_windows_x86_64, "__floatuntixf"); - } else { - symbol(&__floatuntixf, "__floatuntixf"); - } + symbol(&__floatuntixf, "__floatuntixf"); } pub fn __floatuntixf(a: u128) callconv(.c) f80 { return floatFromInt(f80, a); } - -fn __floatuntixf_windows_x86_64(a: @Vector(2, u64)) callconv(.c) f80 { - return floatFromInt(f80, @as(u128, @bitCast(a))); -} diff --git a/lib/compiler_rt/int_from_float.zig b/lib/compiler_rt/int_from_float.zig index 494ac6cdc392001e356f713bee733c73b19069e1..5445e7fb7c6d36111d89112350b5bfc9ced375c8 100644 --- a/lib/compiler_rt/int_from_float.zig +++ b/lib/compiler_rt/int_from_float.zig @@ -6,32 +6,16 @@ const compiler_rt = @import("../compiler_rt.zig"); const symbol = compiler_rt.symbol; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixxfti_windows_x86_64, "__fixxfti"); - } else { - symbol(&__fixxfti, "__fixxfti"); - } - + symbol(&__fixxfti, "__fixxfti"); symbol(&__fixhfsi, "__fixhfsi"); symbol(&__fixhfdi, "__fixhfdi"); - - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__fixhfti_windows_x86_64, "__fixhfti"); - } else { - symbol(&__fixhfti, "__fixhfti"); - } + symbol(&__fixhfti, "__fixhfti"); } -const v2u64 = @Vector(2, u64); - pub fn __fixhfti(a: f16) callconv(.c) i128 { return intFromFloat(i128, a); } -fn __fixhfti_windows_x86_64(a: f16) callconv(.c) v2u64 { - return @bitCast(intFromFloat(i128, a)); -} - fn __fixhfdi(a: f16) callconv(.c) i64 { return intFromFloat(i64, a); } @@ -44,10 +28,6 @@ pub fn __fixxfti(a: f80) callconv(.c) i128 { return intFromFloat(i128, a); } -fn __fixxfti_windows_x86_64(a: f80) callconv(.c) v2u64 { - return @bitCast(intFromFloat(i128, a)); -} - pub inline fn intFromFloat(comptime I: type, a: anytype) I { const F = @TypeOf(a); const float_bits = @typeInfo(F).float.bits; @@ -100,10 +80,18 @@ pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, resul switch (result.len) { 0 => return, inline 1...4 => |limbs_len| { - result[0..limbs_len].* = @bitCast(@as( - @Int(signedness, 32 * limbs_len), - @intFromFloat(a), - )); + 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()) { + .little => low_to_high, + .big => switch (limbs_len) { + 1 => .{low_to_high[0]}, + 2 => .{ low_to_high[1], low_to_high[0] }, + 3 => .{ low_to_high[2], low_to_high[1], low_to_high[0] }, + 4 => .{ low_to_high[3], low_to_high[2], low_to_high[1], low_to_high[0] }, + else => comptime unreachable, + }, + }; return; }, else => {}, diff --git a/lib/compiler_rt/limb64.zig b/lib/compiler_rt/limb64.zig index e21e2f21fdc99ee34dc04c49d922db821fd22385..56e4bfc817373e3ba1e90c3525f83ee6a99fd995 100644 --- a/lib/compiler_rt/limb64.zig +++ b/lib/compiler_rt/limb64.zig @@ -75,7 +75,17 @@ fn asLimbs(v: anytype) Limbs(@TypeOf(v)) { const int_info = @typeInfo(T).int; const limb_cnt = comptime limbCount(int_info.bits); const ET = @Int(int_info.signedness, limb_cnt * 64); - return @bitCast(@as(ET, v)); + const low_to_high: Limbs(T) = @bitCast(@as(ET, v)); + switch (endian) { + .little => return low_to_high, + .big => { + var swapped: Limbs(T) = undefined; + for (low_to_high, 0..) |x, i| { + swapped[limb_cnt - i - 1] = x; + } + return swapped; + }, + } } fn limbWrap(limb: u64, is_signed: bool, bits: u16) u64 { @@ -944,11 +954,7 @@ inline fn add3(x: *[3]u64, start: usize, v0: u64) void { fn mulwide(a: u64, b: u64) [2]u64 { const muldXi = @import("mulXi3.zig").muldXi; - const limbs: [2]u64 = @bitCast(muldXi(u64, a, b)); - return switch (endian) { - .little => limbs, - .big => .{ limbs[1], limbs[0] }, - }; + return @bitCast(muldXi(u64, a, b)); } fn __mulo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool { diff --git a/lib/compiler_rt/mulXi3.zig b/lib/compiler_rt/mulXi3.zig index 9fce9754f3a748e82e55728e5e18195970e53b52..5766a070fdd9bef9da49d03890a8fa65a004cda8 100644 --- a/lib/compiler_rt/mulXi3.zig +++ b/lib/compiler_rt/mulXi3.zig @@ -12,11 +12,7 @@ comptime { } else { symbol(&__muldi3, "__muldi3"); } - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__multi3_windows_x86_64, "__multi3"); - } else { - symbol(&__multi3, "__multi3"); - } + symbol(&__multi3, "__multi3"); } pub fn __mulsi3(a: i32, b: i32) callconv(.c) i32 { @@ -89,12 +85,6 @@ pub fn __multi3(a: i128, b: i128) callconv(.c) i128 { return mulX(i128, a, b); } -const v2u64 = @Vector(2, u64); - -fn __multi3_windows_x86_64(a: v2u64, b: v2u64) callconv(.c) v2u64 { - return @bitCast(mulX(i128, @as(i128, @bitCast(a)), @as(i128, @bitCast(b)))); -} - test { _ = @import("mulXi3_test.zig"); } diff --git a/lib/compiler_rt/udivmod.zig b/lib/compiler_rt/udivmod.zig index fdb338c21ac012c786f2fba1c54f9dfc119f0c88..01b7ebe96753983c8bba0b722e846baaee1b1a75 100644 --- a/lib/compiler_rt/udivmod.zig +++ b/lib/compiler_rt/udivmod.zig @@ -8,40 +8,21 @@ const symbol = compiler_rt.symbol; const HalveInt = compiler_rt.HalveInt; comptime { - if (compiler_rt.want_windows_v2u64_abi) { - symbol(&__umodti3_windows_x86_64, "__umodti3"); - symbol(&__modti3_windows_x86_64, "__modti3"); - symbol(&__udivti3_windows_x86_64, "__udivti3"); - symbol(&__divti3_windows_x86_64, "__divti3"); - symbol(&__udivmodti4_windows_x86_64, "__udivmodti4"); - } else { - symbol(&__umodti3, "__umodti3"); - symbol(&__modti3, "__modti3"); - symbol(&__udivti3, "__udivti3"); - symbol(&__divti3, "__divti3"); - symbol(&__udivmodti4, "__udivmodti4"); - } + symbol(&__umodti3, "__umodti3"); + symbol(&__modti3, "__modti3"); + symbol(&__udivti3, "__udivti3"); + symbol(&__divti3, "__divti3"); + symbol(&__udivmodti4, "__udivmodti4"); } -const v128 = @Vector(2, u64); -const v2u64 = @Vector(2, u64); - pub fn __udivmodti4(a: u128, b: u128, maybe_rem: ?*u128) callconv(.c) u128 { return udivmod(u128, a, b, maybe_rem); } -fn __udivmodti4_windows_x86_64(a: v2u64, b: v2u64, maybe_rem: ?*u128) callconv(.c) v2u64 { - return @bitCast(udivmod(u128, @bitCast(a), @bitCast(b), maybe_rem)); -} - pub fn __divti3(a: i128, b: i128) callconv(.c) i128 { return div(a, b); } -fn __divti3_windows_x86_64(a: v128, b: v128) callconv(.c) v128 { - return @bitCast(div(@bitCast(a), @bitCast(b))); -} - inline fn div(a: i128, b: i128) i128 { const s_a = a >> (128 - 1); const s_b = b >> (128 - 1); @@ -58,18 +39,10 @@ pub fn __udivti3(a: u128, b: u128) callconv(.c) u128 { return udivmod(u128, a, b, null); } -fn __udivti3_windows_x86_64(a: v2u64, b: v2u64) callconv(.c) v2u64 { - return @bitCast(udivmod(u128, @bitCast(a), @bitCast(b), null)); -} - pub fn __modti3(a: i128, b: i128) callconv(.c) i128 { return mod(a, b); } -fn __modti3_windows_x86_64(a: v2u64, b: v2u64) callconv(.c) v2u64 { - return @bitCast(mod(@as(i128, @bitCast(a)), @as(i128, @bitCast(b)))); -} - inline fn mod(a: i128, b: i128) i128 { const s_a = a >> (128 - 1); // s = a < 0 ? -1 : 0 const s_b = b >> (128 - 1); // s = b < 0 ? -1 : 0 @@ -88,18 +61,6 @@ pub fn __umodti3(a: u128, b: u128) callconv(.c) u128 { return r; } -fn __umodti3_windows_x86_64(a: v2u64, b: v2u64) callconv(.c) v2u64 { - var r: u128 = undefined; - _ = udivmod(u128, @bitCast(a), @bitCast(b), &r); - return @bitCast(r); -} - -const lo = switch (builtin.cpu.arch.endian()) { - .big => 1, - .little => 0, -}; -const hi = 1 - lo; - // Let _u1 and _u0 be the high and low limbs of U respectively. // Returns U / v_ and sets r = U % v_. fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { @@ -191,22 +152,22 @@ pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { return 0; } - const a: [2]HalfT = @bitCast(a_); - const b: [2]HalfT = @bitCast(b_); + const a: [2]HalfT = @bitCast(a_); // [0] is low bits, [1] is high bits + const b: [2]HalfT = @bitCast(b_); // [0] is low bits, [1] is high bits var q: [2]HalfT = undefined; var r: [2]HalfT = undefined; // When the divisor fits in 64 bits, we can use an optimized path - if (b[hi] == 0) { - r[hi] = 0; - if (a[hi] < b[lo]) { + if (b[1] == 0) { + r[1] = 0; + if (a[1] < b[0]) { // The result fits in 64 bits - q[hi] = 0; - q[lo] = divwide(HalfT, a[hi], a[lo], b[lo], &r[lo]); + q[1] = 0; + q[0] = divwide(HalfT, a[1], a[0], b[0], &r[0]); } else { // First, divide with the high part to get the remainder. After that a_hi < b_lo. - q[hi] = a[hi] / b[lo]; - q[lo] = divwide(HalfT, a[hi] % b[lo], a[lo], b[lo], &r[lo]); + q[1] = a[1] / b[0]; + q[0] = divwide(HalfT, a[1] % b[0], a[0], b[0], &r[0]); } if (maybe_rem) |rem| { rem.* = @bitCast(r); @@ -214,21 +175,21 @@ pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { return @bitCast(q); } - // Large-divisor case: b[hi] != 0, so the quotient fits in one HalfT word. + // Large-divisor case: b[1] != 0, so the quotient fits in one HalfT word. // // Trial quotient via divwide (Knuth Vol 2, Section 4.3.1): // Normalize the divisor so its high half has the MSB set, then use divwide // on the top bits to get a trial quotient that is at most 1 too large. // This replaces the O(shift) bit-by-bit loop with O(1) operations. - const s: Log2Int(HalfT) = @intCast(@clz(b[hi])); + const s: Log2Int(HalfT) = @intCast(@clz(b[1])); if (s == 0) { - // b[hi] already has its MSB set, so b >= 2^(T_bits - 1). Since a >= b + // b[1] already has its MSB set, so b >= 2^(T_bits - 1). Since a >= b // (we passed the b_ > a_ check), a >= 2^(T_bits - 1) too, meaning - // a[hi] also has its MSB set. Therefore a / b < 2, and the quotient + // a[1] also has its MSB set. Therefore a / b < 2, and the quotient // is exactly 1. q = @bitCast(@as(T, 0)); - q[lo] = 1; + q[0] = 1; if (maybe_rem) |rem| { rem.* = a_ - b_; } @@ -240,12 +201,12 @@ pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { std.math.IntFittingRange(0, half_bits), @intCast(s), )); - const bn_hi: HalfT = (b[hi] << s) | (b[lo] >> sr); + const bn_hi: HalfT = (b[1] << s) | (b[0] >> sr); // Trial numerator: the top (half_bits + s) bits of (a << s), as [a2:a1]. // a2 < bn_hi is guaranteed since a2 < 2^s and bn_hi >= 2^(half_bits - 1). - const a2: HalfT = a[hi] >> sr; - const a1: HalfT = (a[hi] << s) | (a[lo] >> sr); + const a2: HalfT = a[1] >> sr; + const a1: HalfT = (a[1] << s) | (a[0] >> sr); // Trial quotient via divwide: q_hat = floor([a2:a1] / bn_hi). // By Knuth's theorem (normalized divisor), q <= q_hat <= q + 1. @@ -256,42 +217,42 @@ pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { // Compute the product using HalfT * HalfT -> T widening multiplications, // which are native single-instruction ops when HalfT fits in a register // (e.g. u64 * u64 -> u128 via mulq on x86_64, mul on aarch64). - // product = q_hat * [b[hi]:b[lo]] = [p_top : p_mid : p_lo] (3 half-words) - const prod_lo: T = @as(T, q_hat) * @as(T, b[lo]); - const prod_hi: T = @as(T, q_hat) * @as(T, b[hi]); + // product = q_hat * [b[1]:b[0]] = [p_top : p_mid : p_lo] (3 half-words) + const prod_lo: T = @as(T, q_hat) * @as(T, b[0]); + const prod_hi: T = @as(T, q_hat) * @as(T, b[1]); const prod_lo_parts: [2]HalfT = @bitCast(prod_lo); const prod_hi_parts: [2]HalfT = @bitCast(prod_hi); - const mid_add = @addWithOverflow(prod_hi_parts[lo], prod_lo_parts[hi]); + const mid_add = @addWithOverflow(prod_hi_parts[0], prod_lo_parts[1]); var p_mid: HalfT = mid_add[0]; - const p_top: HalfT = prod_hi_parts[hi] +% @as(HalfT, mid_add[1]); - var p_lo: HalfT = prod_lo_parts[lo]; + const p_top: HalfT = prod_hi_parts[1] +% @as(HalfT, mid_add[1]); + var p_lo: HalfT = prod_lo_parts[0]; // If product > a, decrement q_hat (at most once, guaranteed by Knuth). - if (p_top > 0 or p_mid > a[hi] or (p_mid == a[hi] and p_lo > a[lo])) { + if (p_top > 0 or p_mid > a[1] or (p_mid == a[1] and p_lo > a[0])) { q_hat -= 1; // Subtract b from the product for correct remainder computation. // After correction, (q_hat * b) fits in T bits, so borrows into // p_top cancel it to zero -- we only need [p_mid:p_lo]. - const sub_lo = @subWithOverflow(p_lo, b[lo]); + const sub_lo = @subWithOverflow(p_lo, b[0]); p_lo = sub_lo[0]; - const sub_mid = @subWithOverflow(p_mid, b[hi]); + const sub_mid = @subWithOverflow(p_mid, b[1]); const sub_mid2 = @subWithOverflow(sub_mid[0], @as(HalfT, sub_lo[1])); p_mid = sub_mid2[0]; } q = @bitCast(@as(T, 0)); - q[lo] = q_hat; + q[0] = q_hat; if (maybe_rem) |rem| { - // remainder = a - q_hat * b = [a[hi]:a[lo]] - [p_mid:p_lo] + // remainder = a - q_hat * b = [a[1]:a[0]] - [p_mid:p_lo] // This subtraction is non-negative since q_hat <= true quotient. - const rem_lo = @subWithOverflow(a[lo], p_lo); - r[lo] = rem_lo[0]; - const rem_hi = @subWithOverflow(a[hi], p_mid); + const rem_lo = @subWithOverflow(a[0], p_lo); + r[0] = rem_lo[0]; + const rem_hi = @subWithOverflow(a[1], p_mid); const rem_hi2 = @subWithOverflow(rem_hi[0], @as(HalfT, rem_lo[1])); - r[hi] = rem_hi2[0]; + r[1] = rem_hi2[0]; rem.* = @bitCast(r); } return @bitCast(q); diff --git a/lib/docs/wasm/Walk.zig b/lib/docs/wasm/Walk.zig index f0601e6438f80ce8951146fcbb3024bd8f7cee0b..2d5a45d72f739abb1d763bea3d6804b3ee53859d 100644 --- a/lib/docs/wasm/Walk.zig +++ b/lib/docs/wasm/Walk.zig @@ -10,9 +10,9 @@ const Oom = error{OutOfMemory}; pub const Decl = @import("Decl.zig"); -pub var files: std.StringArrayHashMapUnmanaged(File) = .empty; +pub var files: std.array_hash_map.String(File) = .empty; pub var decls: std.ArrayList(Decl) = .empty; -pub var modules: std.StringArrayHashMapUnmanaged(File.Index) = .empty; +pub var modules: std.array_hash_map.String(File.Index) = .empty; file: File.Index, @@ -42,17 +42,17 @@ pub const Category = union(enum(u8)) { pub const File = struct { ast: Ast, /// Maps identifiers to the declarations they point to. - ident_decls: std.AutoArrayHashMapUnmanaged(Ast.TokenIndex, Ast.Node.Index) = .empty, + ident_decls: std.array_hash_map.Auto(Ast.TokenIndex, Ast.Node.Index) = .empty, /// Maps field access identifiers to the containing field access node. - token_parents: std.AutoArrayHashMapUnmanaged(Ast.TokenIndex, Ast.Node.Index) = .empty, + token_parents: std.array_hash_map.Auto(Ast.TokenIndex, Ast.Node.Index) = .empty, /// Maps declarations to their global index. - node_decls: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, Decl.Index) = .empty, + node_decls: std.array_hash_map.Auto(Ast.Node.Index, Decl.Index) = .empty, /// Maps function declarations to doctests. - doctests: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, Ast.Node.Index) = .empty, + doctests: std.array_hash_map.Auto(Ast.Node.Index, Ast.Node.Index) = .empty, /// root node => its namespace scope /// struct/union/enum/opaque decl node => its namespace scope /// local var decl node => its local variable scope - scopes: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, *Scope) = .empty, + scopes: std.array_hash_map.Auto(Ast.Node.Index, *Scope) = .empty, pub fn lookup_token(file: *File, token: Ast.TokenIndex) Decl.Index { const decl_node = file.ident_decls.get(token) orelse return .none; @@ -465,8 +465,8 @@ pub const Scope = struct { const Namespace = struct { base: Scope = .{ .tag = .namespace }, parent: *Scope, - names: std.StringArrayHashMapUnmanaged(Ast.Node.Index) = .empty, - doctests: std.StringArrayHashMapUnmanaged(Ast.Node.Index) = .empty, + names: std.array_hash_map.String(Ast.Node.Index) = .empty, + doctests: std.array_hash_map.String(Ast.Node.Index) = .empty, decl_index: Decl.Index, }; diff --git a/lib/docs/wasm/main.zig b/lib/docs/wasm/main.zig index bee3e4acbcc370261f3b137d40584ea2ad2f8065..d73f2a68160ff2db197067d8cc39e40e4998a824 100644 --- a/lib/docs/wasm/main.zig +++ b/lib/docs/wasm/main.zig @@ -264,7 +264,7 @@ const ErrorIdentifier = packed struct(u64) { }; var string_result: ArrayList(u8) = .empty; -var error_set_result: std.StringArrayHashMapUnmanaged(ErrorIdentifier) = .empty; +var error_set_result: std.array_hash_map.String(ErrorIdentifier) = .empty; export fn decl_error_set(decl_index: Decl.Index) Slice(ErrorIdentifier) { return Slice(ErrorIdentifier).init(decl_error_set_fallible(decl_index) catch @panic("OOM")); @@ -305,7 +305,7 @@ fn sort_error_set_result() void { fn addErrorsFromDecl( decl_index: Decl.Index, - out: *std.StringArrayHashMapUnmanaged(ErrorIdentifier), + out: *std.array_hash_map.String(ErrorIdentifier), ) Oom!void { switch (decl_index.get().categorize()) { .error_set => |node| try addErrorsFromExpr(decl_index, out, node), @@ -316,7 +316,7 @@ fn addErrorsFromDecl( fn addErrorsFromExpr( decl_index: Decl.Index, - out: *std.StringArrayHashMapUnmanaged(ErrorIdentifier), + out: *std.array_hash_map.String(ErrorIdentifier), node: Ast.Node.Index, ) Oom!void { const decl = decl_index.get(); @@ -343,7 +343,7 @@ fn addErrorsFromExpr( fn addErrorsFromNode( decl_index: Decl.Index, - out: *std.StringArrayHashMapUnmanaged(ErrorIdentifier), + out: *std.array_hash_map.String(ErrorIdentifier), node: Ast.Node.Index, ) Oom!void { const decl = decl_index.get(); diff --git a/lib/fuzzer.zig b/lib/fuzzer.zig index 37189a2b635f0a8c8774ee3d88d670e01bc37b90..acb23b66c58777bc2a6738081e23fcb52ee3c1d9 100644 --- a/lib/fuzzer.zig +++ b/lib/fuzzer.zig @@ -340,7 +340,7 @@ const Fuzzer = struct { quality_buf: []Input.Best, input_buf: []Input.Best.Map, }, - seen_uids: std.ArrayHashMapUnmanaged(Uid, struct { + seen_uids: std.array_hash_map.Custom(Uid, struct { slices: union { ints: std.ArrayList([]u64), bytes: std.ArrayList(Input.Data.Bytes), @@ -505,7 +505,7 @@ const Fuzzer = struct { } }; - pub const UidSlices = std.ArrayHashMapUnmanaged(Uid, struct { + pub const UidSlices = std.array_hash_map.Custom(Uid, struct { base: u32, len: u32, }, Uid.hashmap_ctx, false); @@ -584,7 +584,7 @@ const Fuzzer = struct { }; pub const Builder = struct { - uid_slices: std.ArrayHashMapUnmanaged(Uid, union { + uid_slices: std.array_hash_map.Custom(Uid, union { ints: std.MultiArrayList(struct { value: u64, order_i: u32, diff --git a/lib/libc/include/aarch64-linux-any/asm/kvm.h b/lib/libc/include/aarch64-linux-any/asm/kvm.h index 8b5e526846d26113ae86a97811cc1b335f8cb86e..720b270b1cabfdc3e9ce02547648d37091b8d0da 100644 --- a/lib/libc/include/aarch64-linux-any/asm/kvm.h +++ b/lib/libc/include/aarch64-linux-any/asm/kvm.h @@ -416,6 +416,7 @@ enum { #define KVM_DEV_ARM_ITS_RESTORE_TABLES 2 #define KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES 3 #define KVM_DEV_ARM_ITS_CTRL_RESET 4 +#define KVM_DEV_ARM_VGIC_USERSPACE_PPIS 5 /* Device Control API on vcpu fd */ #define KVM_ARM_VCPU_PMU_V3_CTRL 0 diff --git a/lib/libc/include/any-linux-any/drm/amdgpu_drm.h b/lib/libc/include/any-linux-any/drm/amdgpu_drm.h index fd93842e5816e8687c3dbe5281777a31fc0bdf6d..011f02b4c51e25f3667c8495baa497c6fd79e725 100644 --- a/lib/libc/include/any-linux-any/drm/amdgpu_drm.h +++ b/lib/libc/include/any-linux-any/drm/amdgpu_drm.h @@ -479,7 +479,9 @@ struct drm_amdgpu_userq_signal { * @num_syncobj_handles: A count that represents the number of syncobj handles in * @syncobj_handles. */ - __u64 num_syncobj_handles; + __u16 num_syncobj_handles; + __u16 pad0; + __u32 pad1; /** * @bo_read_handles: The list of BO handles that the submitted user queue job * is using for read only. This will update BO fences in the kernel. @@ -563,7 +565,8 @@ struct drm_amdgpu_userq_wait { * @num_syncobj_handles: A count that represents the number of syncobj handles in * @syncobj_handles. */ - __u32 num_syncobj_handles; + __u16 num_syncobj_handles; + __u16 pad0; /** * @num_bo_read_handles: A count that represents the number of read BO handles in * @bo_read_handles. diff --git a/lib/libc/include/any-linux-any/drm/amdxdna_accel.h b/lib/libc/include/any-linux-any/drm/amdxdna_accel.h index 0f74bcb537d2e81406992b682c533cc6cec0708f..ce26bcbdba8215abebecb5f8188a767eb7184dbf 100644 --- a/lib/libc/include/any-linux-any/drm/amdxdna_accel.h +++ b/lib/libc/include/any-linux-any/drm/amdxdna_accel.h @@ -156,10 +156,11 @@ struct amdxdna_drm_config_hwctx { enum amdxdna_bo_type { AMDXDNA_BO_INVALID = 0, - AMDXDNA_BO_SHMEM, - AMDXDNA_BO_DEV_HEAP, - AMDXDNA_BO_DEV, - AMDXDNA_BO_CMD, + AMDXDNA_BO_SHMEM = 1, /* Be compatible with legacy application code. */ + AMDXDNA_BO_SHARE = 1, + AMDXDNA_BO_DEV_HEAP = 2, + AMDXDNA_BO_DEV = 3, + AMDXDNA_BO_CMD = 4, }; /** @@ -353,7 +354,8 @@ struct amdxdna_drm_query_clock_metadata { }; enum amdxdna_sensor_type { - AMDXDNA_SENSOR_TYPE_POWER + AMDXDNA_SENSOR_TYPE_POWER, + AMDXDNA_SENSOR_TYPE_COLUMN_UTILIZATION }; /** @@ -589,8 +591,37 @@ struct amdxdna_async_error { __u64 ex_err_code; }; +/** + * struct amdxdna_drm_bo_usage - all types of BO usage + * BOs managed by XRT/SHIM/driver is counted as internal. + * Others are counted as external which are managed by applications. + * + * Among all types of BOs: + * AMDXDNA_BO_DEV_HEAP - is counted for internal. + * AMDXDNA_BO_SHARE - is counted for external. + * AMDXDNA_BO_CMD - is counted for internal. + * AMDXDNA_BO_DEV - is counted by heap_usage only, not internal + * or external. It does not add to the total memory + * footprint since its mem comes from heap which is + * already counted as internal. + */ +struct amdxdna_drm_bo_usage { + /** @pid: The ID of the process to query from. */ + __s64 pid; + /** @total_usage: Total BO size used by process. */ + __u64 total_usage; + /** @internal_usage: Total internal BO size used by process. */ + __u64 internal_usage; + /** @heap_usage: Total device BO size used by process. */ + __u64 heap_usage; +}; + +/* + * Supported params in struct amdxdna_drm_get_array + */ #define DRM_AMDXDNA_HW_CONTEXT_ALL 0 #define DRM_AMDXDNA_HW_LAST_ASYNC_ERR 2 +#define DRM_AMDXDNA_BO_USAGE 6 /** * struct amdxdna_drm_get_array - Get information array. @@ -603,6 +634,12 @@ struct amdxdna_drm_get_array { * * %DRM_AMDXDNA_HW_CONTEXT_ALL: * Returns all created hardware contexts. + * + * %DRM_AMDXDNA_HW_LAST_ASYNC_ERR: + * Returns last async error. + * + * %DRM_AMDXDNA_BO_USAGE: + * Returns usage of heap/internal/external BOs. */ __u32 param; /** diff --git a/lib/libc/include/any-linux-any/drm/drm_fourcc.h b/lib/libc/include/any-linux-any/drm/drm_fourcc.h index 498ee6226f5f01245b8c423ba709767c4e0c6308..a39442f53e57d837aa815e29c593b7470dbbfd86 100644 --- a/lib/libc/include/any-linux-any/drm/drm_fourcc.h +++ b/lib/libc/include/any-linux-any/drm/drm_fourcc.h @@ -1422,6 +1422,22 @@ drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) #define DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED \ DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_MISC, 1ULL) +/* + * ARM 64k interleaved modifier + * + * This is used by ARM Mali v10+ GPUs. With this modifier, the plane is divided + * into 64k byte 1:1 or 2:1 -sided tiles. The 64k tiles are laid out linearly. + * Each 64k tile is divided into blocks of 16x16 texel blocks, which are + * themselves laid out linearly within a 64k tile. Then within each 16x16 + * block, texel blocks are laid out according to U order, similar to + * 16X16_BLOCK_U_INTERLEAVED. + * + * Note that unlike 16X16_BLOCK_U_INTERLEAVED, the layout does not change + * depending on whether a format is compressed or not. + */ +#define DRM_FORMAT_MOD_ARM_INTERLEAVED_64K \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_MISC, 2ULL) + /* * Allwinner tiled modifier * diff --git a/lib/libc/include/any-linux-any/drm/drm_mode.h b/lib/libc/include/any-linux-any/drm/drm_mode.h index b9d7342bd5a3d8930cbfded47618a9c0539dccb4..bffc2f8987f61ea57ef9e3832fe835faa973d296 100644 --- a/lib/libc/include/any-linux-any/drm/drm_mode.h +++ b/lib/libc/include/any-linux-any/drm/drm_mode.h @@ -27,6 +27,9 @@ #ifndef _DRM_MODE_H #define _DRM_MODE_H +#include +#include + #include "drm.h" #if defined(__cplusplus) @@ -166,6 +169,10 @@ extern "C" { #define DRM_MODE_LINK_STATUS_GOOD 0 #define DRM_MODE_LINK_STATUS_BAD 1 +/* Panel type property */ +#define DRM_MODE_PANEL_TYPE_UNKNOWN 0 +#define DRM_MODE_PANEL_TYPE_OLED 1 + /* * DRM_MODE_ROTATE_ * @@ -1545,6 +1552,83 @@ struct drm_mode_closefb { __u32 pad; }; +/* + * Put 16-bit ARGB values into a standard 64-bit representation that can be + * used for ioctl parameters, inter-driver communication, etc. + * + * If the component values being provided contain less than 16 bits of + * precision, use a conversion ratio to get a better color approximation. + * The ratio is computed as (2^16 - 1) / (2^bpc - 1), where bpc and 16 are + * the input and output precision, respectively. + * Also note bpc must be greater than 0. + */ +#define __DRM_ARGB64_PREP(c, shift) \ + (((__u64)(c) & __GENMASK(15, 0)) << (shift)) + +#define __DRM_ARGB64_PREP_BPC(c, shift, bpc) \ +({ \ + __u16 mask = __GENMASK((bpc) - 1, 0); \ + __u16 conv = __KERNEL_DIV_ROUND_CLOSEST((mask & (c)) * \ + __GENMASK(15, 0), mask);\ + __DRM_ARGB64_PREP(conv, shift); \ +}) + +#define DRM_ARGB64_PREP(alpha, red, green, blue) \ +( \ + __DRM_ARGB64_PREP(alpha, 48) | \ + __DRM_ARGB64_PREP(red, 32) | \ + __DRM_ARGB64_PREP(green, 16) | \ + __DRM_ARGB64_PREP(blue, 0) \ +) + +#define DRM_ARGB64_PREP_BPC(alpha, red, green, blue, bpc) \ +({ \ + __typeof__(bpc) __bpc = bpc; \ + __DRM_ARGB64_PREP_BPC(alpha, 48, __bpc) | \ + __DRM_ARGB64_PREP_BPC(red, 32, __bpc) | \ + __DRM_ARGB64_PREP_BPC(green, 16, __bpc) | \ + __DRM_ARGB64_PREP_BPC(blue, 0, __bpc); \ +}) + +/* + * Extract the specified color component from a standard 64-bit ARGB value. + * + * If the requested precision is less than 16 bits, make use of a conversion + * ratio calculated as (2^bpc - 1) / (2^16 - 1), where bpc and 16 are the + * output and input precision, respectively. + * + * If speed is more important than accuracy, use DRM_ARGB64_GET*_BPCS() + * instead of DRM_ARGB64_GET*_BPC() in order to replace the expensive + * division with a simple bit right-shift operation. + */ +#define __DRM_ARGB64_GET(c, shift) \ + ((__u16)(((__u64)(c) >> (shift)) & __GENMASK(15, 0))) + +#define __DRM_ARGB64_GET_BPC(c, shift, bpc) \ +({ \ + __u16 comp = __DRM_ARGB64_GET(c, shift); \ + __KERNEL_DIV_ROUND_CLOSEST(comp * __GENMASK((bpc) - 1, 0), \ + __GENMASK(15, 0)); \ +}) + +#define __DRM_ARGB64_GET_BPCS(c, shift, bpc) \ + (__DRM_ARGB64_GET(c, shift) >> (16 - (bpc))) + +#define DRM_ARGB64_GETA(c) __DRM_ARGB64_GET(c, 48) +#define DRM_ARGB64_GETR(c) __DRM_ARGB64_GET(c, 32) +#define DRM_ARGB64_GETG(c) __DRM_ARGB64_GET(c, 16) +#define DRM_ARGB64_GETB(c) __DRM_ARGB64_GET(c, 0) + +#define DRM_ARGB64_GETA_BPC(c, bpc) __DRM_ARGB64_GET_BPC(c, 48, bpc) +#define DRM_ARGB64_GETR_BPC(c, bpc) __DRM_ARGB64_GET_BPC(c, 32, bpc) +#define DRM_ARGB64_GETG_BPC(c, bpc) __DRM_ARGB64_GET_BPC(c, 16, bpc) +#define DRM_ARGB64_GETB_BPC(c, bpc) __DRM_ARGB64_GET_BPC(c, 0, bpc) + +#define DRM_ARGB64_GETA_BPCS(c, bpc) __DRM_ARGB64_GET_BPCS(c, 48, bpc) +#define DRM_ARGB64_GETR_BPCS(c, bpc) __DRM_ARGB64_GET_BPCS(c, 32, bpc) +#define DRM_ARGB64_GETG_BPCS(c, bpc) __DRM_ARGB64_GET_BPCS(c, 16, bpc) +#define DRM_ARGB64_GETB_BPCS(c, bpc) __DRM_ARGB64_GET_BPCS(c, 0, bpc) + #if defined(__cplusplus) } #endif diff --git a/lib/libc/include/any-linux-any/drm/drm_ras.h b/lib/libc/include/any-linux-any/drm/drm_ras.h new file mode 100644 index 0000000000000000000000000000000000000000..bae74e86fe040f275d7838c322c678fe3464ac62 --- /dev/null +++ b/lib/libc/include/any-linux-any/drm/drm_ras.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/drm_ras.yaml */ +/* YNL-GEN uapi header */ +/* To regenerate run: tools/net/ynl/ynl-regen.sh */ + +#ifndef _LINUX_DRM_RAS_H +#define _LINUX_DRM_RAS_H + +#define DRM_RAS_FAMILY_NAME "drm-ras" +#define DRM_RAS_FAMILY_VERSION 1 + +/* + * Type of the node. Currently, only error-counter nodes are supported, which + * expose reliability counters for a hardware/software component. + */ +enum drm_ras_node_type { + DRM_RAS_NODE_TYPE_ERROR_COUNTER = 1, +}; + +enum { + DRM_RAS_A_NODE_ATTRS_NODE_ID = 1, + DRM_RAS_A_NODE_ATTRS_DEVICE_NAME, + DRM_RAS_A_NODE_ATTRS_NODE_NAME, + DRM_RAS_A_NODE_ATTRS_NODE_TYPE, + + __DRM_RAS_A_NODE_ATTRS_MAX, + DRM_RAS_A_NODE_ATTRS_MAX = (__DRM_RAS_A_NODE_ATTRS_MAX - 1) +}; + +enum { + DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID = 1, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_NAME, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_VALUE, + + __DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX, + DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1) +}; + +enum { + DRM_RAS_CMD_LIST_NODES = 1, + DRM_RAS_CMD_GET_ERROR_COUNTER, + + __DRM_RAS_CMD_MAX, + DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1) +}; + +#endif /* _LINUX_DRM_RAS_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/drm/msm_drm.h b/lib/libc/include/any-linux-any/drm/msm_drm.h index af4445b6184ba9cca7d53332708272daa566c51b..708a24f4a0484e5ee6d66092c6eee97eb7bb73a1 100644 --- a/lib/libc/include/any-linux-any/drm/msm_drm.h +++ b/lib/libc/include/any-linux-any/drm/msm_drm.h @@ -117,6 +117,7 @@ struct drm_msm_timespec { * ioctl will throw -EPIPE. */ #define MSM_PARAM_EN_VM_BIND 0x16 /* WO, once */ +#define MSM_PARAM_AQE 0x17 /* RO */ /* For backwards compat. The original support for preemption was based on * a single ring per priority level so # of priority levels equals the # diff --git a/lib/libc/include/any-linux-any/drm/nouveau_drm.h b/lib/libc/include/any-linux-any/drm/nouveau_drm.h index ba589a1197c2377a243414ce0b31508d2c72a1da..e40db8acf32e808a955a1f76f44e8ffa102fc3be 100644 --- a/lib/libc/include/any-linux-any/drm/nouveau_drm.h +++ b/lib/libc/include/any-linux-any/drm/nouveau_drm.h @@ -432,6 +432,69 @@ struct drm_nouveau_exec { __u64 push_ptr; }; +struct drm_nouveau_get_zcull_info { + /** + * @width_align_pixels: required alignment for region widths, in pixels + * (typically #TPC's * 16). + */ + __u32 width_align_pixels; + /** + * @height_align_pixels: required alignment for region heights, in + * pixels (typically 32). + */ + __u32 height_align_pixels; + /** + * @pixel_squares_by_aliquots: the pixel area covered by an aliquot + * (typically #Zcull_banks * 16 * 16). + */ + __u32 pixel_squares_by_aliquots; + /** + * @aliquot_total: the total aliquot pool available in hardware + */ + __u32 aliquot_total; + /** + * @zcull_region_byte_multiplier: the size of an aliquot in bytes, which + * is used for save/restore operations on a region + */ + __u32 zcull_region_byte_multiplier; + /** + * @zcull_region_header_size: the region header size in bytes, which is + * used for save/restore operations on a region + */ + __u32 zcull_region_header_size; + /** + * @zcull_subregion_header_size: the subregion header size in bytes, + * which is used for save/restore operations on a region + */ + __u32 zcull_subregion_header_size; + /** + * @subregion_count: the total number of subregions the hardware + * supports + */ + __u32 subregion_count; + /** + * @subregion_width_align_pixels: required alignment for subregion + * widths, in pixels (typically #TPC's * 16). + */ + __u32 subregion_width_align_pixels; + /** + * @subregion_height_align_pixels: required alignment for subregion + * heights, in pixels + */ + __u32 subregion_height_align_pixels; + + /** + * @ctxsw_size: the size, in bytes, of a zcull context switching region. + * Will be zero if the kernel does not support zcull context switching. + */ + __u32 ctxsw_size; + /** + * @ctxsw_align: the alignment, in bytes, of a zcull context switching + * region + */ + __u32 ctxsw_align; +}; + #define DRM_NOUVEAU_GETPARAM 0x00 #define DRM_NOUVEAU_SETPARAM 0x01 /* deprecated */ #define DRM_NOUVEAU_CHANNEL_ALLOC 0x02 @@ -445,6 +508,7 @@ struct drm_nouveau_exec { #define DRM_NOUVEAU_VM_INIT 0x10 #define DRM_NOUVEAU_VM_BIND 0x11 #define DRM_NOUVEAU_EXEC 0x12 +#define DRM_NOUVEAU_GET_ZCULL_INFO 0x13 #define DRM_NOUVEAU_GEM_NEW 0x40 #define DRM_NOUVEAU_GEM_PUSHBUF 0x41 #define DRM_NOUVEAU_GEM_CPU_PREP 0x42 @@ -513,6 +577,8 @@ struct drm_nouveau_svm_bind { #define DRM_IOCTL_NOUVEAU_VM_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_VM_INIT, struct drm_nouveau_vm_init) #define DRM_IOCTL_NOUVEAU_VM_BIND DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_VM_BIND, struct drm_nouveau_vm_bind) #define DRM_IOCTL_NOUVEAU_EXEC DRM_IOWR(DRM_COMMAND_BASE + DRM_NOUVEAU_EXEC, struct drm_nouveau_exec) + +#define DRM_IOCTL_NOUVEAU_GET_ZCULL_INFO DRM_IOR (DRM_COMMAND_BASE + DRM_NOUVEAU_GET_ZCULL_INFO, struct drm_nouveau_get_zcull_info) #if defined(__cplusplus) } #endif diff --git a/lib/libc/include/any-linux-any/drm/panthor_drm.h b/lib/libc/include/any-linux-any/drm/panthor_drm.h index ea2c927003bf70d363d7c05ae2be35193900df49..33b14b9f025e29b8ae79b4f1906a94606f01cb67 100644 --- a/lib/libc/include/any-linux-any/drm/panthor_drm.h +++ b/lib/libc/include/any-linux-any/drm/panthor_drm.h @@ -409,6 +409,38 @@ struct drm_panthor_csif_info { __u32 pad; }; +/** + * enum drm_panthor_timestamp_info_flags - drm_panthor_timestamp_info.flags + */ +enum drm_panthor_timestamp_info_flags { + /** @DRM_PANTHOR_TIMESTAMP_GPU: Query GPU time. */ + DRM_PANTHOR_TIMESTAMP_GPU = 1 << 0, + + /** @DRM_PANTHOR_TIMESTAMP_CPU_NONE: Don't query CPU time. */ + DRM_PANTHOR_TIMESTAMP_CPU_NONE = 0 << 1, + + /** @DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC: Query CPU time using CLOCK_MONOTONIC. */ + DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC = 1 << 1, + + /** @DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC_RAW: Query CPU time using CLOCK_MONOTONIC_RAW. */ + DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC_RAW = 2 << 1, + + /** @DRM_PANTHOR_TIMESTAMP_CPU_TYPE_MASK: Space reserved for CPU clock type. */ + DRM_PANTHOR_TIMESTAMP_CPU_TYPE_MASK = 7 << 1, + + /** @DRM_PANTHOR_TIMESTAMP_GPU_OFFSET: Query GPU offset. */ + DRM_PANTHOR_TIMESTAMP_GPU_OFFSET = 1 << 4, + + /** @DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT: Query GPU cycle count. */ + DRM_PANTHOR_TIMESTAMP_GPU_CYCLE_COUNT = 1 << 5, + + /** @DRM_PANTHOR_TIMESTAMP_FREQ: Query timestamp frequency. */ + DRM_PANTHOR_TIMESTAMP_FREQ = 1 << 6, + + /** @DRM_PANTHOR_TIMESTAMP_DURATION: Return duration of time query. */ + DRM_PANTHOR_TIMESTAMP_DURATION = 1 << 7, +}; + /** * struct drm_panthor_timestamp_info - Timestamp information * @@ -421,11 +453,38 @@ struct drm_panthor_timestamp_info { */ __u64 timestamp_frequency; - /** @current_timestamp: The current timestamp. */ + /** @current_timestamp: The current GPU timestamp. */ __u64 current_timestamp; - /** @timestamp_offset: The offset of the timestamp timer. */ + /** @timestamp_offset: The offset of the GPU timestamp timer. */ __u64 timestamp_offset; + + /** + * @flags: Bitmask of drm_panthor_timestamp_info_flags. + * + * If set to 0, then it is interpreted as: + * DRM_PANTHOR_TIMESTAMP_GPU | + * DRM_PANTHOR_TIMESTAMP_GPU_OFFSET | + * DRM_PANTHOR_TIMESTAMP_FREQ + * + * Note: these flags are exclusive to each other (only one can be used): + * - DRM_PANTHOR_TIMESTAMP_CPU_NONE + * - DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC + * - DRM_PANTHOR_TIMESTAMP_CPU_MONOTONIC_RAW + */ + __u32 flags; + + /** @duration_nsec: Duration of time query. */ + __u32 duration_nsec; + + /** @cycle_count: Value of GPU_CYCLE_COUNT. */ + __u64 cycle_count; + + /** @cpu_timestamp_sec: Seconds part of CPU timestamp. */ + __u64 cpu_timestamp_sec; + + /** @cpu_timestamp_nsec: Nanseconds part of CPU timestamp. */ + __u64 cpu_timestamp_nsec; }; /** diff --git a/lib/libc/include/any-linux-any/drm/xe_drm.h b/lib/libc/include/any-linux-any/drm/xe_drm.h index 249bb0a26ed4c319d0dd810d236c8fafc5871c95..2225db07af5efce2c29957e84ace52f1c7c5aca0 100644 --- a/lib/libc/include/any-linux-any/drm/xe_drm.h +++ b/lib/libc/include/any-linux-any/drm/xe_drm.h @@ -83,6 +83,7 @@ extern "C" { * - &DRM_IOCTL_XE_OBSERVATION * - &DRM_IOCTL_XE_MADVISE * - &DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS + * - &DRM_IOCTL_XE_VM_GET_PROPERTY */ /* @@ -107,6 +108,7 @@ extern "C" { #define DRM_XE_MADVISE 0x0c #define DRM_XE_VM_QUERY_MEM_RANGE_ATTRS 0x0d #define DRM_XE_EXEC_QUEUE_SET_PROPERTY 0x0e +#define DRM_XE_VM_GET_PROPERTY 0x0f /* Must be kept compact -- no holes */ @@ -125,6 +127,7 @@ extern "C" { #define DRM_IOCTL_XE_MADVISE DRM_IOW(DRM_COMMAND_BASE + DRM_XE_MADVISE, struct drm_xe_madvise) #define DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_VM_QUERY_MEM_RANGE_ATTRS, struct drm_xe_vm_query_mem_range_attr) #define DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC_QUEUE_SET_PROPERTY, struct drm_xe_exec_queue_set_property) +#define DRM_IOCTL_XE_VM_GET_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_VM_GET_PROPERTY, struct drm_xe_vm_get_property) /** * DOC: Xe IOCTL Extensions @@ -335,10 +338,6 @@ struct drm_xe_mem_region { __u64 total_size; /** * @used: Estimate of the memory used in bytes for this region. - * - * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable - * accounting. Without this the value here will always equal - * zero. */ __u64 used; /** @@ -363,9 +362,7 @@ struct drm_xe_mem_region { * @cpu_visible_used: Estimate of CPU visible memory used, in * bytes. * - * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable - * accounting. Without this the value here will always equal - * zero. Note this is only currently tracked for + * Note this is only currently tracked for * DRM_XE_MEM_REGION_CLASS_VRAM regions (for other types the value * here will always be zero). */ @@ -412,6 +409,9 @@ struct drm_xe_query_mem_regions { * - %DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT - Flag is set if the * device supports the userspace hint %DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION. * This is exposed only on Xe2+. + * - %DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX - Flag is set + * if a queue can be creaed with + * %DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX * - %DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT - Minimal memory alignment * required by this device, typically SZ_4K or SZ_64K * - %DRM_XE_QUERY_CONFIG_VA_BITS - Maximum bits of a virtual address @@ -431,6 +431,8 @@ struct drm_xe_query_config { #define DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY (1 << 1) #define DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR (1 << 2) #define DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT (1 << 3) + #define DRM_XE_QUERY_CONFIG_FLAG_HAS_DISABLE_STATE_CACHE_PERF_FIX (1 << 4) + #define DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT (1 << 5) #define DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT 2 #define DRM_XE_QUERY_CONFIG_VA_BITS 3 #define DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY 4 @@ -975,6 +977,11 @@ struct drm_xe_gem_mmap_offset { * demand when accessed, and also allows per-VM overcommit of memory. * The xe driver internally uses recoverable pagefaults to implement * this. + * - %DRM_XE_VM_CREATE_FLAG_NO_VM_OVERCOMMIT - Requires also + * DRM_XE_VM_CREATE_FLAG_FAULT_MODE. This disallows per-VM overcommit + * but only during a &DRM_IOCTL_XE_VM_BIND operation with the + * %DRM_XE_VM_BIND_FLAG_IMMEDIATE flag set. This may be useful for + * user-space naively probing the amount of available memory. */ struct drm_xe_vm_create { /** @extensions: Pointer to the first extension struct, if any */ @@ -983,6 +990,7 @@ struct drm_xe_vm_create { #define DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE (1 << 0) #define DRM_XE_VM_CREATE_FLAG_LR_MODE (1 << 1) #define DRM_XE_VM_CREATE_FLAG_FAULT_MODE (1 << 2) +#define DRM_XE_VM_CREATE_FLAG_NO_VM_OVERCOMMIT (1 << 3) /** @flags: Flags */ __u32 flags; @@ -1053,6 +1061,13 @@ struct drm_xe_vm_destroy { * not invoke autoreset. Neither will stack variables going out of scope. * Therefore it's recommended to always explicitly reset the madvises when * freeing the memory backing a region used in a &DRM_IOCTL_XE_MADVISE call. + * - %DRM_XE_VM_BIND_FLAG_DECOMPRESS - Request on-device decompression for a MAP. + * When set on a MAP bind operation, request the driver schedule an on-device + * in-place decompression (via the migrate/resolve path) for the GPU mapping + * created by this bind. Only valid for DRM_XE_VM_BIND_OP_MAP; usage on + * other ops is rejected. The bind's pat_index must select the device's + * "no-compression" PAT. Only meaningful for VRAM-backed BOs on devices that + * support Flat CCS and the required HW generation XE2+. * * The @prefetch_mem_region_instance for %DRM_XE_VM_BIND_OP_PREFETCH can also be: * - %DRM_XE_CONSULT_MEM_ADVISE_PREF_LOC, which ensures prefetching occurs in @@ -1103,7 +1118,9 @@ struct drm_xe_vm_bind_op { * incoherent GT access is possible. * * Note: For userptr and externally imported dma-buf the kernel expects - * either 1WAY or 2WAY for the @pat_index. + * either 1WAY or 2WAY for the @pat_index. Starting from NVL-P, for + * userptr, svm, madvise and externally imported dma-buf the kernel expects + * either 2WAY or 1WAY and XA @pat_index. * * For DRM_XE_VM_BIND_FLAG_NULL bindings there are no KMD restrictions * on the @pat_index. For such mappings there is no actual memory being @@ -1160,6 +1177,7 @@ struct drm_xe_vm_bind_op { #define DRM_XE_VM_BIND_FLAG_CHECK_PXP (1 << 4) #define DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR (1 << 5) #define DRM_XE_VM_BIND_FLAG_MADVISE_AUTORESET (1 << 6) +#define DRM_XE_VM_BIND_FLAG_DECOMPRESS (1 << 7) /** @flags: Bind flags */ __u32 flags; @@ -1249,6 +1267,89 @@ struct drm_xe_vm_bind { __u64 reserved[2]; }; +/** struct xe_vm_fault - Describes faults for %DRM_XE_VM_GET_PROPERTY_FAULTS */ +struct xe_vm_fault { + /** @address: Canonical address of the fault */ + __u64 address; + /** @address_precision: Precision of faulted address */ + __u32 address_precision; + /** @access_type: Type of address access that resulted in fault */ +#define FAULT_ACCESS_TYPE_READ 0 +#define FAULT_ACCESS_TYPE_WRITE 1 +#define FAULT_ACCESS_TYPE_ATOMIC 2 + __u8 access_type; + /** @fault_type: Type of fault reported */ +#define FAULT_TYPE_NOT_PRESENT 0 +#define FAULT_TYPE_WRITE_ACCESS 1 +#define FAULT_TYPE_ATOMIC_ACCESS 2 + __u8 fault_type; + /** @fault_level: fault level of the fault */ +#define FAULT_LEVEL_PTE 0 +#define FAULT_LEVEL_PDE 1 +#define FAULT_LEVEL_PDP 2 +#define FAULT_LEVEL_PML4 3 +#define FAULT_LEVEL_PML5 4 + __u8 fault_level; + /** @pad: MBZ */ + __u8 pad; + /** @reserved: MBZ */ + __u64 reserved[4]; +}; + +/** + * struct drm_xe_vm_get_property - Input of &DRM_IOCTL_XE_VM_GET_PROPERTY + * + * The user provides a VM and a property to query among DRM_XE_VM_GET_PROPERTY_*, + * and sets the values in the vm_id and property members, respectively. This + * determines both the VM to get the property of, as well as the property to + * report. + * + * If size is set to 0, the driver fills it with the required size for the + * requested property. The user is expected here to allocate memory for the + * property structure and to provide a pointer to the allocated memory using the + * data member. For some properties, this may be zero, in which case, the + * value of the property will be saved to the value member and size will remain + * zero on return. + * + * If size is not zero, then the IOCTL will attempt to copy the requested + * property into the data member. + * + * The IOCTL will return -ENOENT if the VM could not be identified from the + * provided VM ID, or -EINVAL if the IOCTL fails for any other reason, such as + * providing an invalid size for the given property or if the property data + * could not be copied to the memory allocated to the data member. + * + * The property member can be: + * - %DRM_XE_VM_GET_PROPERTY_FAULTS + */ +struct drm_xe_vm_get_property { + /** @extensions: Pointer to the first extension struct, if any */ + __u64 extensions; + + /** @vm_id: The ID of the VM to query the properties of */ + __u32 vm_id; + +#define DRM_XE_VM_GET_PROPERTY_FAULTS 0 + /** @property: property to get */ + __u32 property; + + /** @size: Size to allocate for @data */ + __u32 size; + + /** @pad: MBZ */ + __u32 pad; + + union { + /** @data: Pointer to user-defined array of flexible size and type */ + __u64 data; + /** @value: Return value for scalar queries */ + __u64 value; + }; + + /** @reserved: MBZ */ + __u64 reserved[3]; +}; + /** * struct drm_xe_exec_queue_create - Input of &DRM_IOCTL_XE_EXEC_QUEUE_CREATE * @@ -1285,6 +1386,9 @@ struct drm_xe_vm_bind { * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY - Set the queue * priority within the multi-queue group. Current valid priority values are 0–2 * (default is 1), with higher values indicating higher priority. + * - %DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX - Set the queue to + * enable render color cache keying on BTP+BTI instead of just BTI + * (only valid for render queues). * * The example below shows how to use @drm_xe_exec_queue_create to create * a simple exec_queue (no parallel submission) of class @@ -1329,6 +1433,7 @@ struct drm_xe_exec_queue_create { #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP 4 #define DRM_XE_MULTI_GROUP_CREATE (1ull << 63) #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY 5 +#define DRM_XE_EXEC_QUEUE_SET_DISABLE_STATE_CACHE_PERF_FIX 6 /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; @@ -2067,6 +2172,7 @@ struct drm_xe_query_eu_stall { * - DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC: Set preferred memory location. * - DRM_XE_MEM_RANGE_ATTR_ATOMIC: Set atomic access policy. * - DRM_XE_MEM_RANGE_ATTR_PAT: Set page attribute table index. + * - DRM_XE_VMA_ATTR_PURGEABLE_STATE: Set purgeable state for BOs. * * Example: * @@ -2099,6 +2205,7 @@ struct drm_xe_madvise { #define DRM_XE_MEM_RANGE_ATTR_PREFERRED_LOC 0 #define DRM_XE_MEM_RANGE_ATTR_ATOMIC 1 #define DRM_XE_MEM_RANGE_ATTR_PAT 2 +#define DRM_XE_VMA_ATTR_PURGEABLE_STATE 3 /** @type: type of attribute */ __u32 type; @@ -2189,6 +2296,72 @@ struct drm_xe_madvise { /** @pat_index.reserved: Reserved */ __u64 reserved; } pat_index; + + /** + * @purge_state_val: Purgeable state configuration + * + * Used when @type == DRM_XE_VMA_ATTR_PURGEABLE_STATE. + * + * Configures the purgeable state of buffer objects in the specified + * virtual address range. This allows applications to hint to the kernel + * about bo's usage patterns for better memory management. + * + * By default all VMAs are in WILLNEED state. + * + * Supported values for @purge_state_val.val: + * - DRM_XE_VMA_PURGEABLE_STATE_WILLNEED (0): Marks BO as needed. + * If the BO was previously purged, the kernel sets the __u32 at + * @retained_ptr to 0 (backing store lost) so the application knows + * it must recreate the BO. + * + * - DRM_XE_VMA_PURGEABLE_STATE_DONTNEED (1): Marks BO as not currently + * needed. Kernel may purge it under memory pressure to reclaim memory. + * Only applies to non-shared BOs. The kernel sets the __u32 at + * @retained_ptr to 1 if the backing store still exists (not yet purged), + * or 0 if it was already purged. + * + * Important: Once marked as DONTNEED, touching the BO's memory + * is undefined behavior. It may succeed temporarily (before the + * kernel purges the backing store) but will suddenly fail once + * the BO transitions to PURGED state. + * + * To transition back: use WILLNEED and check @retained_ptr — + * if 0, backing store was lost and the BO must be recreated. + * + * The following operations are blocked in DONTNEED state to + * prevent the BO from being re-mapped after madvise: + * - New mmap() calls: Fail with -EBUSY + * - VM_BIND operations: Fail with -EBUSY + * - New dma-buf exports: Fail with -EBUSY + * - CPU page faults (existing mmap): Fail with SIGBUS + * - GPU page faults (fault-mode VMs): Fail with -EACCES + */ + struct { +#define DRM_XE_VMA_PURGEABLE_STATE_WILLNEED 0 +#define DRM_XE_VMA_PURGEABLE_STATE_DONTNEED 1 + /** @purge_state_val.val: value for DRM_XE_VMA_ATTR_PURGEABLE_STATE */ + __u32 val; + + /** @purge_state_val.pad: MBZ */ + __u32 pad; + /** + * @purge_state_val.retained_ptr: Pointer to a __u32 output + * field for backing store status. + * + * Userspace must initialize the __u32 value at this address + * to 0 before the ioctl. Kernel writes a __u32 after the + * operation: + * - 1 if backing store exists (not purged) + * - 0 if backing store was purged + * + * If userspace fails to initialize to 0, ioctl returns -EINVAL. + * This ensures a safe default (0 = assume purged) if kernel + * cannot write the result. + * + * Similar to i915's drm_i915_gem_madvise.retained field. + */ + __u64 retained_ptr; + } purge_state_val; }; /** @reserved: Reserved */ @@ -2357,6 +2530,85 @@ struct drm_xe_exec_queue_set_property { __u64 reserved[2]; }; +/** + * DOC: Xe DRM RAS + * + * The enums and strings defined below map to the attributes of the DRM RAS Netlink Interface. + * Refer to Documentation/netlink/specs/drm_ras.yaml for complete interface specification. + * + * Node Registration + * ================= + * + * The driver registers DRM RAS nodes for each error severity level. + * enum drm_xe_ras_error_severity defines the node-id, while DRM_XE_RAS_ERROR_SEVERITY_NAMES maps + * node-id to node-name. + * + * Error Classification + * ==================== + * + * Each node contains a list of error counters. Each error is identified by a error-id and + * an error-name. enum drm_xe_ras_error_component defines the error-id, while + * DRM_XE_RAS_ERROR_COMPONENT_NAMES maps error-id to error-name. + * + * User Interface + * ============== + * + * To retrieve error values of a error counter, userspace applications should + * follow the below steps: + * + * 1. Use command LIST_NODES to enumerate all available nodes + * 2. Select node by node-id or node-name + * 3. Use command GET_ERROR_COUNTERS to list errors of specific node + * 4. Query specific error values using either error-id or error-name + * + * .. code-block:: C + * + * // Lookup tables for ID-to-name resolution + * static const char *nodes[] = DRM_XE_RAS_ERROR_SEVERITY_NAMES; + * static const char *errors[] = DRM_XE_RAS_ERROR_COMPONENT_NAMES; + * + */ + +/** + * enum drm_xe_ras_error_severity - DRM RAS error severity. + */ +enum drm_xe_ras_error_severity { + /** @DRM_XE_RAS_ERR_SEV_CORRECTABLE: Correctable Error */ + DRM_XE_RAS_ERR_SEV_CORRECTABLE = 0, + /** @DRM_XE_RAS_ERR_SEV_UNCORRECTABLE: Uncorrectable Error */ + DRM_XE_RAS_ERR_SEV_UNCORRECTABLE, + /** @DRM_XE_RAS_ERR_SEV_MAX: Max severity */ + DRM_XE_RAS_ERR_SEV_MAX /* non-ABI */ +}; + +/** + * enum drm_xe_ras_error_component - DRM RAS error component. + */ +enum drm_xe_ras_error_component { + /** @DRM_XE_RAS_ERR_COMP_CORE_COMPUTE: Core Compute Error */ + DRM_XE_RAS_ERR_COMP_CORE_COMPUTE = 1, + /** @DRM_XE_RAS_ERR_COMP_SOC_INTERNAL: SoC Internal Error */ + DRM_XE_RAS_ERR_COMP_SOC_INTERNAL, + /** @DRM_XE_RAS_ERR_COMP_MAX: Max Error */ + DRM_XE_RAS_ERR_COMP_MAX /* non-ABI */ +}; + +/* + * Error severity to name mapping. + */ +#define DRM_XE_RAS_ERROR_SEVERITY_NAMES { \ + [DRM_XE_RAS_ERR_SEV_CORRECTABLE] = "correctable-errors", \ + [DRM_XE_RAS_ERR_SEV_UNCORRECTABLE] = "uncorrectable-errors", \ +} + +/* + * Error component to name mapping. + */ +#define DRM_XE_RAS_ERROR_COMPONENT_NAMES { \ + [DRM_XE_RAS_ERR_COMP_CORE_COMPUTE] = "core-compute", \ + [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-internal" \ +} + #if defined(__cplusplus) } #endif diff --git a/lib/libc/include/any-linux-any/fwctl/bnxt.h b/lib/libc/include/any-linux-any/fwctl/bnxt.h new file mode 100644 index 0000000000000000000000000000000000000000..ef8f733bc42b79530ecbd31863775836e2274a91 --- /dev/null +++ b/lib/libc/include/any-linux-any/fwctl/bnxt.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2026, Broadcom Inc + */ + +#ifndef _FWCTL_BNXT_H_ +#define _FWCTL_BNXT_H_ + +#include + +enum fwctl_bnxt_commands { + FWCTL_BNXT_INLINE_COMMANDS = 0, + FWCTL_BNXT_QUERY_COMMANDS, + FWCTL_BNXT_SEND_COMMANDS, +}; + +/** + * struct fwctl_info_bnxt - ioctl(FWCTL_INFO) out_device_data + * @uctx_caps: The command capabilities driver accepts. + * + * Return basic information about the FW interface available. + */ +struct fwctl_info_bnxt { + __u32 uctx_caps; +}; +#endif \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/fwctl/fwctl.h b/lib/libc/include/any-linux-any/fwctl/fwctl.h index 511c656d93c4ab14c71a33ce4ca488fe6114b93a..83b9dcaf764ffa31846b84f459a604bb319b20ef 100644 --- a/lib/libc/include/any-linux-any/fwctl/fwctl.h +++ b/lib/libc/include/any-linux-any/fwctl/fwctl.h @@ -44,6 +44,7 @@ enum fwctl_device_type { FWCTL_DEVICE_TYPE_ERROR = 0, FWCTL_DEVICE_TYPE_MLX5 = 1, FWCTL_DEVICE_TYPE_CXL = 2, + FWCTL_DEVICE_TYPE_BNXT = 3, FWCTL_DEVICE_TYPE_PDS = 4, }; diff --git a/lib/libc/include/any-linux-any/linux/audit.h b/lib/libc/include/any-linux-any/linux/audit.h index fd93ab126e39a896dd7216fb7e70e401ab2aa81b..a57548c3771444f3aaf5cbc5217672536677c4ce 100644 --- a/lib/libc/include/any-linux-any/linux/audit.h +++ b/lib/libc/include/any-linux-any/linux/audit.h @@ -350,7 +350,7 @@ enum { #define AUDIT_STATUS_ENABLED 0x0001 #define AUDIT_STATUS_FAILURE 0x0002 #define AUDIT_STATUS_PID 0x0004 -#define AUDIT_STATUS_RATE_LIMIT 0x0008 +#define AUDIT_STATUS_RATE_LIMIT 0x0008 #define AUDIT_STATUS_BACKLOG_LIMIT 0x0010 #define AUDIT_STATUS_BACKLOG_WAIT_TIME 0x0020 #define AUDIT_STATUS_LOST 0x0040 @@ -386,8 +386,8 @@ enum { * These bits disambiguate different calling conventions that share an * ELF machine type, bitness, and endianness */ -#define __AUDIT_ARCH_CONVENTION_MASK 0x30000000 -#define __AUDIT_ARCH_CONVENTION_MIPS64_N32 0x20000000 +#define __AUDIT_ARCH_CONVENTION_MASK 0x30000000 +#define __AUDIT_ARCH_CONVENTION_MIPS64_N32 0x20000000 /* distinguish syscall tables */ #define __AUDIT_ARCH_64BIT 0x80000000 @@ -508,7 +508,7 @@ struct audit_tty_status { __u32 log_passwd; /* 1 = enabled, 0 = disabled */ }; -#define AUDIT_UID_UNSET (unsigned int)-1 +#define AUDIT_UID_UNSET ((unsigned int)-1) #define AUDIT_SID_UNSET ((unsigned int)-1) /* audit_rule_data supports filter rules with both integer and string diff --git a/lib/libc/include/any-linux-any/linux/baycom.h b/lib/libc/include/any-linux-any/linux/baycom.h deleted file mode 100644 index 92426d5bdfddcc21c01c482dae84fb81af701bca..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/baycom.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * The Linux BAYCOM driver for the Baycom serial 1200 baud modem - * and the parallel 9600 baud modem - * (C) 1997-1998 by Thomas Sailer, HB9JNX/AE4WA - */ - -#ifndef _BAYCOM_H -#define _BAYCOM_H - -/* -------------------------------------------------------------------- */ -/* - * structs for the IOCTL commands - */ - -struct baycom_debug_data { - unsigned long debug1; - unsigned long debug2; - long debug3; -}; - -struct baycom_ioctl { - int cmd; - union { - struct baycom_debug_data dbg; - } data; -}; - -/* -------------------------------------------------------------------- */ - -/* - * ioctl values change for baycom - */ -#define BAYCOMCTL_GETDEBUG 0x92 - -/* -------------------------------------------------------------------- */ - -#endif /* _BAYCOM_H */ - -/* --------------------------------------------------------------------- */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/bpf.h b/lib/libc/include/any-linux-any/linux/bpf.h index 5fc9addc4643c9d8e16e279672a526fb672b6392..c36772f0a62bee8c198862c5b1890effbc686da6 100644 --- a/lib/libc/include/any-linux-any/linux/bpf.h +++ b/lib/libc/include/any-linux-any/linux/bpf.h @@ -4645,7 +4645,9 @@ union bpf_attr { * Description * Discard reserved ring buffer sample, pointed to by *data*. * If **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification - * of new data availability is sent. + * of new data availability is sent. Discarded records remain in + * the ring buffer until consumed by user space, so a later submit + * using adaptive wakeup might not wake up the consumer. * If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification * of new data availability is sent unconditionally. * If **0** is specified in *flags*, an adaptive notification diff --git a/lib/libc/include/any-linux-any/linux/bsg.h b/lib/libc/include/any-linux-any/linux/bsg.h index b3a21ce6f70328108672a4ac28b57fbce298e9cf..b0242153fccc95010ab982ed6a93c6e59c93c98a 100644 --- a/lib/libc/include/any-linux-any/linux/bsg.h +++ b/lib/libc/include/any-linux-any/linux/bsg.h @@ -63,5 +63,73 @@ struct sg_io_v4 { __u32 padding; }; +struct bsg_uring_cmd { + __u64 request; /* [i], [*i] command descriptor address */ + __u32 request_len; /* [i] command descriptor length in bytes */ + __u32 protocol; /* [i] protocol type (BSG_PROTOCOL_*) */ + __u32 subprotocol; /* [i] subprotocol type (BSG_SUB_PROTOCOL_*) */ + __u32 max_response_len; /* [i] response buffer size in bytes */ + + __u64 response; /* [i], [*o] response data address */ + __u64 dout_xferp; /* [i], [*i] */ + __u32 dout_xfer_len; /* [i] bytes to be transferred to device */ + __u32 dout_iovec_count; /* [i] 0 -> "flat" dout transfer else + * dout_xferp points to array of iovec + */ + __u64 din_xferp; /* [i], [*o] */ + __u32 din_xfer_len; /* [i] bytes to be transferred from device */ + __u32 din_iovec_count; /* [i] 0 -> "flat" din transfer */ + + __u32 timeout_ms; /* [i] timeout in milliseconds */ + __u8 reserved[12]; /* reserved for future extension */ +}; + + + +/* + * SCSI BSG io_uring completion (res2, 64-bit) + * + * When using BSG_PROTOCOL_SCSI + BSG_SUB_PROTOCOL_SCSI_CMD with + * IORING_OP_URING_CMD, the completion queue entry (CQE) contains: + * - result: errno (0 on success) + * - res2: packed SCSI status + * + * res2 bit layout: + * [0..7] device_status (SCSI status byte, e.g. CHECK_CONDITION) + * [8..15] driver_status (e.g. DRIVER_SENSE when sense data is valid) + * [16..23] host_status (e.g. DID_OK, DID_TIME_OUT) + * [24..31] sense_len_wr (bytes of sense data written to response buffer) + * [32..63] resid_len (residual transfer length) + */ +static __inline__ __u8 bsg_scsi_res2_device_status(__u64 res2) +{ + return res2 & 0xff; +} +static __inline__ __u8 bsg_scsi_res2_driver_status(__u64 res2) +{ + return res2 >> 8; +} +static __inline__ __u8 bsg_scsi_res2_host_status(__u64 res2) +{ + return res2 >> 16; +} +static __inline__ __u8 bsg_scsi_res2_sense_len(__u64 res2) +{ + return res2 >> 24; +} +static __inline__ __u32 bsg_scsi_res2_resid_len(__u64 res2) +{ + return res2 >> 32; +} +static __inline__ __u64 bsg_scsi_res2_build(__u8 device_status, __u8 driver_status, + __u8 host_status, __u8 sense_len_wr, + __u32 resid_len) +{ + return ((__u64)(__u32)(resid_len) << 32) | + ((__u64)sense_len_wr << 24) | + ((__u64)host_status << 16) | + ((__u64)driver_status << 8) | + (__u64)device_status; +} #endif /* BSG_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/btf.h b/lib/libc/include/any-linux-any/linux/btf.h index 3a42631355748aeb0573ca00a012839731c8ceaa..0f2ef31bf519f56e229fdc48dc70e98d4167b485 100644 --- a/lib/libc/include/any-linux-any/linux/btf.h +++ b/lib/libc/include/any-linux-any/linux/btf.h @@ -8,6 +8,16 @@ #define BTF_MAGIC 0xeB9F #define BTF_VERSION 1 +/* + * BTF layout section consists of a struct btf_layout for each known + * kind at BTF encoding time. + */ +struct btf_layout { + __u8 info_sz; /* size of singular element after btf_type */ + __u8 elem_sz; /* size of each of btf_vlen(t) elements */ + __u16 flags; /* currently unused */ +}; + struct btf_header { __u16 magic; __u8 version; @@ -19,6 +29,8 @@ struct btf_header { __u32 type_len; /* length of type section */ __u32 str_off; /* offset of string section */ __u32 str_len; /* length of string section */ + __u32 layout_off; /* offset of layout section */ + __u32 layout_len; /* length of layout section */ }; /* Max # of type identifier */ diff --git a/lib/libc/include/any-linux-any/linux/btrfs_tree.h b/lib/libc/include/any-linux-any/linux/btrfs_tree.h index 4dac10eb3d38d82ff7846e402608b909f3c2327a..1eec392e1d5344c64b98dd6e466c21d56701c081 100644 --- a/lib/libc/include/any-linux-any/linux/btrfs_tree.h +++ b/lib/libc/include/any-linux-any/linux/btrfs_tree.h @@ -1241,7 +1241,8 @@ struct btrfs_free_space_info { __le32 flags; } __attribute__ ((__packed__)); -#define BTRFS_FREE_SPACE_USING_BITMAPS (1ULL << 0) +#define BTRFS_FREE_SPACE_USING_BITMAPS (1UL << 0) +#define BTRFS_FREE_SPACE_FLAGS_MASK (BTRFS_FREE_SPACE_USING_BITMAPS) #define BTRFS_QGROUP_LEVEL_SHIFT 48 static __inline__ __u16 btrfs_qgroup_level(__u64 qgroupid) diff --git a/lib/libc/include/any-linux-any/linux/caif/caif_socket.h b/lib/libc/include/any-linux-any/linux/caif/caif_socket.h deleted file mode 100644 index a4761dadee8be6da41f36419afd7cf729e24a0b8..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/caif/caif_socket.h +++ /dev/null @@ -1,195 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* linux/caif_socket.h - * CAIF Definitions for CAIF socket and network layer - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - * License terms: GNU General Public License (GPL) version 2 - */ - -#ifndef _LINUX_CAIF_SOCKET_H -#define _LINUX_CAIF_SOCKET_H - -#include -#include - -/** - * enum caif_link_selector - Physical Link Selection. - * @CAIF_LINK_HIGH_BANDW: Physical interface for high-bandwidth - * traffic. - * @CAIF_LINK_LOW_LATENCY: Physical interface for low-latency - * traffic. - * - * CAIF Link Layers can register their link properties. - * This enum is used for choosing between CAIF Link Layers when - * setting up CAIF Channels when multiple CAIF Link Layers exists. - */ -enum caif_link_selector { - CAIF_LINK_HIGH_BANDW, - CAIF_LINK_LOW_LATENCY -}; - -/** - * enum caif_channel_priority - CAIF channel priorities. - * - * @CAIF_PRIO_MIN: Min priority for a channel. - * @CAIF_PRIO_LOW: Low-priority channel. - * @CAIF_PRIO_NORMAL: Normal/default priority level. - * @CAIF_PRIO_HIGH: High priority level - * @CAIF_PRIO_MAX: Max priority for channel - * - * Priority can be set on CAIF Channels in order to - * prioritize between traffic on different CAIF Channels. - * These priority levels are recommended, but the priority value - * is not restricted to the values defined in this enum, any value - * between CAIF_PRIO_MIN and CAIF_PRIO_MAX could be used. - */ -enum caif_channel_priority { - CAIF_PRIO_MIN = 0x01, - CAIF_PRIO_LOW = 0x04, - CAIF_PRIO_NORMAL = 0x0f, - CAIF_PRIO_HIGH = 0x14, - CAIF_PRIO_MAX = 0x1F -}; - -/** - * enum caif_protocol_type - CAIF Channel type. - * @CAIFPROTO_AT: Classic AT channel. - * @CAIFPROTO_DATAGRAM: Datagram channel. - * @CAIFPROTO_DATAGRAM_LOOP: Datagram loopback channel, used for testing. - * @CAIFPROTO_UTIL: Utility (Psock) channel. - * @CAIFPROTO_RFM: Remote File Manager - * @CAIFPROTO_DEBUG: Debug link - * - * This enum defines the CAIF Channel type to be used. This defines - * the service to connect to on the modem. - */ -enum caif_protocol_type { - CAIFPROTO_AT, - CAIFPROTO_DATAGRAM, - CAIFPROTO_DATAGRAM_LOOP, - CAIFPROTO_UTIL, - CAIFPROTO_RFM, - CAIFPROTO_DEBUG, - _CAIFPROTO_MAX -}; -#define CAIFPROTO_MAX _CAIFPROTO_MAX - -/** - * enum caif_at_type - AT Service Endpoint - * @CAIF_ATTYPE_PLAIN: Connects to a plain vanilla AT channel. - */ -enum caif_at_type { - CAIF_ATTYPE_PLAIN = 2 -}; - /** - * enum caif_debug_type - Content selection for debug connection - * @CAIF_DEBUG_TRACE_INTERACTIVE: Connection will contain - * both trace and interactive debug. - * @CAIF_DEBUG_TRACE: Connection contains trace only. - * @CAIF_DEBUG_INTERACTIVE: Connection to interactive debug. - */ -enum caif_debug_type { - CAIF_DEBUG_TRACE_INTERACTIVE = 0, - CAIF_DEBUG_TRACE, - CAIF_DEBUG_INTERACTIVE, -}; - -/** - * enum caif_debug_service - Debug Service Endpoint - * @CAIF_RADIO_DEBUG_SERVICE: Debug service on the Radio sub-system - * @CAIF_APP_DEBUG_SERVICE: Debug for the applications sub-system - */ -enum caif_debug_service { - CAIF_RADIO_DEBUG_SERVICE = 1, - CAIF_APP_DEBUG_SERVICE -}; - -/** - * struct sockaddr_caif - the sockaddr structure for CAIF sockets. - * @family: Address family number, must be AF_CAIF. - * @u: Union of address data 'switched' by family. - * : - * @u.at: Applies when family = CAIFPROTO_AT. - * - * @u.at.type: Type of AT link to set up (enum caif_at_type). - * - * @u.util: Applies when family = CAIFPROTO_UTIL - * - * @u.util.service: Utility service name. - * - * @u.dgm: Applies when family = CAIFPROTO_DATAGRAM - * - * @u.dgm.connection_id: Datagram connection id. - * - * @u.dgm.nsapi: NSAPI of the PDP-Context. - * - * @u.rfm: Applies when family = CAIFPROTO_RFM - * - * @u.rfm.connection_id: Connection ID for RFM. - * - * @u.rfm.volume: Volume to mount. - * - * @u.dbg: Applies when family = CAIFPROTO_DEBUG. - * - * @u.dbg.type: Type of debug connection to set up - * (caif_debug_type). - * - * @u.dbg.service: Service sub-system to connect (caif_debug_service - * Description: - * This structure holds the connect parameters used for setting up a - * CAIF Channel. It defines the service to connect to on the modem. - */ -struct sockaddr_caif { - __kernel_sa_family_t family; - union { - struct { - __u8 type; /* type: enum caif_at_type */ - } at; /* CAIFPROTO_AT */ - struct { - char service[16]; - } util; /* CAIFPROTO_UTIL */ - union { - __u32 connection_id; - __u8 nsapi; - } dgm; /* CAIFPROTO_DATAGRAM(_LOOP)*/ - struct { - __u32 connection_id; - char volume[16]; - } rfm; /* CAIFPROTO_RFM */ - struct { - __u8 type; /* type:enum caif_debug_type */ - __u8 service; /* service:caif_debug_service */ - } dbg; /* CAIFPROTO_DEBUG */ - } u; -}; - -/** - * enum caif_socket_opts - CAIF option values for getsockopt and setsockopt. - * - * @CAIFSO_LINK_SELECT: Selector used if multiple CAIF Link layers are - * available. Either a high bandwidth - * link can be selected (CAIF_LINK_HIGH_BANDW) or - * a low latency link (CAIF_LINK_LOW_LATENCY). - * This option is of type __u32. - * Alternatively SO_BINDTODEVICE can be used. - * - * @CAIFSO_REQ_PARAM: Used to set the request parameters for a - * utility channel. (maximum 256 bytes). This - * option must be set before connecting. - * - * @CAIFSO_RSP_PARAM: Gets the response parameters for a utility - * channel. (maximum 256 bytes). This option - * is valid after a successful connect. - * - * - * This enum defines the CAIF Socket options to be used on a socket - * of type PF_CAIF. - * - */ -enum caif_socket_opts { - CAIFSO_LINK_SELECT = 127, - CAIFSO_REQ_PARAM = 128, - CAIFSO_RSP_PARAM = 129, -}; - -#endif /* _LINUX_CAIF_SOCKET_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/caif/if_caif.h b/lib/libc/include/any-linux-any/linux/caif/if_caif.h deleted file mode 100644 index f69dfe6534b3c94f048c6de9c452ba5d8a684028..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/caif/if_caif.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright (C) ST-Ericsson AB 2010 - * Author: Sjur Brendeland - * License terms: GNU General Public License (GPL) version 2 - */ - -#ifndef IF_CAIF_H_ -#define IF_CAIF_H_ -#include -#include -#include - -/** - * enum ifla_caif - CAIF NetlinkRT parameters. - * @IFLA_CAIF_IPV4_CONNID: Connection ID for IPv4 PDP Context. - * The type of attribute is NLA_U32. - * @IFLA_CAIF_IPV6_CONNID: Connection ID for IPv6 PDP Context. - * The type of attribute is NLA_U32. - * @IFLA_CAIF_LOOPBACK: If different from zero, device is doing loopback - * The type of attribute is NLA_U8. - * - * When using RT Netlink to create, destroy or configure a CAIF IP interface, - * enum ifla_caif is used to specify the configuration attributes. - */ -enum ifla_caif { - __IFLA_CAIF_UNSPEC, - IFLA_CAIF_IPV4_CONNID, - IFLA_CAIF_IPV6_CONNID, - IFLA_CAIF_LOOPBACK, - __IFLA_CAIF_MAX -}; -#define IFLA_CAIF_MAX (__IFLA_CAIF_MAX-1) - -#endif /*IF_CAIF_H_*/ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/capi.h b/lib/libc/include/any-linux-any/linux/capi.h deleted file mode 100644 index d2ee971fe4eefb38625cebe7ea084c50fa459188..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/capi.h +++ /dev/null @@ -1,132 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: capi.h,v 1.4.6.1 2001/09/23 22:25:05 kai Exp $ - * - * CAPI 2.0 Interface for Linux - * - * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __LINUX_CAPI_H__ -#define __LINUX_CAPI_H__ - -#include -#include -#include - -/* - * CAPI_REGISTER - */ - -typedef struct capi_register_params { /* CAPI_REGISTER */ - __u32 level3cnt; /* No. of simulatneous user data connections */ - __u32 datablkcnt; /* No. of buffered data messages */ - __u32 datablklen; /* Size of buffered data messages */ -} capi_register_params; - -#define CAPI_REGISTER _IOW('C',0x01,struct capi_register_params) - -/* - * CAPI_GET_MANUFACTURER - */ - -#define CAPI_MANUFACTURER_LEN 64 - -#define CAPI_GET_MANUFACTURER _IOWR('C',0x06,int) /* broken: wanted size 64 (CAPI_MANUFACTURER_LEN) */ - -/* - * CAPI_GET_VERSION - */ - -typedef struct capi_version { - __u32 majorversion; - __u32 minorversion; - __u32 majormanuversion; - __u32 minormanuversion; -} capi_version; - -#define CAPI_GET_VERSION _IOWR('C',0x07,struct capi_version) - -/* - * CAPI_GET_SERIAL - */ - -#define CAPI_SERIAL_LEN 8 -#define CAPI_GET_SERIAL _IOWR('C',0x08,int) /* broken: wanted size 8 (CAPI_SERIAL_LEN) */ - -/* - * CAPI_GET_PROFILE - */ - -typedef struct capi_profile { - __u16 ncontroller; /* number of installed controller */ - __u16 nbchannel; /* number of B-Channels */ - __u32 goptions; /* global options */ - __u32 support1; /* B1 protocols support */ - __u32 support2; /* B2 protocols support */ - __u32 support3; /* B3 protocols support */ - __u32 reserved[6]; /* reserved */ - __u32 manu[5]; /* manufacturer specific information */ -} capi_profile; - -#define CAPI_GET_PROFILE _IOWR('C',0x09,struct capi_profile) - -typedef struct capi_manufacturer_cmd { - unsigned long cmd; - void *data; -} capi_manufacturer_cmd; - -/* - * CAPI_MANUFACTURER_CMD - */ - -#define CAPI_MANUFACTURER_CMD _IOWR('C',0x20, struct capi_manufacturer_cmd) - -/* - * CAPI_GET_ERRCODE - * capi errcode is set, * if read, write, or ioctl returns EIO, - * ioctl returns errcode directly, and in arg, if != 0 - */ - -#define CAPI_GET_ERRCODE _IOR('C',0x21, __u16) - -/* - * CAPI_INSTALLED - */ -#define CAPI_INSTALLED _IOR('C',0x22, __u16) - - -/* - * member contr is input for - * CAPI_GET_MANUFACTURER, CAPI_GET_VERSION, CAPI_GET_SERIAL - * and CAPI_GET_PROFILE - */ -typedef union capi_ioctl_struct { - __u32 contr; - capi_register_params rparams; - __u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - __u8 serial[CAPI_SERIAL_LEN]; - capi_profile profile; - capi_manufacturer_cmd cmd; - __u16 errcode; -} capi_ioctl_struct; - -/* - * Middleware extension - */ - -#define CAPIFLAG_HIGHJACKING 0x0001 - -#define CAPI_GET_FLAGS _IOR('C',0x23, unsigned) -#define CAPI_SET_FLAGS _IOR('C',0x24, unsigned) -#define CAPI_CLR_FLAGS _IOR('C',0x25, unsigned) - -#define CAPI_NCCI_OPENCOUNT _IOR('C',0x26, unsigned) - -#define CAPI_NCCI_GETUNIT _IOR('C',0x27, unsigned) - -#endif /* __LINUX_CAPI_H__ */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/const.h b/lib/libc/include/any-linux-any/linux/const.h index 5d2ccb6eb51c137550d84391252bd92e814f1757..2cf4a3dd42c200ca696bf7c9666cc032263bce2f 100644 --- a/lib/libc/include/any-linux-any/linux/const.h +++ b/lib/libc/include/any-linux-any/linux/const.h @@ -50,4 +50,22 @@ #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +/* + * Divide positive or negative dividend by positive or negative divisor + * and round to closest integer. Result is undefined for negative + * divisors if the dividend variable type is unsigned and for negative + * dividends if the divisor variable type is unsigned. + */ +#define __KERNEL_DIV_ROUND_CLOSEST(x, divisor) \ +({ \ + __typeof__(x) __x = x; \ + __typeof__(divisor) __d = divisor; \ + \ + (((__typeof__(x))-1) > 0 || \ + ((__typeof__(divisor))-1) > 0 || \ + (((__x) > 0) == ((__d) > 0))) ? \ + (((__x) + ((__d) / 2)) / (__d)) : \ + (((__x) - ((__d) / 2)) / (__d)); \ +}) + #endif /* _LINUX_CONST_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/devlink.h b/lib/libc/include/any-linux-any/linux/devlink.h index 621e00d943e7ee9fc136586c2a80af2bdaed77f1..72613412e4b8056bc00cc49da4cbdc321f7048a6 100644 --- a/lib/libc/include/any-linux-any/linux/devlink.h +++ b/lib/libc/include/any-linux-any/linux/devlink.h @@ -19,6 +19,8 @@ #define DEVLINK_GENL_VERSION 0x1 #define DEVLINK_GENL_MCGRP_CONFIG_NAME "config" +#define DEVLINK_INDEX_BUS_NAME "devlink_index" + enum devlink_command { /* don't change the order or add anything between, this is ABI! */ DEVLINK_CMD_UNSPEC, @@ -642,6 +644,9 @@ enum devlink_attr { DEVLINK_ATTR_PARAM_VALUE_DEFAULT, /* dynamic */ DEVLINK_ATTR_PARAM_RESET_DEFAULT, /* flag */ + DEVLINK_ATTR_INDEX, /* uint */ + DEVLINK_ATTR_RESOURCE_SCOPE_MASK, /* u32 */ + /* Add new attributes above here, update the spec in * Documentation/netlink/specs/devlink.yaml and re-generate * net/devlink/netlink_gen.c. @@ -700,6 +705,16 @@ enum devlink_resource_unit { DEVLINK_RESOURCE_UNIT_ENTRY, }; +enum devlink_resource_scope { + DEVLINK_RESOURCE_SCOPE_DEV_BIT, + DEVLINK_RESOURCE_SCOPE_PORT_BIT, +}; + +#define DEVLINK_RESOURCE_SCOPE_DEV \ + _BITUL(DEVLINK_RESOURCE_SCOPE_DEV_BIT) +#define DEVLINK_RESOURCE_SCOPE_PORT \ + _BITUL(DEVLINK_RESOURCE_SCOPE_PORT_BIT) + enum devlink_port_fn_attr_cap { DEVLINK_PORT_FN_ATTR_CAP_ROCE_BIT, DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT, diff --git a/lib/libc/include/any-linux-any/linux/dpll.h b/lib/libc/include/any-linux-any/linux/dpll.h index 99ad96d532fcda4a25e013a575d2812a113125c3..68a160b367fceb0d62605fd713305bd8f5a2702d 100644 --- a/lib/libc/include/any-linux-any/linux/dpll.h +++ b/lib/libc/include/any-linux-any/linux/dpll.h @@ -191,7 +191,8 @@ enum dpll_pin_capabilities { DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE = 4, }; -#define DPLL_PHASE_OFFSET_DIVIDER 1000 +#define DPLL_PHASE_OFFSET_DIVIDER 1000 +#define DPLL_PIN_MEASURED_FREQUENCY_DIVIDER 1000 /** * enum dpll_feature_state - Allow control (enable/disable) and status checking @@ -218,6 +219,7 @@ enum dpll_a { DPLL_A_CLOCK_QUALITY_LEVEL, DPLL_A_PHASE_OFFSET_MONITOR, DPLL_A_PHASE_OFFSET_AVG_FACTOR, + DPLL_A_FREQUENCY_MONITOR, __DPLL_A_MAX, DPLL_A_MAX = (__DPLL_A_MAX - 1) @@ -254,6 +256,7 @@ enum dpll_a_pin { DPLL_A_PIN_REFERENCE_SYNC, DPLL_A_PIN_PHASE_ADJUST_GRAN, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT, + DPLL_A_PIN_MEASURED_FREQUENCY, __DPLL_A_PIN_MAX, DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1) diff --git a/lib/libc/include/any-linux-any/linux/ethtool.h b/lib/libc/include/any-linux-any/linux/ethtool.h index 399bf5ccf81a7b679474ea45034e01839e355337..78cccfe2680509b9e555e87ce64f21ec69e5a62b 100644 --- a/lib/libc/include/any-linux-any/linux/ethtool.h +++ b/lib/libc/include/any-linux-any/linux/ethtool.h @@ -225,7 +225,7 @@ enum tunable_id { ETHTOOL_ID_UNSPEC, ETHTOOL_RX_COPYBREAK, ETHTOOL_TX_COPYBREAK, - ETHTOOL_PFC_PREVENTION_TOUT, /* timeout in msecs */ + ETHTOOL_PFC_PREVENTION_TOUT, /* both pause and pfc, see man ethtool */ ETHTOOL_TX_COPYBREAK_BUF_SIZE, /* * Add your fresh new tunable attribute above and remember to update diff --git a/lib/libc/include/any-linux-any/linux/ethtool_netlink_generated.h b/lib/libc/include/any-linux-any/linux/ethtool_netlink_generated.h index 2ab973732a9c37896dd3bf3602870aee7569cc6c..61fa282ac825e6dd97a0880d9f2c535709518642 100644 --- a/lib/libc/include/any-linux-any/linux/ethtool_netlink_generated.h +++ b/lib/libc/include/any-linux-any/linux/ethtool_netlink_generated.h @@ -371,6 +371,8 @@ enum { ETHTOOL_A_COALESCE_TX_AGGR_TIME_USECS, ETHTOOL_A_COALESCE_RX_PROFILE, ETHTOOL_A_COALESCE_TX_PROFILE, + ETHTOOL_A_COALESCE_RX_CQE_FRAMES, + ETHTOOL_A_COALESCE_RX_CQE_NSECS, __ETHTOOL_A_COALESCE_CNT, ETHTOOL_A_COALESCE_MAX = (__ETHTOOL_A_COALESCE_CNT - 1) @@ -381,6 +383,7 @@ enum { ETHTOOL_A_PAUSE_STAT_PAD, ETHTOOL_A_PAUSE_STAT_TX_FRAMES, ETHTOOL_A_PAUSE_STAT_RX_FRAMES, + ETHTOOL_A_PAUSE_STAT_TX_PAUSE_STORM_EVENTS, __ETHTOOL_A_PAUSE_STAT_CNT, ETHTOOL_A_PAUSE_STAT_MAX = (__ETHTOOL_A_PAUSE_STAT_CNT - 1) diff --git a/lib/libc/include/any-linux-any/linux/fs.h b/lib/libc/include/any-linux-any/linux/fs.h index 5548e4a1c57e1b3b732a95e3e22ad2b98f9d8799..5df9a3189e5f442b4ea38bbf4b1aa2ef349f644c 100644 --- a/lib/libc/include/any-linux-any/linux/fs.h +++ b/lib/libc/include/any-linux-any/linux/fs.h @@ -653,4 +653,16 @@ struct procmap_query { __u64 build_id_addr; /* in */ }; +/* + * Shutdown the filesystem. + */ +#define FS_IOC_SHUTDOWN _IOR('X', 125, __u32) + +/* + * Flags for FS_IOC_SHUTDOWN + */ +#define FS_SHUTDOWN_FLAGS_DEFAULT 0x0 +#define FS_SHUTDOWN_FLAGS_LOGFLUSH 0x1 /* flush log but not data*/ +#define FS_SHUTDOWN_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ + #endif /* _LINUX_FS_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/hdlcdrv.h b/lib/libc/include/any-linux-any/linux/hdlcdrv.h deleted file mode 100644 index fa22437bc7a8e148acc3f0e1ab1f1f5c19cc508a..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/hdlcdrv.h +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * hdlcdrv.h -- HDLC packet radio network driver. - * The Linux soundcard driver for 1200 baud and 9600 baud packet radio - * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA - */ - -#ifndef _HDLCDRV_H -#define _HDLCDRV_H - -/* -------------------------------------------------------------------- */ -/* - * structs for the IOCTL commands - */ - -struct hdlcdrv_params { - int iobase; - int irq; - int dma; - int dma2; - int seriobase; - int pariobase; - int midiiobase; -}; - -struct hdlcdrv_channel_params { - int tx_delay; /* the transmitter keyup delay in 10ms units */ - int tx_tail; /* the transmitter keyoff delay in 10ms units */ - int slottime; /* the slottime in 10ms; usually 10 = 100ms */ - int ppersist; /* the p-persistence 0..255 */ - int fulldup; /* some driver do not support full duplex, setting */ - /* this just makes them send even if DCD is on */ -}; - -struct hdlcdrv_old_channel_state { - int ptt; - int dcd; - int ptt_keyed; -}; - -struct hdlcdrv_channel_state { - int ptt; - int dcd; - int ptt_keyed; - unsigned long tx_packets; - unsigned long tx_errors; - unsigned long rx_packets; - unsigned long rx_errors; -}; - -struct hdlcdrv_ioctl { - int cmd; - union { - struct hdlcdrv_params mp; - struct hdlcdrv_channel_params cp; - struct hdlcdrv_channel_state cs; - struct hdlcdrv_old_channel_state ocs; - unsigned int calibrate; - unsigned char bits; - char modename[128]; - char drivername[32]; - } data; -}; - -/* -------------------------------------------------------------------- */ - -/* - * ioctl values - */ -#define HDLCDRVCTL_GETMODEMPAR 0 -#define HDLCDRVCTL_SETMODEMPAR 1 -#define HDLCDRVCTL_MODEMPARMASK 2 /* not handled by hdlcdrv */ -#define HDLCDRVCTL_GETCHANNELPAR 10 -#define HDLCDRVCTL_SETCHANNELPAR 11 -#define HDLCDRVCTL_OLDGETSTAT 20 -#define HDLCDRVCTL_CALIBRATE 21 -#define HDLCDRVCTL_GETSTAT 22 - -/* - * these are mainly for debugging purposes - */ -#define HDLCDRVCTL_GETSAMPLES 30 -#define HDLCDRVCTL_GETBITS 31 - -/* - * not handled by hdlcdrv, but by its depending drivers - */ -#define HDLCDRVCTL_GETMODE 40 -#define HDLCDRVCTL_SETMODE 41 -#define HDLCDRVCTL_MODELIST 42 -#define HDLCDRVCTL_DRIVERNAME 43 - -/* - * mask of needed modem parameters, returned by HDLCDRVCTL_MODEMPARMASK - */ -#define HDLCDRV_PARMASK_IOBASE (1<<0) -#define HDLCDRV_PARMASK_IRQ (1<<1) -#define HDLCDRV_PARMASK_DMA (1<<2) -#define HDLCDRV_PARMASK_DMA2 (1<<3) -#define HDLCDRV_PARMASK_SERIOBASE (1<<4) -#define HDLCDRV_PARMASK_PARIOBASE (1<<5) -#define HDLCDRV_PARMASK_MIDIIOBASE (1<<6) - -/* -------------------------------------------------------------------- */ - - -/* -------------------------------------------------------------------- */ - -#endif /* _HDLCDRV_H */ - -/* -------------------------------------------------------------------- */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/if_link.h b/lib/libc/include/any-linux-any/linux/if_link.h index 991d8cf537390a65b80b6bf07db17b2233f6d678..6116c2f5b90f9017be90cc33a973beb23c93ad90 100644 --- a/lib/libc/include/any-linux-any/linux/if_link.h +++ b/lib/libc/include/any-linux-any/linux/if_link.h @@ -742,6 +742,11 @@ enum in6_addr_gen_mode { * @IFLA_BR_FDB_MAX_LEARNED * Set the number of max dynamically learned FDB entries for the current * bridge. + * + * @IFLA_BR_STP_MODE + * Set the STP mode for the bridge, which controls how the bridge + * selects between userspace and kernel STP. The valid values are + * documented below in the ``BR_STP_MODE_*`` constants. */ enum { IFLA_BR_UNSPEC, @@ -794,11 +799,45 @@ enum { IFLA_BR_MCAST_QUERIER_STATE, IFLA_BR_FDB_N_LEARNED, IFLA_BR_FDB_MAX_LEARNED, + IFLA_BR_STP_MODE, __IFLA_BR_MAX, }; #define IFLA_BR_MAX (__IFLA_BR_MAX - 1) +/** + * DOC: Bridge STP mode values + * + * @BR_STP_MODE_AUTO + * Default. The kernel invokes the ``/sbin/bridge-stp`` helper to hand + * the bridge to a userspace STP daemon (e.g. mstpd). Only attempted in + * the initial network namespace; in other namespaces this falls back to + * kernel STP. + * + * @BR_STP_MODE_USER + * Directly enable userspace STP (``BR_USER_STP``) without invoking the + * ``/sbin/bridge-stp`` helper. Works in any network namespace. + * Userspace is responsible for ensuring an STP daemon manages the + * bridge. + * + * @BR_STP_MODE_KERNEL + * Directly enable kernel STP (``BR_KERNEL_STP``) without invoking the + * helper. + * + * The mode controls how the bridge selects between userspace and kernel + * STP when STP is enabled via ``IFLA_BR_STP_STATE``. It can only be + * changed while STP is disabled (``IFLA_BR_STP_STATE`` == 0), returns + * ``-EBUSY`` otherwise. The default value is ``BR_STP_MODE_AUTO``. + */ +enum br_stp_mode { + BR_STP_MODE_AUTO, + BR_STP_MODE_USER, + BR_STP_MODE_KERNEL, + __BR_STP_MODE_MAX +}; + +#define BR_STP_MODE_MAX (__BR_STP_MODE_MAX - 1) + struct ifla_bridge_id { __u8 prio[2]; __u8 addr[6]; /* ETH_ALEN */ @@ -1294,6 +1333,11 @@ enum netkit_mode { NETKIT_L3, }; +enum netkit_pairing { + NETKIT_DEVICE_PAIR, + NETKIT_DEVICE_SINGLE, +}; + /* NETKIT_SCRUB_NONE leaves clearing skb->{mark,priority} up to * the BPF program if attached. This also means the latter can * consume the two fields if they were populated earlier. @@ -1318,6 +1362,7 @@ enum { IFLA_NETKIT_PEER_SCRUB, IFLA_NETKIT_HEADROOM, IFLA_NETKIT_TAILROOM, + IFLA_NETKIT_PAIRING, __IFLA_NETKIT_MAX, }; #define IFLA_NETKIT_MAX (__IFLA_NETKIT_MAX - 1) @@ -1566,6 +1611,8 @@ enum { IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, IFLA_BOND_SLAVE_PRIO, IFLA_BOND_SLAVE_ACTOR_PORT_PRIO, + IFLA_BOND_SLAVE_AD_CHURN_ACTOR_STATE, + IFLA_BOND_SLAVE_AD_CHURN_PARTNER_STATE, __IFLA_BOND_SLAVE_MAX, }; diff --git a/lib/libc/include/any-linux-any/linux/if_pppox.h b/lib/libc/include/any-linux-any/linux/if_pppox.h index a3988ac76cc21adbf1be70969ba4c09e676677ca..94537cbd51b7292ceed1349851d11c9e89d0b8b3 100644 --- a/lib/libc/include/any-linux-any/linux/if_pppox.h +++ b/lib/libc/include/any-linux-any/linux/if_pppox.h @@ -103,16 +103,6 @@ struct sockaddr_pppol2tpv3in6 { struct pppol2tpv3in6_addr pppol2tp; } __attribute__((packed)); -/********************************************************************* - * - * ioctl interface for defining forwarding of connections - * - ********************************************************************/ - -#define PPPOEIOCSFWD _IOW(0xB1 ,0, size_t) -#define PPPOEIOCDFWD _IO(0xB1 ,1) -/*#define PPPOEIOCGFWD _IOWR(0xB1,2, size_t)*/ - /* Codes to identify message types */ #define PADI_CODE 0x09 #define PADO_CODE 0x07 diff --git a/lib/libc/include/any-linux-any/linux/inet_diag.h b/lib/libc/include/any-linux-any/linux/inet_diag.h index 375684de5bf06327601e240e6b8001df16cbd83c..219a35785fa93279a6a63d5d6c3fce21e3d13c46 100644 --- a/lib/libc/include/any-linux-any/linux/inet_diag.h +++ b/lib/libc/include/any-linux-any/linux/inet_diag.h @@ -129,6 +129,15 @@ struct inet_diag_msg { __u32 idiag_inode; }; +enum { + IDIAG_TIMER_OFF, + IDIAG_TIMER_ON, + IDIAG_TIMER_KEEPALIVE, + IDIAG_TIMER_TIMEWAIT, + IDIAG_TIMER_PROBE0, + IDIAG_TIMER_DELACK, +}; + /* Extensions */ enum { diff --git a/lib/libc/include/any-linux-any/linux/io_uring.h b/lib/libc/include/any-linux-any/linux/io_uring.h index 7616a1ccf344b16fe577c356c11cdb0b84794418..1526ababbaf5482c82a28167f49a723c4c4178ec 100644 --- a/lib/libc/include/any-linux-any/linux/io_uring.h +++ b/lib/libc/include/any-linux-any/linux/io_uring.h @@ -10,6 +10,8 @@ #include #include +#include + /* * this file is shared with liburing and that has to autodetect * if linux/time_types.h is available or not, it can @@ -341,6 +343,10 @@ enum io_uring_op { /* * sqe->timeout_flags + * + * IORING_TIMEOUT_IMMEDIATE_ARG: If set, sqe->addr stores the timeout + * value in nanoseconds instead of + * pointing to a timespec. */ #define IORING_TIMEOUT_ABS (1U << 0) #define IORING_TIMEOUT_UPDATE (1U << 1) @@ -349,6 +355,7 @@ enum io_uring_op { #define IORING_LINK_TIMEOUT_UPDATE (1U << 4) #define IORING_TIMEOUT_ETIME_SUCCESS (1U << 5) #define IORING_TIMEOUT_MULTISHOT (1U << 6) +#define IORING_TIMEOUT_IMMEDIATE_ARG (1U << 7) #define IORING_TIMEOUT_CLOCK_MASK (IORING_TIMEOUT_BOOTTIME | IORING_TIMEOUT_REALTIME) #define IORING_TIMEOUT_UPDATE_MASK (IORING_TIMEOUT_UPDATE | IORING_LINK_TIMEOUT_UPDATE) /* @@ -898,7 +905,8 @@ struct io_uring_buf_reg { __u32 ring_entries; __u16 bgid; __u16 flags; - __u64 resv[3]; + __u32 min_left; + __u32 resv[5]; }; /* argument for IORING_REGISTER_PBUF_STATUS */ @@ -1050,100 +1058,6 @@ struct io_timespec { __u64 tv_nsec; }; -/* Zero copy receive refill queue entry */ -struct io_uring_zcrx_rqe { - __u64 off; - __u32 len; - __u32 __pad; -}; - -struct io_uring_zcrx_cqe { - __u64 off; - __u64 __pad; -}; - -/* The bit from which area id is encoded into offsets */ -#define IORING_ZCRX_AREA_SHIFT 48 -#define IORING_ZCRX_AREA_MASK (~(((__u64)1 << IORING_ZCRX_AREA_SHIFT) - 1)) - -struct io_uring_zcrx_offsets { - __u32 head; - __u32 tail; - __u32 rqes; - __u32 __resv2; - __u64 __resv[2]; -}; - -enum io_uring_zcrx_area_flags { - IORING_ZCRX_AREA_DMABUF = 1, -}; - -struct io_uring_zcrx_area_reg { - __u64 addr; - __u64 len; - __u64 rq_area_token; - __u32 flags; - __u32 dmabuf_fd; - __u64 __resv2[2]; -}; - -enum zcrx_reg_flags { - ZCRX_REG_IMPORT = 1, -}; - -enum zcrx_features { - /* - * The user can ask for the desired rx page size by passing the - * value in struct io_uring_zcrx_ifq_reg::rx_buf_len. - */ - ZCRX_FEATURE_RX_PAGE_SIZE = 1 << 0, -}; - -/* - * Argument for IORING_REGISTER_ZCRX_IFQ - */ -struct io_uring_zcrx_ifq_reg { - __u32 if_idx; - __u32 if_rxq; - __u32 rq_entries; - __u32 flags; - - __u64 area_ptr; /* pointer to struct io_uring_zcrx_area_reg */ - __u64 region_ptr; /* struct io_uring_region_desc * */ - - struct io_uring_zcrx_offsets offsets; - __u32 zcrx_id; - __u32 rx_buf_len; - __u64 __resv[3]; -}; - -enum zcrx_ctrl_op { - ZCRX_CTRL_FLUSH_RQ, - ZCRX_CTRL_EXPORT, - - __ZCRX_CTRL_LAST, -}; - -struct zcrx_ctrl_flush_rq { - __u64 __resv[6]; -}; - -struct zcrx_ctrl_export { - __u32 zcrx_fd; - __u32 __resv1[11]; -}; - -struct zcrx_ctrl { - __u32 zcrx_id; - __u32 op; /* see enum zcrx_ctrl_op */ - __u64 __resv[2]; - - union { - struct zcrx_ctrl_export zc_export; - struct zcrx_ctrl_flush_rq zc_flush; - }; -}; - #ifdef __cplusplus } #endif diff --git a/lib/libc/include/any-linux-any/linux/io_uring/zcrx.h b/lib/libc/include/any-linux-any/linux/io_uring/zcrx.h new file mode 100644 index 0000000000000000000000000000000000000000..a42e55fd3100f8ea71ce40eb7fb05e2f775806c7 --- /dev/null +++ b/lib/libc/include/any-linux-any/linux/io_uring/zcrx.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */ +/* + * Header file for the io_uring zerocopy receive (zcrx) interface. + * + * Copyright (C) 2026 Pavel Begunkov + * Copyright (C) 2026 David Wei + * Copyright (C) Meta Platforms, Inc. + */ +#ifndef LINUX_IO_ZCRX_H +#define LINUX_IO_ZCRX_H + +#include + +/* Zero copy receive refill queue entry */ +struct io_uring_zcrx_rqe { + __u64 off; + __u32 len; + __u32 __pad; +}; + +struct io_uring_zcrx_cqe { + __u64 off; + __u64 __pad; +}; + +/* The bit from which area id is encoded into offsets */ +#define IORING_ZCRX_AREA_SHIFT 48 +#define IORING_ZCRX_AREA_MASK (~(((__u64)1 << IORING_ZCRX_AREA_SHIFT) - 1)) + +struct io_uring_zcrx_offsets { + __u32 head; + __u32 tail; + __u32 rqes; + __u32 __resv2; + __u64 __resv[2]; +}; + +enum io_uring_zcrx_area_flags { + IORING_ZCRX_AREA_DMABUF = 1, +}; + +struct io_uring_zcrx_area_reg { + __u64 addr; + __u64 len; + __u64 rq_area_token; + __u32 flags; + __u32 dmabuf_fd; + __u64 __resv2[2]; +}; + +enum zcrx_reg_flags { + ZCRX_REG_IMPORT = 1, + + /* + * Register a zcrx instance without a net device. All data will be + * copied. The refill queue entries might not be automatically + * consumed and need to be flushed, see ZCRX_CTRL_FLUSH_RQ. + */ + ZCRX_REG_NODEV = 2, +}; + +enum zcrx_features { + /* + * The user can ask for the desired rx page size by passing the + * value in struct io_uring_zcrx_ifq_reg::rx_buf_len. + */ + ZCRX_FEATURE_RX_PAGE_SIZE = 1 << 0, +}; + +/* + * Argument for IORING_REGISTER_ZCRX_IFQ + */ +struct io_uring_zcrx_ifq_reg { + __u32 if_idx; + __u32 if_rxq; + __u32 rq_entries; + __u32 flags; + + __u64 area_ptr; /* pointer to struct io_uring_zcrx_area_reg */ + __u64 region_ptr; /* struct io_uring_region_desc * */ + + struct io_uring_zcrx_offsets offsets; + __u32 zcrx_id; + __u32 rx_buf_len; + __u64 __resv[3]; +}; + +enum zcrx_ctrl_op { + ZCRX_CTRL_FLUSH_RQ, + ZCRX_CTRL_EXPORT, + + __ZCRX_CTRL_LAST, +}; + +struct zcrx_ctrl_flush_rq { + __u64 __resv[6]; +}; + +struct zcrx_ctrl_export { + __u32 zcrx_fd; + __u32 __resv1[11]; +}; + +struct zcrx_ctrl { + __u32 zcrx_id; + __u32 op; /* see enum zcrx_ctrl_op */ + __u64 __resv[2]; + + union { + struct zcrx_ctrl_export zc_export; + struct zcrx_ctrl_flush_rq zc_flush; + }; +}; + +#endif /* LINUX_IO_ZCRX_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/iommufd.h b/lib/libc/include/any-linux-any/linux/iommufd.h index 8489beb6a06c9d4a82c9a57f91510983d7aa1c92..d8d8e4fba370b7dc479219a7d07319d21aafc733 100644 --- a/lib/libc/include/any-linux-any/linux/iommufd.h +++ b/lib/libc/include/any-linux-any/linux/iommufd.h @@ -695,11 +695,15 @@ enum iommu_hw_info_type { * @IOMMU_HW_CAP_PCI_PASID_PRIV: Privileged Mode Supported, user ignores it * when the struct * iommu_hw_info::out_max_pasid_log2 is zero. + * @IOMMU_HW_CAP_PCI_ATS_NOT_SUPPORTED: ATS is not supported or cannot be used + * on this device (absence implies ATS + * may be enabled) */ enum iommufd_hw_capabilities { IOMMU_HW_CAP_DIRTY_TRACKING = 1 << 0, IOMMU_HW_CAP_PCI_PASID_EXEC = 1 << 1, IOMMU_HW_CAP_PCI_PASID_PRIV = 1 << 2, + IOMMU_HW_CAP_PCI_ATS_NOT_SUPPORTED = 1 << 3, }; /** @@ -1052,6 +1056,11 @@ struct iommu_fault_alloc { enum iommu_viommu_type { IOMMU_VIOMMU_TYPE_DEFAULT = 0, IOMMU_VIOMMU_TYPE_ARM_SMMUV3 = 1, + /* + * TEGRA241_CMDQV requirements (otherwise, VCMDQs will not work) + * - Kernel will allocate a VINTF (HYP_OWN=0) to back this VIOMMU. So, + * VMM must wire the HYP_OWN bit to 0 in guest VINTF_CONFIG register + */ IOMMU_VIOMMU_TYPE_TEGRA241_CMDQV = 2, }; diff --git a/lib/libc/include/any-linux-any/linux/isdn/capicmd.h b/lib/libc/include/any-linux-any/linux/isdn/capicmd.h deleted file mode 100644 index c81d27dabf125516352e36bdde5e861e090ba50d..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/isdn/capicmd.h +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: capicmd.h,v 1.2.6.2 2001/09/23 22:24:33 kai Exp $ - * - * CAPI 2.0 Interface for Linux - * - * Copyright 1997 by Carsten Paeth - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __CAPICMD_H__ -#define __CAPICMD_H__ - -#define CAPI_MSG_BASELEN 8 -#define CAPI_DATA_B3_REQ_LEN (CAPI_MSG_BASELEN+4+4+2+2+2) -#define CAPI_DATA_B3_RESP_LEN (CAPI_MSG_BASELEN+4+2) -#define CAPI_DISCONNECT_B3_RESP_LEN (CAPI_MSG_BASELEN+4) - -/*----- CAPI commands -----*/ -#define CAPI_ALERT 0x01 -#define CAPI_CONNECT 0x02 -#define CAPI_CONNECT_ACTIVE 0x03 -#define CAPI_CONNECT_B3_ACTIVE 0x83 -#define CAPI_CONNECT_B3 0x82 -#define CAPI_CONNECT_B3_T90_ACTIVE 0x88 -#define CAPI_DATA_B3 0x86 -#define CAPI_DISCONNECT_B3 0x84 -#define CAPI_DISCONNECT 0x04 -#define CAPI_FACILITY 0x80 -#define CAPI_INFO 0x08 -#define CAPI_LISTEN 0x05 -#define CAPI_MANUFACTURER 0xff -#define CAPI_RESET_B3 0x87 -#define CAPI_SELECT_B_PROTOCOL 0x41 - -/*----- CAPI subcommands -----*/ - -#define CAPI_REQ 0x80 -#define CAPI_CONF 0x81 -#define CAPI_IND 0x82 -#define CAPI_RESP 0x83 - -/*----- CAPI combined commands -----*/ - -#define CAPICMD(cmd,subcmd) (((cmd)<<8)|(subcmd)) - -#define CAPI_DISCONNECT_REQ CAPICMD(CAPI_DISCONNECT,CAPI_REQ) -#define CAPI_DISCONNECT_CONF CAPICMD(CAPI_DISCONNECT,CAPI_CONF) -#define CAPI_DISCONNECT_IND CAPICMD(CAPI_DISCONNECT,CAPI_IND) -#define CAPI_DISCONNECT_RESP CAPICMD(CAPI_DISCONNECT,CAPI_RESP) - -#define CAPI_ALERT_REQ CAPICMD(CAPI_ALERT,CAPI_REQ) -#define CAPI_ALERT_CONF CAPICMD(CAPI_ALERT,CAPI_CONF) - -#define CAPI_CONNECT_REQ CAPICMD(CAPI_CONNECT,CAPI_REQ) -#define CAPI_CONNECT_CONF CAPICMD(CAPI_CONNECT,CAPI_CONF) -#define CAPI_CONNECT_IND CAPICMD(CAPI_CONNECT,CAPI_IND) -#define CAPI_CONNECT_RESP CAPICMD(CAPI_CONNECT,CAPI_RESP) - -#define CAPI_CONNECT_ACTIVE_REQ CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_REQ) -#define CAPI_CONNECT_ACTIVE_CONF CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_CONF) -#define CAPI_CONNECT_ACTIVE_IND CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_IND) -#define CAPI_CONNECT_ACTIVE_RESP CAPICMD(CAPI_CONNECT_ACTIVE,CAPI_RESP) - -#define CAPI_SELECT_B_PROTOCOL_REQ CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_REQ) -#define CAPI_SELECT_B_PROTOCOL_CONF CAPICMD(CAPI_SELECT_B_PROTOCOL,CAPI_CONF) - -#define CAPI_CONNECT_B3_ACTIVE_REQ CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_REQ) -#define CAPI_CONNECT_B3_ACTIVE_CONF CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_CONF) -#define CAPI_CONNECT_B3_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_IND) -#define CAPI_CONNECT_B3_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_ACTIVE,CAPI_RESP) - -#define CAPI_CONNECT_B3_REQ CAPICMD(CAPI_CONNECT_B3,CAPI_REQ) -#define CAPI_CONNECT_B3_CONF CAPICMD(CAPI_CONNECT_B3,CAPI_CONF) -#define CAPI_CONNECT_B3_IND CAPICMD(CAPI_CONNECT_B3,CAPI_IND) -#define CAPI_CONNECT_B3_RESP CAPICMD(CAPI_CONNECT_B3,CAPI_RESP) - - -#define CAPI_CONNECT_B3_T90_ACTIVE_IND CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_IND) -#define CAPI_CONNECT_B3_T90_ACTIVE_RESP CAPICMD(CAPI_CONNECT_B3_T90_ACTIVE,CAPI_RESP) - -#define CAPI_DATA_B3_REQ CAPICMD(CAPI_DATA_B3,CAPI_REQ) -#define CAPI_DATA_B3_CONF CAPICMD(CAPI_DATA_B3,CAPI_CONF) -#define CAPI_DATA_B3_IND CAPICMD(CAPI_DATA_B3,CAPI_IND) -#define CAPI_DATA_B3_RESP CAPICMD(CAPI_DATA_B3,CAPI_RESP) - -#define CAPI_DISCONNECT_B3_REQ CAPICMD(CAPI_DISCONNECT_B3,CAPI_REQ) -#define CAPI_DISCONNECT_B3_CONF CAPICMD(CAPI_DISCONNECT_B3,CAPI_CONF) -#define CAPI_DISCONNECT_B3_IND CAPICMD(CAPI_DISCONNECT_B3,CAPI_IND) -#define CAPI_DISCONNECT_B3_RESP CAPICMD(CAPI_DISCONNECT_B3,CAPI_RESP) - -#define CAPI_RESET_B3_REQ CAPICMD(CAPI_RESET_B3,CAPI_REQ) -#define CAPI_RESET_B3_CONF CAPICMD(CAPI_RESET_B3,CAPI_CONF) -#define CAPI_RESET_B3_IND CAPICMD(CAPI_RESET_B3,CAPI_IND) -#define CAPI_RESET_B3_RESP CAPICMD(CAPI_RESET_B3,CAPI_RESP) - -#define CAPI_LISTEN_REQ CAPICMD(CAPI_LISTEN,CAPI_REQ) -#define CAPI_LISTEN_CONF CAPICMD(CAPI_LISTEN,CAPI_CONF) - -#define CAPI_MANUFACTURER_REQ CAPICMD(CAPI_MANUFACTURER,CAPI_REQ) -#define CAPI_MANUFACTURER_CONF CAPICMD(CAPI_MANUFACTURER,CAPI_CONF) -#define CAPI_MANUFACTURER_IND CAPICMD(CAPI_MANUFACTURER,CAPI_IND) -#define CAPI_MANUFACTURER_RESP CAPICMD(CAPI_MANUFACTURER,CAPI_RESP) - -#define CAPI_FACILITY_REQ CAPICMD(CAPI_FACILITY,CAPI_REQ) -#define CAPI_FACILITY_CONF CAPICMD(CAPI_FACILITY,CAPI_CONF) -#define CAPI_FACILITY_IND CAPICMD(CAPI_FACILITY,CAPI_IND) -#define CAPI_FACILITY_RESP CAPICMD(CAPI_FACILITY,CAPI_RESP) - -#define CAPI_INFO_REQ CAPICMD(CAPI_INFO,CAPI_REQ) -#define CAPI_INFO_CONF CAPICMD(CAPI_INFO,CAPI_CONF) -#define CAPI_INFO_IND CAPICMD(CAPI_INFO,CAPI_IND) -#define CAPI_INFO_RESP CAPICMD(CAPI_INFO,CAPI_RESP) - -#endif /* __CAPICMD_H__ */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/kernelcapi.h b/lib/libc/include/any-linux-any/linux/kernelcapi.h deleted file mode 100644 index 042a0083d78d724fedec907b7ef79cc8370ef695..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/kernelcapi.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $ - * - * Kernel CAPI 2.0 Interface for Linux - * - * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de) - * - */ - -#ifndef __KERNELCAPI_H__ -#define __KERNELCAPI_H__ - -#define CAPI_MAXAPPL 240 /* maximum number of applications */ -#define CAPI_MAXCONTR 32 /* maximum number of controller */ -#define CAPI_MAXDATAWINDOW 8 - - -typedef struct kcapi_flagdef { - int contr; - int flag; -} kcapi_flagdef; - -typedef struct kcapi_carddef { - char driver[32]; - unsigned int port; - unsigned irq; - unsigned int membase; - int cardnr; -} kcapi_carddef; - -/* new ioctls >= 10 */ -#define KCAPI_CMD_TRACE 10 -#define KCAPI_CMD_ADDCARD 11 /* OBSOLETE */ - -/* - * flag > 2 => trace also data - * flag & 1 => show trace - */ -#define KCAPI_TRACE_OFF 0 -#define KCAPI_TRACE_SHORT_NO_DATA 1 -#define KCAPI_TRACE_FULL_NO_DATA 2 -#define KCAPI_TRACE_SHORT 3 -#define KCAPI_TRACE_FULL 4 - - - -#endif /* __KERNELCAPI_H__ */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/keyboard.h b/lib/libc/include/any-linux-any/linux/keyboard.h index 7c073b866ae51b3ab677c8395799bc2952f3f585..4328b04be8606cd2babdf04b3ecf59d2fa51c0a6 100644 --- a/lib/libc/include/any-linux-any/linux/keyboard.h +++ b/lib/libc/include/any-linux-any/linux/keyboard.h @@ -41,6 +41,7 @@ #define KT_SLOCK 12 #define KT_DEAD2 13 #define KT_BRL 14 +#define KT_CSI 15 /* CSI sequences with modifier support */ #define K(t,v) (((t)<<8)|(v)) #define KTYP(x) ((x) >> 8) @@ -461,5 +462,33 @@ #define NR_BRL 11 +/* KT_CSI keys: value is the CSI parameter number for ESC [ ~ */ +#define K_CSI_HOME K(KT_CSI, 1) /* ESC [ 1 ~ */ +#define K_CSI_INSERT K(KT_CSI, 2) /* ESC [ 2 ~ */ +#define K_CSI_DELETE K(KT_CSI, 3) /* ESC [ 3 ~ */ +#define K_CSI_END K(KT_CSI, 4) /* ESC [ 4 ~ */ +#define K_CSI_PGUP K(KT_CSI, 5) /* ESC [ 5 ~ */ +#define K_CSI_PGDN K(KT_CSI, 6) /* ESC [ 6 ~ */ +#define K_CSI_F1 K(KT_CSI, 11) /* ESC [ 11 ~ */ +#define K_CSI_F2 K(KT_CSI, 12) /* ESC [ 12 ~ */ +#define K_CSI_F3 K(KT_CSI, 13) /* ESC [ 13 ~ */ +#define K_CSI_F4 K(KT_CSI, 14) /* ESC [ 14 ~ */ +#define K_CSI_F5 K(KT_CSI, 15) /* ESC [ 15 ~ */ +#define K_CSI_F6 K(KT_CSI, 17) /* ESC [ 17 ~ */ +#define K_CSI_F7 K(KT_CSI, 18) /* ESC [ 18 ~ */ +#define K_CSI_F8 K(KT_CSI, 19) /* ESC [ 19 ~ */ +#define K_CSI_F9 K(KT_CSI, 20) /* ESC [ 20 ~ */ +#define K_CSI_F10 K(KT_CSI, 21) /* ESC [ 21 ~ */ +#define K_CSI_F11 K(KT_CSI, 23) /* ESC [ 23 ~ */ +#define K_CSI_F12 K(KT_CSI, 24) /* ESC [ 24 ~ */ +#define K_CSI_F13 K(KT_CSI, 25) /* ESC [ 25 ~ */ +#define K_CSI_F14 K(KT_CSI, 26) /* ESC [ 26 ~ */ +#define K_CSI_F15 K(KT_CSI, 28) /* ESC [ 28 ~ */ +#define K_CSI_F16 K(KT_CSI, 29) /* ESC [ 29 ~ */ +#define K_CSI_F17 K(KT_CSI, 31) /* ESC [ 31 ~ */ +#define K_CSI_F18 K(KT_CSI, 32) /* ESC [ 32 ~ */ +#define K_CSI_F19 K(KT_CSI, 33) /* ESC [ 33 ~ */ +#define K_CSI_F20 K(KT_CSI, 34) /* ESC [ 34 ~ */ + #define MAX_DIACR 256 #endif /* __LINUX_KEYBOARD_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/kvm.h b/lib/libc/include/any-linux-any/linux/kvm.h index b7e6426d60eddfa931413cf1128892352650ef55..420a3fe8b1c774bc9d2c67f29b0b3f12fab31c2c 100644 --- a/lib/libc/include/any-linux-any/linux/kvm.h +++ b/lib/libc/include/any-linux-any/linux/kvm.h @@ -693,6 +693,11 @@ struct kvm_enable_cap { #define KVM_VM_TYPE_ARM_IPA_SIZE_MASK 0xffULL #define KVM_VM_TYPE_ARM_IPA_SIZE(x) \ ((x) & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) + +#define KVM_VM_TYPE_ARM_PROTECTED (1UL << 31) +#define KVM_VM_TYPE_ARM_MASK (KVM_VM_TYPE_ARM_IPA_SIZE_MASK | \ + KVM_VM_TYPE_ARM_PROTECTED) + /* * ioctls for /dev/kvm fds: */ @@ -979,6 +984,7 @@ struct kvm_enable_cap { #define KVM_CAP_ARM_SEA_TO_USER 245 #define KVM_CAP_S390_USER_OPEREXEC 246 #define KVM_CAP_S390_KEYOP 247 +#define KVM_CAP_S390_VSIE_ESAMODE 248 struct kvm_irq_routing_irqchip { __u32 irqchip; @@ -1214,6 +1220,10 @@ enum kvm_device_type { #define KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_PCHPIC, #define KVM_DEV_TYPE_LOONGARCH_PCHPIC KVM_DEV_TYPE_LOONGARCH_PCHPIC + KVM_DEV_TYPE_LOONGARCH_DMSINTC, +#define KVM_DEV_TYPE_LOONGARCH_DMSINTC KVM_DEV_TYPE_LOONGARCH_DMSINTC + KVM_DEV_TYPE_ARM_VGIC_V5, +#define KVM_DEV_TYPE_ARM_VGIC_V5 KVM_DEV_TYPE_ARM_VGIC_V5 KVM_DEV_TYPE_MAX, diff --git a/lib/libc/include/any-linux-any/linux/landlock.h b/lib/libc/include/any-linux-any/linux/landlock.h index e9c183f4c6882061abde48ca40d1ade1dfca10c1..42ee46819bb6b003527219b52dd54f6c13bf99d1 100644 --- a/lib/libc/include/any-linux-any/linux/landlock.h +++ b/lib/libc/include/any-linux-any/linux/landlock.h @@ -116,7 +116,9 @@ struct landlock_ruleset_attr { * ``LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF``, this flag only affects * future nested domains, not the one being created. It can also be used * with a @ruleset_fd value of -1 to mute subdomain logs without creating a - * domain. + * domain. When combined with %LANDLOCK_RESTRICT_SELF_TSYNC and a + * @ruleset_fd value of -1, this configuration is propagated to all threads + * of the current process. * * The following flag supports policy enforcement in multithreaded processes: * @@ -248,6 +250,26 @@ struct landlock_net_port_attr { * * This access right is available since the fifth version of the Landlock * ABI. + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX: Look up pathname UNIX domain sockets + * (:manpage:`unix(7)`). On UNIX domain sockets, this restricts both calls to + * :manpage:`connect(2)` as well as calls to :manpage:`sendmsg(2)` with an + * explicit recipient address. + * + * This access right only applies to connections to UNIX server sockets which + * were created outside of the newly created Landlock domain (e.g. from within + * a parent domain or from an unrestricted process). Newly created UNIX + * servers within the same Landlock domain continue to be accessible. In this + * regard, %LANDLOCK_ACCESS_FS_RESOLVE_UNIX has the same semantics as the + * ``LANDLOCK_SCOPE_*`` flags. + * + * If a resolve attempt is denied, the operation returns an ``EACCES`` error, + * in line with other filesystem access rights (but different to denials for + * abstract UNIX domain sockets). + * + * This access right is available since the ninth version of the Landlock ABI. + * + * The rationale for this design is described in + * :ref:`Documentation/security/landlock.rst `. * * Whether an opened file can be truncated with :manpage:`ftruncate(2)` or used * with `ioctl(2)` is determined during :manpage:`open(2)`, in the same way as @@ -333,6 +355,7 @@ struct landlock_net_port_attr { #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) #define LANDLOCK_ACCESS_FS_IOCTL_DEV (1ULL << 15) +#define LANDLOCK_ACCESS_FS_RESOLVE_UNIX (1ULL << 16) /* clang-format on */ /** diff --git a/lib/libc/include/any-linux-any/linux/map_benchmark.h b/lib/libc/include/any-linux-any/linux/map_benchmark.h index 1689166dc56bf2b26d7d98e108fd2bf53b7eccb3..42e033de3c065125653bd98e252f3c8c07e694a1 100644 --- a/lib/libc/include/any-linux-any/linux/map_benchmark.h +++ b/lib/libc/include/any-linux-any/linux/map_benchmark.h @@ -17,6 +17,12 @@ #define DMA_MAP_TO_DEVICE 1 #define DMA_MAP_FROM_DEVICE 2 +enum { + DMA_MAP_BENCH_SINGLE_MODE, + DMA_MAP_BENCH_SG_MODE, + DMA_MAP_BENCH_MODE_MAX +}; + struct map_benchmark { __u64 avg_map_100ns; /* average map latency in 100ns */ __u64 map_stddev; /* standard deviation of map latency */ @@ -28,8 +34,11 @@ struct map_benchmark { __u32 dma_bits; /* DMA addressing capability */ __u32 dma_dir; /* DMA data direction */ __u32 dma_trans_ns; /* time for DMA transmission in ns */ - __u32 granule; /* how many PAGE_SIZE will do map/unmap once a time */ - __u8 expansion[76]; /* For future use */ + __u32 granule; /* - SINGLE_MODE: number of pages mapped/unmapped per operation + * - SG_MODE: number of scatterlist entries (each maps one page) + */ + __u8 map_mode; /* the mode of dma map */ + __u8 expansion[75]; /* For future use */ }; #endif /* _DMA_BENCHMARK_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/mii.h b/lib/libc/include/any-linux-any/linux/mii.h index e8e001d058cf49d55e524483a02f2e5780a4460a..a43e06f027a30ea67f1daa29e3b4f01c7c3b7467 100644 --- a/lib/libc/include/any-linux-any/linux/mii.h +++ b/lib/libc/include/any-linux-any/linux/mii.h @@ -82,7 +82,8 @@ #define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ #define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ #define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ -#define ADVERTISE_RESV 0x1000 /* Unused... */ +#define ADVERTISE_XNP 0x1000 /* Extended Next Page */ +#define ADVERTISE_RESV ADVERTISE_XNP /* Used to be reserved */ #define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ #define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ #define ADVERTISE_NPAGE 0x8000 /* Next page bit */ diff --git a/lib/libc/include/any-linux-any/linux/module_signature.h b/lib/libc/include/any-linux-any/linux/module_signature.h new file mode 100644 index 0000000000000000000000000000000000000000..f781c9e651e79918ad411e2929720391c8d4f11a --- /dev/null +++ b/lib/libc/include/any-linux-any/linux/module_signature.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * Module signature handling. + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#ifndef _LINUX_MODULE_SIGNATURE_H +#define _LINUX_MODULE_SIGNATURE_H + +#include + +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ +#define MODULE_SIGNATURE_MARKER "~Module signature appended~\n" + +enum module_signature_type { + MODULE_SIGNATURE_TYPE_PKCS7 = 2, /* Signature in PKCS#7 message */ +}; + +/* + * Module signature information block. + * + * The constituents of the signature section are, in order: + * + * - Signer's name + * - Key identifier + * - Signature data + * - Information block + */ +struct module_signature { + __u8 algo; /* Public-key crypto algorithm [0] */ + __u8 hash; /* Digest algorithm [0] */ + __u8 id_type; /* Key identifier type [enum module_signature_type] */ + __u8 signer_len; /* Length of signer's name [0] */ + __u8 key_id_len; /* Length of key identifier [0] */ + __u8 __pad[3]; + __be32 sig_len; /* Length of signature data */ +}; + +#endif /* _LINUX_MODULE_SIGNATURE_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/mount.h b/lib/libc/include/any-linux-any/linux/mount.h index 85793fab9df1e8941f9ecf224ae39adc1e216b85..f4648d2538f3b3e2378ffbfcfb9bab321c51a54d 100644 --- a/lib/libc/include/any-linux-any/linux/mount.h +++ b/lib/libc/include/any-linux-any/linux/mount.h @@ -110,6 +110,7 @@ enum fsconfig_command { * fsmount() flags. */ #define FSMOUNT_CLOEXEC 0x00000001 +#define FSMOUNT_NAMESPACE 0x00000002 /* Create the mount in a new mount namespace */ /* * Mount attributes. diff --git a/lib/libc/include/any-linux-any/linux/mshv.h b/lib/libc/include/any-linux-any/linux/mshv.h index f01c0c84b31a0a038edcffb148f8d93ba84d9cdc..af91e8bda9ddd465cfab659b05642c1889510878 100644 --- a/lib/libc/include/any-linux-any/linux/mshv.h +++ b/lib/libc/include/any-linux-any/linux/mshv.h @@ -357,7 +357,7 @@ struct mshv_vtl_sint_post_msg { struct mshv_vtl_ram_disposition { __u64 start_pfn; - __u64 last_pfn; + __u64 last_pfn; /* last_pfn is excluded from the range [start_pfn, last_pfn) */ }; struct mshv_vtl_set_poll_file { diff --git a/lib/libc/include/any-linux-any/linux/netdev.h b/lib/libc/include/any-linux-any/linux/netdev.h index d48296f17fb3882dacc8a8eaa16f8d29b3efa8c3..bad43a494eacc89a407c29c89b3cf81de88037ed 100644 --- a/lib/libc/include/any-linux-any/linux/netdev.h +++ b/lib/libc/include/any-linux-any/linux/netdev.h @@ -160,6 +160,7 @@ enum { NETDEV_A_QUEUE_DMABUF, NETDEV_A_QUEUE_IO_URING, NETDEV_A_QUEUE_XSK, + NETDEV_A_QUEUE_LEASE, __NETDEV_A_QUEUE_MAX, NETDEV_A_QUEUE_MAX = (__NETDEV_A_QUEUE_MAX - 1) @@ -202,6 +203,15 @@ enum { NETDEV_A_QSTATS_MAX = (__NETDEV_A_QSTATS_MAX - 1) }; +enum { + NETDEV_A_LEASE_IFINDEX = 1, + NETDEV_A_LEASE_QUEUE, + NETDEV_A_LEASE_NETNS_ID, + + __NETDEV_A_LEASE_MAX, + NETDEV_A_LEASE_MAX = (__NETDEV_A_LEASE_MAX - 1) +}; + enum { NETDEV_A_DMABUF_IFINDEX = 1, NETDEV_A_DMABUF_QUEUES, @@ -228,6 +238,7 @@ enum { NETDEV_CMD_BIND_RX, NETDEV_CMD_NAPI_SET, NETDEV_CMD_BIND_TX, + NETDEV_CMD_QUEUE_CREATE, __NETDEV_CMD_MAX, NETDEV_CMD_MAX = (__NETDEV_CMD_MAX - 1) diff --git a/lib/libc/include/any-linux-any/linux/netfilter/nf_tables.h b/lib/libc/include/any-linux-any/linux/netfilter/nf_tables.h index 4f481f87ecaf7ee34363e0d4d50de2ad2194718f..adbd4f65077b5da7024848cd68ce9db6698818b0 100644 --- a/lib/libc/include/any-linux-any/linux/netfilter/nf_tables.h +++ b/lib/libc/include/any-linux-any/linux/netfilter/nf_tables.h @@ -46,6 +46,7 @@ enum nft_registers { }; #define NFT_REG_MAX (__NFT_REG_MAX - 1) + #define NFT_REG_SIZE 16 #define NFT_REG32_SIZE 4 #define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1) @@ -884,7 +885,7 @@ enum nft_exthdr_flags { * @NFT_EXTHDR_OP_TCPOPT: match against tcp options * @NFT_EXTHDR_OP_IPV4: match against ipv4 options * @NFT_EXTHDR_OP_SCTP: match against sctp chunks - * @NFT_EXTHDR_OP_DCCP: match against dccp otions + * @NFT_EXTHDR_OP_DCCP: match against dccp options */ enum nft_exthdr_op { NFT_EXTHDR_OP_IPV6, diff --git a/lib/libc/include/any-linux-any/linux/netrom.h b/lib/libc/include/any-linux-any/linux/netrom.h deleted file mode 100644 index c80c1466418215e31af99614da7d2d7d4c6fce25..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/netrom.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * These are the public elements of the Linux kernel NET/ROM implementation. - * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the - * definition of the ax25_address structure. - */ - -#ifndef NETROM_KERNEL_H -#define NETROM_KERNEL_H - -#include - -#define NETROM_MTU 236 - -#define NETROM_T1 1 -#define NETROM_T2 2 -#define NETROM_N2 3 -#define NETROM_T4 6 -#define NETROM_IDLE 7 - -#define SIOCNRDECOBS (SIOCPROTOPRIVATE+2) - -struct nr_route_struct { -#define NETROM_NEIGH 0 -#define NETROM_NODE 1 - int type; - ax25_address callsign; - char device[16]; - unsigned int quality; - char mnemonic[7]; - ax25_address neighbour; - unsigned int obs_count; - unsigned int ndigis; - ax25_address digipeaters[AX25_MAX_DIGIS]; -}; - -#endif \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/nfc.h b/lib/libc/include/any-linux-any/linux/nfc.h index 13adaefeb82d697b872b7c498eb72583ce5a975a..bb2f6749a6fb2263784602d23abb0a418f3d8e64 100644 --- a/lib/libc/include/any-linux-any/linux/nfc.h +++ b/lib/libc/include/any-linux-any/linux/nfc.h @@ -55,7 +55,7 @@ * (it sends %NFC_ATTR_DEVICE_INDEX) * @NFC_EVENT_TM_ACTIVATED: event emitted when the adapter is activated in * target mode. - * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated + * @NFC_EVENT_TM_DEACTIVATED: event emitted when the adapter is deactivated * from target mode. * @NFC_CMD_LLC_GET_PARAMS: request LTO, RW, and MIUX parameters for a device * @NFC_CMD_LLC_SET_PARAMS: set one or more of LTO, RW, and MIUX parameters for @@ -156,7 +156,7 @@ enum nfc_commands { * @NFC_ATTR_SE_INDEX: Secure element index * @NFC_ATTR_SE_TYPE: Secure element type (UICC or EMBEDDED) * @NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS: Firmware download operation status - * @NFC_ATTR_APDU: Secure element APDU + * @NFC_ATTR_SE_APDU: Secure element APDU * @NFC_ATTR_TARGET_ISO15693_DSFID: ISO 15693 Data Storage Format Identifier * @NFC_ATTR_TARGET_ISO15693_UID: ISO 15693 Unique Identifier * @NFC_ATTR_SE_PARAMS: Parameters data from an evt_transaction @@ -291,7 +291,7 @@ struct sockaddr_nfc_llcp { #define NFC_HEADER_SIZE 1 -/** +/* * Pseudo-header info for raw socket packets * First byte is the adapter index * Second byte contains flags diff --git a/lib/libc/include/any-linux-any/linux/nfsd/export.h b/lib/libc/include/any-linux-any/linux/nfsd/export.h index babed2e348bbbbd5ffbdbd3e073d1874662d4f86..10b5d0c86b2d7993a0ff2ddcf4813cf9ed3770d3 100644 --- a/lib/libc/include/any-linux-any/linux/nfsd/export.h +++ b/lib/libc/include/any-linux-any/linux/nfsd/export.h @@ -34,7 +34,7 @@ #define NFSEXP_GATHERED_WRITES 0x0020 #define NFSEXP_NOREADDIRPLUS 0x0040 #define NFSEXP_SECURITY_LABEL 0x0080 -/* 0x100 currently unused */ +#define NFSEXP_SIGN_FH 0x0100 #define NFSEXP_NOHIDE 0x0200 #define NFSEXP_NOSUBTREECHECK 0x0400 #define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ @@ -55,7 +55,7 @@ #define NFSEXP_PNFS 0x20000 /* All flags that we claim to support. (Note we don't support NOACL.) */ -#define NFSEXP_ALLFLAGS 0x3FEFF +#define NFSEXP_ALLFLAGS 0x3FFFF /* The flags that may vary depending on security flavor: */ #define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ diff --git a/lib/libc/include/any-linux-any/linux/nfsd_netlink.h b/lib/libc/include/any-linux-any/linux/nfsd_netlink.h index f1a633bce26c7103c8fcb65f181cd7f9190c4fb1..bb104b4490ee434efc637dba2319feb4f6bd1281 100644 --- a/lib/libc/include/any-linux-any/linux/nfsd_netlink.h +++ b/lib/libc/include/any-linux-any/linux/nfsd_netlink.h @@ -36,6 +36,7 @@ enum { NFSD_A_SERVER_LEASETIME, NFSD_A_SERVER_SCOPE, NFSD_A_SERVER_MIN_THREADS, + NFSD_A_SERVER_FH_KEY, __NFSD_A_SERVER_MAX, NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1) diff --git a/lib/libc/include/any-linux-any/linux/nl80211.h b/lib/libc/include/any-linux-any/linux/nl80211.h index 53af5a957a78d76ad7d78de8e07983f1793863ed..903c2127dd42807a29eaa4e95c2e084c833fa33f 100644 --- a/lib/libc/include/any-linux-any/linux/nl80211.h +++ b/lib/libc/include/any-linux-any/linux/nl80211.h @@ -906,8 +906,9 @@ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP * (or GO) interface (i.e. hostapd) to ask for unexpected frames to * implement sending deauth to stations that send unexpected class 3 - * frames. Also used as the event sent by the kernel when such a frame - * is received. + * frames. For NAN_DATA interfaces, this is used to report frames from + * unknown peers (A2 not assigned to any active NDP). + * Also used as the event sent by the kernel when such a frame is received. * For the event, the %NL80211_ATTR_MAC attribute carries the TA and * other attributes like the interface index are present. * If used as the command it must have an interface index and you can @@ -1361,6 +1362,59 @@ * user space that the NAN new cluster has been joined. The cluster ID is * indicated by %NL80211_ATTR_MAC. * + * @NL80211_CMD_INCUMBENT_SIGNAL_DETECT: Once any incumbent signal is detected + * on the operating channel in 6 GHz band, userspace is notified with the + * signal interference bitmap using + * %NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP. The current channel + * definition is also sent. + * + * @NL80211_CMD_NAN_SET_LOCAL_SCHED: Set the local NAN schedule. NAN must be + * operational (%NL80211_CMD_START_NAN was executed). Must contain + * %NL80211_ATTR_NAN_TIME_SLOTS and %NL80211_ATTR_NAN_AVAIL_BLOB, but + * %NL80211_ATTR_NAN_CHANNEL is optional (for example in case of a channel + * removal, that channel won't be provided). + * If %NL80211_ATTR_NAN_SCHED_DEFERRED is set, the command is a request + * from the device to perform an announced schedule update. See + * %NL80211_ATTR_NAN_SCHED_DEFERRED for more details. + * If not set, the schedule should be applied immediately. + * @NL80211_CMD_NAN_SCHED_UPDATE_DONE: Event sent to user space to notify that + * a deferred local NAN schedule update (requested with + * %NL80211_CMD_NAN_SET_LOCAL_SCHED and %NL80211_ATTR_NAN_SCHED_DEFERRED) + * has been completed. The presence of %NL80211_ATTR_NAN_SCHED_UPDATE_SUCCESS + * indicates that the update was successful. + * @NL80211_CMD_NAN_SET_PEER_SCHED: Set the peer NAN schedule. NAN + * must be operational (%NL80211_CMD_START_NAN was executed). + * Required attributes: %NL80211_ATTR_MAC (peer NMI address) and + * %NL80211_ATTR_NAN_COMMITTED_DW. + * Optionally, the full schedule can be provided by including all of: + * %NL80211_ATTR_NAN_SEQ_ID, %NL80211_ATTR_NAN_CHANNEL (one or more), and + * %NL80211_ATTR_NAN_PEER_MAPS (see &enum nl80211_nan_peer_map_attrs). + * If any of these three optional attributes is provided, all three must + * be provided. + * Each peer channel must be compatible with at least one local channel + * set by %NL80211_CMD_SET_LOCAL_NAN_SCHED. Different maps must not + * contain compatible channels. + * For single-radio devices (n_radio <= 1), different maps must not + * schedule the same time slot, as the device cannot operate on multiple + * channels simultaneously. + * When updating an existing peer schedule, the full new schedule must be + * provided - partial updates are not supported. The new schedule will + * completely replace the previous one. + * The peer schedule is automatically removed when the NMI station is + * removed. + * @NL80211_CMD_NAN_ULW_UPDATE: Notification from the driver to user space + * with the updated ULW blob of the device. User space can use this blob + * to attach to frames sent to peers. This notification contains + * %NL80211_ATTR_NAN_ULW with the ULW blob. + * @NL80211_CMD_NAN_CHANNEL_EVAC: Notification to indicate that a NAN + * channel has been evacuated due to resource conflicts with other + * interfaces. This can happen when another interface sharing the channel + * resource with NAN needs to move to a different channel (e.g., channel + * switch or link switch on a BSS interface). + * The notification contains %NL80211_ATTR_NAN_CHANNEL attribute + * identifying the evacuated channel. + * User space may reconfigure the local schedule in response to this + * notification. * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1624,6 +1678,18 @@ enum nl80211_commands { NL80211_CMD_NAN_NEXT_DW_NOTIFICATION, NL80211_CMD_NAN_CLUSTER_JOINED, + NL80211_CMD_INCUMBENT_SIGNAL_DETECT, + + NL80211_CMD_NAN_SET_LOCAL_SCHED, + + NL80211_CMD_NAN_SCHED_UPDATE_DONE, + + NL80211_CMD_NAN_SET_PEER_SCHED, + + NL80211_CMD_NAN_ULW_UPDATE, + + NL80211_CMD_NAN_CHANNEL_EVAC, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -2651,7 +2717,8 @@ enum nl80211_commands { * a flow is assigned on each round of the DRR scheduler. * @NL80211_ATTR_HE_CAPABILITY: HE Capability information element (from * association request when used with NL80211_CMD_NEW_STATION). Can be set - * only if %NL80211_STA_FLAG_WME is set. + * only if %NL80211_STA_FLAG_WME is set (except for NAN, which uses WME + * anyway). * * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing @@ -2983,6 +3050,95 @@ enum nl80211_commands { * @NL80211_ATTR_DISABLE_UHR: Force UHR capable interfaces to disable * this feature during association. This is a flag attribute. * Currently only supported in mac80211 drivers. + * @NL80211_ATTR_NAN_CHANNEL: This is a nested attribute. There can be multiple + * attributes of this type, each one represents a channel definition and + * consists of top-level attributes like %NL80211_ATTR_WIPHY_FREQ. + * When used with %NL80211_CMD_NAN_SET_LOCAL_SCHED, it specifies + * the channel definitions on which the radio needs to operate during + * specific time slots. All of the channel definitions should be mutually + * incompatible. With this command, %NL80211_ATTR_NAN_CHANNEL_ENTRY and + * %NL80211_ATTR_NAN_RX_NSS are mandatory. + * When used with %NL80211_CMD_NAN_SET_PEER_SCHED, it configures the + * peer NAN channels. In that case, the channel definitions can be + * compatible to each other, or even identical just with different RX NSS. + * With this command, %NL80211_ATTR_NAN_CHANNEL_ENTRY and + * %NL80211_ATTR_NAN_RX_NSS are mandatory. + * The number of channels should fit the current configuration of channels + * and the possible interface combinations. + * If an existing NAN channel is changed but the chandef isn't, the + * channel entry must also remain unchanged. + * When used with %NL80211_CMD_NAN_CHANNEL_EVAC, this identifies the + * channels that were evacuated. + * @NL80211_ATTR_NAN_CHANNEL_ENTRY: a byte array of 6 bytes. contains the + * Channel Entry as defined in Wi-Fi Aware (TM) 4.0 specification Table + * 100 (Channel Entry format for the NAN Availability attribute). + * @NL80211_ATTR_NAN_RX_NSS: (u8) RX NSS used for a NAN channel. This is + * used with %NL80211_ATTR_NAN_CHANNEL when configuring NAN channels with + * %NL80211_CMD_NAN_SET_LOCAL_SCHED or %NL80211_CMD_NAN_SET_PEER_SCHED. + * @NL80211_ATTR_NAN_TIME_SLOTS: an array of u8 values and 32 cells. each value + * maps a time slot to the chandef on which the radio should operate on in + * that time. %NL80211_NAN_SCHED_NOT_AVAIL_SLOT indicates unscheduled. + * The chandef is represented using its index, where the index is the + * sequential number of the %NL80211_ATTR_NAN_CHANNEL attribute within all + * the attributes of this type. + * Each slots spans over 16TUs, hence the entire schedule spans over + * 512TUs. Other slot durations and periods are currently not supported. + * @NL80211_ATTR_NAN_AVAIL_BLOB: (Binary) The NAN Availability attribute blob, + * including the attribute header, as defined in Wi-Fi Aware (TM) 4.0 + * specification Table 93 (NAN Availability attribute format). Required with + * %NL80211_CMD_NAN_SET_LOCAL_SCHED to provide the raw NAN Availability + * attribute. Used by the device to publish Schedule Update NAFs. + * @NL80211_ATTR_NAN_SCHED_DEFERRED: Flag attribute used with + * %NL80211_CMD_NAN_SET_LOCAL_SCHED. When present, the command is a + * request from the device to perform an announced schedule update. This + * means that it needs to send the updated NAN availability to the peers, + * and do the actual switch on the right time (i.e. at the end of the slot + * after the slot in which the updated NAN Availability was sent). Since + * the slots management is done in the device, the update to the peers + * needs to be sent by the device, so it knows the actual switch time. + * If the flag is not set, the schedule should be applied immediately. + * When this flag is set, the total number of NAN channels from both the + * old and new schedules must not exceed the allowed number of local NAN + * channels, because with deferred scheduling the old channels cannot be + * removed before adding the new ones to free up space. + * @NL80211_ATTR_NAN_SCHED_UPDATE_SUCCESS: flag attribute used with + * %NL80211_CMD_NAN_SCHED_UPDATE_DONE to indicate that the deferred + * schedule update completed successfully. If this flag is not present, + * the update failed. + * @NL80211_ATTR_NAN_NMI_MAC: The address of the NMI station to which this NDI + * station belongs. Used with %NL80211_CMD_NEW_STATION when adding an NDI + * station. + * @NL80211_ATTR_NAN_ULW: (Binary) The initial ULW(s) as published by the + * peer, as defined in the Wi-Fi Aware (TM) 4.0 specification Table 109 + * (Unaligned Schedule attribute format). Used to configure the device + * with the initial ULW(s) of a peer, before the device starts tracking it. + * @NL80211_ATTR_NAN_COMMITTED_DW: (u16) The committed DW as published by the + * peer, as defined in the Wi-Fi Aware (TM) 4.0 specification Table 80 + * (Committed DW Information field format). + * @NL80211_ATTR_NAN_SEQ_ID: (u8) The sequence ID of the peer schedule that + * %NL80211_CMD_NAN_SET_PEER_SCHED defines. The device follows the + * sequence ID in the frames to identify newer schedules. Once a schedule + * with a higher sequence ID is received, the device may stop communicating + * with that peer until a new peer schedule with a matching sequence ID is + * received. + * @NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME: (u16) The maximum channel switch + * time, in microseconds. + * @NL80211_ATTR_NAN_PEER_MAPS: Nested array of peer schedule maps. + * Used with %NL80211_CMD_NAN_SET_PEER_SCHED. Contains up to 2 entries, + * each containing nested attributes from &enum nl80211_nan_peer_map_attrs. + * + * @NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP: u32 attribute specifying + * the signal interference bitmap detected on the operating bandwidth for + * %NL80211_CMD_INCUMBENT_SIGNAL_DETECT. Each bit represents a 20 MHz + * segment, lowest bit corresponds to the lowest 20 MHz segment, in the + * operating bandwidth where the interference is detected. Punctured + * sub-channels are included in the bitmap structure; however, since + * interference detection is not performed on these sub-channels, their + * corresponding bits are consistently set to zero. + * + * @NL80211_ATTR_UHR_OPERATION: Full UHR Operation element, as it appears in + * association response etc., since it's abridged in the beacon. Used + * for START_AP etc. * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined @@ -3557,6 +3713,26 @@ enum nl80211_attrs { NL80211_ATTR_UHR_CAPABILITY, NL80211_ATTR_DISABLE_UHR, + NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP, + + NL80211_ATTR_UHR_OPERATION, + + NL80211_ATTR_NAN_CHANNEL, + NL80211_ATTR_NAN_CHANNEL_ENTRY, + NL80211_ATTR_NAN_TIME_SLOTS, + NL80211_ATTR_NAN_RX_NSS, + NL80211_ATTR_NAN_AVAIL_BLOB, + NL80211_ATTR_NAN_SCHED_DEFERRED, + NL80211_ATTR_NAN_SCHED_UPDATE_SUCCESS, + + NL80211_ATTR_NAN_NMI_MAC, + + NL80211_ATTR_NAN_ULW, + NL80211_ATTR_NAN_COMMITTED_DW, + NL80211_ATTR_NAN_SEQ_ID, + NL80211_ATTR_NAN_MAX_CHAN_SWITCH_TIME, + NL80211_ATTR_NAN_PEER_MAPS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3650,6 +3826,9 @@ enum nl80211_attrs { * @NL80211_IFTYPE_OCB: Outside Context of a BSS * This mode corresponds to the MIB variable dot11OCBActivated=true * @NL80211_IFTYPE_NAN: NAN device interface type (not a netdev) + * @NL80211_IFTYPE_NAN_DATA: NAN data interface type (netdev); NAN data + * interfaces can only be brought up (IFF_UP) when a NAN interface + * already exists and NAN has been started (using %NL80211_CMD_START_NAN). * @NL80211_IFTYPE_MAX: highest interface type number currently defined * @NUM_NL80211_IFTYPES: number of defined interface types * @@ -3671,6 +3850,7 @@ enum nl80211_iftype { NL80211_IFTYPE_P2P_DEVICE, NL80211_IFTYPE_OCB, NL80211_IFTYPE_NAN, + NL80211_IFTYPE_NAN_DATA, /* keep last */ NUM_NL80211_IFTYPES, @@ -4359,6 +4539,46 @@ enum nl80211_band_attr { #define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA +/** + * enum nl80211_nan_phy_cap_attr - NAN PHY capabilities attributes + * @__NL80211_NAN_PHY_CAP_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET: 16-byte attribute containing HT MCS set + * @NL80211_NAN_PHY_CAP_ATTR_HT_CAPA: HT capabilities (u16) + * @NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR: HT A-MPDU factor (u8) + * @NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY: HT A-MPDU density (u8) + * @NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET: 8-byte attribute containing VHT MCS set + * @NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA: VHT capabilities (u32) + * @NL80211_NAN_PHY_CAP_ATTR_HE_MAC: HE MAC capabilities + * @NL80211_NAN_PHY_CAP_ATTR_HE_PHY: HE PHY capabilities + * @NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET: HE supported NSS/MCS combinations + * @NL80211_NAN_PHY_CAP_ATTR_HE_PPE: HE PPE thresholds + * @NL80211_NAN_PHY_CAP_ATTR_MAX: highest NAN PHY cap attribute number + * @__NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST: internal use + */ +enum nl80211_nan_phy_cap_attr { + __NL80211_NAN_PHY_CAP_ATTR_INVALID, + + /* HT capabilities */ + NL80211_NAN_PHY_CAP_ATTR_HT_MCS_SET, + NL80211_NAN_PHY_CAP_ATTR_HT_CAPA, + NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_FACTOR, + NL80211_NAN_PHY_CAP_ATTR_HT_AMPDU_DENSITY, + + /* VHT capabilities */ + NL80211_NAN_PHY_CAP_ATTR_VHT_MCS_SET, + NL80211_NAN_PHY_CAP_ATTR_VHT_CAPA, + + /* HE capabilities */ + NL80211_NAN_PHY_CAP_ATTR_HE_MAC, + NL80211_NAN_PHY_CAP_ATTR_HE_PHY, + NL80211_NAN_PHY_CAP_ATTR_HE_MCS_SET, + NL80211_NAN_PHY_CAP_ATTR_HE_PPE, + + /* keep last */ + __NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST, + NL80211_NAN_PHY_CAP_ATTR_MAX = __NL80211_NAN_PHY_CAP_ATTR_AFTER_LAST - 1 +}; + /** * enum nl80211_wmm_rule - regulatory wmm rule * @@ -4480,6 +4700,10 @@ enum nl80211_wmm_rule { * as a non-primary subchannel. Only applicable to S1G channels. * @NL80211_FREQUENCY_ATTR_NO_UHR: UHR operation is not allowed on this channel * in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_CAC_START_TIME: Channel Availability Check (CAC) + * start time (CLOCK_BOOTTIME, nanoseconds). Only present when CAC is + * currently in progress on this channel. + * @NL80211_FREQUENCY_ATTR_PAD: attribute used for padding for 64-bit alignment * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -4530,6 +4754,8 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_16MHZ, NL80211_FREQUENCY_ATTR_S1G_NO_PRIMARY, NL80211_FREQUENCY_ATTR_NO_UHR, + NL80211_FREQUENCY_ATTR_CAC_START_TIME, + NL80211_FREQUENCY_ATTR_PAD, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -5466,6 +5692,8 @@ enum nl80211_bss_status { * @NL80211_AUTHTYPE_FILS_SK_PFS: Fast Initial Link Setup shared key with PFS * @NL80211_AUTHTYPE_FILS_PK: Fast Initial Link Setup public key * @NL80211_AUTHTYPE_EPPKE: Enhanced Privacy Protection Key Exchange + * @NL80211_AUTHTYPE_IEEE8021X: IEEE 802.1X authentication utilizing + * Authentication frames * @__NL80211_AUTHTYPE_NUM: internal * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by @@ -5482,6 +5710,7 @@ enum nl80211_auth_type { NL80211_AUTHTYPE_FILS_SK_PFS, NL80211_AUTHTYPE_FILS_PK, NL80211_AUTHTYPE_EPPKE, + NL80211_AUTHTYPE_IEEE8021X, /* keep last */ __NL80211_AUTHTYPE_NUM, @@ -6795,6 +7024,11 @@ enum nl80211_feature_flags { * frames in both non‑AP STA and AP mode as specified in * "IEEE P802.11bi/D3.0, 12.16.6". * + * @NL80211_EXT_FEATURE_IEEE8021X_AUTH: Driver supports IEEE 802.1X + * authentication utilizing Authentication frames with user space SME + * (NL80211_CMD_AUTHENTICATE) in non-AP STA mode, as specified in + * "IEEE P802.11bi/D4.0, 12.16.5". + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -6873,6 +7107,7 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_BEACON_RATE_EHT, NL80211_EXT_FEATURE_EPPKE, NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION, + NL80211_EXT_FEATURE_IEEE8021X_AUTH, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -8517,6 +8752,8 @@ enum nl80211_s1g_short_beacon_attrs { * @NL80211_NAN_CAPA_CAPABILITIES: u8 attribute containing the * capabilities of the device as defined in Wi-Fi Aware (TM) * specification Table 79 (Capabilities field). + * @NL80211_NAN_CAPA_PHY: nested attribute containing band-agnostic + * capabilities for NAN data path. See &enum nl80211_nan_phy_cap_attr. * @__NL80211_NAN_CAPABILITIES_LAST: Internal * @NL80211_NAN_CAPABILITIES_MAX: Highest NAN capability attribute. */ @@ -8529,9 +8766,38 @@ enum nl80211_nan_capabilities { NL80211_NAN_CAPA_NUM_ANTENNAS, NL80211_NAN_CAPA_MAX_CHANNEL_SWITCH_TIME, NL80211_NAN_CAPA_CAPABILITIES, + NL80211_NAN_CAPA_PHY, /* keep last */ __NL80211_NAN_CAPABILITIES_LAST, NL80211_NAN_CAPABILITIES_MAX = __NL80211_NAN_CAPABILITIES_LAST - 1, }; +/** + * enum nl80211_nan_peer_map_attrs - NAN peer schedule map attributes + * + * Nested attributes used within %NL80211_ATTR_NAN_PEER_MAPS to define + * individual peer schedule maps. + * + * @__NL80211_NAN_PEER_MAP_ATTR_INVALID: Invalid + * @NL80211_NAN_PEER_MAP_ATTR_MAP_ID: (u8) The map ID for this schedule map. + * @NL80211_NAN_PEER_MAP_ATTR_TIME_SLOTS: An array of u8 values with 32 cells. + * Each value maps a time slot to a channel index within the schedule's + * channel list (%NL80211_ATTR_NAN_CHANNEL attributes). + * %NL80211_NAN_SCHED_NOT_AVAIL_SLOT indicates unscheduled. + * @__NL80211_NAN_PEER_MAP_ATTR_LAST: Internal + * @NL80211_NAN_PEER_MAP_ATTR_MAX: Highest peer map attribute + */ +enum nl80211_nan_peer_map_attrs { + __NL80211_NAN_PEER_MAP_ATTR_INVALID, + + NL80211_NAN_PEER_MAP_ATTR_MAP_ID, + NL80211_NAN_PEER_MAP_ATTR_TIME_SLOTS, + + /* keep last */ + __NL80211_NAN_PEER_MAP_ATTR_LAST, + NL80211_NAN_PEER_MAP_ATTR_MAX = __NL80211_NAN_PEER_MAP_ATTR_LAST - 1, +}; + +#define NL80211_NAN_SCHED_NOT_AVAIL_SLOT 0xff + #endif /* __LINUX_NL80211_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/openvswitch.h b/lib/libc/include/any-linux-any/linux/openvswitch.h index 730ff8bb46cec0b8163113b05bb3f59622417fa5..2754f46325a6bddf30bc1776c8ec621d3e47f0a9 100644 --- a/lib/libc/include/any-linux-any/linux/openvswitch.h +++ b/lib/libc/include/any-linux-any/linux/openvswitch.h @@ -70,12 +70,15 @@ enum ovs_datapath_cmd { * set on the datapath port (for OVS_ACTION_ATTR_MISS). Only valid on * %OVS_DP_CMD_NEW requests. A value of zero indicates that upcalls should * not be sent. + * @OVS_DP_ATTR_MASKS_CACHE_SIZE: Number of the entries in the flow table + * masks cache. * @OVS_DP_ATTR_PER_CPU_PIDS: Per-cpu array of PIDs for upcalls when * OVS_DP_F_DISPATCH_UPCALL_PER_CPU feature is set. * @OVS_DP_ATTR_STATS: Statistics about packets that have passed through the * datapath. Always present in notifications. * @OVS_DP_ATTR_MEGAFLOW_STATS: Statistics about mega flow masks usage for the * datapath. Always present in notifications. + * @OVS_DP_ATTR_USER_FEATURES: OVS_DP_F_* flags. * @OVS_DP_ATTR_IFINDEX: Interface index for a new datapath netdev. Only * valid for %OVS_DP_CMD_NEW requests. * @@ -83,18 +86,23 @@ enum ovs_datapath_cmd { * payload for %OVS_DP_* commands. */ enum ovs_datapath_attr { + /* private: */ OVS_DP_ATTR_UNSPEC, + /* public: */ OVS_DP_ATTR_NAME, /* name of dp_ifindex netdev */ OVS_DP_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls */ OVS_DP_ATTR_STATS, /* struct ovs_dp_stats */ OVS_DP_ATTR_MEGAFLOW_STATS, /* struct ovs_dp_megaflow_stats */ OVS_DP_ATTR_USER_FEATURES, /* OVS_DP_F_* */ + /* private: */ OVS_DP_ATTR_PAD, + /* public: */ OVS_DP_ATTR_MASKS_CACHE_SIZE, OVS_DP_ATTR_PER_CPU_PIDS, /* Netlink PIDS to receive upcalls in * per-cpu dispatch mode */ OVS_DP_ATTR_IFINDEX, + /* private: */ __OVS_DP_ATTR_MAX }; @@ -181,6 +189,7 @@ enum ovs_packet_cmd { * %OVS_USERSPACE_ATTR_EGRESS_TUN_PORT attribute, which is sent only if the * output port is actually a tunnel port. Contains the output tunnel key * extracted from the packet as nested %OVS_TUNNEL_KEY_ATTR_* attributes. + * @OVS_PACKET_ATTR_PROBE: Packet operation is a feature probe. * @OVS_PACKET_ATTR_MRU: Present for an %OVS_PACKET_CMD_ACTION and * @OVS_PACKET_ATTR_LEN: Packet size before truncation. * %OVS_PACKET_ATTR_USERSPACE action specify the Maximum received fragment @@ -196,21 +205,26 @@ enum ovs_packet_cmd { * payload for %OVS_PACKET_* commands. */ enum ovs_packet_attr { + /* private: */ OVS_PACKET_ATTR_UNSPEC, + /* public: */ OVS_PACKET_ATTR_PACKET, /* Packet data. */ OVS_PACKET_ATTR_KEY, /* Nested OVS_KEY_ATTR_* attributes. */ OVS_PACKET_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */ OVS_PACKET_ATTR_USERDATA, /* OVS_ACTION_ATTR_USERSPACE arg. */ OVS_PACKET_ATTR_EGRESS_TUN_KEY, /* Nested OVS_TUNNEL_KEY_ATTR_* attributes. */ + /* private: */ OVS_PACKET_ATTR_UNUSED1, OVS_PACKET_ATTR_UNUSED2, + /* public: */ OVS_PACKET_ATTR_PROBE, /* Packet operation is a feature probe, error logging should be suppressed. */ OVS_PACKET_ATTR_MRU, /* Maximum received IP fragment size. */ OVS_PACKET_ATTR_LEN, /* Packet size before truncation. */ OVS_PACKET_ATTR_HASH, /* Packet hash. */ OVS_PACKET_ATTR_UPCALL_PID, /* u32 Netlink PID. */ + /* private: */ __OVS_PACKET_ATTR_MAX }; @@ -257,6 +271,11 @@ enum ovs_vport_type { * upcalls should not be sent. * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for * packets sent or received through the vport. + * @OVS_VPORT_ATTR_IFINDEX: Provides the ifindex of a vport, or sets the desired + * ifindex while creating a new vport with type %OVS_VPORT_TYPE_INTERNAL. + * @OVS_VPORT_ATTR_NETNSID: Provides the netns id of the vport if it's not local. + * @OVS_VPORT_ATTR_UPCALL_STATS: Provides upcall statistics for a vport. + * Contains nested %OVS_VPORT_UPCALL_ATTR_* attributes. * * These attributes follow the &struct ovs_header within the Generic Netlink * payload for %OVS_VPORT_* commands. @@ -272,7 +291,9 @@ enum ovs_vport_type { * ovs_header plus %OVS_VPORT_ATTR_PORT_NO determine the vport. */ enum ovs_vport_attr { + /* private: */ OVS_VPORT_ATTR_UNSPEC, + /* public: */ OVS_VPORT_ATTR_PORT_NO, /* u32 port number within datapath */ OVS_VPORT_ATTR_TYPE, /* u32 OVS_VPORT_TYPE_* constant. */ OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */ @@ -280,23 +301,27 @@ enum ovs_vport_attr { OVS_VPORT_ATTR_UPCALL_PID, /* array of u32 Netlink socket PIDs for */ /* receiving upcalls */ OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */ + /* private: */ OVS_VPORT_ATTR_PAD, + /* public: */ OVS_VPORT_ATTR_IFINDEX, OVS_VPORT_ATTR_NETNSID, OVS_VPORT_ATTR_UPCALL_STATS, + /* private: */ __OVS_VPORT_ATTR_MAX }; #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1) /** - * enum ovs_vport_upcall_attr - attributes for %OVS_VPORT_UPCALL* commands - * @OVS_VPORT_UPCALL_SUCCESS: 64-bit upcall success packets. - * @OVS_VPORT_UPCALL_FAIL: 64-bit upcall fail packets. + * enum ovs_vport_upcall_attr - attributes for %OVS_VPORT_ATTR_UPCALL_STATS + * @OVS_VPORT_UPCALL_ATTR_SUCCESS: 64-bit upcall success packets. + * @OVS_VPORT_UPCALL_ATTR_FAIL: 64-bit upcall fail packets. */ enum ovs_vport_upcall_attr { OVS_VPORT_UPCALL_ATTR_SUCCESS, OVS_VPORT_UPCALL_ATTR_FAIL, + /* private: */ __OVS_VPORT_UPCALL_ATTR_MAX }; @@ -431,6 +456,7 @@ enum ovs_frag_type { OVS_FRAG_TYPE_NONE, OVS_FRAG_TYPE_FIRST, OVS_FRAG_TYPE_LATER, + /* private: */ __OVS_FRAG_TYPE_MAX }; @@ -604,6 +630,8 @@ struct ovs_nsh_key_md1 { * a wildcarded match. Omitting attribute is treated as wildcarding all * corresponding fields. Optional for all requests. If not present, * all flow key bits are exact match bits. + * @OVS_FLOW_ATTR_PROBE: Flow operation is a feature probe, error logging + * should be suppressed. * @OVS_FLOW_ATTR_UFID: A value between 1-16 octets specifying a unique * identifier for the flow. Causes the flow to be indexed by this value rather * than the value of the %OVS_FLOW_ATTR_KEY attribute. Optional for all @@ -617,7 +645,9 @@ struct ovs_nsh_key_md1 { * payload for %OVS_FLOW_* commands. */ enum ovs_flow_attr { + /* private: */ OVS_FLOW_ATTR_UNSPEC, + /* public: */ OVS_FLOW_ATTR_KEY, /* Sequence of OVS_KEY_ATTR_* attributes. */ OVS_FLOW_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */ OVS_FLOW_ATTR_STATS, /* struct ovs_flow_stats. */ @@ -629,13 +659,14 @@ enum ovs_flow_attr { * logging should be suppressed. */ OVS_FLOW_ATTR_UFID, /* Variable length unique flow identifier. */ OVS_FLOW_ATTR_UFID_FLAGS,/* u32 of OVS_UFID_F_*. */ + /* private: */ OVS_FLOW_ATTR_PAD, __OVS_FLOW_ATTR_MAX }; #define OVS_FLOW_ATTR_MAX (__OVS_FLOW_ATTR_MAX - 1) -/** +/* * Omit attributes for notifications. * * If a datapath request contains an %OVS_UFID_F_OMIT_* flag, then the datapath @@ -653,17 +684,23 @@ enum ovs_flow_attr { * fractions of packets. * @OVS_SAMPLE_ATTR_ACTIONS: Set of actions to execute in sampling event. * Actions are passed as nested attributes. + * @OVS_SAMPLE_ATTR_ARG: For in-kernel use, passing &struct sample_arg + * derived from other attributes. * * Executes the specified actions with the given probability on a per-packet * basis. Nested actions will be able to access the probability value of the * parent @OVS_ACTION_ATTR_SAMPLE. */ enum ovs_sample_attr { + /* private: */ OVS_SAMPLE_ATTR_UNSPEC, + /* public: */ OVS_SAMPLE_ATTR_PROBABILITY, /* u32 number */ OVS_SAMPLE_ATTR_ACTIONS, /* Nested OVS_ACTION_ATTR_* attributes. */ + /* private: */ __OVS_SAMPLE_ATTR_MAX, + /* public: */ }; #define OVS_SAMPLE_ATTR_MAX (__OVS_SAMPLE_ATTR_MAX - 1) @@ -680,12 +717,15 @@ enum ovs_sample_attr { * @OVS_USERSPACE_ATTR_ACTIONS: If present, send actions with upcall. */ enum ovs_userspace_attr { + /* private: */ OVS_USERSPACE_ATTR_UNSPEC, + /* public: */ OVS_USERSPACE_ATTR_PID, /* u32 Netlink PID to receive upcalls. */ OVS_USERSPACE_ATTR_USERDATA, /* Optional user-specified cookie. */ OVS_USERSPACE_ATTR_EGRESS_TUN_PORT, /* Optional, u32 output port * to get tunnel info. */ OVS_USERSPACE_ATTR_ACTIONS, /* Optional flag to get actions. */ + /* private: */ __OVS_USERSPACE_ATTR_MAX }; @@ -806,7 +846,9 @@ struct ovs_action_hash { * @OVS_CT_ATTR_TIMEOUT: Variable length string defining conntrack timeout. */ enum ovs_ct_attr { + /* private: */ OVS_CT_ATTR_UNSPEC, + /* public: */ OVS_CT_ATTR_COMMIT, /* No argument, commits connection. */ OVS_CT_ATTR_ZONE, /* u16 zone id. */ OVS_CT_ATTR_MARK, /* mark to associate with this connection. */ @@ -818,6 +860,7 @@ enum ovs_ct_attr { OVS_CT_ATTR_EVENTMASK, /* u32 mask of IPCT_* events. */ OVS_CT_ATTR_TIMEOUT, /* Associate timeout with this connection for * fine-grain timeout tuning. */ + /* private: */ __OVS_CT_ATTR_MAX }; @@ -846,7 +889,9 @@ enum ovs_ct_attr { * @OVS_NAT_ATTR_PROTO_RANDOM: Flag for fully randomized L4 port mapping */ enum ovs_nat_attr { + /* private: */ OVS_NAT_ATTR_UNSPEC, + /* public: */ OVS_NAT_ATTR_SRC, OVS_NAT_ATTR_DST, OVS_NAT_ATTR_IP_MIN, @@ -856,38 +901,44 @@ enum ovs_nat_attr { OVS_NAT_ATTR_PERSISTENT, OVS_NAT_ATTR_PROTO_HASH, OVS_NAT_ATTR_PROTO_RANDOM, + /* private: */ __OVS_NAT_ATTR_MAX, }; #define OVS_NAT_ATTR_MAX (__OVS_NAT_ATTR_MAX - 1) -/* +/** * struct ovs_action_push_eth - %OVS_ACTION_ATTR_PUSH_ETH action argument. * @addresses: Source and destination MAC addresses. - * @eth_type: Ethernet type */ struct ovs_action_push_eth { struct ovs_key_ethernet addresses; }; -/* +/** * enum ovs_check_pkt_len_attr - Attributes for %OVS_ACTION_ATTR_CHECK_PKT_LEN. * * @OVS_CHECK_PKT_LEN_ATTR_PKT_LEN: u16 Packet length to check for. * @OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER: Nested OVS_ACTION_ATTR_* * actions to apply if the packer length is greater than the specified * length in the attr - OVS_CHECK_PKT_LEN_ATTR_PKT_LEN. - * @OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL - Nested OVS_ACTION_ATTR_* + * @OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL: Nested OVS_ACTION_ATTR_* * actions to apply if the packer length is lesser or equal to the specified * length in the attr - OVS_CHECK_PKT_LEN_ATTR_PKT_LEN. + * @OVS_CHECK_PKT_LEN_ATTR_ARG: For in-kernel use, passing &struct + * check_pkt_len_arg derived from other attributes. */ enum ovs_check_pkt_len_attr { + /* private: */ OVS_CHECK_PKT_LEN_ATTR_UNSPEC, + /* public: */ OVS_CHECK_PKT_LEN_ATTR_PKT_LEN, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_GREATER, OVS_CHECK_PKT_LEN_ATTR_ACTIONS_IF_LESS_EQUAL, + /* private: */ __OVS_CHECK_PKT_LEN_ATTR_MAX, + /* public: */ }; #define OVS_CHECK_PKT_LEN_ATTR_MAX (__OVS_CHECK_PKT_LEN_ATTR_MAX - 1) @@ -940,6 +991,9 @@ enum ovs_psample_attr { * from the packet. * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in * the nested %OVS_SAMPLE_ATTR_* attributes. + * @OVS_ACTION_ATTR_RECIRC: Recirculate the clone of the packet through the + * datapath with the new id (u32 recirc_id). + * @OVS_ACTION_ATTR_HASH: Compute the packet hash, using &struct ovs_action_hash. * @OVS_ACTION_ATTR_PUSH_MPLS: Push a new MPLS label stack entry onto the * top of the packets MPLS label stack. Set the ethertype of the * encapsulating frame to either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC to @@ -969,6 +1023,8 @@ enum ovs_psample_attr { * start of the packet or at the start of the l3 header depending on the value * of l3 tunnel flag in the tun_flags field of OVS_ACTION_ATTR_ADD_MPLS * argument. + * @OVS_ACTION_ATTR_DEC_TTL: Decrement TTL or hop limit of the packet. Execute + * nested %OVS_DEC_TTL_ATTR_* actions if the value is less or equal to 1. * @OVS_ACTION_ATTR_DROP: Explicit drop action. * @OVS_ACTION_ATTR_PSAMPLE: Send a sample of the packet to external observers * via psample. @@ -982,7 +1038,9 @@ enum ovs_psample_attr { */ enum ovs_action_attr { + /* private: */ OVS_ACTION_ATTR_UNSPEC, + /* public: */ OVS_ACTION_ATTR_OUTPUT, /* u32 port number. */ OVS_ACTION_ATTR_USERSPACE, /* Nested OVS_USERSPACE_ATTR_*. */ OVS_ACTION_ATTR_SET, /* One nested OVS_KEY_ATTR_*. */ @@ -1012,9 +1070,11 @@ enum ovs_action_attr { OVS_ACTION_ATTR_DROP, /* u32 error code. */ OVS_ACTION_ATTR_PSAMPLE, /* Nested OVS_PSAMPLE_ATTR_*. */ + /* private: */ __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted * from userspace. */ + /* public: */ }; #define OVS_ACTION_ATTR_MAX (__OVS_ACTION_ATTR_MAX - 1) diff --git a/lib/libc/include/any-linux-any/linux/ovpn.h b/lib/libc/include/any-linux-any/linux/ovpn.h index 5c3959fcb6d7db810868d5c892a750f7536c151d..89c97f903ca84bd3d295d56ae1a7dbbbaaa11692 100644 --- a/lib/libc/include/any-linux-any/linux/ovpn.h +++ b/lib/libc/include/any-linux-any/linux/ovpn.h @@ -55,6 +55,7 @@ enum { OVPN_A_PEER_LINK_TX_BYTES, OVPN_A_PEER_LINK_RX_PACKETS, OVPN_A_PEER_LINK_TX_PACKETS, + OVPN_A_PEER_TX_ID, __OVPN_A_PEER_MAX, OVPN_A_PEER_MAX = (__OVPN_A_PEER_MAX - 1) @@ -100,6 +101,7 @@ enum { OVPN_CMD_KEY_SWAP, OVPN_CMD_KEY_SWAP_NTF, OVPN_CMD_KEY_DEL, + OVPN_CMD_PEER_FLOAT_NTF, __OVPN_CMD_MAX, OVPN_CMD_MAX = (__OVPN_CMD_MAX - 1) diff --git a/lib/libc/include/any-linux-any/linux/pidfd.h b/lib/libc/include/any-linux-any/linux/pidfd.h index b6b447e819543c8829d8dfc37aa6b63674dc4703..7bf8a8cf339b87a34c1a219a06258fe2b60c5dee 100644 --- a/lib/libc/include/any-linux-any/linux/pidfd.h +++ b/lib/libc/include/any-linux-any/linux/pidfd.h @@ -24,10 +24,12 @@ #define PIDFD_INFO_COREDUMP (1UL << 4) /* Only returned if requested. */ #define PIDFD_INFO_SUPPORTED_MASK (1UL << 5) /* Want/got supported mask flags */ #define PIDFD_INFO_COREDUMP_SIGNAL (1UL << 6) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ +#define PIDFD_INFO_COREDUMP_CODE (1UL << 7) /* Always returned if PIDFD_INFO_COREDUMP is requested. */ #define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */ #define PIDFD_INFO_SIZE_VER1 72 /* sizeof second published struct */ #define PIDFD_INFO_SIZE_VER2 80 /* sizeof third published struct */ +#define PIDFD_INFO_SIZE_VER3 88 /* sizeof fourth published struct */ /* * Values for @coredump_mask in pidfd_info. @@ -94,6 +96,8 @@ struct pidfd_info { struct /* coredump info */ { __u32 coredump_mask; __u32 coredump_signal; + __u32 coredump_code; + __u32 coredump_pad; /* align supported_mask to 8 bytes */ }; __u64 supported_mask; /* Mask flags that this kernel supports */ }; diff --git a/lib/libc/include/any-linux-any/linux/psp-sev.h b/lib/libc/include/any-linux-any/linux/psp-sev.h index ba30f4cd48a256788db8016bbb51b88a607f9d98..5f69905a2ede55d0ab2815f940035b99953f367a 100644 --- a/lib/libc/include/any-linux-any/linux/psp-sev.h +++ b/lib/libc/include/any-linux-any/linux/psp-sev.h @@ -277,7 +277,7 @@ struct sev_user_data_snp_wrapped_vlek_hashstick { * struct sev_issue_cmd - SEV ioctl parameters * * @cmd: SEV commands to execute - * @opaque: pointer to the command structure + * @data: pointer to the command structure * @error: SEV FW return code on failure */ struct sev_issue_cmd { diff --git a/lib/libc/include/any-linux-any/linux/rose.h b/lib/libc/include/any-linux-any/linux/rose.h deleted file mode 100644 index 5dcdc842e3f315a9c63697e72e6608d1b4156390..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/rose.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * These are the public elements of the Linux kernel Rose implementation. - * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the - * definition of the ax25_address structure. - */ - -#ifndef ROSE_KERNEL_H -#define ROSE_KERNEL_H - -#include -#include - -#define ROSE_MTU 251 - -#define ROSE_MAX_DIGIS 6 - -#define ROSE_DEFER 1 -#define ROSE_T1 2 -#define ROSE_T2 3 -#define ROSE_T3 4 -#define ROSE_IDLE 5 -#define ROSE_QBITINCL 6 -#define ROSE_HOLDBACK 7 - -#define SIOCRSGCAUSE (SIOCPROTOPRIVATE+0) -#define SIOCRSSCAUSE (SIOCPROTOPRIVATE+1) -#define SIOCRSL2CALL (SIOCPROTOPRIVATE+2) -#define SIOCRSSL2CALL (SIOCPROTOPRIVATE+2) -#define SIOCRSACCEPT (SIOCPROTOPRIVATE+3) -#define SIOCRSCLRRT (SIOCPROTOPRIVATE+4) -#define SIOCRSGL2CALL (SIOCPROTOPRIVATE+5) -#define SIOCRSGFACILITIES (SIOCPROTOPRIVATE+6) - -#define ROSE_DTE_ORIGINATED 0x00 -#define ROSE_NUMBER_BUSY 0x01 -#define ROSE_INVALID_FACILITY 0x03 -#define ROSE_NETWORK_CONGESTION 0x05 -#define ROSE_OUT_OF_ORDER 0x09 -#define ROSE_ACCESS_BARRED 0x0B -#define ROSE_NOT_OBTAINABLE 0x0D -#define ROSE_REMOTE_PROCEDURE 0x11 -#define ROSE_LOCAL_PROCEDURE 0x13 -#define ROSE_SHIP_ABSENT 0x39 - -typedef struct { - char rose_addr[5]; -} rose_address; - -struct sockaddr_rose { - __kernel_sa_family_t srose_family; - rose_address srose_addr; - ax25_address srose_call; - int srose_ndigis; - ax25_address srose_digi; -}; - -struct full_sockaddr_rose { - __kernel_sa_family_t srose_family; - rose_address srose_addr; - ax25_address srose_call; - unsigned int srose_ndigis; - ax25_address srose_digis[ROSE_MAX_DIGIS]; -}; - -struct rose_route_struct { - rose_address address; - unsigned short mask; - ax25_address neighbour; - char device[16]; - unsigned char ndigis; - ax25_address digipeaters[AX25_MAX_DIGIS]; -}; - -struct rose_cause_struct { - unsigned char cause; - unsigned char diagnostic; -}; - -struct rose_facilities_struct { - rose_address source_addr, dest_addr; - ax25_address source_call, dest_call; - unsigned char source_ndigis, dest_ndigis; - ax25_address source_digis[ROSE_MAX_DIGIS]; - ax25_address dest_digis[ROSE_MAX_DIGIS]; - unsigned int rand; - rose_address fail_addr; - ax25_address fail_call; -}; - -#endif \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/rseq.h b/lib/libc/include/any-linux-any/linux/rseq.h index b84d319db3f09c895b91aa44586ed2ba22bc6aac..072890252ed6cdd503e69c25b38f3e0c3ca08940 100644 --- a/lib/libc/include/any-linux-any/linux/rseq.h +++ b/lib/libc/include/any-linux-any/linux/rseq.h @@ -28,7 +28,7 @@ enum rseq_cs_flags_bit { RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT_BIT = 0, RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL_BIT = 1, RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE_BIT = 2, - /* (3) Intentional gap to put new bits into a separate byte */ + /* (3) Intentional gap to keep new bits separate */ /* User read only feature flags */ RSEQ_CS_FLAG_SLICE_EXT_AVAILABLE_BIT = 4, @@ -161,6 +161,9 @@ struct rseq { * - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT * - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL * - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE + * + * It is now used for feature status advertisement by the kernel. + * See: enum rseq_cs_flags_bit for further information. */ __u32 flags; diff --git a/lib/libc/include/any-linux-any/linux/scc.h b/lib/libc/include/any-linux-any/linux/scc.h deleted file mode 100644 index b629398387a65b29dfeb395ad8dc0baf7f92a7fa..0000000000000000000000000000000000000000 --- a/lib/libc/include/any-linux-any/linux/scc.h +++ /dev/null @@ -1,174 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* $Id: scc.h,v 1.29 1997/04/02 14:56:45 jreuter Exp jreuter $ */ - -#ifndef _SCC_H -#define _SCC_H - -#include - -/* selection of hardware types */ - -#define PA0HZP 0x00 /* hardware type for PA0HZP SCC card and compatible */ -#define EAGLE 0x01 /* hardware type for EAGLE card */ -#define PC100 0x02 /* hardware type for PC100 card */ -#define PRIMUS 0x04 /* hardware type for PRIMUS-PC (DG9BL) card */ -#define DRSI 0x08 /* hardware type for DRSI PC*Packet card */ -#define BAYCOM 0x10 /* hardware type for BayCom (U)SCC */ - -/* DEV ioctl() commands */ - -enum SCC_ioctl_cmds { - SIOCSCCRESERVED = SIOCDEVPRIVATE, - SIOCSCCCFG, - SIOCSCCINI, - SIOCSCCCHANINI, - SIOCSCCSMEM, - SIOCSCCGKISS, - SIOCSCCSKISS, - SIOCSCCGSTAT, - SIOCSCCCAL -}; - -/* Device parameter control (from WAMPES) */ - -enum L1_params { - PARAM_DATA, - PARAM_TXDELAY, - PARAM_PERSIST, - PARAM_SLOTTIME, - PARAM_TXTAIL, - PARAM_FULLDUP, - PARAM_SOFTDCD, /* was: PARAM_HW */ - PARAM_MUTE, /* ??? */ - PARAM_DTR, - PARAM_RTS, - PARAM_SPEED, - PARAM_ENDDELAY, /* ??? */ - PARAM_GROUP, - PARAM_IDLE, - PARAM_MIN, - PARAM_MAXKEY, - PARAM_WAIT, - PARAM_MAXDEFER, - PARAM_TX, - PARAM_HWEVENT = 31, - PARAM_RETURN = 255 /* reset kiss mode */ -}; - -/* fulldup parameter */ - -enum FULLDUP_modes { - KISS_DUPLEX_HALF, /* normal CSMA operation */ - KISS_DUPLEX_FULL, /* fullduplex, key down trx after transmission */ - KISS_DUPLEX_LINK, /* fullduplex, key down trx after 'idletime' sec */ - KISS_DUPLEX_OPTIMA /* fullduplex, let the protocol layer control the hw */ -}; - -/* misc. parameters */ - -#define TIMER_OFF 65535U /* to switch off timers */ -#define NO_SUCH_PARAM 65534U /* param not implemented */ - -/* HWEVENT parameter */ - -enum HWEVENT_opts { - HWEV_DCD_ON, - HWEV_DCD_OFF, - HWEV_ALL_SENT -}; - -/* channel grouping */ - -#define RXGROUP 0100 /* if set, only tx when all channels clear */ -#define TXGROUP 0200 /* if set, don't transmit simultaneously */ - -/* Tx/Rx clock sources */ - -enum CLOCK_sources { - CLK_DPLL, /* normal halfduplex operation */ - CLK_EXTERNAL, /* external clocking (G3RUH/DF9IC modems) */ - CLK_DIVIDER, /* Rx = DPLL, Tx = divider (fullduplex with */ - /* modems without clock regeneration */ - CLK_BRG /* experimental fullduplex mode with DPLL/BRG for */ - /* MODEMs without clock recovery */ -}; - -/* Tx state */ - -enum TX_state { - TXS_IDLE, /* Transmitter off, no data pending */ - TXS_BUSY, /* waiting for permission to send / tailtime */ - TXS_ACTIVE, /* Transmitter on, sending data */ - TXS_NEWFRAME, /* reset CRC and send (next) frame */ - TXS_IDLE2, /* Transmitter on, no data pending */ - TXS_WAIT, /* Waiting for Mintime to expire */ - TXS_TIMEOUT /* We had a transmission timeout */ -}; - -typedef unsigned long io_port; /* type definition for an 'io port address' */ - -/* SCC statistical information */ - -struct scc_stat { - long rxints; /* Receiver interrupts */ - long txints; /* Transmitter interrupts */ - long exints; /* External/status interrupts */ - long spints; /* Special receiver interrupts */ - - long txframes; /* Packets sent */ - long rxframes; /* Number of Frames Actually Received */ - long rxerrs; /* CRC Errors */ - long txerrs; /* KISS errors */ - - unsigned int nospace; /* "Out of buffers" */ - unsigned int rx_over; /* Receiver Overruns */ - unsigned int tx_under; /* Transmitter Underruns */ - - unsigned int tx_state; /* Transmitter state */ - int tx_queued; /* tx frames enqueued */ - - unsigned int maxqueue; /* allocated tx_buffers */ - unsigned int bufsize; /* used buffersize */ -}; - -struct scc_modem { - long speed; /* Line speed, bps */ - char clocksrc; /* 0 = DPLL, 1 = external, 2 = divider */ - char nrz; /* NRZ instead of NRZI */ -}; - -struct scc_kiss_cmd { - int command; /* one of the KISS-Commands defined above */ - unsigned param; /* KISS-Param */ -}; - -struct scc_hw_config { - io_port data_a; /* data port channel A */ - io_port ctrl_a; /* control port channel A */ - io_port data_b; /* data port channel B */ - io_port ctrl_b; /* control port channel B */ - io_port vector_latch; /* INTACK-Latch (#) */ - io_port special; /* special function port */ - - int irq; /* irq */ - long clock; /* clock */ - char option; /* command for function port */ - - char brand; /* hardware type */ - char escc; /* use ext. features of a 8580/85180/85280 */ -}; - -/* (#) only one INTACK latch allowed. */ - - -struct scc_mem_config { - unsigned int dummy; - unsigned int bufsize; -}; - -struct scc_calibrate { - unsigned int time; - unsigned char pattern; -}; - -#endif /* _SCC_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/sched.h b/lib/libc/include/any-linux-any/linux/sched.h index 82995e5dd0f4d230ceec49453d51b74c34539ead..e88d5440602d1bbae51351dd276981339e8e4acf 100644 --- a/lib/libc/include/any-linux-any/linux/sched.h +++ b/lib/libc/include/any-linux-any/linux/sched.h @@ -34,8 +34,12 @@ #define CLONE_IO 0x80000000 /* Clone io context */ /* Flags for the clone3() syscall. */ -#define CLONE_CLEAR_SIGHAND 0x100000000ULL /* Clear any signal handler and reset to SIG_DFL. */ -#define CLONE_INTO_CGROUP 0x200000000ULL /* Clone into a specific cgroup given the right permissions. */ +#define CLONE_CLEAR_SIGHAND (1ULL << 32) /* Clear any signal handler and reset to SIG_DFL. */ +#define CLONE_INTO_CGROUP (1ULL << 33) /* Clone into a specific cgroup given the right permissions. */ +#define CLONE_AUTOREAP (1ULL << 34) /* Auto-reap child on exit. */ +#define CLONE_NNP (1ULL << 35) /* Set no_new_privs on child. */ +#define CLONE_PIDFD_AUTOKILL (1ULL << 36) /* Kill child when clone pidfd closes. */ +#define CLONE_EMPTY_MNTNS (1ULL << 37) /* Create an empty mount namespace. */ /* * cloning flags intersect with CSIGNAL so can be used with unshare and clone3 @@ -43,6 +47,12 @@ */ #define CLONE_NEWTIME 0x00000080 /* New time namespace */ +/* + * unshare flags share the bit space with clone flags but only apply to the + * unshare syscall: + */ +#define UNSHARE_EMPTY_MNTNS 0x00100000 /* Unshare an empty mount namespace. */ + #ifndef __ASSEMBLY__ /** * struct clone_args - arguments for the clone3 syscall @@ -146,4 +156,7 @@ struct clone_args { SCHED_FLAG_KEEP_ALL | \ SCHED_FLAG_UTIL_CLAMP) +/* Only for sched_getattr() own flag param, if task is SCHED_DEADLINE */ +#define SCHED_GETATTR_FLAG_DL_DYNAMIC 0x01 + #endif /* _LINUX_SCHED_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/sed-opal.h b/lib/libc/include/any-linux-any/linux/sed-opal.h index 733afdf08dca56cb5596fd9ff1eef1366dce6c11..4774427e7b7c3a0839fb1c6bfca6abbf9a2c0881 100644 --- a/lib/libc/include/any-linux-any/linux/sed-opal.h +++ b/lib/libc/include/any-linux-any/linux/sed-opal.h @@ -74,6 +74,19 @@ struct opal_lr_act { __u8 align[2]; /* Align to 8 byte boundary */ }; +struct opal_lr_react { + struct opal_key key; + struct opal_key new_admin_key; /* Set new Admin1 PIN if key_len is > 0 */ + __u8 num_lrs; /* + * Configure selected ranges (from lr[]) in SUM. + * If num_lrs > 0 the 'entire_table' must be 0 + */ + __u8 lr[OPAL_MAX_LRS]; + __u8 range_policy; /* Set RangeStartRangeLengthPolicy parameter */ + __u8 entire_table; /* Set all locking objects in SUM */ + __u8 align[4]; /* Align to 8 byte boundary */ +}; + struct opal_session_info { __u32 sum; __u32 who; @@ -98,6 +111,18 @@ struct opal_lr_status { __u8 align[4]; }; +struct opal_sum_ranges { + /* + * Initiate Admin1 session if key_len > 0, + * use Anybody session otherwise. + */ + struct opal_key key; + __u8 num_lrs; + __u8 lr[OPAL_MAX_LRS]; + __u8 range_policy; + __u8 align[5]; /* Align to 8 byte boundary */ +}; + struct opal_lock_unlock { struct opal_session_info session; __u32 l_state; @@ -216,5 +241,10 @@ struct opal_revert_lsp { #define IOC_OPAL_DISCOVERY _IOW('p', 239, struct opal_discovery) #define IOC_OPAL_REVERT_LSP _IOW('p', 240, struct opal_revert_lsp) #define IOC_OPAL_SET_SID_PW _IOW('p', 241, struct opal_new_pw) +#define IOC_OPAL_REACTIVATE_LSP _IOW('p', 242, struct opal_lr_react) +#define IOC_OPAL_LR_SET_START_LEN _IOW('p', 243, struct opal_user_lr_setup) +#define IOC_OPAL_ENABLE_DISABLE_LR _IOW('p', 244, struct opal_user_lr_setup) +#define IOC_OPAL_GET_SUM_STATUS _IOW('p', 245, struct opal_sum_ranges) +#define IOC_OPAL_STACK_RESET _IO('p', 246) #endif /* _SED_OPAL_H */ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/seg6_iptunnel.h b/lib/libc/include/any-linux-any/linux/seg6_iptunnel.h index 4361e5c5a1bbfa4244f22cc85932ca719d6390bf..19d538851169c5b73c0830909cbd114958b1b521 100644 --- a/lib/libc/include/any-linux-any/linux/seg6_iptunnel.h +++ b/lib/libc/include/any-linux-any/linux/seg6_iptunnel.h @@ -20,6 +20,7 @@ enum { SEG6_IPTUNNEL_UNSPEC, SEG6_IPTUNNEL_SRH, + SEG6_IPTUNNEL_SRC, /* struct in6_addr */ __SEG6_IPTUNNEL_MAX, }; #define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1) diff --git a/lib/libc/include/any-linux-any/linux/tee.h b/lib/libc/include/any-linux-any/linux/tee.h index 4f8d7d97a77a2749fb910e0620e0bca74a92d805..0d64a060b18a76630cf37d18a43a634eef7da9aa 100644 --- a/lib/libc/include/any-linux-any/linux/tee.h +++ b/lib/libc/include/any-linux-any/linux/tee.h @@ -470,6 +470,7 @@ struct tee_ioctl_object_invoke_arg { __u32 op; __u32 ret; __u32 num_params; + __u32 :32; /* num_params tells the actual number of element in params */ struct tee_ioctl_param params[]; }; diff --git a/lib/libc/include/any-linux-any/linux/trace_mmap.h b/lib/libc/include/any-linux-any/linux/trace_mmap.h index fb720ddd3b650afc9bd42f2092408c00ffa38222..27e098d364b2c548d19fd24e917e6d6863b1fdf1 100644 --- a/lib/libc/include/any-linux-any/linux/trace_mmap.h +++ b/lib/libc/include/any-linux-any/linux/trace_mmap.h @@ -10,6 +10,7 @@ * @meta_struct_len: Size of this structure. * @subbuf_size: Size of each sub-buffer. * @nr_subbufs: Number of subbfs in the ring-buffer, including the reader. + * @reader: The reader composite info structure * @reader.lost_events: Number of events lost at the time of the reader swap. * @reader.id: subbuf ID of the current reader. ID range [0 : @nr_subbufs - 1] * @reader.read: Number of bytes read on the reader subbuf. @@ -17,8 +18,8 @@ * @entries: Number of entries in the ring-buffer. * @overrun: Number of entries lost in the ring-buffer. * @read: Number of entries that have been read. - * @Reserved1: Internal use only. - * @Reserved2: Internal use only. + * @pages_lost: Number of pages overwritten by the writer. + * @pages_touched: Number of pages written by the writer. */ struct trace_buffer_meta { __u32 meta_page_size; @@ -39,8 +40,8 @@ struct trace_buffer_meta { __u64 overrun; __u64 read; - __u64 Reserved1; - __u64 Reserved2; + __u64 pages_lost; + __u64 pages_touched; }; #define TRACE_MMAP_IOCTL_GET_READER _IO('R', 0x20) diff --git a/lib/libc/include/any-linux-any/linux/ublk_cmd.h b/lib/libc/include/any-linux-any/linux/ublk_cmd.h index a8a5dff94e9f8722ce8a1d69cf4df91403087b22..7aee5d9b127619e9a20978f3850b6fd00c8c2045 100644 --- a/lib/libc/include/any-linux-any/linux/ublk_cmd.h +++ b/lib/libc/include/any-linux-any/linux/ublk_cmd.h @@ -57,6 +57,45 @@ _IOWR('u', 0x16, struct ublksrv_ctrl_cmd) #define UBLK_U_CMD_TRY_STOP_DEV \ _IOWR('u', 0x17, struct ublksrv_ctrl_cmd) +/* + * Register a shared memory buffer for zero-copy I/O. + * Input: ctrl_cmd.addr points to struct ublk_shmem_buf_reg (buffer VA + size) + * ctrl_cmd.len = sizeof(struct ublk_shmem_buf_reg) + * Result: >= 0 is the assigned buffer index, < 0 is error + * + * The kernel pins pages from the calling process's address space + * and inserts PFN ranges into a per-device maple tree. When a block + * request's pages match registered pages, the driver sets + * UBLK_IO_F_SHMEM_ZC and encodes the buffer index + offset in addr, + * allowing the server to access the data via its own mapping of the + * same shared memory — true zero copy. + * + * The memory can be backed by memfd, hugetlbfs, or any GUP-compatible + * shared mapping. Queue freeze is handled internally. + * + * The buffer VA and size are passed via a user buffer (not __inline__ in + * ctrl_cmd) so that unprivileged devices can prepend the device path + * to ctrl_cmd.addr without corrupting the VA. + */ +#define UBLK_U_CMD_REG_BUF \ + _IOWR('u', 0x18, struct ublksrv_ctrl_cmd) +/* + * Unregister a shared memory buffer. + * Input: ctrl_cmd.data[0] = buffer index + */ +#define UBLK_U_CMD_UNREG_BUF \ + _IOWR('u', 0x19, struct ublksrv_ctrl_cmd) + +/* Parameter buffer for UBLK_U_CMD_REG_BUF, pointed to by ctrl_cmd.addr */ +struct ublk_shmem_buf_reg { + __u64 addr; /* userspace virtual address of shared memory */ + __u64 len; /* buffer size in bytes, page-aligned, default max 4GB */ + __u32 flags; + __u32 reserved; +}; + +/* Pin pages without FOLL_WRITE; usable with write-sealed memfd */ +#define UBLK_SHMEM_BUF_READ_ONLY (1U << 0) /* * 64bits are enough now, and it should be easy to extend in case of * running out of feature flags @@ -370,6 +409,14 @@ /* Disable automatic partition scanning when device is started */ #define UBLK_F_NO_AUTO_PART_SCAN (1ULL << 18) +/* + * Enable shared memory zero copy. When enabled, the server can register + * shared memory buffers via UBLK_U_CMD_REG_BUF. If a block request's + * pages match a registered buffer, UBLK_IO_F_SHMEM_ZC is set and addr + * encodes the buffer index + offset instead of a userspace buffer address. + */ +#define UBLK_F_SHMEM_ZC (1ULL << 19) + /* device state */ #define UBLK_S_DEV_DEAD 0 #define UBLK_S_DEV_LIVE 1 @@ -469,6 +516,12 @@ struct ublksrv_ctrl_dev_info { #define UBLK_IO_F_NEED_REG_BUF (1U << 17) /* Request has an integrity data buffer */ #define UBLK_IO_F_INTEGRITY (1UL << 18) +/* + * I/O buffer is in a registered shared memory buffer. When set, the addr + * field in ublksrv_io_desc encodes buffer index and byte offset instead + * of a userspace virtual address. + */ +#define UBLK_IO_F_SHMEM_ZC (1U << 19) /* * io cmd is described by this structure, and stored in share memory, indexed @@ -743,4 +796,31 @@ struct ublk_params { struct ublk_param_integrity integrity; }; +/* + * Shared memory zero-copy addr encoding for UBLK_IO_F_SHMEM_ZC. + * + * When UBLK_IO_F_SHMEM_ZC is set, ublksrv_io_desc.addr is encoded as: + * bits [0:31] = byte offset within the buffer (up to 4GB) + * bits [32:47] = buffer index (up to 65536) + * bits [48:63] = reserved (must be zero) + */ +#define UBLK_SHMEM_ZC_OFF_MASK 0xffffffffULL +#define UBLK_SHMEM_ZC_IDX_OFF 32 +#define UBLK_SHMEM_ZC_IDX_MASK 0xffffULL + +static __inline__ __u64 ublk_shmem_zc_addr(__u16 index, __u32 offset) +{ + return ((__u64)index << UBLK_SHMEM_ZC_IDX_OFF) | offset; +} + +static __inline__ __u16 ublk_shmem_zc_index(__u64 addr) +{ + return (addr >> UBLK_SHMEM_ZC_IDX_OFF) & UBLK_SHMEM_ZC_IDX_MASK; +} + +static __inline__ __u32 ublk_shmem_zc_offset(__u64 addr) +{ + return (__u32)(addr & UBLK_SHMEM_ZC_OFF_MASK); +} + #endif \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/udp.h b/lib/libc/include/any-linux-any/linux/udp.h index f101b125180675b639d0d25d540ca99ee19df8a6..c63c35eb84cfbff6ca7928000c3e8bff2a3addec 100644 --- a/lib/libc/include/any-linux-any/linux/udp.h +++ b/lib/libc/include/any-linux-any/linux/udp.h @@ -29,6 +29,8 @@ struct udphdr { /* UDP socket options */ #define UDP_CORK 1 /* Never send partially complete segments */ +/* Deprecated, reserved for UDPLITE_SEND_CSCOV 10 */ +/* Deprecated, reserved for UDPLITE_RECV_CSCOV 11 */ #define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */ #define UDP_NO_CHECK6_TX 101 /* Disable sending checksum for UDP6X */ #define UDP_NO_CHECK6_RX 102 /* Disable accepting checksum for UDP6 */ diff --git a/lib/libc/include/any-linux-any/linux/um_timetravel.h b/lib/libc/include/any-linux-any/linux/um_timetravel.h index f7e7a05844665250a965d9e7ad966e9c40e0b3f8..7d6119490ca5a7a191dd695be866ef47b6c99161 100644 --- a/lib/libc/include/any-linux-any/linux/um_timetravel.h +++ b/lib/libc/include/any-linux-any/linux/um_timetravel.h @@ -56,6 +56,9 @@ enum um_timetravel_shared_mem_fds { * in the control message */ UM_TIMETRAVEL_SHARED_LOGFD, + /** + * @UM_TIMETRAVEL_SHARED_MAX_FDS: number of fds listed here + */ UM_TIMETRAVEL_SHARED_MAX_FDS, }; @@ -242,6 +245,7 @@ union um_timetravel_schedshm_client { __u64 req_time; __u64 name; }; + /* private: */ char reserve[128]; /* reserved for future usage */ }; @@ -264,7 +268,7 @@ union um_timetravel_schedshm_client { * is made by any client. Clients also must update this value when they * insert/update an own request into the shared memory while not running * themselves, and the new request is before than the current value. - * current_time: Current time, can only be set by the client in running state + * @current_time: Current time, can only be set by the client in running state * (indicated by @running_id), though that client may only run until @free_until, * so it must remain smaller than @free_until. * @running_id: The current client in state running, set before a client is diff --git a/lib/libc/include/any-linux-any/linux/usb/ch9.h b/lib/libc/include/any-linux-any/linux/usb/ch9.h index bfd55b636e238097c146610fdfd4cff4f1ab9ec6..1554e43dd9622f49a10b3004e434bf8c7c31be18 100644 --- a/lib/libc/include/any-linux-any/linux/usb/ch9.h +++ b/lib/libc/include/any-linux-any/linux/usb/ch9.h @@ -102,6 +102,8 @@ #define USB_REQ_LOOPBACK_DATA_WRITE 0x15 #define USB_REQ_LOOPBACK_DATA_READ 0x16 #define USB_REQ_SET_INTERFACE_DS 0x17 +#define USB_REQ_AUTH_IN 0x18 +#define USB_REQ_AUTH_OUT 0x19 /* specific requests for USB Power Delivery */ #define USB_REQ_GET_PARTNER_PDO 20 @@ -121,15 +123,17 @@ * are at most sixteen features of each type.) Hubs may also support a * new USB_REQ_TEST_AND_SET_FEATURE to put ports into L1 suspend. */ -#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ -#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ -#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ -#define USB_DEVICE_BATTERY 2 /* (wireless) */ -#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ -#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ -#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ -#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ -#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ +#define USB_DEVICE_SELF_POWERED 0 /* (read only) */ +#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */ +#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */ +#define USB_DEVICE_BATTERY 2 /* (wireless) */ +#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */ +#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/ +#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */ +#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */ +#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */ + +#define USB_DEVICE_BULK_MAX_PACKET_UPDATE 8 /* (eUSB2v2) bump maxpacket to 1024 */ /* * Test Mode Selectors @@ -1147,6 +1151,17 @@ struct usb_ptm_cap_descriptor { /*-------------------------------------------------------------------------*/ +struct usb_authentication_capability_descriptor { + __u8 bLength; + __u8 bDescriptorType; /* set to USB_DT_DEVICE_CAPABILITY */ + __u8 bmAttributes; + + __u8 bcdProtocolVersion; + __u8 bcdCapability; +} __attribute__((packed)); + +/*-------------------------------------------------------------------------*/ + /* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with * each endpoint descriptor for a wireless device */ diff --git a/lib/libc/include/any-linux-any/linux/version.h b/lib/libc/include/any-linux-any/linux/version.h index 00d7d509bb5698f58c7847ae0a751cb2627381e2..94b0184204d7238ddd4a9e7ee445358fd4672097 100644 --- a/lib/libc/include/any-linux-any/linux/version.h +++ b/lib/libc/include/any-linux-any/linux/version.h @@ -1,5 +1,5 @@ -#define LINUX_VERSION_CODE 458752 +#define LINUX_VERSION_CODE 459008 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c))) #define LINUX_VERSION_MAJOR 7 -#define LINUX_VERSION_PATCHLEVEL 0 +#define LINUX_VERSION_PATCHLEVEL 1 #define LINUX_VERSION_SUBLEVEL 0 \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/linux/vfio.h b/lib/libc/include/any-linux-any/linux/vfio.h index 2e2dcfc6fbe30ef94fc77c16572c508c5ba267c5..6733e6f96bbc0a29ec2d42e550e9f13c4b9bf008 100644 --- a/lib/libc/include/any-linux-any/linux/vfio.h +++ b/lib/libc/include/any-linux-any/linux/vfio.h @@ -141,7 +141,7 @@ struct vfio_info_cap_header { * * Retrieve information about the group. Fills in provided * struct vfio_group_info. Caller sets argsz. - * Return: 0 on succes, -errno on failure. + * Return: 0 on success, -errno on failure. * Availability: Always */ struct vfio_group_status { @@ -1266,6 +1266,19 @@ enum vfio_device_mig_state { * The initial_bytes field indicates the amount of initial precopy * data available from the device. This field should have a non-zero initial * value and decrease as migration data is read from the device. + * The presence of the VFIO_PRECOPY_INFO_REINIT output flag indicates + * that new initial data is present on the stream. + * The new initial data may result, for example, from device reconfiguration + * during migration that requires additional initialization data. + * In that case initial_bytes may report a non-zero value irrespective of + * any previously reported values, which progresses towards zero as precopy + * data is read from the data stream. dirty_bytes is also reset + * to zero and represents the state change of the device relative to the new + * initial_bytes. + * VFIO_PRECOPY_INFO_REINIT can be reported only after userspace opts in to + * VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2. Without this opt-in, the flags field + * of struct vfio_precopy_info is reserved for bug-compatibility reasons. + * * It is recommended to leave PRE_COPY for STOP_COPY only after this field * reaches zero. Leaving PRE_COPY earlier might make things slower. * @@ -1301,6 +1314,7 @@ enum vfio_device_mig_state { struct vfio_precopy_info { __u32 argsz; __u32 flags; +#define VFIO_PRECOPY_INFO_REINIT (1 << 0) /* output - new initial data is present */ __aligned_u64 initial_bytes; __aligned_u64 dirty_bytes; }; @@ -1510,6 +1524,16 @@ struct vfio_device_feature_dma_buf { struct vfio_region_dma_range dma_ranges[] __counted_by(nr_ranges); }; +/* + * Enables the migration precopy_info_v2 behaviour. + * + * VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2. + * + * On SET, enables the v2 pre_copy_info behaviour, where the + * vfio_precopy_info.flags is a valid output field. + */ +#define VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2 12 + /* -------- API for Type1 VFIO IOMMU -------- */ /** diff --git a/lib/libc/include/any-linux-any/rdma/bnxt_re-abi.h b/lib/libc/include/any-linux-any/rdma/bnxt_re-abi.h index 8dda9fba76c4abef5e5667fb7301f1702bf05798..d04bff1136963c6be8f2b733c11a9697d3b81f0f 100644 --- a/lib/libc/include/any-linux-any/rdma/bnxt_re-abi.h +++ b/lib/libc/include/any-linux-any/rdma/bnxt_re-abi.h @@ -102,12 +102,17 @@ struct bnxt_re_pd_resp { struct bnxt_re_cq_req { __aligned_u64 cq_va; __aligned_u64 cq_handle; + __aligned_u64 comp_mask; }; -enum bnxt_re_cq_mask { +enum bnxt_re_resp_cq_mask { BNXT_RE_CQ_TOGGLE_PAGE_SUPPORT = 0x1, }; +enum bnxt_re_req_cq_mask { + BNXT_RE_CQ_FIXED_NUM_CQE_ENABLE = 0x1, +}; + struct bnxt_re_cq_resp { __u32 cqid; __u32 tail; @@ -163,6 +168,8 @@ enum bnxt_re_objects { BNXT_RE_OBJECT_ALLOC_PAGE = (1U << UVERBS_ID_NS_SHIFT), BNXT_RE_OBJECT_NOTIFY_DRV, BNXT_RE_OBJECT_GET_TOGGLE_MEM, + BNXT_RE_OBJECT_DBR, + BNXT_RE_OBJECT_DEFAULT_DBR, }; enum bnxt_re_alloc_page_type { @@ -231,4 +238,31 @@ struct bnxt_re_packet_pacing_caps { struct bnxt_re_query_device_ex_resp { struct bnxt_re_packet_pacing_caps packet_pacing_caps; }; + +struct bnxt_re_db_region { + __u32 dpi; + __u32 reserved; + __aligned_u64 umdbr; +}; + +enum bnxt_re_obj_dbr_alloc_attrs { + BNXT_RE_ALLOC_DBR_HANDLE = (1U << UVERBS_ID_NS_SHIFT), + BNXT_RE_ALLOC_DBR_ATTR, + BNXT_RE_ALLOC_DBR_OFFSET, +}; + +enum bnxt_re_obj_dbr_free_attrs { + BNXT_RE_FREE_DBR_HANDLE = (1U << UVERBS_ID_NS_SHIFT), +}; + +enum bnxt_re_obj_default_dbr_attrs { + BNXT_RE_DEFAULT_DBR_ATTR = (1U << UVERBS_ID_NS_SHIFT), +}; + +enum bnxt_re_obj_dpi_methods { + BNXT_RE_METHOD_DBR_ALLOC = (1U << UVERBS_ID_NS_SHIFT), + BNXT_RE_METHOD_DBR_FREE, + BNXT_RE_METHOD_GET_DEFAULT_DBR, +}; + #endif /* __BNXT_RE_UVERBS_ABI_H__*/ \ No newline at end of file diff --git a/lib/libc/include/any-linux-any/rdma/efa-abi.h b/lib/libc/include/any-linux-any/rdma/efa-abi.h index 35553184b7fed0735c2eda73954a206000406e92..6d2ab8a6efc1e002bc0cb78201011583a9babc71 100644 --- a/lib/libc/include/any-linux-any/rdma/efa-abi.h +++ b/lib/libc/include/any-linux-any/rdma/efa-abi.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */ /* - * Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved. */ #ifndef EFA_ABI_USER_H @@ -22,12 +22,12 @@ */ enum { - EFA_ALLOC_UCONTEXT_CMD_COMP_TX_BATCH = 1 << 0, - EFA_ALLOC_UCONTEXT_CMD_COMP_MIN_SQ_WR = 1 << 1, + EFA_ALLOC_UCONTEXT_CMD_SUPP_CAPS_TX_BATCH = 1 << 0, + EFA_ALLOC_UCONTEXT_CMD_SUPP_CAPS_MIN_SQ_WR = 1 << 1, }; struct efa_ibv_alloc_ucontext_cmd { - __u32 comp_mask; + __u32 supported_caps; __u8 reserved_20[4]; }; @@ -44,7 +44,8 @@ struct efa_ibv_alloc_ucontext_resp { __u32 max_llq_size; /* bytes */ __u16 max_tx_batch; /* units of 64 bytes */ __u16 min_sq_wr; - __u8 reserved_a0[4]; + __u16 inline_buf_size_ex; + __u8 reserved_b0[2]; }; struct efa_ibv_alloc_pd_resp { diff --git a/lib/libc/include/any-linux-any/rdma/ib_user_ioctl_verbs.h b/lib/libc/include/any-linux-any/rdma/ib_user_ioctl_verbs.h index 087df334051c1fd445ef1db9e4fc0f454d1f0158..8559ecbb749dee64f37301aa87e182a79961d2ac 100644 --- a/lib/libc/include/any-linux-any/rdma/ib_user_ioctl_verbs.h +++ b/lib/libc/include/any-linux-any/rdma/ib_user_ioctl_verbs.h @@ -46,6 +46,7 @@ enum ib_uverbs_core_support { IB_UVERBS_CORE_SUPPORT_OPTIONAL_MR_ACCESS = 1 << 0, + IB_UVERBS_CORE_SUPPORT_ROBUST_UDATA = 1 << 1, }; enum ib_uverbs_access_flags { diff --git a/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_cmds.h b/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_cmds.h index b6bf89d8e61e9985d4cd88ec3d04e34c13f11d04..fdd63256f66e4d09e23f910e36e25760953b94e6 100644 --- a/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_cmds.h +++ b/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_cmds.h @@ -139,6 +139,7 @@ enum mlx5_ib_var_alloc_attrs { MLX5_IB_ATTR_VAR_OBJ_ALLOC_MMAP_OFFSET, MLX5_IB_ATTR_VAR_OBJ_ALLOC_MMAP_LENGTH, MLX5_IB_ATTR_VAR_OBJ_ALLOC_PAGE_ID, + MLX5_IB_ATTR_VAR_OBJ_ALLOC_FLAGS, }; enum mlx5_ib_var_obj_destroy_attrs { diff --git a/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_verbs.h b/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_verbs.h index 9cdf7447e3109739d0749919f160f63787218e98..789d33f8e7e9bcffaea299bc18d0523f1d69c01b 100644 --- a/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_verbs.h +++ b/lib/libc/include/any-linux-any/rdma/mlx5_user_ioctl_verbs.h @@ -100,6 +100,10 @@ enum mlx5_ib_uapi_query_port_flags { MLX5_IB_UAPI_QUERY_PORT_ESW_OWNER_VHCA_ID = 1 << 5, }; +enum mlx5_ib_uapi_var_alloc_flags { + MLX5_IB_UAPI_VAR_ALLOC_FLAG_TLP = 1 << 0, +}; + struct mlx5_ib_uapi_reg { __u32 value; __u32 mask; diff --git a/lib/libc/include/any-linux-any/rdma/rdma_netlink.h b/lib/libc/include/any-linux-any/rdma/rdma_netlink.h index 869200781e8204039008ba985e761c8d1d9be9b5..0c5336f6c9b081b8832270d2ff6c2ecbfd3d639d 100644 --- a/lib/libc/include/any-linux-any/rdma/rdma_netlink.h +++ b/lib/libc/include/any-linux-any/rdma/rdma_netlink.h @@ -308,6 +308,10 @@ enum rdma_nldev_command { RDMA_NLDEV_CMD_MONITOR, + RDMA_NLDEV_CMD_FRMR_POOLS_GET, /* can dump */ + + RDMA_NLDEV_CMD_FRMR_POOLS_SET, + RDMA_NLDEV_NUM_OPS }; @@ -582,6 +586,24 @@ enum rdma_nldev_attr { RDMA_NLDEV_SYS_ATTR_MONITOR_MODE, /* u8 */ RDMA_NLDEV_ATTR_STAT_OPCOUNTER_ENABLED, /* u8 */ + + /* + * FRMR Pools attributes + */ + RDMA_NLDEV_ATTR_FRMR_POOLS, /* nested table */ + RDMA_NLDEV_ATTR_FRMR_POOL_ENTRY, /* nested table */ + RDMA_NLDEV_ATTR_FRMR_POOL_KEY, /* nested table */ + RDMA_NLDEV_ATTR_FRMR_POOL_KEY_ATS, /* u8 */ + RDMA_NLDEV_ATTR_FRMR_POOL_KEY_ACCESS_FLAGS, /* u32 */ + RDMA_NLDEV_ATTR_FRMR_POOL_KEY_VENDOR_KEY, /* u64 */ + RDMA_NLDEV_ATTR_FRMR_POOL_KEY_NUM_DMA_BLOCKS, /* u64 */ + RDMA_NLDEV_ATTR_FRMR_POOL_QUEUE_HANDLES, /* u32 */ + RDMA_NLDEV_ATTR_FRMR_POOL_MAX_IN_USE, /* u64 */ + RDMA_NLDEV_ATTR_FRMR_POOL_IN_USE, /* u64 */ + RDMA_NLDEV_ATTR_FRMR_POOLS_AGING_PERIOD, /* u32 */ + RDMA_NLDEV_ATTR_FRMR_POOL_PINNED_HANDLES, /* u32 */ + RDMA_NLDEV_ATTR_FRMR_POOL_KEY_KERNEL_VENDOR_KEY, /* u64 */ + /* * Always the end */ diff --git a/lib/libc/include/any-linux-any/scsi/fc/fc_els.h b/lib/libc/include/any-linux-any/scsi/fc/fc_els.h index 5220bc05d555ca0a732033006cb7645aa564f41b..68d3472d896d88f196001f83a3d2a3c7da3c2ed4 100644 --- a/lib/libc/include/any-linux-any/scsi/fc/fc_els.h +++ b/lib/libc/include/any-linux-any/scsi/fc/fc_els.h @@ -1026,7 +1026,7 @@ struct fc_fn_li_desc { */ __be32 event_count; /* minimum number of event * occurrences during the event - * threshold to caause the LI event + * threshold to cause the LI event */ __be32 pname_count; /* number of portname_list elements */ __be64 pname_list[]; /* list of N_Port_Names accessible diff --git a/lib/libc/include/hexagon-linux-any/asm/sigcontext.h b/lib/libc/include/hexagon-linux-any/asm/sigcontext.h index 7064daf5a5bc7916d2325a1cf1e201c0e37e7850..ff1dd437caf8098d68c557c315c2bc1048d73174 100644 --- a/lib/libc/include/hexagon-linux-any/asm/sigcontext.h +++ b/lib/libc/include/hexagon-linux-any/asm/sigcontext.h @@ -29,6 +29,6 @@ */ struct sigcontext { struct user_regs_struct sc_regs; -} __aligned(8); +} __attribute__((aligned(8))); #endif \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-any/asm/hwcap.h b/lib/libc/include/loongarch-linux-any/asm/hwcap.h index 9201ebbf041c18921f5a657385cab7594001b5fc..3f1a3d5b9784ce183b6977c5422f5c4cdd68b8ab 100644 --- a/lib/libc/include/loongarch-linux-any/asm/hwcap.h +++ b/lib/libc/include/loongarch-linux-any/asm/hwcap.h @@ -19,5 +19,6 @@ #define HWCAP_LOONGARCH_PTW (1 << 13) #define HWCAP_LOONGARCH_LSPW (1 << 14) #define HWCAP_LOONGARCH_SCQ (1 << 15) +#define HWCAP_LOONGARCH_LAM_BH (1 << 16) #endif /* _ASM_HWCAP_H */ \ No newline at end of file diff --git a/lib/libc/include/loongarch-linux-any/asm/kvm.h b/lib/libc/include/loongarch-linux-any/asm/kvm.h index 069fc9f13f26a6222cbc8ca440468efa6ea9c764..91d26cfcb481e0aad31cc7f1fb36e4853bb10811 100644 --- a/lib/libc/include/loongarch-linux-any/asm/kvm.h +++ b/lib/libc/include/loongarch-linux-any/asm/kvm.h @@ -155,4 +155,8 @@ struct kvm_iocsr_entry { #define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000006 #define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 +#define KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL 0x40000007 +#define KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_BASE 0x0 +#define KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_SIZE 0x1 + #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ \ No newline at end of file diff --git a/lib/libc/include/m68k-linux-any/asm/ucontext.h b/lib/libc/include/m68k-linux-any/asm/ucontext.h new file mode 100644 index 0000000000000000000000000000000000000000..ce57d5cfd90482e8e6e901d7cee792581bca4c08 --- /dev/null +++ b/lib/libc/include/m68k-linux-any/asm/ucontext.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _M68K_UCONTEXT_H +#define _M68K_UCONTEXT_H + +#include +#include + +typedef int greg_t; +#define NGREG 18 +typedef greg_t gregset_t[NGREG]; + +typedef struct fpregset { + int f_fpcntl[3]; + int f_fpregs[8*3]; +} fpregset_t; + +struct mcontext { + int version; + gregset_t gregs; + fpregset_t fpregs; +}; + +#define MCONTEXT_VERSION 2 + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct mcontext uc_mcontext; + unsigned long uc_filler[80]; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif \ No newline at end of file diff --git a/lib/libc/include/riscv-linux-any/asm/kvm.h b/lib/libc/include/riscv-linux-any/asm/kvm.h index 99f9a958941b5acbd836def26f95f2c86eca186a..293195b123236ebf4b01987a0172bc3f0732bf37 100644 --- a/lib/libc/include/riscv-linux-any/asm/kvm.h +++ b/lib/libc/include/riscv-linux-any/asm/kvm.h @@ -110,6 +110,10 @@ struct kvm_riscv_timer { __u64 state; }; +/* Possible states for kvm_riscv_timer */ +#define KVM_RISCV_TIMER_STATE_OFF 0 +#define KVM_RISCV_TIMER_STATE_ON 1 + /* * ISA extension IDs specific to KVM. This is not the same as the host ISA * extension IDs as that is internal to the host and should not be exposed @@ -238,10 +242,6 @@ struct kvm_riscv_sbi_fwft { struct kvm_riscv_sbi_fwft_feature pointer_masking; }; -/* Possible states for kvm_riscv_timer */ -#define KVM_RISCV_TIMER_STATE_OFF 0 -#define KVM_RISCV_TIMER_STATE_ON 1 - /* If you need to interpret the index values, here is the key: */ #define KVM_REG_RISCV_TYPE_MASK 0x00000000FF000000 #define KVM_REG_RISCV_TYPE_SHIFT 24 diff --git a/lib/libc/include/riscv-linux-any/asm/setup.h b/lib/libc/include/riscv-linux-any/asm/setup.h index 1094751b59fb571a1c24db0f162af1abd15a65d2..9f043d39ecbe9ef57204eaaaf2868e6d5870348c 100644 --- a/lib/libc/include/riscv-linux-any/asm/setup.h +++ b/lib/libc/include/riscv-linux-any/asm/setup.h @@ -3,6 +3,6 @@ #ifndef _ASM_RISCV_SETUP_H #define _ASM_RISCV_SETUP_H -#define COMMAND_LINE_SIZE 1024 +#define COMMAND_LINE_SIZE 2048 #endif /* _ASM_RISCV_SETUP_H */ \ No newline at end of file diff --git a/lib/libc/mingw/math/lroundl.c b/lib/libc/mingw/math/lroundl.c deleted file mode 100644 index b4584a896d3e0190c88049a9bebfeb26c48916ed..0000000000000000000000000000000000000000 --- a/lib/libc/mingw/math/lroundl.c +++ /dev/null @@ -1,37 +0,0 @@ -/** - * This file has no copyright assigned and is placed in the Public Domain. - * This file is part of the mingw-w64 runtime package. - * No warranty is given; refer to the file DISCLAIMER.PD within this package. - */ -#include -#include -#include - -long -lroundl (long double x) -{ - long double res; - - if (x >= 0.0L) - { - res = ceill (x); - if (res - x > 0.5L) - res -= 1.0; - } - else - { - res = ceill (-x); - if (res + x > 0.5L) - res -= 1.0L; - res = -res; - } - if (!isfinite (res) - || res > (long double)LONG_MAX - || res < (long double)LONG_MIN) - { - errno = ERANGE; - /* Undefined behaviour, so we could return anything. */ - /* return res > 0.0L ? LONG_MAX : LONG_MIN; */ - } - return (long) res; -} diff --git a/lib/libc/musl/src/internal/floatscan.c b/lib/libc/musl/src/internal/floatscan.c index 8c0828fcb39e6e0e742309913eef1aa955e582e5..b15366b685e9757d56b3c41d5caf7a69c4682d35 100644 --- a/lib/libc/musl/src/internal/floatscan.c +++ b/lib/libc/musl/src/internal/floatscan.c @@ -347,7 +347,7 @@ static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok) else d = c-'0'; if (dc<8) { x = x*16 + d; - } else if (dc < LDBL_MANT_DIG/4+1) { + } else if (dc < (LDBL_MANT_DIG+3)/4+1) { y += d*(scale/=16); } else if (d && !gottail) { y += 0.5*scale; diff --git a/lib/libc/musl/src/math/aarch64/lround.c b/lib/libc/musl/src/math/aarch64/lround.c deleted file mode 100644 index 85656c78d1c334a1618b2fa606670ae8e1038c5b..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/aarch64/lround.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -long lround(double x) -{ - long n; - __asm__ ("fcvtas %x0, %d1" : "=r"(n) : "w"(x)); - return n; -} diff --git a/lib/libc/musl/src/math/aarch64/lroundf.c b/lib/libc/musl/src/math/aarch64/lroundf.c deleted file mode 100644 index 32e51f3cc3c738214bde60d0873532415cdd4acc..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/aarch64/lroundf.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -long lroundf(float x) -{ - long n; - __asm__ ("fcvtas %x0, %s1" : "=r"(n) : "w"(x)); - return n; -} diff --git a/lib/libc/musl/src/math/lround.c b/lib/libc/musl/src/math/lround.c deleted file mode 100644 index b8b795470f1868d831e7c2893c7f3b7f019ddbdb..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/lround.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -long lround(double x) -{ - return round(x); -} diff --git a/lib/libc/musl/src/math/lroundf.c b/lib/libc/musl/src/math/lroundf.c deleted file mode 100644 index c4707e7db712cd545915efea603173e21efc709e..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/lroundf.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -long lroundf(float x) -{ - return roundf(x); -} diff --git a/lib/libc/musl/src/math/lroundl.c b/lib/libc/musl/src/math/lroundl.c deleted file mode 100644 index 094fdf6483842e90a9fac200394255d02bb8073d..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/lroundl.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -long lroundl(long double x) -{ - return roundl(x); -} diff --git a/lib/libc/musl/src/math/powerpc64/lround.c b/lib/libc/musl/src/math/powerpc64/lround.c deleted file mode 100644 index ee4d1143c33de9b15f09ba3d79b5704a4187d1a4..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/powerpc64/lround.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#ifdef __VSX__ - -long lround(double x) -{ - long n; - __asm__ ( - "xsrdpi %1, %1\n" - "fctid %0, %1\n" : "=d"(n), "+d"(x)); - return n; -} - -#else - -#include "../lround.c" - -#endif diff --git a/lib/libc/musl/src/math/powerpc64/lroundf.c b/lib/libc/musl/src/math/powerpc64/lroundf.c deleted file mode 100644 index 033094ffb2ccd645253b1a2b7338862af7455e54..0000000000000000000000000000000000000000 --- a/lib/libc/musl/src/math/powerpc64/lroundf.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -#ifdef __VSX__ - -long lroundf(float x) -{ - long n; - __asm__ ( - "xsrdpi %1, %1\n" - "fctid %0, %1\n" : "=d"(n), "+f"(x)); - return n; -} - -#else - -#include "../lroundf.c" - -#endif diff --git a/lib/libc/musl/src/thread/x32/clone.s b/lib/libc/musl/src/thread/x32/clone.s index d713452676333d3e34ef9f004fcec4eebf2bcd6d..31e2ccabe61d5b9443cc08b9606ae26ca664bc5c 100644 --- a/lib/libc/musl/src/thread/x32/clone.s +++ b/lib/libc/musl/src/thread/x32/clone.s @@ -8,7 +8,7 @@ __clone: mov %rdx,%rdi mov %r8,%rdx mov %r9,%r8 - mov 8(%rsp),%r10 + mov 8(%rsp),%r10d mov %r11,%r9 and $-16,%rsi sub $8,%rsi diff --git a/lib/libc/wasi/libc-top-half/musl/src/internal/floatscan.c b/lib/libc/wasi/libc-top-half/musl/src/internal/floatscan.c index ec50fe0765046a04a8757bb7114f8ed530a6ed09..4cc6059f438e4368da315a13f12988f0ea1ec3f2 100644 --- a/lib/libc/wasi/libc-top-half/musl/src/internal/floatscan.c +++ b/lib/libc/wasi/libc-top-half/musl/src/internal/floatscan.c @@ -388,7 +388,7 @@ static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok) else d = c-'0'; if (dc<8) { x = x*16 + d; - } else if (dc < LDBL_MANT_DIG/4+1) { + } else if (dc < (LDBL_MANT_DIG+3)/4+1) { y += d*(scale/=16); } else if (d && !gottail) { y += 0.5*scale; diff --git a/lib/libcxx/include/__config b/lib/libcxx/include/__config index de32af8f760e0f88f74b7ffa7554be2b7a9ae7f9..cc7a377334a83cbb34b8a997151b7e76b3810a9c 100644 --- a/lib/libcxx/include/__config +++ b/lib/libcxx/include/__config @@ -30,7 +30,7 @@ // _LIBCPP_VERSION represents the version of libc++, which matches the version of LLVM. // Given a LLVM release LLVM XX.YY.ZZ (e.g. LLVM 17.0.1 == 17.00.01), _LIBCPP_VERSION is // defined to XXYYZZ. -# define _LIBCPP_VERSION 220104 +# define _LIBCPP_VERSION 220108 # define _LIBCPP_CONCAT_IMPL(_X, _Y) _X##_Y # define _LIBCPP_CONCAT(_X, _Y) _LIBCPP_CONCAT_IMPL(_X, _Y) diff --git a/lib/libcxx/include/__tree b/lib/libcxx/include/__tree index eb17f7d36936c819a89586da357c4957b57cb317..ddeb82f91b8ad587c15fa7d2af8b3bd3784379f8 100644 --- a/lib/libcxx/include/__tree +++ b/lib/libcxx/include/__tree @@ -2026,8 +2026,8 @@ __tree<_Tp, _Compare, _Allocator>::__node_handle_insert_unique(const_iterator __ template template _LIBCPP_HIDE_FROM_ABI _NodeHandle __tree<_Tp, _Compare, _Allocator>::__node_handle_extract(key_type const& __key) { - iterator __it = find(__key); - if (__it == end()) + iterator __it = __lower_bound_multi(__key); + if (__it == end() || __value_comp_(__key, *__it)) return _NodeHandle(); return __node_handle_extract<_NodeHandle>(__it); } diff --git a/lib/libcxx/include/optional b/lib/libcxx/include/optional index 12fbcdfa5c5d605ca01f0dedc64a0fc931b75176..4d85ac1e0ff5e800f9adf1e6aa8059b015e55713 100644 --- a/lib/libcxx/include/optional +++ b/lib/libcxx/include/optional @@ -828,6 +828,10 @@ private: template constexpr static bool __libcpp_opt_ref_ctor_deleted = is_lvalue_reference_v<_Tp> && reference_constructs_from_temporary_v<_Tp, _Up>; + + template + constexpr static bool __ref_ctor_enabled = + is_lvalue_reference_v<_Tp> && !reference_constructs_from_temporary_v<_Tp, _Up>; # endif // LWG2756: conditionally explicit conversion from _Up @@ -935,7 +939,7 @@ public: template ::template __enable_implicit<_Up>(), int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) # if _LIBCPP_STD_VER >= 26 - noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, const _Up&>) # endif { this->__construct_from(__v); @@ -943,7 +947,7 @@ public: template ::template __enable_explicit<_Up>(), int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) # if _LIBCPP_STD_VER >= 26 - noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>) + noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, const _Up&>) # endif { this->__construct_from(__v); @@ -981,25 +985,25 @@ public: // optional(optional& rhs) template - requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> + requires __ref_ctor_enabled<_Up&> && (!is_same_v, optional<_Up>>) && (!is_same_v<_Tp&, _Up>) && + is_constructible_v<_Tp&, _Up&> _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up&, _Tp&>) optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) { this->__construct_from(__rhs); } template - requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v, optional<_Up>>) && + requires __libcpp_opt_ref_ctor_deleted<_Up&> && (!is_same_v, optional<_Up>>) && (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&> constexpr explicit optional(optional<_Up>& __rhs) noexcept = delete; // optional(const optional&) template ::template __enable_implicit<_Up>(), int> = 0> - requires __libcpp_opt_ref_ctor_deleted<_Up> + requires __libcpp_opt_ref_ctor_deleted optional(const optional<_Up>&) = delete; template ::template __enable_explicit<_Up>(), int> = 0> - requires __libcpp_opt_ref_ctor_deleted<_Up> + requires __libcpp_opt_ref_ctor_deleted explicit optional(const optional<_Up>&) = delete; // optional(optional&&) @@ -1013,16 +1017,16 @@ public: // optional(const optional&&) template - requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + requires __ref_ctor_enabled && (!is_same_v, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, const _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v) optional(const optional<_Up>&& __v) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) { this->__construct_from(std::move(__v)); } template - requires __libcpp_opt_ref_ctor_deleted<_Up> && (!is_same_v, optional<_Up>>) && - (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up> + requires __libcpp_opt_ref_ctor_deleted && (!is_same_v, optional<_Up>>) && + (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, const _Up> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>&& __v) noexcept = delete; # endif diff --git a/lib/lldb/pretty_printers.py b/lib/lldb/pretty_printers.py index 553c7672fb278e0b2b1e43f4565f02c4181ac049..222484e5b4ab55fe45e8ab03ddb85f894850bb51 100644 --- a/lib/lldb/pretty_printers.py +++ b/lib/lldb/pretty_printers.py @@ -707,7 +707,7 @@ def root_InternPool_Index_SummaryProvider(value, _=None): return re.sub( expr_path_re, lambda matchobj: getattr(unwrapped.GetValueForExpressionPath(matchobj[1]), matchobj[2]).strip(matchobj[3] or ''), - summary.summary.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"'), + summary.value.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"'), ) class root_InternPool_Index_SynthProvider: @@ -773,7 +773,7 @@ class root_InternPool_Index_Unwrapped_SynthProvider: trailing_type = encoding_trailing.GetValueAsType() trailing_bytes, trailing_data = bytearray(trailing_type.size), lldb.SBData() def eval_config(config_name): - expr = encoding_config.GetChildMemberWithName(config_name).summary.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"') + expr = encoding_config.GetChildMemberWithName(config_name).value.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"') if 'payload.' in expr: return self.payload.EvaluateExpression(expr.replace('payload.', '@this().')) elif expr.startswith('trailing.'): @@ -848,7 +848,8 @@ def root_InternPool_String_SummaryProvider(value, _=None): if local_value is None: wrapped = 0 local_value = locals_value.child[0] - string = local_value.GetChildMemberWithName('shared').GetChildMemberWithName('strings').GetChildMemberWithName('view').GetChildMemberWithName('0').child[wrapped & (1 << tid_shift_32) - 1].address_of + shared = local_value.GetChildMemberWithName('shared') + string = shared.GetChildMemberWithName('string_bytes').GetChildMemberWithName('view').GetChildMemberWithName('0').child[shared.GetChildMemberWithName('strings').GetChildMemberWithName('view').GetChildMemberWithName('0').child[wrapped & (1 << tid_shift_32) - 1].unsigned].address_of string.format = lldb.eFormatCString return string.value @@ -878,13 +879,13 @@ class root_InternPool_Nav_Index_SynthProvider: wrapped = self.value.unsigned if wrapped == (1 << 32) - 1: return ip = self.value.CreateValueFromType(self.value.type).GetChildMemberWithName('debug_state').GetChildMemberWithName('intern_pool').GetNonSyntheticValue().GetChildMemberWithName('?') - tid_shift_32 = ip.GetChildMemberWithName('tid_shift_32').unsigned + tid_shift_30 = ip.GetChildMemberWithName('tid_shift_30').unsigned locals_value = ip.GetChildMemberWithName('locals').GetSyntheticValue() - local_value = locals_value.child[wrapped >> tid_shift_32] + local_value = locals_value.child[wrapped >> tid_shift_30] if local_value is None: wrapped = 0 local_value = locals_value.child[0] - self.nav = local_value.GetChildMemberWithName('shared').GetChildMemberWithName('navs').GetChildMemberWithName('view').child[wrapped & (1 << tid_shift_32) - 1] + self.nav = local_value.GetChildMemberWithName('shared').GetChildMemberWithName('navs').GetChildMemberWithName('view').child[wrapped & (1 << tid_shift_30) - 1] def has_children(self): return False if self.nav is None else self.nav.GetNumChildren(1) > 0 def num_children(self): return 0 if self.nav is None else self.nav.GetNumChildren() def get_child_index(self, name): return -1 if self.nav is None else self.nav.GetIndexOfChildWithName(name) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index c5bf7d889dbae2ab9a7a8a4d00c2ec1ce74b09ec..a3bf69604e4ec7e68847e6caced7ed91fbbcf269 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -33,7 +33,7 @@ user_input_options: UserInputOptionsMap, available_options_map: std.array_hash_map.String(AvailableOption) = .empty, invalid_user_input: bool, default_step: *Step, -top_level_steps: std.StringArrayHashMapUnmanaged(*Step.TopLevel), +top_level_steps: std.array_hash_map.String(*Step.TopLevel), /// Path to the directory containing build.zig. root: Cache.Path, debug_log_scopes: []const []const u8 = &.{}, @@ -78,11 +78,11 @@ pub const Graph = struct { io: Io, /// Process lifetime. arena: Allocator, - system_integration_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .empty, + system_integration_options: std.array_hash_map.String(SystemLibraryMode) = .empty, system_package_mode: bool = false, zig_exe: []const u8, environ_map: process.Environ.Map, - needed_lazy_dependencies: std.StringArrayHashMapUnmanaged(void) = .empty, + needed_lazy_dependencies: std.array_hash_map.String(void) = .empty, /// Information about the native target. Computed before build() is invoked. host: ResolvedTarget, dependency_cache: InitializedDepMap = .empty, @@ -898,17 +898,7 @@ pub fn addRunArtifact(b: *Build, exe: *Step.Compile) *Step.Run { const run_step = Step.Run.create(b, step_name); run_step.producer = exe; if (exe.kind == .@"test") { - if (exe.exec_cmd_args) |exec_cmd_args| { - for (exec_cmd_args) |cmd_arg| { - if (cmd_arg) |arg| { - run_step.addArg(arg); - } else { - run_step.addArtifactArg(exe); - } - } - } else { - run_step.addArtifactArg(exe); - } + run_step.addArtifactArg(exe); const test_server_mode: bool = s: { if (exe.test_runner) |r| break :s r.mode == .server; @@ -1836,10 +1826,14 @@ fn tryFindProgram(b: *Build, full_path: []const u8) ?[]const u8 { if (b.graph.environ_map.get("PATHEXT")) |PATHEXT| { var it = mem.tokenizeScalar(u8, PATHEXT, fs.path.delimiter); + const extended_path_buf = arena.alloc(u8, full_path.len + 1 + std.process.WindowsExtension.max_len) catch @panic("OOM"); + @memcpy(extended_path_buf[0..full_path.len], full_path); + while (it.next()) |ext| { if (!supportedWindowsProgramExtension(ext)) continue; - const extended_path = try mem.concat(arena, &.{ full_path, ext }); + @memcpy(extended_path_buf[full_path.len..][0..ext.len], ext); + const extended_path = extended_path_buf[0 .. full_path.len + ext.len]; if (Io.Dir.cwd().access(io, extended_path, .{ .execute = true })) |_| { return extended_path; @@ -2563,6 +2557,16 @@ pub const LazyPath = union(enum) { return dupeInner(lazy_path, graph.arena); } + /// Copies the slice of paths and all internal strings. + /// + /// The `graph` parameter is only used for the global arena allocator. + pub fn dupeList(lazy_paths: []const LazyPath, graph: *const Graph) []const LazyPath { + const arena = graph.arena; + const result = graph.alloc(LazyPath, lazy_paths.len); + for (result, lazy_paths) |*d, s| d.* = dupeInner(s, arena); + return result; + } + 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) } }, @@ -2707,4 +2711,6 @@ pub fn systemIntegrationOption( test { _ = Cache; _ = Step; + _ = Configuration; + _ = &findProgram; } diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index fe40251590f090d567744bcddd3451f62e52eac7..33c3148dd22080b5916100f4c3e210dabe38e14d 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -351,7 +351,7 @@ pub const Manifest = struct { }; }; - pub const Files = std.ArrayHashMapUnmanaged(File, void, FilesContext, false); + pub const Files = std.array_hash_map.Custom(File, void, FilesContext, false); pub const FilesContext = struct { pub fn hash(fc: FilesContext, file: File) u32 { diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index d01ad0c89785c79c3d42d185cf371dd0bd7ec38f..12746e4498f76b745898559660dfb03c4722c233 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -1,10 +1,12 @@ const Configuration = @This(); const std = @import("../std.zig"); +const builtin = @import("builtin"); const Io = std.Io; const Allocator = std.mem.Allocator; const assert = std.debug.assert; const max_u32 = std.math.maxInt(u32); +const native_endian = builtin.target.cpu.arch.endian(); string_bytes: []u8, steps: []Step, @@ -569,6 +571,8 @@ 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), captured_stdout: Storage.FlagOptional(.flags, .captured_stdout, CapturedStream), captured_stderr: Storage.FlagOptional(.flags, .captured_stderr, CapturedStream), file_inputs: Storage.LengthPrefixedList(LazyPath.Index), @@ -583,6 +587,8 @@ pub const Step = extern struct { expect_stderr_match: Storage.FlagLengthPrefixedList(.flags2, .expect_stderr_match, Bytes), expect_stdout_match: Storage.FlagLengthPrefixedList(.flags2, .expect_stdout_match, Bytes), expect_term_value: Storage.FlagOptional(.flags2, .expect_term, u32), + expect_stdout_snapshot: Storage.FlagOptional(.flags2, .expect_stdout_snapshot, LazyPath.Index), + expect_stderr_snapshot: Storage.FlagOptional(.flags2, .expect_stderr_snapshot, LazyPath.Index), pub const CapturedStream = extern struct { generated_file: GeneratedFileIndex, @@ -608,7 +614,8 @@ pub const Step = extern struct { producer: bool, generated: bool, dep_file: bool, - _: u21 = 0, + make_absolute: bool, + _: u20 = 0, }; pub const Tag = enum(u4) { @@ -681,7 +688,9 @@ pub const Step = extern struct { expect_stdout_match: bool, expect_term: bool, expect_term_status: ExpectTermStatus, - _: u25 = 0, + expect_stdout_snapshot: bool, + expect_stderr_snapshot: bool, + _: u23 = 0, }; }; @@ -695,7 +704,6 @@ pub const Step = extern struct { root_name: String, filters: Storage.FlagLengthPrefixedList(.flags, .filters_len, String), - exec_cmd_args: Storage.FlagLengthPrefixedList(.flags, .exec_cmd_args_len, OptionalString), installed_headers: Storage.FlagLengthPrefixedList(.flags, .installed_headers_len, Storage.Extended(InstalledHeader.Flags, InstalledHeader)), force_undefined_symbols: Storage.FlagLengthPrefixedList(.flags, .force_undefined_symbols_len, String), expect_errors: Storage.FlagUnion(.flags4, .expect_errors, ExpectErrors), @@ -924,7 +932,6 @@ pub const Step = extern struct { tag: Tag = .compile, filters_len: bool, - exec_cmd_args_len: bool, installed_headers_len: bool, force_undefined_symbols_len: bool, @@ -951,6 +958,7 @@ pub const Step = extern struct { force_load_objc: bool, discard_local_symbols: bool, mingw_unicode_entry_point: bool, + _: u1 = 0, }; pub const Flags2 = packed struct(u32) { @@ -1016,7 +1024,8 @@ pub const Step = extern struct { generated_llvm_bc: bool, generated_llvm_ir: bool, generated_h: bool, - _: u9 = 0, + incremental: DefaultingBool, + _: u7 = 0, }; pub fn isDynamicLibrary(compile: *const Compile) bool { @@ -2268,6 +2277,8 @@ pub const TargetQuery = struct { gnux32, eabi, eabihf, + abin32, + x32, ilp32, android, androideabi, @@ -2301,6 +2312,8 @@ pub const TargetQuery = struct { .gnux32 => .gnux32, .eabi => .eabi, .eabihf => .eabihf, + .abin32 => .abin32, + .x32 => .x32, .ilp32 => .ilp32, .android => .android, .androideabi => .androideabi, @@ -2334,6 +2347,8 @@ pub const TargetQuery = struct { .gnux32 => .gnux32, .eabi => .eabi, .eabihf => .eabihf, + .abin32 => .abin32, + .x32 => .x32, .ilp32 => .ilp32, .android => .android, .androideabi => .androideabi, @@ -2581,6 +2596,8 @@ pub const TargetQuery = struct { windows, uefi, @"3ds", + wiiu, + psx, ps3, ps4, ps5, @@ -2629,6 +2646,8 @@ pub const TargetQuery = struct { .windows => .windows, .uefi => .uefi, .@"3ds" => .@"3ds", + .wiiu => .wiiu, + .psx => .psx, .ps3 => .ps3, .ps4 => .ps4, .ps5 => .ps5, @@ -2677,6 +2696,8 @@ pub const TargetQuery = struct { .windows => .windows, .uefi => .uefi, .@"3ds" => .@"3ds", + .wiiu => .wiiu, + .psx => .psx, .ps3 => .ps3, .ps4 => .ps4, .ps5 => .ps5, @@ -3199,7 +3220,8 @@ pub const Storage = enum { .@"extern" => { const n = @divExact(@sizeOf(Field), @sizeOf(u32)); defer i.* += n; - return @bitCast(buffer[i.*..][0..n].*); + const ptr: *align(@alignOf(u32)) const Field = @ptrCast(buffer[i.*..][0..n]); + return ptr.*; }, }, else => comptime unreachable, @@ -3365,7 +3387,8 @@ pub const Storage = enum { }, .@"extern" => { const n = @divExact(@sizeOf(Field), @sizeOf(u32)); - buffer[i..][0..n].* = @bitCast(value); + const ptr: *align(@alignOf(Field)) const [n]u32 = @ptrCast(&value); + buffer[i..][0..n].* = ptr.*; return n; }, }, @@ -3433,18 +3456,46 @@ pub fn load(arena: Allocator, reader: *Io.Reader) LoadError!Configuration { return result; } +/// Loads bits using native endianness when `value` spans multiple bytes. +/// On big endian architectures, `bit_offset` uses MSb 0 bit numbering. +/// On little endian architectures, `bit_offset` uses LSb 0 bit numbering. +/// See `storeBits`. pub fn loadBits(comptime Int: type, buffer: []const Int, bit_offset: usize, comptime Result: type) Result { const index = bit_offset / @bitSizeOf(Int); const small_bit_offset = bit_offset % @bitSizeOf(Int); const ResultInt = @Int(.unsigned, @bitSizeOf(Result)); - const result: ResultInt = @truncate(buffer[index] >> @intCast(small_bit_offset)); - const available_bits = @bitSizeOf(Int) - small_bit_offset; - if (available_bits >= @bitSizeOf(ResultInt)) return @bitCast(result); - const missing_bits = @bitSizeOf(ResultInt) - available_bits; - const upper: ResultInt = @truncate(buffer[index + 1] & ((@as(usize, 1) << @intCast(missing_bits)) - 1)); - return @bitCast(result | (upper << @intCast(available_bits))); + switch (native_endian) { + .little => { + const result: ResultInt = @truncate(buffer[index] >> @intCast(small_bit_offset)); + const available_bits = @bitSizeOf(Int) - small_bit_offset; + if (available_bits >= @bitSizeOf(ResultInt)) return @bitCast(result); + const missing_bits = @bitSizeOf(ResultInt) - available_bits; + const upper: ResultInt = @truncate(buffer[index + 1] & ((@as(usize, 1) << @intCast(missing_bits)) - 1)); + return @bitCast(result | (upper << @intCast(available_bits))); + }, + .big => { + const available_bits = @bitSizeOf(Int) - small_bit_offset; + if (available_bits >= @bitSizeOf(ResultInt)) { + const shift = available_bits - @bitSizeOf(ResultInt); + const result: ResultInt = @truncate(buffer[index] >> @intCast(shift)); + return @bitCast(result); + } + const mask = (@as(Int, 1) << @intCast(available_bits)) - 1; + const result: ResultInt = @intCast(buffer[index] & mask); + const missing_bits = @bitSizeOf(ResultInt) - available_bits; + const lower: ResultInt = @truncate(buffer[index + 1] >> @intCast(@bitSizeOf(Int) - missing_bits)); + return @bitCast((result << @intCast(missing_bits)) | lower); + }, + } } +/// Store bits using native endianness when `value` spans multiple bytes. +/// On big endian architectures: +/// - For a given value, the bits of an earlier byte are more significant than the bits of subsequent bytes. +/// - `bit_offset` uses MSb 0 bit numbering. +/// On little endian architectures: +/// - For a given value, the bits of an earlier byte are less significant than the bits of subsequent bytes. +/// - `bit_offset` uses LSb 0 bit numbering. pub fn storeBits(comptime Int: type, buffer: []Int, bit_offset: usize, value: anytype) void { const Value = @TypeOf(value); const ValueInt = @Int(.unsigned, @bitSizeOf(Value)); @@ -3453,27 +3504,70 @@ pub fn storeBits(comptime Int: type, buffer: []Int, bit_offset: usize, value: an const small_bit_offset = bit_offset % @bitSizeOf(Int); const available_bits = @bitSizeOf(Int) - small_bit_offset; if (available_bits >= @bitSizeOf(ValueInt)) { - buffer[index] &= ~(((@as(Int, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset)); - buffer[index] |= @as(Int, value_int) << @intCast(small_bit_offset); + const shift = switch (native_endian) { + .little => small_bit_offset, + .big => available_bits - @bitSizeOf(ValueInt), + }; + buffer[index] &= ~(((@as(Int, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(shift)); + buffer[index] |= @as(Int, value_int) << @intCast(shift); } else { const DoubleInt = @Int(.unsigned, @bitSizeOf(Int) * 2); + const shift = switch (native_endian) { + .little => small_bit_offset, + .big => @bitSizeOf(DoubleInt) - small_bit_offset - @bitSizeOf(ValueInt), + }; const ptr: *align(@alignOf(Int)) DoubleInt = @ptrCast(buffer[index..][0..2]); - ptr.* &= ~(((@as(DoubleInt, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(small_bit_offset)); - ptr.* |= @as(DoubleInt, value_int) << @intCast(small_bit_offset); + ptr.* &= ~(((@as(DoubleInt, 1) << @intCast(@bitSizeOf(Value))) - 1) << @intCast(shift)); + ptr.* |= @as(DoubleInt, value_int) << @intCast(shift); } } test "loadBits and storeBits" { - var buffer: [2]u32 = .{ - 0b01111111000000001111111100000000, - 0b11111111000000001111111100000100, + var buffer: [2]u32 = switch (native_endian) { + .little => .{ + //──┐ 0b100011 (end) ┌─┐ 0b100 + 0b01111111000000001111111100000000, + // n <── bit offset 0 ┘ + // ┌── 0b100011 (start) + 0b11111111000000001111111100000100, + }, + .big => .{ + // ┌─┐ 0b100 ┌── 0b100011 (start) + 0b11111110000000001111111100000100, + //└ bit offset 0 ──> n + //──┐ 0b100011 (end) + 0b01111111000000001111111100000000, + }, }; + try std.testing.expectEqual(0b100, loadBits(u32, &buffer, 6, u3)); try std.testing.expectEqual(0b100011, loadBits(u32, &buffer, 29, u6)); + storeBits(u32, &buffer, 0, @as(u1, 0b0)); storeBits(u32, &buffer, 6, @as(u3, 0b010)); - storeBits(u32, &buffer, 29, @as(u6, 0b010010)); + storeBits(u32, &buffer, 29, @as(u6, 0b010110)); + storeBits(u32, &buffer, 40, @as(u17, 0b01110110011111110)); + try std.testing.expectEqual(0b0, loadBits(u32, &buffer, 0, u1)); try std.testing.expectEqual(0b010, loadBits(u32, &buffer, 6, u3)); - try std.testing.expectEqual(0b010010, loadBits(u32, &buffer, 29, u6)); + try std.testing.expectEqual(0b010110, loadBits(u32, &buffer, 29, u6)); + try std.testing.expectEqual(0b01110110011111110, loadBits(u32, &buffer, 40, u17)); + + // Test roundtripping of size/offset combinations + inline for (1..32) |value_size| { + for (0..64) |bit_offset| { + if (value_size + bit_offset > @bitSizeOf(@TypeOf(buffer))) continue; + + buffer = .{ 0, 0 }; + + const Value = @Int(.unsigned, value_size); + const value: Value = @intCast((@as(u32, 1) << @intCast(@bitSizeOf(Value))) - 1); + storeBits(u32, &buffer, bit_offset, value); + std.testing.expectEqual(value, loadBits(u32, &buffer, bit_offset, Value)) catch |err| { + std.debug.print("value size: {} bit offset: {}\n", .{ value_size, bit_offset }); + std.debug.print("buffer: {b:0>32} {b:0>32}\n", .{ buffer[0], buffer[1] }); + return err; + }; + } + } } diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 35a07f1eb88b911f2a0303ee556de7de1bb43e93..f8996ccad050ea9b542a6f37b470a9c33ceb335d 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -12,7 +12,7 @@ root_source_file: ?LazyPath, /// The modules that are mapped into this module's import table. /// Use `addImport` rather than modifying this field directly in order to /// maintain step dependency edges. -import_table: std.StringArrayHashMapUnmanaged(*Module), +import_table: std.array_hash_map.String(*Module), resolved_target: ?std.Build.ResolvedTarget = null, optimize: ?std.builtin.OptimizeMode = null, @@ -22,7 +22,7 @@ c_macros: ArrayList([]const u8), include_dirs: ArrayList(IncludeDir), lib_paths: ArrayList(LazyPath), rpaths: ArrayList(RPath), -frameworks: std.StringArrayHashMapUnmanaged(LinkFrameworkOptions), +frameworks: std.array_hash_map.String(LinkFrameworkOptions), link_objects: ArrayList(LinkObject), strip: ?bool, @@ -146,13 +146,10 @@ pub const RcSourceFile = struct { include_paths: []const LazyPath = &.{}, pub fn dupe(file: RcSourceFile, graph: *const std.Build.Graph) RcSourceFile { - const arena = graph.arena; - const include_paths = arena.alloc(LazyPath, file.include_paths.len) catch @panic("OOM"); - for (include_paths, file.include_paths) |*dest, lazy_path| dest.* = lazy_path.dupe(graph); return .{ .file = file.file.dupe(graph), .flags = graph.dupeStrings(file.flags), - .include_paths = include_paths, + .include_paths = LazyPath.dupeList(file.include_paths, graph), }; } }; @@ -563,7 +560,7 @@ pub fn getGraph(root: *Module) Graph { const arena = root.owner.graph.arena; - var modules: std.AutoArrayHashMapUnmanaged(*std.Build.Module, []const u8) = .empty; + var modules: std.array_hash_map.Auto(*std.Build.Module, []const u8) = .empty; var next_idx: usize = 0; modules.putNoClobber(arena, root, "root") catch @panic("OOM"); diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 5de789c8b2a7b762601c73a2b16a1598338e37c4..4fd3cc4b8098fdbc6ebd4571dfd395c5f6b0b195 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -51,7 +51,6 @@ shared_memory: bool = false, global_base: ?u64 = null, /// Set via options; intended to be read-only after that. zig_lib_dir: ?LazyPath, -exec_cmd_args: ?[]const ?[]const u8, filters: []const []const u8, test_runner: ?TestRunner, wasi_exec_model: ?std.builtin.WasiExecModel = null, @@ -187,7 +186,7 @@ entry: Entry = .default, /// List of symbols forced as undefined in the symbol table /// thus forcing their resolution by the linker. /// Corresponds to `-u ` for ELF/MachO and `/include:` for COFF/PE. -force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), +force_undefined_symbols: std.array_hash_map.String(void), /// Overrides the default stack size stack_size: ?u64 = null, @@ -234,6 +233,12 @@ is_linking_libcpp: bool = false, /// builtin fuzzer, see the `fuzz` flag in `Module`. sanitize_coverage_trace_pc_guard: ?bool = null, +/// Enable or disable incremental compilation. +/// +/// Incremental compilation reduces compile time by mutating an existing build artifact. Non- +/// incremental compilation is slower but preserves previous build artifacts. +incremental: ?bool = null, + emit_directory: Configuration.OptionalGeneratedFileIndex = .none, generated_docs: Configuration.OptionalGeneratedFileIndex = .none, generated_asm: Configuration.OptionalGeneratedFileIndex = .none, @@ -413,7 +418,6 @@ pub fn create(owner: *std.Build, options: Options) *Compile { .out_filename = out_filename, .installed_headers = .empty, .zig_lib_dir = null, - .exec_cmd_args = null, .filters = options.filters, .test_runner = null, // set below .rdynamic = false, @@ -730,17 +734,6 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath { return compile.getEmittedFileGeneric(&compile.generated_llvm_bc); } -pub fn setExecCmd(compile: *Compile, args: []const ?[]const u8) void { - const graph = compile.step.owner.graph; - const arena = graph.arena; - assert(compile.kind == .@"test"); - const duped_args = arena.alloc(?[]const u8, args.len) catch @panic("OOM"); - for (args, 0..) |arg, i| { - duped_args[i] = if (arg) |a| graph.dupeString(a) else null; - } - compile.exec_cmd_args = duped_args; -} - pub fn rootModuleTarget(c: *Compile) std.Target { // The root module is always given a target, so we know this to be non-null. return c.root_module.resolved_target.?.result; @@ -753,7 +746,7 @@ pub fn rootModuleTarget(c: *Compile) std.Target { pub fn getCompileDependencies(start: *Compile, chase_dynamic: bool) []const *Compile { const arena = start.step.owner.graph.arena; - var compiles: std.AutoArrayHashMapUnmanaged(*Compile, void) = .empty; + var compiles: std.array_hash_map.Auto(*Compile, void) = .empty; var next_idx: usize = 0; compiles.putNoClobber(arena, start, {}) catch @panic("OOM"); diff --git a/lib/std/Build/Step/Fmt.zig b/lib/std/Build/Step/Fmt.zig index 294afdb9af1c23b1500598afe3f1c4bbc68080a7..4052e21bd08c0c43e66f4e1bae94991f5fcc6b00 100644 --- a/lib/std/Build/Step/Fmt.zig +++ b/lib/std/Build/Step/Fmt.zig @@ -34,8 +34,8 @@ pub fn create(owner: *std.Build, options: Options) *Fmt { .name = if (options.check) "zig fmt --check" else "zig fmt", .owner = owner, }), - .paths = options.paths, - .exclude_paths = options.exclude_paths, + .paths = LazyPath.dupeList(options.paths, graph), + .exclude_paths = LazyPath.dupeList(options.exclude_paths, graph), .check = options.check, }; diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index 4ace7803225ea6e14caf26bf6769bf4a061567a0..a0fc19f5dc8dc33d5f2ee870bd6210c0172d1bd4 100644 --- a/lib/std/Build/Step/Run.zig +++ b/lib/std/Build/Step/Run.zig @@ -26,6 +26,10 @@ cwd: ?Build.LazyPath, /// Override this field to modify the environment, or use setEnvironmentVariable 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), + /// Controls the `NO_COLOR` and `CLICOLOR_FORCE` environment variables. color: Color = .auto, @@ -129,14 +133,16 @@ pub const StdIo = union(enum) { expect_stdout_exact: []const u8, expect_stdout_match: []const u8, expect_term: process.Child.Term, + expect_stderr_snapshot: std.Build.LazyPath, + expect_stdout_snapshot: std.Build.LazyPath, }; }; pub const Arg = union(enum) { - artifact: PrefixedArtifact, - lazy_path: PrefixedLazyPath, + artifact: DecoratedArtifact, + lazy_path: DecoratedLazyPath, decorated_directory: DecoratedLazyPath, - file_content: PrefixedLazyPath, + file_content: DecoratedFileContent, bytes: []const u8, output_file: *Output, output_file_dep: *Output, @@ -145,30 +151,38 @@ pub const Arg = union(enum) { passthru, }; -pub const PrefixedArtifact = struct { +pub const DecoratedArtifact = struct { prefix: []const u8, + suffix: []const u8, artifact: *Step.Compile, -}; - -pub const PrefixedLazyPath = struct { - prefix: []const u8, - lazy_path: std.Build.LazyPath, + make_absolute: bool, }; pub const DecoratedLazyPath = struct { prefix: []const u8, lazy_path: std.Build.LazyPath, suffix: []const u8, + make_absolute: bool, +}; + +pub const DecoratedFileContent = struct { + prefix: []const u8, + lazy_path: std.Build.LazyPath, + suffix: []const u8, }; pub const Output = struct { generated_file: Configuration.GeneratedFileIndex, prefix: []const u8, basename: []const u8, + suffix: []const u8, + make_absolute: bool, }; pub const CapturedStdIo = struct { - output: Output, + generated_file: Configuration.GeneratedFileIndex, + prefix: []const u8, + basename: []const u8, trim_whitespace: TrimWhitespace, pub const Options = struct { @@ -192,6 +206,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run { .argv = .empty, .cwd = null, .environ_map = null, + .preopens = .empty, .disable_zig_progress = false, .stdio = .infer_from_args, .stdin = .none, @@ -219,17 +234,38 @@ pub fn enableTestRunnerMode(run: *Run) void { run.test_runner_mode = true; } +pub const ArgOptions = struct { + prefix: []const u8 = "", + suffix: []const u8 = "", +}; + +pub const PathArgOptions = struct { + prefix: []const u8 = "", + suffix: []const u8 = "", + /// Makes the path absolute before passing it to the child process. Not supported by all hosts, + /// prefer accepting relative paths when possible. + make_absolute: bool = false, +}; + +/// Deprecated, use `addArtifactArg2`. pub fn addArtifactArg(run: *Run, artifact: *Step.Compile) void { - run.addPrefixedArtifactArg("", artifact); + run.addArtifactArg2(artifact, .{}); } +/// Deprecated, use `addArtifactArg2`. pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Compile) void { + run.addArtifactArg2(artifact, .{ .prefix = prefix }); +} + +pub fn addArtifactArg2(run: *Run, artifact: *Step.Compile, options: PathArgOptions) void { const graph = run.step.owner.graph; const arena = graph.arena; - const prefixed_artifact: PrefixedArtifact = .{ - .prefix = graph.dupeString(prefix), + const prefixed_artifact: DecoratedArtifact = .{ + .prefix = graph.dupeString(options.prefix), .artifact = artifact, + .suffix = graph.dupeString(options.suffix), + .make_absolute = options.make_absolute, }; run.argv.append(arena, .{ .artifact = prefixed_artifact }) catch @panic("OOM"); @@ -237,19 +273,18 @@ pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Com bin_file.addStepDependencies(&run.step); } -/// Provides a file path as a command line argument to the command being run. -/// -/// Returns a `std.Build.LazyPath` which can be used as inputs to other APIs -/// throughout the build system. -/// -/// `sub_path` is the name of the generated output file which may have zero or -/// more path components. -/// -/// Related: -/// * `addPrefixedOutputFileArg` - same thing but prepends a string to the argument -/// * `addFileArg` - for input files given to the child process +/// Deprecated, use `addOutputFileArg2`. pub fn addOutputFileArg(run: *Run, sub_path: []const u8) std.Build.LazyPath { - return run.addPrefixedOutputFileArg("", sub_path); + return run.addOutputFileArg2(sub_path, .{}); +} + +/// Deprecated, use `addOutputFileArg2`. +pub fn addPrefixedOutputFileArg( + run: *Run, + prefix: []const u8, + sub_path: []const u8, +) std.Build.LazyPath { + return run.addOutputFileArg2(sub_path, .{ .prefix = prefix }); } /// Provides a file path as a command line argument to the command being run. @@ -264,16 +299,15 @@ pub fn addOutputFileArg(run: *Run, sub_path: []const u8) std.Build.LazyPath { /// throughout the build system. /// /// Related: -/// * `addOutputFileArg` - same thing but without the prefix /// * `addFileArg` - for input files given to the child process -pub fn addPrefixedOutputFileArg( +pub fn addOutputFileArg2( run: *Run, - prefix: []const u8, /// The name of the generated output file which may have zero or more path /// components. /// /// Asserted to be non-empty. sub_path: []const u8, + options: PathArgOptions, ) std.Build.LazyPath { const b = run.step.owner; const graph = b.graph; @@ -282,9 +316,11 @@ pub fn addPrefixedOutputFileArg( const output = graph.create(Output); output.* = .{ - .prefix = graph.dupeString(prefix), + .prefix = graph.dupeString(options.prefix), .basename = graph.dupeString(sub_path), + .suffix = graph.dupeString(options.suffix), .generated_file = graph.addGeneratedFile(&run.step), + .make_absolute = options.make_absolute, }; run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM"); @@ -295,17 +331,14 @@ pub fn addPrefixedOutputFileArg( return .{ .generated = .{ .index = output.generated_file } }; } -/// Appends an input file to the command line arguments. -/// -/// The child process will see a file path. Modifications to this file will be -/// detected as a cache miss in subsequent builds, causing the child process to -/// be re-executed. -/// -/// Related: -/// * `addPrefixedFileArg` - same thing but prepends a string to the argument -/// * `addOutputFileArg` - for files generated by the child process +/// See `addFileArg2`. pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void { - run.addPrefixedFileArg("", lp); + run.addFileArg2(lp, .{}); +} + +/// See `addFileArg2`. +pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void { + run.addFileArg2(lp, .{ .prefix = prefix }); } /// Appends an input file to the command line arguments prepended with a string. @@ -318,36 +351,29 @@ pub fn addFileArg(run: *Run, lp: std.Build.LazyPath) void { /// subsequent builds, causing the child process to be re-executed. /// /// Related: -/// * `addFileArg` - same thing but without the prefix /// * `addOutputFileArg` - for files generated by the child process -pub fn addPrefixedFileArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void { +pub fn addFileArg2(run: *Run, lp: std.Build.LazyPath, options: PathArgOptions) void { const graph = run.step.owner.graph; const arena = graph.arena; - const prefixed_file_source: PrefixedLazyPath = .{ - .prefix = graph.dupeString(prefix), + const prefixed_file_source: DecoratedLazyPath = .{ + .prefix = graph.dupeString(options.prefix), .lazy_path = lp.dupe(graph), + .suffix = graph.dupeString(options.suffix), + .make_absolute = options.make_absolute, }; run.argv.append(arena, .{ .lazy_path = prefixed_file_source }) catch @panic("OOM"); lp.addStepDependencies(&run.step); } -/// Appends the content of an input file to the command line arguments. -/// -/// The child process will see a single argument, even if the file contains whitespace. -/// This means that the entire file content up to EOF is rendered as one contiguous -/// string, including escape sequences. Notably, any (trailing) newlines will show up -/// like this: "hello,\nfile world!\n" -/// -/// Modifications to the source file will be detected as a cache miss in subsequent -/// builds, causing the child process to be re-executed. -/// -/// This function may not be used to supply the first argument of a `Run` step. -/// -/// Related: -/// * `addPrefixedFileContentArg` - same thing but prepends a string to the argument +/// Deprecated, use `addFileContentArg2`. pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void { - run.addPrefixedFileContentArg("", lp); + return run.addFileContentArg2(lp, .{}); +} + +/// Deprecated, use `addFileContentArg2`. +pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void { + return run.addFileContentArg2(lp, .{ .prefix = prefix }); } /// Appends the content of an input file to the command line arguments prepended with a string. @@ -368,7 +394,7 @@ pub fn addFileContentArg(run: *Run, lp: std.Build.LazyPath) void { /// /// Related: /// * `addFileContentArg` - same thing but without the prefix -pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.LazyPath) void { +pub fn addFileContentArg2(run: *Run, lp: std.Build.LazyPath, options: ArgOptions) void { const graph = run.step.owner.graph; const arena = graph.arena; @@ -379,24 +405,27 @@ pub fn addPrefixedFileContentArg(run: *Run, prefix: []const u8, lp: std.Build.La @panic("'addFileContentArg'/'addPrefixedFileContentArg' cannot be first argument"); } - const prefixed_file_source: PrefixedLazyPath = .{ - .prefix = graph.dupeString(prefix), + const file_content: DecoratedFileContent = .{ + .prefix = graph.dupeString(options.prefix), .lazy_path = lp.dupe(graph), + .suffix = graph.dupeString(options.suffix), }; - run.argv.append(arena, .{ .file_content = prefixed_file_source }) catch @panic("OOM"); + run.argv.append(arena, .{ .file_content = file_content }) catch @panic("OOM"); lp.addStepDependencies(&run.step); } -/// Provides a directory path as a command line argument to the command being run. -/// -/// Returns a `std.Build.LazyPath` which can be used as inputs to other APIs -/// throughout the build system. -/// -/// Related: -/// * `addPrefixedOutputDirectoryArg` - same thing but prepends a string to the argument -/// * `addDirectoryArg` - for input directories given to the child process +/// Deprecated, use `addOutputDirectoryArg2`. pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath { - return run.addPrefixedOutputDirectoryArg("", basename); + return run.addOutputDirectoryArg2(basename, .{}); +} + +/// Deprecated, use `addOutputDirectoryArg2`. +pub fn addPrefixedOutputDirectoryArg( + run: *Run, + prefix: []const u8, + basename: []const u8, +) std.Build.LazyPath { + return run.addOutputDirectoryArg2(basename, .{ .prefix = prefix }); } /// Provides a directory path as a command line argument to the command being run. @@ -412,12 +441,11 @@ pub fn addOutputDirectoryArg(run: *Run, basename: []const u8) std.Build.LazyPath /// throughout the build system. /// /// Related: -/// * `addOutputDirectoryArg` - same thing but without the prefix /// * `addDirectoryArg` - for input directories given to the child process -pub fn addPrefixedOutputDirectoryArg( +pub fn addOutputDirectoryArg2( run: *Run, - prefix: []const u8, basename: []const u8, + options: PathArgOptions, ) std.Build.LazyPath { if (basename.len == 0) @panic("basename must not be empty"); const graph = run.step.owner.graph; @@ -425,9 +453,11 @@ pub fn addPrefixedOutputDirectoryArg( const output = arena.create(Output) catch @panic("OOM"); output.* = .{ - .prefix = graph.dupeString(prefix), + .prefix = graph.dupeString(options.prefix), .basename = graph.dupeString(basename), + .suffix = graph.dupeString(options.suffix), .generated_file = graph.addGeneratedFile(&run.step), + .make_absolute = options.make_absolute, }; run.argv.append(arena, .{ .output_directory = output }) catch @panic("OOM"); @@ -438,56 +468,67 @@ pub fn addPrefixedOutputDirectoryArg( return .{ .generated = .{ .index = output.generated_file } }; } +/// Deprecated, use `addDirectoryArg2`. pub fn addDirectoryArg(run: *Run, lazy_directory: std.Build.LazyPath) void { - run.addDecoratedDirectoryArg("", lazy_directory, ""); + run.addDirectoryArg2(lazy_directory, .{}); } +/// Deprecated, use `addDirectoryArg2`. pub fn addPrefixedDirectoryArg(run: *Run, prefix: []const u8, lazy_directory: std.Build.LazyPath) void { - const graph = run.step.owner.graph; - const arena = graph.arena; - run.argv.append(arena, .{ .decorated_directory = .{ - .prefix = graph.dupeString(prefix), - .lazy_path = lazy_directory.dupe(graph), - .suffix = "", - } }) catch @panic("OOM"); - lazy_directory.addStepDependencies(&run.step); + run.addDirectoryArg2(lazy_directory, .{ .prefix = prefix }); } +/// Deprecated, use `addDirectoryArg2`. pub fn addDecoratedDirectoryArg( run: *Run, prefix: []const u8, lazy_directory: std.Build.LazyPath, suffix: []const u8, +) void { + run.addDirectoryArg2(lazy_directory, .{ .prefix = prefix, .suffix = suffix }); +} + +pub fn addDirectoryArg2( + run: *Run, + lazy_directory: std.Build.LazyPath, + options: PathArgOptions, ) void { const graph = run.step.owner.graph; const arena = graph.arena; run.argv.append(arena, .{ .decorated_directory = .{ - .prefix = graph.dupeString(prefix), + .prefix = graph.dupeString(options.prefix), .lazy_path = lazy_directory.dupe(graph), - .suffix = graph.dupeString(suffix), + .suffix = graph.dupeString(options.suffix), + .make_absolute = options.make_absolute, } }) catch @panic("OOM"); lazy_directory.addStepDependencies(&run.step); } +/// Deprecated, use `addDepFileOutputArg2`. +pub fn addDepFileOutputArg(run: *Run, basename: []const u8) std.Build.LazyPath { + return run.addDepFileOutputArg2(basename, .{}); +} + +/// Deprecated, use `addDepFileOutputArg2`. +pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath { + return run.addDepFileOutputArg2(basename, .{ .prefix = prefix }); +} + /// Add a path argument to a dep file (.d) for the child process to write its /// discovered additional dependencies. /// Only one dep file argument is allowed by instance. -pub fn addDepFileOutputArg(run: *Run, basename: []const u8) std.Build.LazyPath { - return run.addPrefixedDepFileOutputArg("", basename); -} - -/// Add a prefixed path argument to a dep file (.d) for the child process to -/// write its discovered additional dependencies. -pub fn addPrefixedDepFileOutputArg(run: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath { +pub fn addDepFileOutputArg2(run: *Run, basename: []const u8, options: PathArgOptions) std.Build.LazyPath { const b = run.step.owner; const graph = b.graph; const arena = graph.arena; const dep_file = arena.create(Output) catch @panic("OOM"); dep_file.* = .{ - .prefix = graph.dupeString(prefix), + .prefix = graph.dupeString(options.prefix), .basename = graph.dupeString(basename), + .suffix = graph.dupeString(options.suffix), .generated_file = graph.addGeneratedFile(&run.step), + .make_absolute = options.make_absolute, }; run.argv.append(arena, .{ .output_file_dep = dep_file }) catch @panic("OOM"); @@ -581,6 +622,17 @@ pub fn removeEnvironmentVariable(run: *Run, key: []const u8) void { _ = run.getEnvMap().swapRemove(key); } +pub fn setPreopen(run: *Run, name: []const u8, resource: Build.LazyPath) void { + const graph = run.step.owner.graph; + const arena = graph.arena; + resource.addStepDependencies(&run.step); + run.preopens.put( + arena, + graph.dupeString(name), + resource.dupe(graph), + ) catch @panic("OOM"); +} + /// Adds a check for exact stderr match. Does not add any other checks. pub fn expectStdErrEqual(run: *Run, bytes: []const u8) void { const graph = run.step.owner.graph; @@ -632,6 +684,13 @@ pub fn addCheck(run: *Run, new_check: StdIo.Check) void { .check => |*checks| checks.append(b.allocator, new_check) catch @panic("OOM"), else => @panic("illegal call to addCheck: conflicting helper method calls. Suggest to directly set stdio field of Run instead"), } + + switch (new_check) { + .expect_stderr_snapshot, + .expect_stdout_snapshot, + => |file| run.addFileInput(file), + else => {}, + } } pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPath { @@ -642,19 +701,17 @@ pub fn captureStdErr(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa const graph = b.graph; const arena = graph.arena; - if (run.captured_stderr) |captured| return .{ .generated = .{ .index = captured.output.generated_file } }; + if (run.captured_stderr) |captured| return .{ .generated = .{ .index = captured.generated_file } }; const captured = arena.create(CapturedStdIo) catch @panic("OOM"); captured.* = .{ - .output = .{ - .prefix = "", - .basename = if (options.basename) |basename| graph.dupeString(basename) else "stderr", - .generated_file = graph.addGeneratedFile(&run.step), - }, + .prefix = "", + .basename = if (options.basename) |basename| graph.dupeString(basename) else "stderr", + .generated_file = graph.addGeneratedFile(&run.step), .trim_whitespace = options.trim_whitespace, }; run.captured_stderr = captured; - return .{ .generated = .{ .index = captured.output.generated_file } }; + return .{ .generated = .{ .index = captured.generated_file } }; } pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPath { @@ -665,19 +722,17 @@ pub fn captureStdOut(run: *Run, options: CapturedStdIo.Options) std.Build.LazyPa const graph = b.graph; const arena = graph.arena; - if (run.captured_stdout) |captured| return .{ .generated = .{ .index = captured.output.generated_file } }; + if (run.captured_stdout) |captured| return .{ .generated = .{ .index = captured.generated_file } }; const captured = arena.create(CapturedStdIo) catch @panic("OOM"); captured.* = .{ - .output = .{ - .prefix = "", - .basename = if (options.basename) |basename| graph.dupeString(basename) else "stdout", - .generated_file = graph.addGeneratedFile(&run.step), - }, + .prefix = "", + .basename = if (options.basename) |basename| graph.dupeString(basename) else "stdout", + .generated_file = graph.addGeneratedFile(&run.step), .trim_whitespace = options.trim_whitespace, }; run.captured_stdout = captured; - return .{ .generated = .{ .index = captured.output.generated_file } }; + return .{ .generated = .{ .index = captured.generated_file } }; } /// Adds an additional input files that, when modified, indicates that this Run diff --git a/lib/std/DoublyLinkedList.zig b/lib/std/DoublyLinkedList.zig index b7a5ed2e112cb926396261047becfebcc934f553..a792dc9b4ec291fc9be8a1841e180305cd45fa3d 100644 --- a/lib/std/DoublyLinkedList.zig +++ b/lib/std/DoublyLinkedList.zig @@ -127,20 +127,17 @@ pub fn remove(list: *DoublyLinkedList, node: *Node) void { } } -/// Remove and return the last node in the list. -/// -/// Returns: -/// A pointer to the last node in the list. -pub fn pop(list: *DoublyLinkedList) ?*Node { +/// Remove and return a pointer to the last node in the list. +pub fn popLast(list: *DoublyLinkedList) ?*Node { const last = list.last orelse return null; list.remove(last); return last; } -/// Remove and return the first node in the list. -/// -/// Returns: -/// A pointer to the first node in the list. +/// Deprecated in favor of `popLast` +pub const pop = popLast; + +/// Remove and return a pointer to the first node in the list. pub fn popFirst(list: *DoublyLinkedList) ?*Node { const first = list.first orelse return null; list.remove(first); @@ -200,11 +197,14 @@ test "basics" { } _ = list.popFirst(); // {2, 3, 4, 5} - _ = list.pop(); // {2, 3, 4} + _ = list.popLast(); // {2, 3, 4} list.remove(&three.node); // {2, 4} + // peek first and last elements of the list try testing.expect(@as(*L, @fieldParentPtr("node", list.first.?)).data == 2); try testing.expect(@as(*L, @fieldParentPtr("node", list.last.?)).data == 4); + + // list length try testing.expect(list.len() == 2); } diff --git a/lib/std/Io/Dir.zig b/lib/std/Io/Dir.zig index eda18e2579525f5299fda9a357bb89edb67adbd5..414e63c99cea565c4176dfa2dc0a327fe2ebec63 100644 --- a/lib/std/Io/Dir.zig +++ b/lib/std/Io/Dir.zig @@ -1116,6 +1116,10 @@ pub const RenamePreserveError = error{ /// /// On Windows, this error may be returned instead of PathAlreadyExists when /// renaming a directory over an existing directory. + /// + /// On Darwin, this error may be returned when a component of either pathname + /// refers to a "dataless" directory that requires materialization, and the I/O + /// policy of the current thread or process disallows dataless directory materialization. AccessDenied, PathAlreadyExists, /// Operating system or file system does not support atomic nonreplacing diff --git a/lib/std/Io/Kqueue.zig b/lib/std/Io/Kqueue.zig index 63fd846b72abecaf75f44487d6023385b486d345..45e49b0f0cadf89efee58186ac08d71f2739cfce 100644 --- a/lib/std/Io/Kqueue.zig +++ b/lib/std/Io/Kqueue.zig @@ -40,7 +40,7 @@ const Thread = struct { steal_ready_search_index: u32, /// For ensuring multiple fibers waiting on the same file descriptor and /// filter use the same kevent. - wait_queues: std.AutoArrayHashMapUnmanaged(WaitQueueKey, *Fiber), + wait_queues: std.array_hash_map.Auto(WaitQueueKey, *Fiber), const WaitQueueKey = struct { ident: usize, diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 90d74d4b3703bc8ed927c7d0ced77242fcc10f0f..d4b202e12d0fa9087716209c24215bc179d71c1a 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -218,6 +218,7 @@ pub const Environ = struct { DEBUGINFOD_CACHE_PATH: ?[:0]const u8 = null, XDG_CACHE_HOME: ?[:0]const u8 = null, HOME: ?[:0]const u8 = null, + TERM: ?[:0]const u8 = null, }, }; @@ -1562,7 +1563,7 @@ pub const splat_buffer_size = 64; /// NtWaitForMultipleObjects accepts. We use this value also for poll() on /// posix systems. const poll_buffer_len = 64; -pub const default_PATH = "/usr/local/bin:/bin/:/usr/bin"; +pub const default_PATH = "/usr/local/bin:/bin:/usr/bin"; /// There are multiple kernel bugs being worked around with retries. const max_windows_kernel_bug_retries = 13; @@ -7505,6 +7506,7 @@ fn dirRenamePreserve( ) Dir.RenamePreserveError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); if (is_windows) return dirRenameWindowsInner(old_dir, old_sub_path, new_dir, new_sub_path, false); + if (is_darwin) return dirRenamePreserveDarwin(old_dir, old_sub_path, new_dir, new_sub_path); if (native_os == .linux) return dirRenamePreserveLinux(old_dir, old_sub_path, new_dir, new_sub_path); // Make a hard link then delete the original. try dirHardLink(t, old_dir, old_sub_path, new_dir, new_sub_path, .{ .follow_symlinks = false }); @@ -7696,6 +7698,58 @@ fn dirRenamePosix( return renameat(old_dir.handle, old_sub_path_posix, new_dir.handle, new_sub_path_posix); } +fn dirRenamePreserveDarwin( + old_dir: Dir, + old_sub_path: []const u8, + new_dir: Dir, + new_sub_path: []const u8, +) Dir.RenamePreserveError!void { + var old_path_buffer: [posix.PATH_MAX]u8 = undefined; + var new_path_buffer: [posix.PATH_MAX]u8 = undefined; + const old_sub_path_posix = try pathToPosix(old_sub_path, &old_path_buffer); + const new_sub_path_posix = try pathToPosix(new_sub_path, &new_path_buffer); + + const syscall: Syscall = try .start(); + while (true) { + switch (posix.errno(std.c.renameatx_np( + old_dir.handle, + old_sub_path_posix, + new_dir.handle, + new_sub_path_posix, + .{ .EXCL = true }, + ))) { + .SUCCESS => { + syscall.finish(); + break; + }, + .INTR => { + try syscall.checkCancel(); + continue; + }, + .INVAL => |err| return syscall.errnoBug(err), + .FAULT => |err| return syscall.errnoBug(err), + .BADF => |err| return syscall.errnoBug(err), + .ISDIR => |err| return syscall.errnoBug(err), + .NOTEMPTY => |err| return syscall.errnoBug(err), + .OPNOTSUPP => return syscall.fail(error.OperationUnsupported), + .IO => return syscall.fail(error.HardwareFailure), + .DEADLK => return syscall.fail(error.AccessDenied), + .ACCES => return syscall.fail(error.AccessDenied), + .DQUOT => return syscall.fail(error.DiskQuota), + .EXIST => return syscall.fail(error.PathAlreadyExists), + .LOOP => return syscall.fail(error.LinkQuotaExceeded), + .NAMETOOLONG => return syscall.fail(error.NameTooLong), + .NOENT => return syscall.fail(error.FileNotFound), + .NOSPC => return syscall.fail(error.NoSpaceLeft), + .NOTDIR => return syscall.fail(error.NotDir), + .PERM => return syscall.fail(error.PermissionDenied), + .ROFS => return syscall.fail(error.ReadOnlyFileSystem), + .XDEV => return syscall.fail(error.CrossDevice), + else => |err| return syscall.unexpectedErrno(err), + } + } +} + fn dirRenamePreserveLinux( old_dir: Dir, old_sub_path: []const u8, @@ -7783,49 +7837,6 @@ fn renameat( }; } -fn renameatPreserve( - old_dir: posix.fd_t, - old_sub_path: [*:0]const u8, - new_dir: posix.fd_t, - new_sub_path: [*:0]const u8, -) Dir.RenameError!void { - const syscall: Syscall = try .start(); - while (true) { - switch (posix.errno(posix.system.renameat(old_dir, old_sub_path, new_dir, new_sub_path))) { - .SUCCESS => return syscall.finish(), - .INTR => { - try syscall.checkCancel(); - continue; - }, - else => |e| { - syscall.finish(); - switch (e) { - .ACCES => return error.AccessDenied, - .PERM => return error.PermissionDenied, - .BUSY => return error.FileBusy, - .DQUOT => return error.DiskQuota, - .FAULT => |err| return errnoBug(err), - .INVAL => |err| return errnoBug(err), - .ISDIR => return error.IsDir, - .LOOP => return error.SymLinkLoop, - .MLINK => return error.LinkQuotaExceeded, - .NAMETOOLONG => return error.NameTooLong, - .NOENT => return error.FileNotFound, - .NOTDIR => return error.NotDir, - .NOMEM => return error.SystemResources, - .NOSPC => return error.NoSpaceLeft, - .EXIST => return error.PathAlreadyExists, - .NOTEMPTY => return error.PathAlreadyExists, - .ROFS => return error.ReadOnlyFileSystem, - .XDEV => return error.CrossDevice, - .ILSEQ => return error.BadPathName, - else => |err| return posix.unexpectedErrno(err), - } - }, - } - } -} - const dirSymLink = switch (native_os) { .windows => dirSymLinkWindows, .wasi => dirSymLinkWasi, @@ -8165,31 +8176,16 @@ fn dirReadLinkWindows(dir: Dir, sub_path: []const u8, buffer: []u8) Dir.ReadLink defer windows.CloseHandle(result_handle); var reparse_buf: [windows.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]u8 align(@alignOf(windows.REPARSE_DATA_BUFFER)) = undefined; - - syscall = try .start(); - while (true) switch (windows.ntdll.NtFsControlFile( - result_handle, - null, // event - null, // APC routine - null, // APC context - &io_status_block, - .GET_REPARSE_POINT, - null, // input buffer - 0, // input buffer length - &reparse_buf, - reparse_buf.len, - )) { - .SUCCESS => { - syscall.finish(); - break; - }, - .CANCELLED => { - try syscall.checkCancel(); - continue; - }, - .NOT_A_REPARSE_POINT => return syscall.fail(error.NotLink), - else => |status| return syscall.unexpectedNtstatus(status), - }; + switch ((try deviceIoControl(&.{ + .file = .{ .handle = result_handle, .flags = .{ .nonblocking = true } }, + .code = .GET_REPARSE_POINT, + .out = &reparse_buf, + })).u.Status) { + .SUCCESS => {}, + .CANCELLED => unreachable, + .NOT_A_REPARSE_POINT => return error.NotLink, + else => |status| return windows.unexpectedStatus(status), + } const reparse_struct: *const windows.REPARSE_DATA_BUFFER = @ptrCast(@alignCast(&reparse_buf)); const IoReparseTagInt = @typeInfo(windows.IO_REPARSE_TAG).@"struct".backing_integer.?; @@ -8790,9 +8786,8 @@ fn isTty(file: File) Io.Cancelable!bool { fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiEscapeCodesError!void { const t: *Threaded = @ptrCast(@alignCast(userdata)); - _ = t; - if (!is_windows) return if (!try supportsAnsiEscapeCodes(file)) error.NotTerminalDevice; + if (!is_windows) return if (!try supportsAnsiEscapeCodes(t, file)) error.NotTerminalDevice; // For Windows Terminal, VT Sequences processing is enabled by default. const console: File = .{ @@ -8840,14 +8835,13 @@ fn fileEnableAnsiEscapeCodes(userdata: ?*anyopaque, file: File) File.EnableAnsiE fn fileSupportsAnsiEscapeCodes(userdata: ?*anyopaque, file: File) Io.Cancelable!bool { const t: *Threaded = @ptrCast(@alignCast(userdata)); - _ = t; - return supportsAnsiEscapeCodes(file); + return supportsAnsiEscapeCodes(t, file); } -fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool { +fn supportsAnsiEscapeCodes(t: *Threaded, file: File) Io.Cancelable!bool { if (is_windows) { var get_console_mode = windows.CONSOLE.USER_IO.GET_MODE; - switch ((try deviceIoControl(&.{ + return switch ((try deviceIoControl(&.{ .file = .{ .handle = windows.peb().ProcessParameters.ConsoleHandle, .flags = .{ .nonblocking = false }, @@ -8855,15 +8849,33 @@ fn supportsAnsiEscapeCodes(file: File) Io.Cancelable!bool { .code = windows.IOCTL.CONDRV.ISSUE_USER_IO, .in = @ptrCast(&get_console_mode.request(file, 0, .{}, 0, .{})), })).u.Status) { - .SUCCESS => if (get_console_mode.Data & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0) - return true, + .SUCCESS => get_console_mode.Data & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0, .CANCELLED => unreachable, - .INVALID_HANDLE => return isCygwinPty(file), - else => return false, + .INVALID_HANDLE => isCygwinPty(file), + else => false, + }; + } + + if (native_os == .wasi) { + // WASI sanitizes stdout when fd is a tty so ANSI escape codes + // will not be interpreted as actual cursor commands, and + // stderr is always sanitized. + + return false; + } + + if (try isTty(file)) { + if (file.handle == posix.STDOUT_FILENO or file.handle == posix.STDERR_FILENO) { + t.scanEnviron(); + if (t.environ.string.TERM) |term| { + if (std.mem.eql(u8, term, "dumb")) { + return false; + } + } } - } - if (try isTty(file)) return true; + return true; + } return false; } @@ -10168,7 +10180,7 @@ fn fileSeekBy(userdata: ?*anyopaque, file: File, offset: i64) File.SeekError!voi if (posix.SEEK == void) return error.Unseekable; - if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { + if (native_os == .linux and !builtin.link_libc and @sizeOf(posix.system.syscall_arg_t) == 4) { var result: i64 = undefined; const syscall: Syscall = try .start(); while (true) { @@ -10280,7 +10292,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: File, offset: u64) File.SeekError!voi } fn posixSeekTo(fd: posix.fd_t, offset: u64) File.SeekError!void { - if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { + if (native_os == .linux and !builtin.link_libc and @sizeOf(posix.system.syscall_arg_t) == 4) { const syscall: Syscall = try .start(); while (true) { var result: i64 = undefined; @@ -10892,6 +10904,7 @@ fn fileWriteStreaming( .PIPE => return error.BrokenPipe, .CONNRESET => |err| return errnoBug(err), // Not a socket handle. .BUSY => return error.DeviceBusy, + .ACCES => return error.AccessDenied, else => |err| return posix.unexpectedErrno(err), } }, @@ -13676,7 +13689,7 @@ fn netLookupFallible( // Check for equal to "localhost(.)" or ends in ".localhost(.)" const localhost = if (name[name.len - 1] == '.') "localhost." else "localhost"; if (std.mem.endsWith(u8, name, localhost) and - (name.len == localhost.len or name[name.len - localhost.len] == '.')) + (name.len == localhost.len or name[name.len - localhost.len - 1] == '.')) { var results_buffer: [3]HostName.LookupResult = undefined; var results_index: usize = 0; @@ -14160,9 +14173,11 @@ fn addressUnixToPosix(a: *const net.UnixAddress, storage: *UnixAddress) posix.so } fn address4FromPosix(in: *const posix.sockaddr.in) net.Ip4Address { + // The network byte order address in `in.addr` is already the byte order we want. + const addr_bytes: *const [4]u8 = @ptrCast(&in.addr); return .{ .port = std.mem.bigToNative(u16, in.port), - .bytes = @bitCast(in.addr), + .bytes = addr_bytes.*, }; } @@ -14176,9 +14191,11 @@ fn address6FromPosix(in6: *const posix.sockaddr.in6) net.Ip6Address { } fn address4ToPosix(a: net.Ip4Address) posix.sockaddr.in { + // The byte order of `a.bytes` is already equivalent to a network byte order address. + const addr_raw: *align(1) const u32 = @ptrCast(&a.bytes); return .{ .port = std.mem.nativeToBig(u16, a.port), - .addr = @bitCast(a.bytes), + .addr = addr_raw.*, }; } diff --git a/lib/std/Io/Uring.zig b/lib/std/Io/Uring.zig index 9184cd574153b4768c76347d4e246120827b4a26..e560500a755281510f64954d12040b1b6c5504b4 100644 --- a/lib/std/Io/Uring.zig +++ b/lib/std/Io/Uring.zig @@ -917,7 +917,7 @@ pub fn deinit(ev: *Evented) void { const idle_stack_end_offset = std.mem.alignForward( usize, ev.threads.allocated.len * @sizeOf(Thread) + idle_stack_size, - std.heap.page_size_max, + std.heap.pageSize(), ); for (ev.threads.allocated[1..active_threads]) |*thread| thread.thread.join(); for (ev.threads.allocated[0..active_threads]) |*thread| thread.deinit(ev.backing_allocator); diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig index e4eb52d294ec7972b2059ada1fb9e15f313b3f6a..c5dd1f6bae8a7dce41a8ff26692e73fc43c65ba3 100644 --- a/lib/std/Io/Writer.zig +++ b/lib/std/Io/Writer.zig @@ -771,7 +771,7 @@ pub fn writeBytePreserve(w: *Writer, preserve: usize, byte: u8) Error!void { w.end += 1; return; } - try w.vtable.rebase(w, preserve, 1); + try w.vtable.rebase(w, preserve -| 1, 1); w.buffer[w.end] = byte; w.end += 1; } diff --git a/lib/std/Io/net.zig b/lib/std/Io/net.zig index c704d8b9e924da4578e447f9d3e5be3ad9f42533..6611502cc157238167445e516cb5ea5b6a0af832 100644 --- a/lib/std/Io/net.zig +++ b/lib/std/Io/net.zig @@ -576,7 +576,7 @@ pub const Ip6Address = struct { const name = text[text_i..]; if (name.len == 0) return .incomplete; interface_name_text = name; - text_i = @intCast(text.len); + text_i = std.math.cast(u8, text.len) orelse return .{ .overflow = text.len }; continue :state .end; }, else => return .{ .invalid_byte = text_i }, @@ -592,11 +592,7 @@ pub const Ip6Address = struct { if (remaining != 0) return .incomplete; } - // Workaround that can be removed when this proposal is - // implemented https://github.com/ziglang/zig/issues/19755 - if ((comptime @import("builtin").cpu.arch.endian()) != .big) { - for (&parts) |*part| part.* = @byteSwap(part.*); - } + for (&parts) |*part| part.* = @byteSwap(part.*); return .{ .success = .{ .bytes = @bitCast(parts), diff --git a/lib/std/Io/net/test.zig b/lib/std/Io/net/test.zig index 1565904c574a6e392593dc7ad4b3c85a9ac1fd0a..308dc1a32670e207e72511d0128b634972050e6a 100644 --- a/lib/std/Io/net/test.zig +++ b/lib/std/Io/net/test.zig @@ -92,6 +92,11 @@ test "invalid but parseable IPv6 scope ids" { try testing.expectError(error.InterfaceNotFound, net.IpAddress.resolveIp6(io, "ff01::fb%123s45678901234", 0)); } +test "oversized IPv6 scope id" { + const long_scope: [256]u8 = @splat('a'); + try testing.expectError(error.ParseFailed, net.IpAddress.resolveIp6(testing.io, "ff01::fb%" ++ &long_scope, 0)); +} + test "parse and render IPv4 addresses" { try testIp4ParseAndRender("0.0.0.0"); try testIp4ParseAndRender("255.255.255.255"); diff --git a/lib/std/Random/RomuTrio.zig b/lib/std/Random/RomuTrio.zig index 5b7664d7f2b6cd7844020c1cd045a77955a0bc1f..9f005bf2f9fac8082eb4e71355dc90c73280d2b9 100644 --- a/lib/std/Random/RomuTrio.zig +++ b/lib/std/Random/RomuTrio.zig @@ -5,6 +5,7 @@ const std = @import("std"); const math = std.math; const RomuTrio = @This(); +const builtin = @import("builtin"); x_state: u64, y_state: u64, @@ -33,7 +34,7 @@ fn next(self: *RomuTrio) u64 { } pub fn seedWithBuf(self: *RomuTrio, buf: [24]u8) void { - const seed_buf = @as([3]u64, @bitCast(buf)); + const seed_buf: [3]u64 = @bitCast(buf); self.x_state = seed_buf[0]; self.y_state = seed_buf[1]; self.z_state = seed_buf[2]; @@ -121,7 +122,8 @@ test fill { } test "buf seeding test" { - const buf0 = @as([24]u8, @bitCast([3]u64{ 16294208416658607535, 13964609475759908645, 4703697494102998476 })); + 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); r.seedWithBuf(buf0); diff --git a/lib/std/Random/Xoshiro256.zig b/lib/std/Random/Xoshiro256.zig index fb65c2ba58e89b0bb50b22d1937ee8d359324e1c..6cb0583d982622b3f7df21b94368b03ddeb80c17 100644 --- a/lib/std/Random/Xoshiro256.zig +++ b/lib/std/Random/Xoshiro256.zig @@ -46,12 +46,12 @@ pub fn jump(self: *Xoshiro256) void { while (table != 0) : (table >>= 1) { if (@as(u1, @truncate(table)) != 0) { - s ^= @as(u256, @bitCast(self.s)); + s ^= @bitCast(self.s); } _ = self.next(); } - self.s = @as([4]u64, @bitCast(s)); + self.s = @bitCast(s); } pub fn seed(self: *Xoshiro256, init_s: u64) void { diff --git a/lib/std/Target.zig b/lib/std/Target.zig index fdeacdd719aaf0c02deec5e40c7c55b38dda0943..a75d23ca4d7530da5aaeda2c3f9c5a2056914391 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -49,7 +49,9 @@ pub const Os = struct { uefi, @"3ds", + wiiu, + psx, ps3, ps4, ps5, @@ -165,6 +167,7 @@ pub const Os = struct { .plan9, .serenity, + .psx, .ps3, .ps4, .ps5, @@ -196,6 +199,7 @@ pub const Os = struct { .uefi, .@"3ds", + .wiiu, .psp, .vita, @@ -400,6 +404,7 @@ pub const Os = struct { .plan9, .serenity, + .psx, .ps3, .ps4, .ps5, @@ -453,7 +458,7 @@ pub const Os = struct { break :blk default_min; }, - .max = .{ .major = 7, .minor = 0, .patch = 9 }, + .max = .{ .major = 7, .minor = 1, .patch = 9 }, }, .glibc = blk: { // For 32-bit targets that traditionally used 32-bit time, we require @@ -622,6 +627,13 @@ pub const Os = struct { }, }, + .wiiu => .{ + .semver = .{ + .min = .{ .major = 5, .minor = 5, .patch = 5 }, // Latest global release + .max = .{ .major = 5, .minor = 5, .patch = 6 }, // Latest US only release + }, + }, + .psp => .{ .semver = .{ // https://www.psdevwiki.com/psp/Official_Firmware_(OFW)#1.XX_Kernel @@ -787,6 +799,8 @@ pub const Abi = enum { gnux32, eabi, eabihf, + abin32, + x32, ilp32, android, androideabi, @@ -878,8 +892,12 @@ pub const Abi = enum { => .muslabi64, // No musl support. + .alpha, .arc, .arceb, + .or1k, + .sparc, + .sparc64, => .gnu, .csky, => .gnueabi, @@ -933,6 +951,8 @@ pub const Abi = enum { .windows => .gnu, .uefi => .msvc, .@"3ds" => .eabihf, + .wiiu => .eabihf, + .psx => .eabi, .psp => .eabihf, .vita => .eabihf, .wasi, .emscripten => .musl, @@ -1984,6 +2004,8 @@ pub const Cpu = struct { .spirv_kernel, .spirv_fragment, .spirv_vertex, + .spirv_task, + .spirv_mesh, => &.{ .spirv32, .spirv64 }, .ez80_cet, @@ -2080,6 +2102,7 @@ pub const Cpu = struct { .m68k => &m68k.cpu.M68030, .mips => &mips.cpu.mips32r2, .mipsel => switch (os.tag) { + .psx => &mips.cpu.r3000a, .psp => &mips.cpu.allegrex, else => &mips.cpu.mips32r2, }, @@ -2091,7 +2114,7 @@ pub const Cpu = struct { .msp430 => &msp430.cpu.msp430, .nvptx, .nvptx64 => &nvptx.cpu.sm_52, .powerpc => switch (os.tag) { - .openbsd => &powerpc.cpu.@"750", + .openbsd, .wiiu => &powerpc.cpu.@"750", else => generic(arch), }, .powerpc64 => switch (os.tag) { @@ -2272,11 +2295,12 @@ pub fn requiresLibC(target: *const Target) bool { .freestanding, .fuchsia, .managarm, - .ps3, .rtems, .cuda, .nvcl, .amdhsa, + .psx, + .ps3, .ps4, .ps5, .psp, @@ -2296,6 +2320,7 @@ pub fn requiresLibC(target: *const Target) bool { .other, .@"3ds", .tios, + .wiiu, => false, }; } @@ -2341,9 +2366,11 @@ pub fn supportsAddressSpace( .lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2), .global, .local, .shared => is_gpu, - .constant => is_gpu and (context == null or context == .constant), + .constant => (is_gpu and (context == null or context == .constant)) or + (is_spirv and (context == null or context == .constant or context == .pointer)), .param => is_nvptx, .input, .output, .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => is_spirv, + .externref, .funcref => target.cpu.has(.wasm, .reference_types), }; } @@ -2440,6 +2467,7 @@ pub const DynamicLinker = struct { .windows, .@"3ds", + .wiiu, .emscripten, .wasi, @@ -2453,6 +2481,7 @@ pub const DynamicLinker = struct { .opengl, .vulkan, + .psx, .ps3, .ps4, .ps5, @@ -2862,7 +2891,9 @@ pub const DynamicLinker = struct { .windows, .@"3ds", + .wiiu, + .psx, .psp, .vita, @@ -2903,10 +2934,17 @@ pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 { pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 { switch (abi) { - .gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32, - .gnuabi64, .muslabi64 => return 64, + .gnux32, + .muslx32, + .x32, + .gnuabin32, + .muslabin32, + .abin32, + .ilp32, + => return 32, else => {}, } + return switch (cpu_arch) { .avr, .msp430, @@ -2985,12 +3023,12 @@ pub fn ptrBitWidth(target: *const Target) u16 { pub fn stackAlignment(target: *const Target) u16 { // Overrides for when the stack alignment is not equal to the pointer width. switch (target.cpu.arch) { - .ez80, - => return 1, - .m68k, - => return 2, - .amdgcn, - => return 4, + .ez80 => return 1, + + .m68k => return 2, + + .amdgcn => return 4, + .arm, .armeb, .hppa, @@ -3001,6 +3039,7 @@ pub fn stackAlignment(target: *const Target) u16 { .thumb, .thumbeb, => return 8, + .aarch64, .aarch64_be, .alpha, @@ -3017,18 +3056,23 @@ pub fn stackAlignment(target: *const Target) u16 { .wasm64, .x86_64, => return 16, + // Some of the following prongs should really be testing the ABI, but our current `Abi` enum // can't handle that level of nuance yet. .powerpc64, .powerpc64le, => if (target.os.tag == .linux) return 16, + .riscv32, .riscv32be, .riscv64, .riscv64be, => if (!target.cpu.has(.riscv, .e)) return 16, + .x86 => if (target.os.tag != .windows and target.os.tag != .uefi) return 16, + .kvx => return 32, + else => {}, } @@ -3131,7 +3175,9 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 { pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { switch (target.os.tag) { .freestanding, .other => switch (target.cpu.arch) { - .msp430, .x86_16 => switch (c_type) { + .msp430, + .x86_16, + => switch (c_type) { .char => return 8, .short, .ushort, .int, .uint => return 16, .float, .long, .ulong => return 32, @@ -3143,12 +3189,14 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .long, .ulong, .float, .double, .longdouble => return 32, .longlong, .ulonglong => return 64, }, - .mips64, .mips64el => switch (c_type) { + .mips64, + .mips64el, + => switch (c_type) { .char => return 8, .short, .ushort => return 16, .int, .uint, .float => return 32, .long, .ulong => switch (target.abi) { - .gnuabin32, .muslabin32 => return 32, + .abin32 => return 32, else => return 64, }, .longlong, .ulonglong, .double => return 64, @@ -3159,7 +3207,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .short, .ushort => return 16, .int, .uint, .float => return 32, .long, .ulong => switch (target.abi) { - .gnux32, .muslx32 => return 32, + .x32 => return 32, else => return 64, }, .longlong, .ulonglong, .double => return 64, @@ -3172,25 +3220,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .long, .ulong => return target.ptrBitWidth(), .longlong, .ulonglong, .double => return 64, .longdouble => switch (target.cpu.arch) { - .x86 => switch (target.abi) { - .android => return 64, - else => return 80, - }, - - .powerpc, - .powerpcle, - .powerpc64, - .powerpc64le, - => switch (target.abi) { - .musl, - .muslabin32, - .muslabi64, - .musleabi, - .musleabihf, - .muslx32, - => return 64, - else => return 128, - }, + .x86 => return 80, .alpha, .riscv32, @@ -3199,6 +3229,10 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .riscv64be, .aarch64, .aarch64_be, + .powerpc, + .powerpcle, + .powerpc64, + .powerpc64le, .s390x, .sparc64, .wasm32, @@ -3232,23 +3266,25 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .wasi, .emscripten, => switch (target.cpu.arch) { - .mips64, .mips64el => switch (c_type) { + .mips64, + .mips64el, + => switch (c_type) { .char => return 8, .short, .ushort => return 16, .int, .uint, .float => return 32, .long, .ulong => switch (target.abi) { - .gnuabin32, .muslabin32 => return 32, + .gnuabin32, .muslabin32, .abin32 => return 32, else => return 64, }, .longlong, .ulonglong, .double => return 64, - .longdouble => if (target.os.tag == .freebsd) return 64 else return 128, + .longdouble => return 128, }, .x86_64 => switch (c_type) { .char => return 8, .short, .ushort => return 16, .int, .uint, .float => return 32, .long, .ulong => switch (target.abi) { - .gnux32, .muslx32 => return 32, + .gnux32, .muslx32, .x32 => return 32, else => return 64, }, .longlong, .ulonglong, .double => return 64, @@ -3269,15 +3305,11 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .powerpc, .powerpcle, => switch (target.abi) { - .musl, - .muslabin32, - .muslabi64, - .musleabi, - .musleabihf, - .muslx32, - => return 64, + .musleabi, .musleabihf => return 64, else => switch (target.os.tag) { - .freebsd, .netbsd, .openbsd => return 64, + .netbsd, + .openbsd, + => return 64, else => return 128, }, }, @@ -3285,15 +3317,11 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .powerpc64, .powerpc64le, => switch (target.abi) { - .musl, - .muslabin32, - .muslabi64, - .musleabi, - .musleabihf, - .muslx32, - => return 64, + .musl => return 64, else => switch (target.os.tag) { - .freebsd, .openbsd => return 64, + .freebsd, + .openbsd, + => return 64, else => return 128, }, }, @@ -3329,7 +3357,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .long, .ulong => return 32, .longlong, .ulonglong, .double => return 64, .longdouble => switch (target.abi) { - .gnu, .ilp32 => return 80, + .gnu => return 80, else => return 64, }, }, @@ -3340,7 +3368,7 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .long, .ulong => return 32, .longlong, .ulonglong, .double => return 64, .longdouble => switch (target.abi) { - .gnu, .ilp32 => return 80, + .gnu => return 80, else => return 64, }, }, @@ -3418,6 +3446,19 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { .longlong, .ulonglong, .double, .longdouble => return 64, }, + .wiiu => switch (c_type) { + .char => return 8, + .short, .ushort => return 16, + .int, .uint, .float, .long, .ulong => return 32, + .longlong, .ulonglong, .double, .longdouble => return 64, + }, + + .psx => switch (c_type) { + .char => return 8, + .short, .ushort => return 16, + .int, .uint, .long, .ulong, .float => return 32, + .longlong, .ulonglong, .double, .longdouble => return 64, + }, .ps4, .ps5 => switch (c_type) { .char => return 8, .short, .ushort => return 16, @@ -3452,12 +3493,14 @@ pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 { pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { // Overrides for unusual alignments switch (target.cpu.arch) { - .avr, .ez80 => return 1, + .avr, + .ez80, + => return 1, .x86 => switch (target.os.tag) { .windows, .uefi => switch (c_type) { .longlong, .ulonglong, .double => return 8, .longdouble => switch (target.abi) { - .gnu, .ilp32 => return 4, + .gnu => return 4, else => return 8, }, else => {}, @@ -3482,8 +3525,6 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { return @min( std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8), @as(u16, switch (target.cpu.arch) { - .ez80 => 1, - .msp430, .x86_16, => 2, @@ -3551,6 +3592,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 { => 16, .avr, + .ez80, => unreachable, // Handled above. }), ); @@ -3563,11 +3605,13 @@ pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 { .longdouble => return 4, else => {}, }, - .avr, .ez80 => return 1, + .avr, + .ez80, + => return 1, .x86 => switch (target.os.tag) { .windows, .uefi => switch (c_type) { .longdouble => switch (target.abi) { - .gnu, .ilp32 => return 4, + .gnu => return 4, else => return 8, }, else => {}, @@ -3595,9 +3639,9 @@ pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 { return @min( std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8), @as(u16, switch (target.cpu.arch) { - .ez80 => 1, - - .x86_16, .msp430 => 2, + .x86_16, + .msp430, + => 2, .arc, .arceb, @@ -3662,6 +3706,7 @@ pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 { => 16, .avr, + .ez80, => unreachable, // Handled above. }), ); @@ -3673,7 +3718,9 @@ pub fn cMaxIntAlignment(target: *const Target) u16 { .ez80, => 1, - .msp430, .x86_16 => 2, + .msp430, + .x86_16, + => 2, .arc, .arceb, @@ -3742,14 +3789,18 @@ 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 => .{ .x86_64_x32 = .{} }, + .gnux32, .muslx32, .x32 => .{ .x86_64_x32 = .{} }, else => .{ .x86_64_sysv = .{} }, }, }, .x86 => switch (target.os.tag) { - .windows, .uefi => .{ .x86_win = .{} }, + .windows, + .uefi, + => .{ .x86_win = .{} }, else => .{ .x86_sysv = .{} }, }, .x86_16 => .{ .x86_16_cdecl = .{} }, @@ -3765,7 +3816,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention .hard => .{ .arm_aapcs_vfp = .{} }, }, .mips64, .mips64el => switch (target.abi) { - .gnuabin32, .muslabin32 => .{ .mips64_n32 = .{} }, + .gnuabin32, .muslabin32, .abin32 => .{ .mips64_n32 = .{} }, else => .{ .mips64_n64 = .{} }, }, .mips, .mipsel => .{ .mips_o32 = .{} }, diff --git a/lib/std/Target/mips.zig b/lib/std/Target/mips.zig index 02ff2f6a9d338d52e5b188a13e4d8fbcd6673f6f..dad3a54940b45a9e9f2a7f45f8fb52cf34545f63 100644 --- a/lib/std/Target/mips.zig +++ b/lib/std/Target/mips.zig @@ -587,4 +587,13 @@ pub const cpu = struct { .p5600, }), }; + pub const r3000a: CpuModel = .{ + .name = "r3000a", + .llvm_name = null, + .features = featureSet(&[_]Feature{ + .mips1, + .notraps, + .soft_float, + }), + }; }; diff --git a/lib/std/Target/spirv.zig b/lib/std/Target/spirv.zig index 04b4530978776a746b30ce12928ecedcc03a60e8..90d43cdbad5a9ccc699f94e5f53483ec94d7e502 100644 --- a/lib/std/Target/spirv.zig +++ b/lib/std/Target/spirv.zig @@ -5,12 +5,225 @@ const CpuFeature = std.Target.Cpu.Feature; const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { - arbitrary_precision_integers, + abort_khr, + addresses, + arithmetic_fence_ext, + atomic_float16add_ext, + atomic_float16min_max_ext, + atomic_float32add_ext, + atomic_float32min_max_ext, + atomic_float64add_ext, + atomic_float64min_max_ext, + atomic_storage, + atomic_storage_ops, + b_float16cooperative_matrix_khr, + b_float16dot_product_khr, + b_float16type_khr, + bit_instructions, + clip_distance, + compute_derivative_group_linear_khr, + compute_derivative_group_quads_khr, + constant_data_khr, + cooperative_matrix_khr, + cull_distance, + demote_to_helper_invocation, + denorm_flush_to_zero, + denorm_preserve, + derivative_control, + descriptor_heap_ext, + device_enqueue, + device_group, + dot_product, + dot_product_input4x8bit, + dot_product_input4x8bit_packed, + dot_product_input_all, + draw_parameters, + expect_assume_khr, float16, + float16buffer, float64, + float8cooperative_matrix_ext, + float8ext, + float_controls2, + fmakhr, + fragment_barycentric_khr, + fragment_density_ext, + fragment_fully_covered_ext, + fragment_shader_pixel_interlock_ext, + fragment_shader_sample_interlock_ext, + fragment_shader_shading_rate_interlock_ext, + fragment_shading_rate_khr, generic_pointer, + geometry, + geometry_point_size, + geometry_streams, + group_non_uniform, + group_non_uniform_arithmetic, + group_non_uniform_ballot, + group_non_uniform_clustered, + group_non_uniform_partitioned_ext, + group_non_uniform_quad, + group_non_uniform_rotate_khr, + group_non_uniform_shuffle, + group_non_uniform_shuffle_relative, + group_non_uniform_vote, + group_uniform_arithmetic_khr, + groups, + image_basic, + image_buffer, + image_cube_array, + image_gather_extended, + image_mipmap, + image_ms_array, + image_query, + image_read_write, + image_rect, + input_attachment, + input_attachment_array_dynamic_indexing, + input_attachment_array_non_uniform_indexing, + int16, int64, + int64atomics, + int64image_ext, + int8, + interpolation_function, + kernel, + linkage, + literal_sampler, + long_vector_ext, + matrix, + mesh_shading_ext, + min_lod, + multi_view, + multi_viewport, + named_barrier, + opt_none_ext, + physical_storage_buffer_addresses, + pipe_storage, + pipes, + poison_freeze_khr, + quad_control_khr, + ray_cull_mask_khr, + ray_query_khr, + ray_query_position_fetch_khr, + ray_query_provisional_khr, + ray_tracing_khr, + ray_tracing_opacity_micromap_ext, + ray_tracing_position_fetch_khr, + ray_tracing_provisional_khr, + ray_traversal_primitive_culling_khr, + replicated_composites_ext, + runtime_descriptor_array, + sample_mask_post_depth_coverage, + sample_rate_shading, + sampled_buffer, + sampled_cube_array, + sampled_image_array_dynamic_indexing, + sampled_image_array_non_uniform_indexing, + sampled_rect, + shader, + shader64bit_indexing_ext, + shader_clock_khr, + shader_invocation_reorder_ext, + shader_layer, + shader_non_uniform, + shader_viewport_index, + shader_viewport_index_layer_ext, + signed_zero_inf_nan_preserve, + sparse_residency, + SPV_EXT_arithmetic_fence, + SPV_EXT_demote_to_helper_invocation, + SPV_EXT_descriptor_heap, + SPV_EXT_descriptor_indexing, + SPV_EXT_float8, + SPV_EXT_fragment_fully_covered, + SPV_EXT_fragment_invocation_density, + SPV_EXT_fragment_shader_interlock, + SPV_EXT_long_vector, + SPV_EXT_mesh_shader, + SPV_EXT_opacity_micromap, + SPV_EXT_optnone, + SPV_EXT_physical_storage_buffer, + SPV_EXT_replicated_composites, + SPV_EXT_shader_64bit_indexing, + SPV_EXT_shader_atomic_float16_add, + SPV_EXT_shader_atomic_float_add, + SPV_EXT_shader_atomic_float_min_max, + SPV_EXT_shader_image_int64, + SPV_EXT_shader_invocation_reorder, + SPV_EXT_shader_stencil_export, + SPV_EXT_shader_subgroup_partitioned, + SPV_EXT_shader_tile_image, + SPV_EXT_shader_viewport_index_layer, + SPV_KHR_16bit_storage, + SPV_KHR_8bit_storage, + SPV_KHR_abort, + SPV_KHR_bfloat16, + SPV_KHR_bit_instructions, + SPV_KHR_compute_shader_derivatives, + SPV_KHR_constant_data, + SPV_KHR_cooperative_matrix, + SPV_KHR_device_group, + SPV_KHR_expect_assume, + SPV_KHR_float_controls, + SPV_KHR_float_controls2, + SPV_KHR_fma, + SPV_KHR_fragment_shader_barycentric, + SPV_KHR_fragment_shading_rate, + SPV_KHR_integer_dot_product, + SPV_KHR_multiview, + SPV_KHR_physical_storage_buffer, + SPV_KHR_poison_freeze, + SPV_KHR_post_depth_coverage, + SPV_KHR_quad_control, + SPV_KHR_ray_cull_mask, + SPV_KHR_ray_query, + SPV_KHR_ray_tracing, + SPV_KHR_ray_tracing_position_fetch, + SPV_KHR_shader_atomic_counter_ops, + SPV_KHR_shader_ballot, + SPV_KHR_shader_clock, + SPV_KHR_shader_draw_parameters, + SPV_KHR_subgroup_rotate, + SPV_KHR_subgroup_vote, + SPV_KHR_uniform_group_instructions, + SPV_KHR_untyped_pointers, + SPV_KHR_variable_pointers, + SPV_KHR_vulkan_memory_model, + SPV_KHR_workgroup_memory_explicit_layout, + stencil_export_ext, + storage_buffer16bit_access, + storage_buffer8bit_access, + storage_buffer_array_dynamic_indexing, + storage_buffer_array_non_uniform_indexing, + storage_image_array_dynamic_indexing, + storage_image_array_non_uniform_indexing, + storage_image_extended_formats, + storage_image_multisample, + storage_image_read_without_format, + storage_image_write_without_format, + storage_input_output16, storage_push_constant16, + storage_push_constant8, + storage_texel_buffer_array_dynamic_indexing, + storage_texel_buffer_array_non_uniform_indexing, + subgroup_ballot_khr, + subgroup_dispatch, + subgroup_vote_khr, + tessellation, + tessellation_point_size, + tile_image_color_read_access_ext, + tile_image_depth_read_access_ext, + tile_image_stencil_read_access_ext, + transform_feedback, + uniform_and_storage_buffer16bit_access, + uniform_and_storage_buffer8bit_access, + uniform_buffer_array_dynamic_indexing, + uniform_buffer_array_non_uniform_indexing, + uniform_decoration, + uniform_texel_buffer_array_dynamic_indexing, + uniform_texel_buffer_array_non_uniform_indexing, + untyped_pointers_khr, v1_0, v1_1, v1_2, @@ -19,7 +232,13 @@ pub const Feature = enum { v1_5, v1_6, variable_pointers, + variable_pointers_storage_buffer, vector16, + vulkan_memory_model, + vulkan_memory_model_device_scope, + workgroup_memory_explicit_layout16bit_access_khr, + workgroup_memory_explicit_layout8bit_access_khr, + workgroup_memory_explicit_layout_khr, }; pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet; @@ -32,109 +251,1611 @@ pub const all_features = blk: { const len = @typeInfo(Feature).@"enum".field_names.len; std.debug.assert(len <= CpuFeature.Set.needed_bit_count); var result: [len]CpuFeature = undefined; - result[@intFromEnum(Feature.arbitrary_precision_integers)] = .{ + result[@intFromEnum(Feature.abort_khr)] = .{ .llvm_name = null, - .description = "Enable SPV_INTEL_arbitrary_precision_integers extension and the ArbitraryPrecisionIntegersINTEL capability", + .description = "Enable abort_khr Capability.", .dependencies = featureSet(&[_]Feature{ - .v1_5, + .SPV_KHR_abort, + .v1_0, + }), + }; + result[@intFromEnum(Feature.addresses)] = .{ + .llvm_name = null, + .description = "Enable addresses Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.arithmetic_fence_ext)] = .{ + .llvm_name = null, + .description = "Enable arithmetic_fence_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_arithmetic_fence, + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_float16add_ext)] = .{ + .llvm_name = null, + .description = "Enable atomic_float16add_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_atomic_float16_add, + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_float16min_max_ext)] = .{ + .llvm_name = null, + .description = "Enable atomic_float16min_max_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_atomic_float_min_max, + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_float32add_ext)] = .{ + .llvm_name = null, + .description = "Enable atomic_float32add_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_atomic_float_add, + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_float32min_max_ext)] = .{ + .llvm_name = null, + .description = "Enable atomic_float32min_max_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_atomic_float_min_max, + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_float64add_ext)] = .{ + .llvm_name = null, + .description = "Enable atomic_float64add_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_atomic_float_add, + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_float64min_max_ext)] = .{ + .llvm_name = null, + .description = "Enable atomic_float64min_max_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_atomic_float_min_max, + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_storage)] = .{ + .llvm_name = null, + .description = "Enable atomic_storage Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.atomic_storage_ops)] = .{ + .llvm_name = null, + .description = "Enable atomic_storage_ops Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_shader_atomic_counter_ops, + .v1_0, + }), + }; + result[@intFromEnum(Feature.b_float16cooperative_matrix_khr)] = .{ + .llvm_name = null, + .description = "Enable b_float16cooperative_matrix_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_bfloat16, + .v1_0, + }), + }; + result[@intFromEnum(Feature.b_float16dot_product_khr)] = .{ + .llvm_name = null, + .description = "Enable b_float16dot_product_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_bfloat16, + .v1_0, + }), + }; + result[@intFromEnum(Feature.b_float16type_khr)] = .{ + .llvm_name = null, + .description = "Enable b_float16type_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_bfloat16, + .v1_0, + }), + }; + result[@intFromEnum(Feature.bit_instructions)] = .{ + .llvm_name = null, + .description = "Enable bit_instructions Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_bit_instructions, + .v1_0, + }), + }; + result[@intFromEnum(Feature.clip_distance)] = .{ + .llvm_name = null, + .description = "Enable clip_distance Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.compute_derivative_group_linear_khr)] = .{ + .llvm_name = null, + .description = "Enable compute_derivative_group_linear_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_compute_shader_derivatives, + .v1_0, + }), + }; + result[@intFromEnum(Feature.compute_derivative_group_quads_khr)] = .{ + .llvm_name = null, + .description = "Enable compute_derivative_group_quads_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_compute_shader_derivatives, + .v1_0, + }), + }; + result[@intFromEnum(Feature.constant_data_khr)] = .{ + .llvm_name = null, + .description = "Enable constant_data_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_constant_data, + .v1_0, + }), + }; + result[@intFromEnum(Feature.cooperative_matrix_khr)] = .{ + .llvm_name = null, + .description = "Enable cooperative_matrix_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_cooperative_matrix, + .v1_0, + }), + }; + result[@intFromEnum(Feature.cull_distance)] = .{ + .llvm_name = null, + .description = "Enable cull_distance Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.demote_to_helper_invocation)] = .{ + .llvm_name = null, + .description = "Enable demote_to_helper_invocation Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_demote_to_helper_invocation, + .v1_6, + }), + }; + result[@intFromEnum(Feature.denorm_flush_to_zero)] = .{ + .llvm_name = null, + .description = "Enable denorm_flush_to_zero Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_float_controls, + .v1_4, + }), + }; + result[@intFromEnum(Feature.denorm_preserve)] = .{ + .llvm_name = null, + .description = "Enable denorm_preserve Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_float_controls, + .v1_4, + }), + }; + result[@intFromEnum(Feature.derivative_control)] = .{ + .llvm_name = null, + .description = "Enable derivative_control Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.descriptor_heap_ext)] = .{ + .llvm_name = null, + .description = "Enable descriptor_heap_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_heap, + .v1_0, + }), + }; + result[@intFromEnum(Feature.device_enqueue)] = .{ + .llvm_name = null, + .description = "Enable device_enqueue Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.device_group)] = .{ + .llvm_name = null, + .description = "Enable device_group Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_device_group, + .v1_3, + }), + }; + result[@intFromEnum(Feature.dot_product)] = .{ + .llvm_name = null, + .description = "Enable dot_product Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_integer_dot_product, + .v1_6, + }), + }; + result[@intFromEnum(Feature.dot_product_input4x8bit)] = .{ + .llvm_name = null, + .description = "Enable dot_product_input4x8bit Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_integer_dot_product, + .v1_6, + }), + }; + result[@intFromEnum(Feature.dot_product_input4x8bit_packed)] = .{ + .llvm_name = null, + .description = "Enable dot_product_input4x8bit_packed Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_integer_dot_product, + .v1_6, + }), + }; + result[@intFromEnum(Feature.dot_product_input_all)] = .{ + .llvm_name = null, + .description = "Enable dot_product_input_all Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_integer_dot_product, + .v1_6, + }), + }; + result[@intFromEnum(Feature.draw_parameters)] = .{ + .llvm_name = null, + .description = "Enable draw_parameters Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_shader_draw_parameters, + .v1_3, + }), + }; + result[@intFromEnum(Feature.expect_assume_khr)] = .{ + .llvm_name = null, + .description = "Enable expect_assume_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_expect_assume, + .v1_0, }), }; result[@intFromEnum(Feature.float16)] = .{ .llvm_name = null, - .description = "Enable Float16 capability", + .description = "Enable float16 Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.float16buffer)] = .{ + .llvm_name = null, + .description = "Enable float16buffer Capability.", .dependencies = featureSet(&[_]Feature{ .v1_0, }), }; result[@intFromEnum(Feature.float64)] = .{ .llvm_name = null, - .description = "Enable Float64 capability", + .description = "Enable float64 Capability.", .dependencies = featureSet(&[_]Feature{ .v1_0, }), }; + result[@intFromEnum(Feature.float8cooperative_matrix_ext)] = .{ + .llvm_name = null, + .description = "Enable float8cooperative_matrix_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_float8, + .v1_0, + }), + }; + result[@intFromEnum(Feature.float8ext)] = .{ + .llvm_name = null, + .description = "Enable float8ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_float8, + .v1_0, + }), + }; + result[@intFromEnum(Feature.float_controls2)] = .{ + .llvm_name = null, + .description = "Enable float_controls2 Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_float_controls2, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fmakhr)] = .{ + .llvm_name = null, + .description = "Enable fmakhr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_fma, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fragment_barycentric_khr)] = .{ + .llvm_name = null, + .description = "Enable fragment_barycentric_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_fragment_shader_barycentric, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fragment_density_ext)] = .{ + .llvm_name = null, + .description = "Enable fragment_density_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_fragment_invocation_density, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fragment_fully_covered_ext)] = .{ + .llvm_name = null, + .description = "Enable fragment_fully_covered_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_fragment_fully_covered, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fragment_shader_pixel_interlock_ext)] = .{ + .llvm_name = null, + .description = "Enable fragment_shader_pixel_interlock_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_fragment_shader_interlock, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fragment_shader_sample_interlock_ext)] = .{ + .llvm_name = null, + .description = "Enable fragment_shader_sample_interlock_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_fragment_shader_interlock, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fragment_shader_shading_rate_interlock_ext)] = .{ + .llvm_name = null, + .description = "Enable fragment_shader_shading_rate_interlock_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_fragment_shader_interlock, + .v1_0, + }), + }; + result[@intFromEnum(Feature.fragment_shading_rate_khr)] = .{ + .llvm_name = null, + .description = "Enable fragment_shading_rate_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_fragment_shading_rate, + .v1_0, + }), + }; result[@intFromEnum(Feature.generic_pointer)] = .{ .llvm_name = null, - .description = "Enable GenericPointer capability", + .description = "Enable generic_pointer Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.geometry)] = .{ + .llvm_name = null, + .description = "Enable geometry Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.geometry_point_size)] = .{ + .llvm_name = null, + .description = "Enable geometry_point_size Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.geometry_streams)] = .{ + .llvm_name = null, + .description = "Enable geometry_streams Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.group_non_uniform)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_arithmetic)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_arithmetic Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_ballot)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_ballot Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_clustered)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_clustered Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_partitioned_ext)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_partitioned_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_subgroup_partitioned, + .v1_0, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_quad)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_quad Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_rotate_khr)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_rotate_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_subgroup_rotate, + .v1_0, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_shuffle)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_shuffle Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_shuffle_relative)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_shuffle_relative Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_non_uniform_vote)] = .{ + .llvm_name = null, + .description = "Enable group_non_uniform_vote Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_3, + }), + }; + result[@intFromEnum(Feature.group_uniform_arithmetic_khr)] = .{ + .llvm_name = null, + .description = "Enable group_uniform_arithmetic_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_uniform_group_instructions, + .v1_0, + }), + }; + result[@intFromEnum(Feature.groups)] = .{ + .llvm_name = null, + .description = "Enable groups Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_basic)] = .{ + .llvm_name = null, + .description = "Enable image_basic Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_buffer)] = .{ + .llvm_name = null, + .description = "Enable image_buffer Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_cube_array)] = .{ + .llvm_name = null, + .description = "Enable image_cube_array Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_gather_extended)] = .{ + .llvm_name = null, + .description = "Enable image_gather_extended Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_mipmap)] = .{ + .llvm_name = null, + .description = "Enable image_mipmap Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_ms_array)] = .{ + .llvm_name = null, + .description = "Enable image_ms_array Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_query)] = .{ + .llvm_name = null, + .description = "Enable image_query Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_read_write)] = .{ + .llvm_name = null, + .description = "Enable image_read_write Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.image_rect)] = .{ + .llvm_name = null, + .description = "Enable image_rect Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.input_attachment)] = .{ + .llvm_name = null, + .description = "Enable input_attachment Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.input_attachment_array_dynamic_indexing)] = .{ + .llvm_name = null, + .description = "Enable input_attachment_array_dynamic_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.input_attachment_array_non_uniform_indexing)] = .{ + .llvm_name = null, + .description = "Enable input_attachment_array_non_uniform_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.int16)] = .{ + .llvm_name = null, + .description = "Enable int16 Capability.", .dependencies = featureSet(&[_]Feature{ .v1_0, }), }; result[@intFromEnum(Feature.int64)] = .{ .llvm_name = null, - .description = "Enable Int64 capability", + .description = "Enable int64 Capability.", .dependencies = featureSet(&[_]Feature{ .v1_0, }), }; + result[@intFromEnum(Feature.int64atomics)] = .{ + .llvm_name = null, + .description = "Enable int64atomics Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.int64image_ext)] = .{ + .llvm_name = null, + .description = "Enable int64image_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_image_int64, + .v1_0, + }), + }; + result[@intFromEnum(Feature.int8)] = .{ + .llvm_name = null, + .description = "Enable int8 Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.interpolation_function)] = .{ + .llvm_name = null, + .description = "Enable interpolation_function Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.kernel)] = .{ + .llvm_name = null, + .description = "Enable kernel Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.linkage)] = .{ + .llvm_name = null, + .description = "Enable linkage Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.literal_sampler)] = .{ + .llvm_name = null, + .description = "Enable literal_sampler Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.long_vector_ext)] = .{ + .llvm_name = null, + .description = "Enable long_vector_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_long_vector, + .v1_0, + }), + }; + result[@intFromEnum(Feature.matrix)] = .{ + .llvm_name = null, + .description = "Enable matrix Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.mesh_shading_ext)] = .{ + .llvm_name = null, + .description = "Enable mesh_shading_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_mesh_shader, + .v1_0, + }), + }; + result[@intFromEnum(Feature.min_lod)] = .{ + .llvm_name = null, + .description = "Enable min_lod Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.multi_view)] = .{ + .llvm_name = null, + .description = "Enable multi_view Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_multiview, + .v1_3, + }), + }; + result[@intFromEnum(Feature.multi_viewport)] = .{ + .llvm_name = null, + .description = "Enable multi_viewport Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.named_barrier)] = .{ + .llvm_name = null, + .description = "Enable named_barrier Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_1, + }), + }; + result[@intFromEnum(Feature.opt_none_ext)] = .{ + .llvm_name = null, + .description = "Enable opt_none_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_optnone, + .v1_0, + }), + }; + result[@intFromEnum(Feature.physical_storage_buffer_addresses)] = .{ + .llvm_name = null, + .description = "Enable physical_storage_buffer_addresses Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_physical_storage_buffer, + .SPV_KHR_physical_storage_buffer, + .v1_5, + }), + }; + result[@intFromEnum(Feature.pipe_storage)] = .{ + .llvm_name = null, + .description = "Enable pipe_storage Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_1, + }), + }; + result[@intFromEnum(Feature.pipes)] = .{ + .llvm_name = null, + .description = "Enable pipes Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.poison_freeze_khr)] = .{ + .llvm_name = null, + .description = "Enable poison_freeze_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_poison_freeze, + .v1_0, + }), + }; + result[@intFromEnum(Feature.quad_control_khr)] = .{ + .llvm_name = null, + .description = "Enable quad_control_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_quad_control, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_cull_mask_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_cull_mask_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_cull_mask, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_query_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_query_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_query, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_query_position_fetch_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_query_position_fetch_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_tracing_position_fetch, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_query_provisional_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_query_provisional_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_query, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_tracing_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_tracing_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_tracing, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_tracing_opacity_micromap_ext)] = .{ + .llvm_name = null, + .description = "Enable ray_tracing_opacity_micromap_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_opacity_micromap, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_tracing_position_fetch_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_tracing_position_fetch_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_tracing_position_fetch, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_tracing_provisional_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_tracing_provisional_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_tracing, + .v1_0, + }), + }; + result[@intFromEnum(Feature.ray_traversal_primitive_culling_khr)] = .{ + .llvm_name = null, + .description = "Enable ray_traversal_primitive_culling_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_ray_query, + .SPV_KHR_ray_tracing, + .v1_0, + }), + }; + result[@intFromEnum(Feature.replicated_composites_ext)] = .{ + .llvm_name = null, + .description = "Enable replicated_composites_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_replicated_composites, + .v1_0, + }), + }; + result[@intFromEnum(Feature.runtime_descriptor_array)] = .{ + .llvm_name = null, + .description = "Enable runtime_descriptor_array Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.sample_mask_post_depth_coverage)] = .{ + .llvm_name = null, + .description = "Enable sample_mask_post_depth_coverage Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_post_depth_coverage, + .v1_0, + }), + }; + result[@intFromEnum(Feature.sample_rate_shading)] = .{ + .llvm_name = null, + .description = "Enable sample_rate_shading Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.sampled_buffer)] = .{ + .llvm_name = null, + .description = "Enable sampled_buffer Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.sampled_cube_array)] = .{ + .llvm_name = null, + .description = "Enable sampled_cube_array Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.sampled_image_array_dynamic_indexing)] = .{ + .llvm_name = null, + .description = "Enable sampled_image_array_dynamic_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.sampled_image_array_non_uniform_indexing)] = .{ + .llvm_name = null, + .description = "Enable sampled_image_array_non_uniform_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.sampled_rect)] = .{ + .llvm_name = null, + .description = "Enable sampled_rect Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.shader)] = .{ + .llvm_name = null, + .description = "Enable shader Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.shader64bit_indexing_ext)] = .{ + .llvm_name = null, + .description = "Enable shader64bit_indexing_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_64bit_indexing, + .v1_0, + }), + }; + result[@intFromEnum(Feature.shader_clock_khr)] = .{ + .llvm_name = null, + .description = "Enable shader_clock_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_shader_clock, + .v1_0, + }), + }; + result[@intFromEnum(Feature.shader_invocation_reorder_ext)] = .{ + .llvm_name = null, + .description = "Enable shader_invocation_reorder_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_invocation_reorder, + .v1_0, + }), + }; + result[@intFromEnum(Feature.shader_layer)] = .{ + .llvm_name = null, + .description = "Enable shader_layer Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_5, + }), + }; + result[@intFromEnum(Feature.shader_non_uniform)] = .{ + .llvm_name = null, + .description = "Enable shader_non_uniform Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.shader_viewport_index)] = .{ + .llvm_name = null, + .description = "Enable shader_viewport_index Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_5, + }), + }; + result[@intFromEnum(Feature.shader_viewport_index_layer_ext)] = .{ + .llvm_name = null, + .description = "Enable shader_viewport_index_layer_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_viewport_index_layer, + .v1_0, + }), + }; + result[@intFromEnum(Feature.signed_zero_inf_nan_preserve)] = .{ + .llvm_name = null, + .description = "Enable signed_zero_inf_nan_preserve Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_float_controls, + .v1_4, + }), + }; + result[@intFromEnum(Feature.sparse_residency)] = .{ + .llvm_name = null, + .description = "Enable sparse_residency Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.SPV_EXT_arithmetic_fence)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_arithmetic_fence Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_demote_to_helper_invocation)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_demote_to_helper_invocation Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_descriptor_heap)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_descriptor_heap Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_descriptor_indexing)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_descriptor_indexing Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_float8)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_float8 Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_fragment_fully_covered)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_fragment_fully_covered Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_fragment_invocation_density)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_fragment_invocation_density Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_fragment_shader_interlock)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_fragment_shader_interlock Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_long_vector)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_long_vector Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_mesh_shader)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_mesh_shader Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_opacity_micromap)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_opacity_micromap Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_optnone)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_optnone Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_physical_storage_buffer)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_physical_storage_buffer Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_replicated_composites)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_replicated_composites Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_64bit_indexing)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_64bit_indexing Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_atomic_float16_add)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_atomic_float16_add Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_atomic_float_add)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_atomic_float_add Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_atomic_float_min_max)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_atomic_float_min_max Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_image_int64)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_image_int64 Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_invocation_reorder)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_invocation_reorder Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_stencil_export)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_stencil_export Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_subgroup_partitioned)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_subgroup_partitioned Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_tile_image)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_tile_image Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_EXT_shader_viewport_index_layer)] = .{ + .llvm_name = null, + .description = "Enable SPV_EXT_shader_viewport_index_layer Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_16bit_storage)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_16bit_storage Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_8bit_storage)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_8bit_storage Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_abort)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_abort Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_bfloat16)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_bfloat16 Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_bit_instructions)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_bit_instructions Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_compute_shader_derivatives)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_compute_shader_derivatives Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_constant_data)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_constant_data Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_cooperative_matrix)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_cooperative_matrix Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_device_group)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_device_group Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_expect_assume)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_expect_assume Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_float_controls)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_float_controls Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_float_controls2)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_float_controls2 Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_fma)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_fma Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_fragment_shader_barycentric)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_fragment_shader_barycentric Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_fragment_shading_rate)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_fragment_shading_rate Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_integer_dot_product)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_integer_dot_product Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_multiview)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_multiview Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_physical_storage_buffer)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_physical_storage_buffer Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_poison_freeze)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_poison_freeze Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_post_depth_coverage)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_post_depth_coverage Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_quad_control)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_quad_control Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_ray_cull_mask)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_ray_cull_mask Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_ray_query)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_ray_query Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_ray_tracing)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_ray_tracing Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_ray_tracing_position_fetch)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_ray_tracing_position_fetch Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_shader_atomic_counter_ops)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_shader_atomic_counter_ops Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_shader_ballot)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_shader_ballot Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_shader_clock)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_shader_clock Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_shader_draw_parameters)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_shader_draw_parameters Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_subgroup_rotate)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_subgroup_rotate Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_subgroup_vote)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_subgroup_vote Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_uniform_group_instructions)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_uniform_group_instructions Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_untyped_pointers)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_untyped_pointers Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_variable_pointers)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_variable_pointers Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_vulkan_memory_model)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_vulkan_memory_model Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.SPV_KHR_workgroup_memory_explicit_layout)] = .{ + .llvm_name = null, + .description = "Enable SPV_KHR_workgroup_memory_explicit_layout Extension.", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@intFromEnum(Feature.stencil_export_ext)] = .{ + .llvm_name = null, + .description = "Enable stencil_export_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_stencil_export, + .v1_0, + }), + }; + result[@intFromEnum(Feature.storage_buffer16bit_access)] = .{ + .llvm_name = null, + .description = "Enable storage_buffer16bit_access Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_16bit_storage, + .v1_3, + }), + }; + result[@intFromEnum(Feature.storage_buffer8bit_access)] = .{ + .llvm_name = null, + .description = "Enable storage_buffer8bit_access Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_8bit_storage, + .v1_5, + }), + }; + result[@intFromEnum(Feature.storage_buffer_array_dynamic_indexing)] = .{ + .llvm_name = null, + .description = "Enable storage_buffer_array_dynamic_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.storage_buffer_array_non_uniform_indexing)] = .{ + .llvm_name = null, + .description = "Enable storage_buffer_array_non_uniform_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.storage_image_array_dynamic_indexing)] = .{ + .llvm_name = null, + .description = "Enable storage_image_array_dynamic_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.storage_image_array_non_uniform_indexing)] = .{ + .llvm_name = null, + .description = "Enable storage_image_array_non_uniform_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.storage_image_extended_formats)] = .{ + .llvm_name = null, + .description = "Enable storage_image_extended_formats Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.storage_image_multisample)] = .{ + .llvm_name = null, + .description = "Enable storage_image_multisample Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.storage_image_read_without_format)] = .{ + .llvm_name = null, + .description = "Enable storage_image_read_without_format Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.storage_image_write_without_format)] = .{ + .llvm_name = null, + .description = "Enable storage_image_write_without_format Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.storage_input_output16)] = .{ + .llvm_name = null, + .description = "Enable storage_input_output16 Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_16bit_storage, + .v1_3, + }), + }; result[@intFromEnum(Feature.storage_push_constant16)] = .{ .llvm_name = null, - .description = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability", + .description = "Enable storage_push_constant16 Capability.", .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_16bit_storage, .v1_3, }), }; + result[@intFromEnum(Feature.storage_push_constant8)] = .{ + .llvm_name = null, + .description = "Enable storage_push_constant8 Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_8bit_storage, + .v1_5, + }), + }; + result[@intFromEnum(Feature.storage_texel_buffer_array_dynamic_indexing)] = .{ + .llvm_name = null, + .description = "Enable storage_texel_buffer_array_dynamic_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.storage_texel_buffer_array_non_uniform_indexing)] = .{ + .llvm_name = null, + .description = "Enable storage_texel_buffer_array_non_uniform_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.subgroup_ballot_khr)] = .{ + .llvm_name = null, + .description = "Enable subgroup_ballot_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_shader_ballot, + .v1_0, + }), + }; + result[@intFromEnum(Feature.subgroup_dispatch)] = .{ + .llvm_name = null, + .description = "Enable subgroup_dispatch Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_1, + }), + }; + result[@intFromEnum(Feature.subgroup_vote_khr)] = .{ + .llvm_name = null, + .description = "Enable subgroup_vote_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_subgroup_vote, + .v1_0, + }), + }; + result[@intFromEnum(Feature.tessellation)] = .{ + .llvm_name = null, + .description = "Enable tessellation Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.tessellation_point_size)] = .{ + .llvm_name = null, + .description = "Enable tessellation_point_size Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.tile_image_color_read_access_ext)] = .{ + .llvm_name = null, + .description = "Enable tile_image_color_read_access_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_tile_image, + .v1_0, + }), + }; + result[@intFromEnum(Feature.tile_image_depth_read_access_ext)] = .{ + .llvm_name = null, + .description = "Enable tile_image_depth_read_access_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_tile_image, + .v1_0, + }), + }; + result[@intFromEnum(Feature.tile_image_stencil_read_access_ext)] = .{ + .llvm_name = null, + .description = "Enable tile_image_stencil_read_access_ext Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_shader_tile_image, + .v1_0, + }), + }; + result[@intFromEnum(Feature.transform_feedback)] = .{ + .llvm_name = null, + .description = "Enable transform_feedback Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.uniform_and_storage_buffer16bit_access)] = .{ + .llvm_name = null, + .description = "Enable uniform_and_storage_buffer16bit_access Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_16bit_storage, + .v1_3, + }), + }; + result[@intFromEnum(Feature.uniform_and_storage_buffer8bit_access)] = .{ + .llvm_name = null, + .description = "Enable uniform_and_storage_buffer8bit_access Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_8bit_storage, + .v1_5, + }), + }; + result[@intFromEnum(Feature.uniform_buffer_array_dynamic_indexing)] = .{ + .llvm_name = null, + .description = "Enable uniform_buffer_array_dynamic_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_0, + }), + }; + result[@intFromEnum(Feature.uniform_buffer_array_non_uniform_indexing)] = .{ + .llvm_name = null, + .description = "Enable uniform_buffer_array_non_uniform_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.uniform_decoration)] = .{ + .llvm_name = null, + .description = "Enable uniform_decoration Capability.", + .dependencies = featureSet(&[_]Feature{ + .v1_6, + }), + }; + result[@intFromEnum(Feature.uniform_texel_buffer_array_dynamic_indexing)] = .{ + .llvm_name = null, + .description = "Enable uniform_texel_buffer_array_dynamic_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.uniform_texel_buffer_array_non_uniform_indexing)] = .{ + .llvm_name = null, + .description = "Enable uniform_texel_buffer_array_non_uniform_indexing Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_EXT_descriptor_indexing, + .v1_5, + }), + }; + result[@intFromEnum(Feature.untyped_pointers_khr)] = .{ + .llvm_name = null, + .description = "Enable untyped_pointers_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_untyped_pointers, + .v1_0, + }), + }; result[@intFromEnum(Feature.v1_0)] = .{ .llvm_name = null, - .description = "Enable version 1.0", + .description = "Enable v1_0 Extension.", .dependencies = featureSet(&[_]Feature{}), }; result[@intFromEnum(Feature.v1_1)] = .{ .llvm_name = null, - .description = "Enable version 1.1", - .dependencies = featureSet(&[_]Feature{ - .v1_0, - }), + .description = "Enable v1_1 Extension.", + .dependencies = featureSet(&[_]Feature{}), }; result[@intFromEnum(Feature.v1_2)] = .{ .llvm_name = null, - .description = "Enable version 1.2", - .dependencies = featureSet(&[_]Feature{ - .v1_1, - }), + .description = "Enable v1_2 Extension.", + .dependencies = featureSet(&[_]Feature{}), }; result[@intFromEnum(Feature.v1_3)] = .{ .llvm_name = null, - .description = "Enable version 1.3", - .dependencies = featureSet(&[_]Feature{ - .v1_2, - }), + .description = "Enable v1_3 Extension.", + .dependencies = featureSet(&[_]Feature{}), }; result[@intFromEnum(Feature.v1_4)] = .{ .llvm_name = null, - .description = "Enable version 1.4", - .dependencies = featureSet(&[_]Feature{ - .v1_3, - }), + .description = "Enable v1_4 Extension.", + .dependencies = featureSet(&[_]Feature{}), }; result[@intFromEnum(Feature.v1_5)] = .{ .llvm_name = null, - .description = "Enable version 1.5", - .dependencies = featureSet(&[_]Feature{ - .v1_4, - }), + .description = "Enable v1_5 Extension.", + .dependencies = featureSet(&[_]Feature{}), }; result[@intFromEnum(Feature.v1_6)] = .{ .llvm_name = null, - .description = "Enable version 1.6", - .dependencies = featureSet(&[_]Feature{ - .v1_5, - }), + .description = "Enable v1_6 Extension.", + .dependencies = featureSet(&[_]Feature{}), }; result[@intFromEnum(Feature.variable_pointers)] = .{ .llvm_name = null, - .description = "Enable SPV_KHR_variable_pointers extension and the VariablePointers capability", + .description = "Enable variable_pointers Capability.", .dependencies = featureSet(&[_]Feature{ - .v1_0, + .SPV_KHR_variable_pointers, + .v1_3, + }), + }; + result[@intFromEnum(Feature.variable_pointers_storage_buffer)] = .{ + .llvm_name = null, + .description = "Enable variable_pointers_storage_buffer Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_variable_pointers, + .v1_3, }), }; result[@intFromEnum(Feature.vector16)] = .{ .llvm_name = null, - .description = "Enable Vector16 capability", + .description = "Enable vector16 Capability.", .dependencies = featureSet(&[_]Feature{ .v1_0, }), }; + result[@intFromEnum(Feature.vulkan_memory_model)] = .{ + .llvm_name = null, + .description = "Enable vulkan_memory_model Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_vulkan_memory_model, + .v1_5, + }), + }; + result[@intFromEnum(Feature.vulkan_memory_model_device_scope)] = .{ + .llvm_name = null, + .description = "Enable vulkan_memory_model_device_scope Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_vulkan_memory_model, + .v1_5, + }), + }; + result[@intFromEnum(Feature.workgroup_memory_explicit_layout16bit_access_khr)] = .{ + .llvm_name = null, + .description = "Enable workgroup_memory_explicit_layout16bit_access_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_workgroup_memory_explicit_layout, + .v1_0, + }), + }; + result[@intFromEnum(Feature.workgroup_memory_explicit_layout8bit_access_khr)] = .{ + .llvm_name = null, + .description = "Enable workgroup_memory_explicit_layout8bit_access_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_workgroup_memory_explicit_layout, + .v1_0, + }), + }; + result[@intFromEnum(Feature.workgroup_memory_explicit_layout_khr)] = .{ + .llvm_name = null, + .description = "Enable workgroup_memory_explicit_layout_khr Capability.", + .dependencies = featureSet(&[_]Feature{ + .SPV_KHR_workgroup_memory_explicit_layout, + .v1_0, + }), + }; const ti = @typeInfo(Feature); for (&result, 0..) |*elem, i| { elem.index = i; diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index d7e4f0f0190058dbfa8baadd99cee183826cccc6..4f7b457c287f65311239290cce9019c6a9622cf7 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -1171,7 +1171,7 @@ const LinuxThreadImpl = struct { [len] "{ecx}" (self.mapped.len), ), .x86_64 => asm volatile (switch (target.abi) { - .gnux32, .muslx32 => + .gnux32, .muslx32, .x32 => \\ movl $0x4000000b, %%eax # SYS_munmap \\ syscall \\ movl $0x4000003c, %%eax # SYS_exit @@ -1286,7 +1286,7 @@ const LinuxThreadImpl = struct { [len] "{$5}" (self.mapped.len), ), .mips64, .mips64el => asm volatile (switch (target.abi) { - .gnuabin32, .muslabin32 => + .gnuabin32, .muslabin32, .abin32 => \\ li $v0, 6011 # SYS_munmap \\ syscall \\ li $v0, 6058 # SYS_exit diff --git a/lib/std/c.zig b/lib/std/c.zig index 5c61cbb676d9e73309af48f0d898cb2e9ddab48d..13a2b7eb4e6607ba9ea1fba0fe6a19feec998890 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -11389,6 +11389,7 @@ pub const clock_res_t = darwin.clock_res_t; pub const @"close$NOCANCEL" = darwin.@"close$NOCANCEL"; pub const dispatch = darwin.dispatch; pub const fcopyfile = darwin.fcopyfile; +pub const renameatx_np = darwin.renameatx_np; pub const host_t = darwin.host_t; pub const integer_t = darwin.integer_t; pub const ipc_space_t = darwin.ipc_space_t; diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 7e475a057b87df7e68bbce4c5c681510405bd780..1a24cb11331fef306846d1686119f41b0be74010 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -380,6 +380,18 @@ pub const copyfile_state_t = *opaque {}; pub extern "c" fn fcopyfile(from: fd_t, to: fd_t, state: ?copyfile_state_t, flags: COPYFILE) c_int; pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize; +pub const RENAME = packed struct(u32) { + SECLUDE: bool = false, + SWAP: bool = false, + EXCL: bool = false, + RESERVED1: bool = false, + NOFOLLOW_ANY: bool = false, + RESOLVE_BENEATH: bool = false, + _: u26 = 0, +}; + +pub extern "c" fn renameatx_np(fromfd: c_int, from: [*:0]const u8, tofd: c_int, to: [*:0]const u8, flags: RENAME) c_int; + pub extern "c" fn mach_absolute_time() u64; pub extern "c" fn mach_continuous_time() u64; pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) kern_return_t; diff --git a/lib/std/coff.zig b/lib/std/coff.zig index 6286ad5657b0a660baa2fb7d3966aadc02b3572b..d855495e399fff55db9a02ade2be45d0566a7095 100644 --- a/lib/std/coff.zig +++ b/lib/std/coff.zig @@ -2,6 +2,12 @@ const std = @import("std.zig"); const assert = std.debug.assert; const mem = std.mem; +pub const archive_signature = "!\n"; +pub const archive_end_of_header = "`\n"; + +pub const pe_signature = "PE\x00\x00"; +pub const pe_pointer_offset = 0x3C; + pub const Header = extern struct { /// The number that identifies the type of target machine. machine: IMAGE.FILE.MACHINE, @@ -367,6 +373,36 @@ pub const DebugType = enum(u32) { _, }; +pub fn TlsDirectoryEntry(comptime magic: std.coff.OptionalHeader.Magic) type { + return switch (magic) { + _ => comptime unreachable, + .PE32 => extern struct { + raw_data_start_va: u32, + raw_data_end_va: u32, + tls_index_va: u32, + callbacks_va: u32, + size_of_zero_fill: u32, + characteristics: packed struct(u32) { + _reserved_0: u19, + alignment: SectionHeader.Flags.Align, + _reserved_1: u9, + }, + }, + .@"PE32+" => extern struct { + raw_data_start_va: u64, + raw_data_end_va: u64, + tls_index_va: u64, + callbacks_va: u64, + size_of_zero_fill: u32, + characteristics: packed struct(u32) { + _reserved_0: u19, + alignment: SectionHeader.Flags.Align, + _reserved_1: u9, + }, + }, + }; +} + pub const ImportDirectoryEntry = extern struct { /// The RVA of the import lookup table. /// This table contains a name or ordinal for each import. @@ -389,56 +425,28 @@ pub const ImportDirectoryEntry = extern struct { import_address_table_rva: u32, }; -pub const ImportLookupEntry32 = struct { - pub const ByName = packed struct(u32) { - name_table_rva: u31, - flag: u1 = 0, +pub fn ImportLookupTableEntry(comptime magic: std.coff.OptionalHeader.Magic) type { + const Payload = packed union(u31) { + ordinal: packed struct(u31) { + ordinal: u16, + _: u15 = 0, + }, + hint_name_rva: u31, }; - pub const ByOrdinal = packed struct(u32) { - ordinal_number: u16, - unused: u15 = 0, - flag: u1 = 1, + return switch (magic) { + _ => comptime unreachable, + .PE32 => packed struct(u32) { + payload: Payload, + is_ordinal: bool, + }, + .@"PE32+" => packed struct(u64) { + payload: Payload, + _: u32 = 0, + is_ordinal: bool, + }, }; - - const mask = 0x80000000; - - pub fn getImportByName(raw: u32) ?ByName { - if (mask & raw != 0) return null; - return @as(ByName, @bitCast(raw)); - } - - pub fn getImportByOrdinal(raw: u32) ?ByOrdinal { - if (mask & raw == 0) return null; - return @as(ByOrdinal, @bitCast(raw)); - } -}; - -pub const ImportLookupEntry64 = struct { - pub const ByName = packed struct(u64) { - name_table_rva: u31, - unused: u32 = 0, - flag: u1 = 0, - }; - - pub const ByOrdinal = packed struct(u64) { - ordinal_number: u16, - unused: u47 = 0, - flag: u1 = 1, - }; - - const mask = 0x8000000000000000; - - pub fn getImportByName(raw: u64) ?ByName { - if (mask & raw != 0) return null; - return @as(ByName, @bitCast(raw)); - } - - pub fn getImportByOrdinal(raw: u64) ?ByOrdinal { - if (mask & raw == 0) return null; - return @as(ByOrdinal, @bitCast(raw)); - } -}; +} /// Every name ends with a NULL byte. IF the NULL byte does not fall on /// 2byte boundary, the entry structure is padded to ensure 2byte alignment. @@ -452,6 +460,50 @@ pub const ImportHintNameEntry = extern struct { name: [1]u8, }; +pub const ExportDirectoryTable = extern struct { + /// Reserved + flags: u32, + + /// Creation time of this table + time_date_stamp: u32, + + major_version: u16, + minor_version: u16, + + /// The address of an ASCII string that contains the name of the DLL. + /// This address is relative to the image base. + name_rva: u32, + + /// The ordinal of the first export in this image + ordinal_base: u32, + + /// Number of entries in the export address table + number_of_entries: u32, + + /// Number of entries in the name pointer table and ordinal table + number_of_names: u32, + + export_address_table_rva: u32, + name_pointer_table_rva: u32, + ordinal_table_rva: u32, +}; + +pub const ExportAddressTableEntry = extern struct { + /// If this address is within the export section, then this is the address of the export + /// Otherwise, this is the address of a string that specfies a symbol in another DLL: + /// . + /// .# + export_or_forwarder_rva: u32, +}; + +pub const ExportNamePointerTableEntry = extern struct { + name_rva: u32, +}; + +pub const ExportOrdinalTableEntry = extern struct { + unbiased_ordinal: u16, +}; + pub const SectionHeader = extern struct { name: [8]u8, virtual_size: u32, @@ -610,11 +662,15 @@ pub const SectionHeader = extern struct { std.debug.assert(std.math.isPowerOfTwo(n)); return @enumFromInt(@ctz(n) + 1); } + + pub fn alignment(a: Align) ?std.mem.Alignment { + return .fromByteUnitsOptional(a.toByteUnits() orelse null); + } }; }; }; -pub const Symbol = struct { +pub const Symbol = extern struct { name: [8]u8, value: u32, section_number: SectionNumber, @@ -622,7 +678,7 @@ pub const Symbol = struct { storage_class: StorageClass, number_of_aux_symbols: u8, - pub fn sizeOf() usize { + pub fn sizeOf() comptime_int { return 18; } @@ -639,18 +695,18 @@ pub const Symbol = struct { } }; -pub const SectionNumber = enum(u16) { +pub const SectionNumber = enum(i16) { /// The symbol record is not yet assigned a section. /// A value of zero indicates that a reference to an external symbol is defined elsewhere. /// A value of non-zero is a common symbol with a size that is specified by the value. UNDEFINED = 0, /// The symbol has an absolute (non-relocatable) value and is not an address. - ABSOLUTE = 0xffff, + ABSOLUTE = -1, /// The symbol provides general type or debugging information but does not correspond to a section. /// Microsoft tools use this setting along with .file records (storage class FILE). - DEBUG = 0xfffe, + DEBUG = -2, _, }; @@ -822,7 +878,7 @@ pub const StorageClass = enum(u8) { _, }; -pub const FunctionDefinition = struct { +pub const FunctionDefinition = extern struct { /// The symbol-table index of the corresponding .bf (begin function) symbol record. tag_index: u32, @@ -841,7 +897,7 @@ pub const FunctionDefinition = struct { unused: [2]u8, }; -pub const SectionDefinition = struct { +pub const SectionDefinition = extern struct { /// The size of section data; the same as SizeOfRawData in the section header. length: u32, @@ -863,7 +919,7 @@ pub const SectionDefinition = struct { unused: [3]u8, }; -pub const FileDefinition = struct { +pub const FileDefinition = extern struct { /// An ANSI string that gives the name of the source file. /// This is padded with nulls if it is less than the maximum length. file_name: [18]u8, @@ -874,7 +930,7 @@ pub const FileDefinition = struct { } }; -pub const WeakExternalDefinition = struct { +pub const WeakExternalDefinition = extern struct { /// The symbol-table index of sym2, the symbol to be linked if sym1 is not found. tag_index: u32, @@ -885,7 +941,7 @@ pub const WeakExternalDefinition = struct { unused: [10]u8, - pub fn sizeOf() usize { + pub fn sizeOf() comptime_int { return 18; } }; @@ -933,7 +989,7 @@ pub const ComdatSelection = enum(u8) { _, }; -pub const DebugInfoDefinition = struct { +pub const DebugInfoDefinition = extern struct { unused_1: [4]u8, /// The actual ordinal line number (1, 2, 3, and so on) within the source file, corresponding to the .bf or .ef record. @@ -971,13 +1027,10 @@ pub const Coff = struct { // The lifetime of `data` must be longer than the lifetime of the returned Coff pub fn init(data: []const u8, is_loaded: bool) error{ EndOfStream, MissingPEHeader }!Coff { - const pe_pointer_offset = 0x3C; - const pe_magic = "PE\x00\x00"; - if (data.len < pe_pointer_offset + 4) return error.EndOfStream; const header_offset = mem.readInt(u32, data[pe_pointer_offset..][0..4], .little); if (data.len < header_offset + 4) return error.EndOfStream; - const is_image = mem.eql(u8, data[header_offset..][0..4], pe_magic); + const is_image = mem.eql(u8, data[header_offset..][0..4], pe_signature); const coff: Coff = .{ .data = data, @@ -1348,6 +1401,10 @@ pub const Relocation = extern struct { virtual_address: u32, symbol_table_index: u32, type: u16, + + pub fn sizeOf() comptime_int { + return 10; + } }; pub const IMAGE = struct { @@ -1465,6 +1522,36 @@ pub const IMAGE = struct { _, /// AXP 64 (Same as Alpha 64) pub const AXP64: IMAGE.FILE.MACHINE = .ALPHA64; + + pub fn RelocationType(comptime machine: IMAGE.FILE.MACHINE) type { + return switch (machine) { + .AMD64, + => REL.AMD64, + .ARM, + .ARMNT, + => REL.ARM, + .ARM64, + .ARM64EC, + .ARM64X, + => REL.ARM64, + .I386 => REL.I386, + .IA64 => REL.IA64, + .M32R => REL.M32R, + .MIPS16, + .MIPSFPU, + .MIPSFPU16, + => REL.MIPS, + .POWERPC, + .POWERPCFP, + => REL.PPC, + .SH3, + .SH3DSP, + .SH4, + .SH5, + => REL.SH, + else => void, + }; + } }; }; @@ -1919,3 +2006,100 @@ pub const IMAGE = struct { }; }; }; + +pub const ArchiveMemberHeader = extern struct { + /// Left-justified '/' terminated member name + name: [16]u8, + /// Left-justified ASCII decimal: seconds since January 1st, 1970 + date: [12]u8, + /// Left-justified ASCII decimal: user id + user_id: [6]u8, + /// Left-justified ASCII decimal: group id + group_id: [6]u8, + /// Left-justified ASCII octal: file mode + file_mode: [8]u8, + /// Left-justified ASCII decimal: size of the member following this header, + /// not including the size of this header. + size: [10]u8, + /// The literal string '`\n' + end_of_header: [2]u8, + + /// Extracts the name of the member by either reading it directly from + /// the header, or by finding it inside the longnames member, if provided. + pub fn parseName( + self: *const ArchiveMemberHeader, + opt_longnames: ?[]const u8, + ) ![]const u8 { + const trim = std.mem.trimEnd(u8, &self.name, &.{' '}); + + if (trim.len == 0) return error.BadName; + return if (trim[0] == '/') name: { + if (trim.len == 1 or + trim.len == 2 and trim[1] == '/') + break :name trim; + + const offset = std.fmt.parseUnsigned(u50, trim[1..], 10) catch + return error.BadName; + + if (opt_longnames) |longnames| { + if (offset >= longnames.len) return error.BadName; + break :name std.mem.sliceTo(longnames[@intCast(offset)..], 0); + } else return error.NoLongNames; + } else if (trim[trim.len - 1] == '/') + trim[0 .. trim.len - 1] + else + return error.BadName; + } + + fn parseField(field: []const u8, T: type, base: u8) !T { + if (std.mem.allEqual(u8, field, ' ')) return 0; + if (field[0] == '-') + return @bitCast(try std.fmt.parseInt( + @Int(.signed, @typeInfo(T).int.bits), + std.mem.trimEnd(u8, field, &.{' '}), + base, + )); + + return std.fmt.parseUnsigned(T, std.mem.trimEnd(u8, field, &.{' '}), base); + } + + pub fn parseDate(self: *const ArchiveMemberHeader) !u40 { + return parseField(&self.date, u40, 10); + } + + pub fn parseUserId(self: *const ArchiveMemberHeader) !u20 { + return parseField(&self.user_id, u20, 10); + } + + pub fn parseGroupId(self: *const ArchiveMemberHeader) !u20 { + return parseField(&self.group_id, u20, 10); + } + + pub fn parseFileMode(self: *const ArchiveMemberHeader) !u20 { + return parseField(&self.group_id, u20, 8); + } + + pub fn parseSize(self: *const ArchiveMemberHeader) !u34 { + return parseField(&self.size, u34, 10); + } + + pub const Kind = enum { + first_linker, + second_linker, + longnames, + coff, + import, + }; +}; + +pub const LineNumber = extern struct { + type: extern union { + symbol_table_index: u32, + virtual_address: u32, + }, + line_number: u16, + + pub fn sizeOf() comptime_int { + return 6; + } +}; diff --git a/lib/std/compress/flate/Decompress.zig b/lib/std/compress/flate/Decompress.zig index 27743e23bfd5d63f791297fa857143db88c21c5a..8251c0c5f230c42565d77b6b05dca38be0cd6e11 100644 --- a/lib/std/compress/flate/Decompress.zig +++ b/lib/std/compress/flate/Decompress.zig @@ -578,7 +578,7 @@ fn peekBitsShortEnding(d: *Decompress, n: u4) !u16 { } fn tossBitsShort(d: *Decompress, n: u4) !void { - if (d.input.bufferedLen() * 8 + d.consumed_bits < n) return error.EndOfStream; + if (d.input.bufferedLen() * 8 - d.consumed_bits < n) return error.EndOfStream; d.tossBits(n); } @@ -1064,6 +1064,15 @@ test "bug 18966" { ); } +test "truncated input ending when reading dynamic length bits" { + try testFailure(.raw, &[_]u8{ + 0x15, 0xd5, 0x07, 0x3b, 0x16, 0x0c, 0x03, 0x86, + 0x61, 0x2b, 0xa3, 0xec, 0xec, 0x15, 0x95, 0x6c, + 0x92, 0x4d, 0x19, 0x95, 0x4a, 0xb6, 0x22, 0x23, + 0xc9, + }, error.EndOfStream); +} + test "reading into empty buffer" { // Inspired by https://github.com/ziglang/zig/issues/19895 const input = &[_]u8{ diff --git a/lib/std/compress/flate/testdata/rfc1951.txt b/lib/std/compress/flate/testdata/rfc1951.txt deleted file mode 100644 index 403c8c722ff24ca034973876fa819d37715b9b6a..0000000000000000000000000000000000000000 --- a/lib/std/compress/flate/testdata/rfc1951.txt +++ /dev/null @@ -1,955 +0,0 @@ - - - - - - -Network Working Group P. Deutsch -Request for Comments: 1951 Aladdin Enterprises -Category: Informational May 1996 - - - DEFLATE Compressed Data Format Specification version 1.3 - -Status of This Memo - - This memo provides information for the Internet community. This memo - does not specify an Internet standard of any kind. Distribution of - this memo is unlimited. - -IESG Note: - - The IESG takes no position on the validity of any Intellectual - Property Rights statements contained in this document. - -Notices - - Copyright (c) 1996 L. Peter Deutsch - - Permission is granted to copy and distribute this document for any - purpose and without charge, including translations into other - languages and incorporation into compilations, provided that the - copyright notice and this notice are preserved, and that any - substantive changes or deletions from the original are clearly - marked. - - A pointer to the latest version of this and related documentation in - HTML format can be found at the URL - . - -Abstract - - This specification defines a lossless compressed data format that - compresses data using a combination of the LZ77 algorithm and Huffman - coding, with efficiency comparable to the best currently available - general-purpose compression methods. The data can be produced or - consumed, even for an arbitrarily long sequentially presented input - data stream, using only an a priori bounded amount of intermediate - storage. The format can be implemented readily in a manner not - covered by patents. - - - - - - - - -Deutsch Informational [Page 1] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - -Table of Contents - - 1. Introduction ................................................... 2 - 1.1. Purpose ................................................... 2 - 1.2. Intended audience ......................................... 3 - 1.3. Scope ..................................................... 3 - 1.4. Compliance ................................................ 3 - 1.5. Definitions of terms and conventions used ................ 3 - 1.6. Changes from previous versions ............................ 4 - 2. Compressed representation overview ............................. 4 - 3. Detailed specification ......................................... 5 - 3.1. Overall conventions ....................................... 5 - 3.1.1. Packing into bytes .................................. 5 - 3.2. Compressed block format ................................... 6 - 3.2.1. Synopsis of prefix and Huffman coding ............... 6 - 3.2.2. Use of Huffman coding in the "deflate" format ....... 7 - 3.2.3. Details of block format ............................. 9 - 3.2.4. Non-compressed blocks (BTYPE=00) ................... 11 - 3.2.5. Compressed blocks (length and distance codes) ...... 11 - 3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12 - 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13 - 3.3. Compliance ............................................... 14 - 4. Compression algorithm details ................................. 14 - 5. References .................................................... 16 - 6. Security Considerations ....................................... 16 - 7. Source code ................................................... 16 - 8. Acknowledgements .............................................. 16 - 9. Author's Address .............................................. 17 - -1. Introduction - - 1.1. Purpose - - The purpose of this specification is to define a lossless - compressed data format that: - * Is independent of CPU type, operating system, file system, - and character set, and hence can be used for interchange; - * Can be produced or consumed, even for an arbitrarily long - sequentially presented input data stream, using only an a - priori bounded amount of intermediate storage, and hence - can be used in data communications or similar structures - such as Unix filters; - * Compresses data with efficiency comparable to the best - currently available general-purpose compression methods, - and in particular considerably better than the "compress" - program; - * Can be implemented readily in a manner not covered by - patents, and hence can be practiced freely; - - - -Deutsch Informational [Page 2] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - * Is compatible with the file format produced by the current - widely used gzip utility, in that conforming decompressors - will be able to read data produced by the existing gzip - compressor. - - The data format defined by this specification does not attempt to: - - * Allow random access to compressed data; - * Compress specialized data (e.g., raster graphics) as well - as the best currently available specialized algorithms. - - A simple counting argument shows that no lossless compression - algorithm can compress every possible input data set. For the - format defined here, the worst case expansion is 5 bytes per 32K- - byte block, i.e., a size increase of 0.015% for large data sets. - English text usually compresses by a factor of 2.5 to 3; - executable files usually compress somewhat less; graphical data - such as raster images may compress much more. - - 1.2. Intended audience - - This specification is intended for use by implementors of software - to compress data into "deflate" format and/or decompress data from - "deflate" format. - - The text of the specification assumes a basic background in - programming at the level of bits and other primitive data - representations. Familiarity with the technique of Huffman coding - is helpful but not required. - - 1.3. Scope - - The specification specifies a method for representing a sequence - of bytes as a (usually shorter) sequence of bits, and a method for - packing the latter bit sequence into bytes. - - 1.4. Compliance - - Unless otherwise indicated below, a compliant decompressor must be - able to accept and decompress any data set that conforms to all - the specifications presented here; a compliant compressor must - produce data sets that conform to all the specifications presented - here. - - 1.5. Definitions of terms and conventions used - - Byte: 8 bits stored or transmitted as a unit (same as an octet). - For this specification, a byte is exactly 8 bits, even on machines - - - -Deutsch Informational [Page 3] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - which store a character on a number of bits different from eight. - See below, for the numbering of bits within a byte. - - String: a sequence of arbitrary bytes. - - 1.6. Changes from previous versions - - There have been no technical changes to the deflate format since - version 1.1 of this specification. In version 1.2, some - terminology was changed. Version 1.3 is a conversion of the - specification to RFC style. - -2. Compressed representation overview - - A compressed data set consists of a series of blocks, corresponding - to successive blocks of input data. The block sizes are arbitrary, - except that non-compressible blocks are limited to 65,535 bytes. - - Each block is compressed using a combination of the LZ77 algorithm - and Huffman coding. The Huffman trees for each block are independent - of those for previous or subsequent blocks; the LZ77 algorithm may - use a reference to a duplicated string occurring in a previous block, - up to 32K input bytes before. - - Each block consists of two parts: a pair of Huffman code trees that - describe the representation of the compressed data part, and a - compressed data part. (The Huffman trees themselves are compressed - using Huffman encoding.) The compressed data consists of a series of - elements of two types: literal bytes (of strings that have not been - detected as duplicated within the previous 32K input bytes), and - pointers to duplicated strings, where a pointer is represented as a - pair . The representation used in the - "deflate" format limits distances to 32K bytes and lengths to 258 - bytes, but does not limit the size of a block, except for - uncompressible blocks, which are limited as noted above. - - Each type of value (literals, distances, and lengths) in the - compressed data is represented using a Huffman code, using one code - tree for literals and lengths and a separate code tree for distances. - The code trees for each block appear in a compact form just before - the compressed data for that block. - - - - - - - - - - -Deutsch Informational [Page 4] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - -3. Detailed specification - - 3.1. Overall conventions In the diagrams below, a box like this: - - +---+ - | | <-- the vertical bars might be missing - +---+ - - represents one byte; a box like this: - - +==============+ - | | - +==============+ - - represents a variable number of bytes. - - Bytes stored within a computer do not have a "bit order", since - they are always treated as a unit. However, a byte considered as - an integer between 0 and 255 does have a most- and least- - significant bit, and since we write numbers with the most- - significant digit on the left, we also write bytes with the most- - significant bit on the left. In the diagrams below, we number the - bits of a byte so that bit 0 is the least-significant bit, i.e., - the bits are numbered: - - +--------+ - |76543210| - +--------+ - - Within a computer, a number may occupy multiple bytes. All - multi-byte numbers in the format described here are stored with - the least-significant byte first (at the lower memory address). - For example, the decimal number 520 is stored as: - - 0 1 - +--------+--------+ - |00001000|00000010| - +--------+--------+ - ^ ^ - | | - | + more significant byte = 2 x 256 - + less significant byte = 8 - - 3.1.1. Packing into bytes - - This document does not address the issue of the order in which - bits of a byte are transmitted on a bit-sequential medium, - since the final data format described here is byte- rather than - - - -Deutsch Informational [Page 5] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - bit-oriented. However, we describe the compressed block format - in below, as a sequence of data elements of various bit - lengths, not a sequence of bytes. We must therefore specify - how to pack these data elements into bytes to form the final - compressed byte sequence: - - * Data elements are packed into bytes in order of - increasing bit number within the byte, i.e., starting - with the least-significant bit of the byte. - * Data elements other than Huffman codes are packed - starting with the least-significant bit of the data - element. - * Huffman codes are packed starting with the most- - significant bit of the code. - - In other words, if one were to print out the compressed data as - a sequence of bytes, starting with the first byte at the - *right* margin and proceeding to the *left*, with the most- - significant bit of each byte on the left as usual, one would be - able to parse the result from right to left, with fixed-width - elements in the correct MSB-to-LSB order and Huffman codes in - bit-reversed order (i.e., with the first bit of the code in the - relative LSB position). - - 3.2. Compressed block format - - 3.2.1. Synopsis of prefix and Huffman coding - - Prefix coding represents symbols from an a priori known - alphabet by bit sequences (codes), one code for each symbol, in - a manner such that different symbols may be represented by bit - sequences of different lengths, but a parser can always parse - an encoded string unambiguously symbol-by-symbol. - - We define a prefix code in terms of a binary tree in which the - two edges descending from each non-leaf node are labeled 0 and - 1 and in which the leaf nodes correspond one-for-one with (are - labeled with) the symbols of the alphabet; then the code for a - symbol is the sequence of 0's and 1's on the edges leading from - the root to the leaf labeled with that symbol. For example: - - - - - - - - - - - -Deutsch Informational [Page 6] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - /\ Symbol Code - 0 1 ------ ---- - / \ A 00 - /\ B B 1 - 0 1 C 011 - / \ D 010 - A /\ - 0 1 - / \ - D C - - A parser can decode the next symbol from an encoded input - stream by walking down the tree from the root, at each step - choosing the edge corresponding to the next input bit. - - Given an alphabet with known symbol frequencies, the Huffman - algorithm allows the construction of an optimal prefix code - (one which represents strings with those symbol frequencies - using the fewest bits of any possible prefix codes for that - alphabet). Such a code is called a Huffman code. (See - reference [1] in Chapter 5, references for additional - information on Huffman codes.) - - Note that in the "deflate" format, the Huffman codes for the - various alphabets must not exceed certain maximum code lengths. - This constraint complicates the algorithm for computing code - lengths from symbol frequencies. Again, see Chapter 5, - references for details. - - 3.2.2. Use of Huffman coding in the "deflate" format - - The Huffman codes used for each alphabet in the "deflate" - format have two additional rules: - - * All codes of a given bit length have lexicographically - consecutive values, in the same order as the symbols - they represent; - - * Shorter codes lexicographically precede longer codes. - - - - - - - - - - - - -Deutsch Informational [Page 7] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - We could recode the example above to follow this rule as - follows, assuming that the order of the alphabet is ABCD: - - Symbol Code - ------ ---- - A 10 - B 0 - C 110 - D 111 - - I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are - lexicographically consecutive. - - Given this rule, we can define the Huffman code for an alphabet - just by giving the bit lengths of the codes for each symbol of - the alphabet in order; this is sufficient to determine the - actual codes. In our example, the code is completely defined - by the sequence of bit lengths (2, 1, 3, 3). The following - algorithm generates the codes as integers, intended to be read - from most- to least-significant bit. The code lengths are - initially in tree[I].Len; the codes are produced in - tree[I].Code. - - 1) Count the number of codes for each code length. Let - bl_count[N] be the number of codes of length N, N >= 1. - - 2) Find the numerical value of the smallest code for each - code length: - - code = 0; - bl_count[0] = 0; - for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; - next_code[bits] = code; - } - - 3) Assign numerical values to all codes, using consecutive - values for all codes of the same length with the base - values determined at step 2. Codes that are never used - (which have a bit length of zero) must not be assigned a - value. - - for (n = 0; n <= max_code; n++) { - len = tree[n].Len; - if (len != 0) { - tree[n].Code = next_code[len]; - next_code[len]++; - } - - - -Deutsch Informational [Page 8] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - } - - Example: - - Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3, - 3, 2, 4, 4). After step 1, we have: - - N bl_count[N] - - ----------- - 2 1 - 3 5 - 4 2 - - Step 2 computes the following next_code values: - - N next_code[N] - - ------------ - 1 0 - 2 0 - 3 2 - 4 14 - - Step 3 produces the following code values: - - Symbol Length Code - ------ ------ ---- - A 3 010 - B 3 011 - C 3 100 - D 3 101 - E 3 110 - F 2 00 - G 4 1110 - H 4 1111 - - 3.2.3. Details of block format - - Each block of compressed data begins with 3 header bits - containing the following data: - - first bit BFINAL - next 2 bits BTYPE - - Note that the header bits do not necessarily begin on a byte - boundary, since a block does not necessarily occupy an integral - number of bytes. - - - - - -Deutsch Informational [Page 9] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - BFINAL is set if and only if this is the last block of the data - set. - - BTYPE specifies how the data are compressed, as follows: - - 00 - no compression - 01 - compressed with fixed Huffman codes - 10 - compressed with dynamic Huffman codes - 11 - reserved (error) - - The only difference between the two compressed cases is how the - Huffman codes for the literal/length and distance alphabets are - defined. - - In all cases, the decoding algorithm for the actual data is as - follows: - - do - read block header from input stream. - if stored with no compression - skip any remaining bits in current partially - processed byte - read LEN and NLEN (see next section) - copy LEN bytes of data to output - otherwise - if compressed with dynamic Huffman codes - read representation of code trees (see - subsection below) - loop (until end of block code recognized) - decode literal/length value from input stream - if value < 256 - copy value (literal byte) to output stream - otherwise - if value = end of block (256) - break from loop - otherwise (value = 257..285) - decode distance from input stream - - move backwards distance bytes in the output - stream, and copy length bytes from this - position to the output stream. - end loop - while not last block - - Note that a duplicated string reference may refer to a string - in a previous block; i.e., the backward distance may cross one - or more block boundaries. However a distance cannot refer past - the beginning of the output stream. (An application using a - - - -Deutsch Informational [Page 10] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - preset dictionary might discard part of the output stream; a - distance can refer to that part of the output stream anyway) - Note also that the referenced string may overlap the current - position; for example, if the last 2 bytes decoded have values - X and Y, a string reference with - adds X,Y,X,Y,X to the output stream. - - We now specify each compression method in turn. - - 3.2.4. Non-compressed blocks (BTYPE=00) - - Any bits of input up to the next byte boundary are ignored. - The rest of the block consists of the following information: - - 0 1 2 3 4... - +---+---+---+---+================================+ - | LEN | NLEN |... LEN bytes of literal data...| - +---+---+---+---+================================+ - - LEN is the number of data bytes in the block. NLEN is the - one's complement of LEN. - - 3.2.5. Compressed blocks (length and distance codes) - - As noted above, encoded data blocks in the "deflate" format - consist of sequences of symbols drawn from three conceptually - distinct alphabets: either literal bytes, from the alphabet of - byte values (0..255), or pairs, - where the length is drawn from (3..258) and the distance is - drawn from (1..32,768). In fact, the literal and length - alphabets are merged into a single alphabet (0..285), where - values 0..255 represent literal bytes, the value 256 indicates - end-of-block, and values 257..285 represent length codes - (possibly in conjunction with extra bits following the symbol - code) as follows: - - - - - - - - - - - - - - - - -Deutsch Informational [Page 11] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - Extra Extra Extra - Code Bits Length(s) Code Bits Lengths Code Bits Length(s) - ---- ---- ------ ---- ---- ------- ---- ---- ------- - 257 0 3 267 1 15,16 277 4 67-82 - 258 0 4 268 1 17,18 278 4 83-98 - 259 0 5 269 2 19-22 279 4 99-114 - 260 0 6 270 2 23-26 280 4 115-130 - 261 0 7 271 2 27-30 281 5 131-162 - 262 0 8 272 2 31-34 282 5 163-194 - 263 0 9 273 3 35-42 283 5 195-226 - 264 0 10 274 3 43-50 284 5 227-257 - 265 1 11,12 275 3 51-58 285 0 258 - 266 1 13,14 276 3 59-66 - - The extra bits should be interpreted as a machine integer - stored with the most-significant bit first, e.g., bits 1110 - represent the value 14. - - Extra Extra Extra - Code Bits Dist Code Bits Dist Code Bits Distance - ---- ---- ---- ---- ---- ------ ---- ---- -------- - 0 0 1 10 4 33-48 20 9 1025-1536 - 1 0 2 11 4 49-64 21 9 1537-2048 - 2 0 3 12 5 65-96 22 10 2049-3072 - 3 0 4 13 5 97-128 23 10 3073-4096 - 4 1 5,6 14 6 129-192 24 11 4097-6144 - 5 1 7,8 15 6 193-256 25 11 6145-8192 - 6 2 9-12 16 7 257-384 26 12 8193-12288 - 7 2 13-16 17 7 385-512 27 12 12289-16384 - 8 3 17-24 18 8 513-768 28 13 16385-24576 - 9 3 25-32 19 8 769-1024 29 13 24577-32768 - - 3.2.6. Compression with fixed Huffman codes (BTYPE=01) - - The Huffman codes for the two alphabets are fixed, and are not - represented explicitly in the data. The Huffman code lengths - for the literal/length alphabet are: - - Lit Value Bits Codes - --------- ---- ----- - 0 - 143 8 00110000 through - 10111111 - 144 - 255 9 110010000 through - 111111111 - 256 - 279 7 0000000 through - 0010111 - 280 - 287 8 11000000 through - 11000111 - - - -Deutsch Informational [Page 12] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - The code lengths are sufficient to generate the actual codes, - as described above; we show the codes in the table for added - clarity. Literal/length values 286-287 will never actually - occur in the compressed data, but participate in the code - construction. - - Distance codes 0-31 are represented by (fixed-length) 5-bit - codes, with possible additional bits as shown in the table - shown in Paragraph 3.2.5, above. Note that distance codes 30- - 31 will never actually occur in the compressed data. - - 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) - - The Huffman codes for the two alphabets appear in the block - immediately after the header bits and before the actual - compressed data, first the literal/length code and then the - distance code. Each code is defined by a sequence of code - lengths, as discussed in Paragraph 3.2.2, above. For even - greater compactness, the code length sequences themselves are - compressed using a Huffman code. The alphabet for code lengths - is as follows: - - 0 - 15: Represent code lengths of 0 - 15 - 16: Copy the previous code length 3 - 6 times. - The next 2 bits indicate repeat length - (0 = 3, ... , 3 = 6) - Example: Codes 8, 16 (+2 bits 11), - 16 (+2 bits 10) will expand to - 12 code lengths of 8 (1 + 6 + 5) - 17: Repeat a code length of 0 for 3 - 10 times. - (3 bits of length) - 18: Repeat a code length of 0 for 11 - 138 times - (7 bits of length) - - A code length of 0 indicates that the corresponding symbol in - the literal/length or distance alphabet will not occur in the - block, and should not participate in the Huffman code - construction algorithm given earlier. If only one distance - code is used, it is encoded using one bit, not zero bits; in - this case there is a single code length of one, with one unused - code. One distance code of zero bits means that there are no - distance codes used at all (the data is all literals). - - We can now define the format of the block: - - 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) - 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) - 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) - - - -Deutsch Informational [Page 13] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - (HCLEN + 4) x 3 bits: code lengths for the code length - alphabet given just above, in the order: 16, 17, 18, - 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - - These code lengths are interpreted as 3-bit integers - (0-7); as above, a code length of 0 means the - corresponding symbol (literal/length or distance code - length) is not used. - - HLIT + 257 code lengths for the literal/length alphabet, - encoded using the code length Huffman code - - HDIST + 1 code lengths for the distance alphabet, - encoded using the code length Huffman code - - The actual compressed data of the block, - encoded using the literal/length and distance Huffman - codes - - The literal/length symbol 256 (end of data), - encoded using the literal/length Huffman code - - The code length repeat codes can cross from HLIT + 257 to the - HDIST + 1 code lengths. In other words, all code lengths form - a single sequence of HLIT + HDIST + 258 values. - - 3.3. Compliance - - A compressor may limit further the ranges of values specified in - the previous section and still be compliant; for example, it may - limit the range of backward pointers to some value smaller than - 32K. Similarly, a compressor may limit the size of blocks so that - a compressible block fits in memory. - - A compliant decompressor must accept the full range of possible - values defined in the previous section, and must accept blocks of - arbitrary size. - -4. Compression algorithm details - - While it is the intent of this document to define the "deflate" - compressed data format without reference to any particular - compression algorithm, the format is related to the compressed - formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below); - since many variations of LZ77 are patented, it is strongly - recommended that the implementor of a compressor follow the general - algorithm presented here, which is known not to be patented per se. - The material in this section is not part of the definition of the - - - -Deutsch Informational [Page 14] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - - specification per se, and a compressor need not follow it in order to - be compliant. - - The compressor terminates a block when it determines that starting a - new block with fresh trees would be useful, or when the block size - fills up the compressor's block buffer. - - The compressor uses a chained hash table to find duplicated strings, - using a hash function that operates on 3-byte sequences. At any - given point during compression, let XYZ be the next 3 input bytes to - be examined (not necessarily all different, of course). First, the - compressor examines the hash chain for XYZ. If the chain is empty, - the compressor simply writes out X as a literal byte and advances one - byte in the input. If the hash chain is not empty, indicating that - the sequence XYZ (or, if we are unlucky, some other 3 bytes with the - same hash function value) has occurred recently, the compressor - compares all strings on the XYZ hash chain with the actual input data - sequence starting at the current point, and selects the longest - match. - - The compressor searches the hash chains starting with the most recent - strings, to favor small distances and thus take advantage of the - Huffman encoding. The hash chains are singly linked. There are no - deletions from the hash chains; the algorithm simply discards matches - that are too old. To avoid a worst-case situation, very long hash - chains are arbitrarily truncated at a certain length, determined by a - run-time parameter. - - To improve overall compression, the compressor optionally defers the - selection of matches ("lazy matching"): after a match of length N has - been found, the compressor searches for a longer match starting at - the next input byte. If it finds a longer match, it truncates the - previous match to a length of one (thus producing a single literal - byte) and then emits the longer match. Otherwise, it emits the - original match, and, as described above, advances N bytes before - continuing. - - Run-time parameters also control this "lazy match" procedure. If - compression ratio is most important, the compressor attempts a - complete second search regardless of the length of the first match. - In the normal case, if the current match is "long enough", the - compressor reduces the search for a longer match, thus speeding up - the process. If speed is most important, the compressor inserts new - strings in the hash table only when no match was found, or when the - match is not "too long". This degrades the compression ratio but - saves time since there are both fewer insertions and fewer searches. - - - - - -Deutsch Informational [Page 15] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - -5. References - - [1] Huffman, D. A., "A Method for the Construction of Minimum - Redundancy Codes", Proceedings of the Institute of Radio - Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101. - - [2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data - Compression", IEEE Transactions on Information Theory, Vol. 23, - No. 3, pp. 337-343. - - [3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources, - available in ftp://ftp.uu.net/pub/archiving/zip/doc/ - - [4] Gailly, J.-L., and Adler, M., GZIP documentation and sources, - available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/ - - [5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix - encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169. - - [6] Hirschberg and Lelewer, "Efficient decoding of prefix codes," - Comm. ACM, 33,4, April 1990, pp. 449-459. - -6. Security Considerations - - Any data compression method involves the reduction of redundancy in - the data. Consequently, any corruption of the data is likely to have - severe effects and be difficult to correct. Uncompressed text, on - the other hand, will probably still be readable despite the presence - of some corrupted bytes. - - It is recommended that systems using this data format provide some - means of validating the integrity of the compressed data. See - reference [3], for example. - -7. Source code - - Source code for a C language implementation of a "deflate" compliant - compressor and decompressor is available within the zlib package at - ftp://ftp.uu.net/pub/archiving/zip/zlib/. - -8. Acknowledgements - - Trademarks cited in this document are the property of their - respective owners. - - Phil Katz designed the deflate format. Jean-Loup Gailly and Mark - Adler wrote the related software described in this specification. - Glenn Randers-Pehrson converted this document to RFC and HTML format. - - - -Deutsch Informational [Page 16] - -RFC 1951 DEFLATE Compressed Data Format Specification May 1996 - - -9. Author's Address - - L. Peter Deutsch - Aladdin Enterprises - 203 Santa Margarita Ave. - Menlo Park, CA 94025 - - Phone: (415) 322-0103 (AM only) - FAX: (415) 322-1734 - EMail: - - Questions about the technical content of this specification can be - sent by email to: - - Jean-Loup Gailly and - Mark Adler - - Editorial comments on this specification can be sent by email to: - - L. Peter Deutsch and - Glenn Randers-Pehrson - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Deutsch Informational [Page 17] - diff --git a/lib/std/compress/testdata/rfc8478.txt b/lib/std/compress/testdata/rfc8478.txt deleted file mode 100644 index e4ac22a302bd209796f2de1dd7d7bdc861fe9f63..0000000000000000000000000000000000000000 --- a/lib/std/compress/testdata/rfc8478.txt +++ /dev/null @@ -1,3027 +0,0 @@ - - - - - - -Internet Engineering Task Force (IETF) Y. Collet -Request for Comments: 8478 M. Kucherawy, Ed. -Category: Informational Facebook -ISSN: 2070-1721 October 2018 - - - Zstandard Compression and the application/zstd Media Type - -Abstract - - Zstandard, or "zstd" (pronounced "zee standard"), is a data - compression mechanism. This document describes the mechanism and - registers a media type and content encoding to be used when - transporting zstd-compressed content via Multipurpose Internet Mail - Extensions (MIME). - - Despite use of the word "standard" as part of its name, readers are - advised that this document is not an Internet Standards Track - specification; it is being published for informational purposes only. - -Status of This Memo - - This document is not an Internet Standards Track specification; it is - published for informational purposes. - - This document is a product of the Internet Engineering Task Force - (IETF). It represents the consensus of the IETF community. It has - received public review and has been approved for publication by the - Internet Engineering Steering Group (IESG). Not all documents - approved by the IESG are candidates for any level of Internet - Standard; see Section 2 of RFC 7841. - - Information about the current status of this document, any errata, - and how to provide feedback on it may be obtained at - https://www.rfc-editor.org/info/rfc8478. - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 1] - -RFC 8478 application/zstd October 2018 - - -Copyright Notice - - Copyright (c) 2018 IETF Trust and the persons identified as the - document authors. All rights reserved. - - This document is subject to BCP 78 and the IETF Trust's Legal - Provisions Relating to IETF Documents - (https://trustee.ietf.org/license-info) in effect on the date of - publication of this document. Please review these documents - carefully, as they describe your rights and restrictions with respect - to this document. Code Components extracted from this document must - include Simplified BSD License text as described in Section 4.e of - the Trust Legal Provisions and are provided without warranty as - described in the Simplified BSD License. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 2] - -RFC 8478 application/zstd October 2018 - - -Table of Contents - - 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 - 2. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . 4 - 3. Compression Algorithm . . . . . . . . . . . . . . . . . . . . 5 - 3.1. Frames . . . . . . . . . . . . . . . . . . . . . . . . . 6 - 3.1.1. Zstandard Frames . . . . . . . . . . . . . . . . . . 6 - 3.1.1.1. Frame Header . . . . . . . . . . . . . . . . . . 7 - 3.1.1.2. Blocks . . . . . . . . . . . . . . . . . . . . . 12 - 3.1.1.3. Compressed Blocks . . . . . . . . . . . . . . . . 14 - 3.1.1.4. Sequence Execution . . . . . . . . . . . . . . . 28 - 3.1.1.5. Repeat Offsets . . . . . . . . . . . . . . . . . 29 - 3.1.2. Skippable Frames . . . . . . . . . . . . . . . . . . 30 - 4. Entropy Encoding . . . . . . . . . . . . . . . . . . . . . . 30 - 4.1. FSE . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 - 4.1.1. FSE Table Description . . . . . . . . . . . . . . . . 31 - 4.2. Huffman Coding . . . . . . . . . . . . . . . . . . . . . 34 - 4.2.1. Huffman Tree Description . . . . . . . . . . . . . . 35 - 4.2.1.1. Huffman Tree Header . . . . . . . . . . . . . . . 36 - 4.2.1.2. FSE Compression of Huffman Weights . . . . . . . 37 - 4.2.1.3. Conversion from Weights to Huffman Prefix Codes . 38 - 4.2.2. Huffman-Coded Streams . . . . . . . . . . . . . . . . 39 - 5. Dictionary Format . . . . . . . . . . . . . . . . . . . . . . 40 - 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 42 - 6.1. The 'application/zstd' Media Type . . . . . . . . . . . . 42 - 6.2. Content Encoding . . . . . . . . . . . . . . . . . . . . 43 - 6.3. Dictionaries . . . . . . . . . . . . . . . . . . . . . . 43 - 7. Security Considerations . . . . . . . . . . . . . . . . . . . 43 - 8. Implementation Status . . . . . . . . . . . . . . . . . . . . 44 - 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 45 - 9.1. Normative References . . . . . . . . . . . . . . . . . . 45 - 9.2. Informative References . . . . . . . . . . . . . . . . . 45 - Appendix A. Decoding Tables for Predefined Codes . . . . . . . . 46 - A.1. Literal Length Code Table . . . . . . . . . . . . . . . . 46 - A.2. Match Length Code Table . . . . . . . . . . . . . . . . . 49 - A.3. Offset Code Table . . . . . . . . . . . . . . . . . . . . 52 - Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 53 - Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 54 - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 3] - -RFC 8478 application/zstd October 2018 - - -1. Introduction - - Zstandard, or "zstd" (pronounced "zee standard"), is a data - compression mechanism, akin to gzip [RFC1952]. - - Despite use of the word "standard" as part of its name, readers are - advised that this document is not an Internet Standards Track - specification; it is being published for informational purposes only. - - This document describes the Zstandard format. Also, to enable the - transport of a data object compressed with Zstandard, this document - registers a media type that can be used to identify such content when - it is used in a payload encoded using Multipurpose Internet Mail - Extensions (MIME). - -2. Definitions - - Some terms used elsewhere in this document are defined here for - clarity. - - uncompressed: Describes an arbitrary set of bytes in their original - form, prior to being subjected to compression. - - compress, compression: The act of processing a set of bytes via the - compression mechanism described here. - - compressed: Describes the result of passing a set of bytes through - this mechanism. The original input has thus been compressed. - - decompress, decompression: The act of processing a set of bytes - through the inverse of the compression mechanism described here, - in an attempt to recover the original set of bytes prior to - compression. - - decompressed: Describes the result of passing a set of bytes through - the reverse of this mechanism. When this is successful, the - decompressed payload and the uncompressed payload are - indistinguishable. - - encode: The process of translating data from one form to another; - this may include compression or it may refer to other translations - done as part of this specification. - - decode: The reverse of "encode"; describes a process of reversing a - prior encoding to recover the original content. - - - - - - -Collet & Kucherawy Informational [Page 4] - -RFC 8478 application/zstd October 2018 - - - frame: Content compressed by Zstandard is transformed into a - Zstandard frame. Multiple frames can be appended into a single - file or stream. A frame is completely independent, has a defined - beginning and end, and has a set of parameters that tells the - decoder how to decompress it. - - block: A frame encapsulates one or multiple blocks. Each block - contains arbitrary content, which is described by its header, and - has a guaranteed maximum content size that depends upon frame - parameters. Unlike frames, each block depends on previous blocks - for proper decoding. However, each block can be decompressed - without waiting for its successor, allowing streaming operations. - - natural order: A sequence or ordering of objects or values that is - typical of that type of object or value. A set of unique - integers, for example, is in "natural order" if when progressing - from one element in the set or sequence to the next, there is - never a decrease in value. - - The naming convention for identifiers within the specification is - Mixed_Case_With_Underscores. Identifiers inside square brackets - indicate that the identifier is optional in the presented context. - -3. Compression Algorithm - - This section describes the Zstandard algorithm. - - The purpose of this document is to define a lossless compressed data - format that is a) independent of the CPU type, operating system, file - system, and character set and b) is suitable for file compression and - pipe and streaming compression, using the Zstandard algorithm. The - text of the specification assumes a basic background in programming - at the level of bits and other primitive data representations. - - The data can be produced or consumed, even for an arbitrarily long - sequentially presented input data stream, using only an a priori - bounded amount of intermediate storage, and hence can be used in data - communications. The format uses the Zstandard compression method, - and an optional xxHash-64 checksum method [XXHASH], for detection of - data corruption. - - The data format defined by this specification does not attempt to - allow random access to compressed data. - - Unless otherwise indicated below, a compliant compressor must produce - data sets that conform to the specifications presented here. - However, it does not need to support all options. - - - - -Collet & Kucherawy Informational [Page 5] - -RFC 8478 application/zstd October 2018 - - - A compliant decompressor must be able to decompress at least one - working set of parameters that conforms to the specifications - presented here. It may also ignore informative fields, such as the - checksum. Whenever it does not support a parameter defined in the - compressed stream, it must produce a non-ambiguous error code and - associated error message explaining which parameter is unsupported. - - This specification is intended for use by implementers of software to - compress data into Zstandard format and/or decompress data from - Zstandard format. The Zstandard format is supported by an open - source reference implementation, written in portable C, and available - at [ZSTD]. - -3.1. Frames - - Zstandard compressed data is made up of one or more frames. Each - frame is independent and can be decompressed independently of other - frames. The decompressed content of multiple concatenated frames is - the concatenation of each frame's decompressed content. - - There are two frame formats defined for Zstandard: Zstandard frames - and skippable frames. Zstandard frames contain compressed data, - while skippable frames contain custom user metadata. - -3.1.1. Zstandard Frames - - The structure of a single Zstandard frame is as follows: - - +--------------------+------------+ - | Magic_Number | 4 bytes | - +--------------------+------------+ - | Frame_Header | 2-14 bytes | - +--------------------+------------+ - | Data_Block | n bytes | - +--------------------+------------+ - | [More Data_Blocks] | | - +--------------------+------------+ - | [Content_Checksum] | 0-4 bytes | - +--------------------+------------+ - - Magic_Number: 4 bytes, little-endian format. Value: 0xFD2FB528. - - Frame_Header: 2 to 14 bytes, detailed in Section 3.1.1.1. - - Data_Block: Detailed in Section 3.1.1.2. This is where data - appears. - - - - - -Collet & Kucherawy Informational [Page 6] - -RFC 8478 application/zstd October 2018 - - - Content_Checksum: An optional 32-bit checksum, only present if - Content_Checksum_Flag is set. The content checksum is the result - of the XXH64() hash function [XXHASH] digesting the original - (decoded) data as input, and a seed of zero. The low 4 bytes of - the checksum are stored in little-endian format. - - The magic number was selected to be less probable to find at the - beginning of an arbitrary file. It avoids trivial patterns (0x00, - 0xFF, repeated bytes, increasing bytes, etc.), contains byte values - outside of ASCII range, and doesn't map into UTF-8 space, all of - which reduce the likelihood of its appearance at the top of a text - file. - -3.1.1.1. Frame Header - - The frame header has a variable size, with a minimum of 2 bytes and - up to 14 bytes depending on optional parameters. The structure of - Frame_Header is as follows: - - +-------------------------+-----------+ - | Frame_Header_Descriptor | 1 byte | - +-------------------------+-----------+ - | [Window_Descriptor] | 0-1 byte | - +-------------------------+-----------+ - | [Dictionary_ID] | 0-4 bytes | - +-------------------------+-----------+ - | [Frame_Content_Size] | 0-8 bytes | - +-------------------------+-----------+ - - - - - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 7] - -RFC 8478 application/zstd October 2018 - - -3.1.1.1.1. Frame_Header_Descriptor - - The first header's byte is called the Frame_Header_Descriptor. It - describes which other fields are present. Decoding this byte is - enough to tell the size of Frame_Header. - - +------------+-------------------------+ - | Bit Number | Field Name | - +------------+-------------------------+ - | 7-6 | Frame_Content_Size_Flag | - +------------+-------------------------+ - | 5 | Single_Segment_Flag | - +------------+-------------------------+ - | 4 | (unused) | - +------------+-------------------------+ - | 3 | (reserved) | - +------------+-------------------------+ - | 2 | Content_Checksum_Flag | - +------------+-------------------------+ - | 1-0 | Dictionary_ID_Flag | - +------------+-------------------------+ - - In this table, bit 7 is the highest bit, while bit 0 is the lowest - one. - -3.1.1.1.1.1. Frame_Content_Size_Flag - - This is a 2-bit flag (equivalent to Frame_Header_Descriptor right- - shifted 6 bits) specifying whether Frame_Content_Size (the - decompressed data size) is provided within the header. Flag_Value - provides FCS_Field_Size, which is the number of bytes used by - Frame_Content_Size according to the following table: - - +----------------+--------+---+---+---+ - | Flag_Value | 0 | 1 | 2 | 3 | - +----------------+--------+---+---+---+ - | FCS_Field_Size | 0 or 1 | 2 | 4 | 8 | - +----------------+--------+---+---+---+ - - When Flag_Value is 0, FCS_Field_Size depends on Single_Segment_Flag: - If Single_Segment_Flag is set, FCS_Field_Size is 1. Otherwise, - FCS_Field_Size is 0; Frame_Content_Size is not provided. - - - - - - - - - -Collet & Kucherawy Informational [Page 8] - -RFC 8478 application/zstd October 2018 - - -3.1.1.1.1.2. Single_Segment_Flag - - If this flag is set, data must be regenerated within a single - continuous memory segment. - - In this case, Window_Descriptor byte is skipped, but - Frame_Content_Size is necessarily present. As a consequence, the - decoder must allocate a memory segment of size equal or larger than - Frame_Content_Size. - - In order to protect the decoder from unreasonable memory - requirements, a decoder is allowed to reject a compressed frame that - requests a memory size beyond the decoder's authorized range. - - For broader compatibility, decoders are recommended to support memory - sizes of at least 8 MB. This is only a recommendation; each decoder - is free to support higher or lower limits, depending on local - limitations. - -3.1.1.1.1.3. Unused Bit - - A decoder compliant with this specification version shall not - interpret this bit. It might be used in a future version, to signal - a property that is not mandatory to properly decode the frame. An - encoder compliant with this specification must set this bit to zero. - -3.1.1.1.1.4. Reserved Bit - - This bit is reserved for some future feature. Its value must be - zero. A decoder compliant with this specification version must - ensure it is not set. This bit may be used in a future revision, to - signal a feature that must be interpreted to decode the frame - correctly. - -3.1.1.1.1.5. Content_Checksum_Flag - - If this flag is set, a 32-bit Content_Checksum will be present at the - frame's end. See the description of Content_Checksum above. - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 9] - -RFC 8478 application/zstd October 2018 - - -3.1.1.1.1.6. Dictionary_ID_Flag - - This is a 2-bit flag (= Frame_Header_Descriptor & 0x3) indicating - whether a dictionary ID is provided within the header. It also - specifies the size of this field as DID_Field_Size: - - +----------------+---+---+---+---+ - | Flag_Value | 0 | 1 | 2 | 3 | - +----------------+---+---+---+---+ - | DID_Field_Size | 0 | 1 | 2 | 4 | - +----------------+---+---+---+---+ - -3.1.1.1.2. Window Descriptor - - This provides guarantees about the minimum memory buffer required to - decompress a frame. This information is important for decoders to - allocate enough memory. - - The Window_Descriptor byte is optional. When Single_Segment_Flag is - set, Window_Descriptor is not present. In this case, Window_Size is - Frame_Content_Size, which can be any value from 0 to 2^64-1 bytes (16 - ExaBytes). - - +------------+----------+----------+ - | Bit Number | 7-3 | 2-0 | - +------------+----------+----------+ - | Field Name | Exponent | Mantissa | - +------------+----------+----------+ - - The minimum memory buffer size is called Window_Size. It is - described by the following formulae: - - windowLog = 10 + Exponent; - windowBase = 1 << windowLog; - windowAdd = (windowBase / 8) * Mantissa; - Window_Size = windowBase + windowAdd; - - The minimum Window_Size is 1 KB. The maximum Window_Size is (1<<41) - + 7*(1<<38) bytes, which is 3.75 TB. - - In general, larger Window_Size values tend to improve the compression - ratio, but at the cost of increased memory usage. - - To properly decode compressed data, a decoder will need to allocate a - buffer of at least Window_Size bytes. - - - - - - -Collet & Kucherawy Informational [Page 10] - -RFC 8478 application/zstd October 2018 - - - In order to protect decoders from unreasonable memory requirements, a - decoder is allowed to reject a compressed frame that requests a - memory size beyond decoder's authorized range. - - For improved interoperability, it's recommended for decoders to - support values of Window_Size up to 8 MB and for encoders not to - generate frames requiring a Window_Size larger than 8 MB. It's - merely a recommendation though, and decoders are free to support - larger or lower limits, depending on local limitations. - -3.1.1.1.3. Dictionary_ID - - This is a variable size field, which contains the ID of the - dictionary required to properly decode the frame. This field is - optional. When it's not present, it's up to the decoder to know - which dictionary to use. - - Dictionary_ID field size is provided by DID_Field_Size. - DID_Field_Size is directly derived from the value of - Dictionary_ID_Flag. One byte can represent an ID 0-255; 2 bytes can - represent an ID 0-65535; 4 bytes can represent an ID 0-4294967295. - Format is little-endian. - - It is permitted to represent a small ID (for example, 13) with a - large 4-byte dictionary ID, even if it is less efficient. - - Within private environments, any dictionary ID can be used. However, - for frames and dictionaries distributed in public space, - Dictionary_ID must be attributed carefully. The following ranges are - reserved for use only with dictionaries that have been registered - with IANA (see Section 6.3): - - low range: <= 32767 - high range: >= (1 << 31) - - Any other value for Dictionary_ID can be used by private arrangement - between participants. - - Any payload presented for decompression that references an - unregistered reserved dictionary ID results in an error. - - - - - - - - - - - -Collet & Kucherawy Informational [Page 11] - -RFC 8478 application/zstd October 2018 - - -3.1.1.1.4. Frame Content Size - - This is the original (uncompressed) size. This information is - optional. Frame_Content_Size uses a variable number of bytes, - provided by FCS_Field_Size. FCS_Field_Size is provided by the value - of Frame_Content_Size_Flag. FCS_Field_Size can be equal to 0 (not - present), 1, 2, 4, or 8 bytes. - - +----------------+--------------+ - | FCS Field Size | Range | - +----------------+--------------+ - | 0 | unknown | - +----------------+--------------+ - | 1 | 0 - 255 | - +----------------+--------------+ - | 2 | 256 - 65791 | - +----------------+--------------+ - | 4 | 0 - 2^32 - 1 | - +----------------+--------------+ - | 8 | 0 - 2^64 - 1 | - +----------------+--------------+ - - Frame_Content_Size format is little-endian. When FCS_Field_Size is - 1, 4, or 8 bytes, the value is read directly. When FCS_Field_Size is - 2, the offset of 256 is added. It's allowed to represent a small - size (for example 18) using any compatible variant. - -3.1.1.2. Blocks - - After Magic_Number and Frame_Header, there are some number of blocks. - Each frame must have at least 1 block, but there is no upper limit on - the number of blocks per frame. - - The structure of a block is as follows: - - +--------------+---------------+ - | Block_Header | Block_Content | - +--------------+---------------+ - | 3 bytes | n bytes | - +--------------+---------------+ - - - - - - - - - - - -Collet & Kucherawy Informational [Page 12] - -RFC 8478 application/zstd October 2018 - - - Block_Header uses 3 bytes, written using little-endian convention. - It contains three fields: - - +------------+------------+------------+ - | Last_Block | Block_Type | Block_Size | - +------------+------------+------------+ - | bit 0 | bits 1-2 | bits 3-23 | - +------------+------------+------------+ - -3.1.1.2.1. Last_Block - - The lowest bit (Last_Block) signals whether this block is the last - one. The frame will end after this last block. It may be followed - by an optional Content_Checksum (see Section 3.1.1). - -3.1.1.2.2. Block_Type - - The next 2 bits represent the Block_Type. There are four block - types: - - +-----------+------------------+ - | Value | Block_Type | - +-----------+------------------+ - | 0 | Raw_Block | - +-----------+------------------+ - | 1 | RLE_Block | - +-----------+------------------+ - | 2 | Compressed_Block | - +-----------+------------------+ - | 3 | Reserved | - +-----------+------------------+ - - Raw_Block: This is an uncompressed block. Block_Content contains - Block_Size bytes. - - RLE_Block: This is a single byte, repeated Block_Size times. - Block_Content consists of a single byte. On the decompression - side, this byte must be repeated Block_Size times. - - Compressed_Block: This is a compressed block as described in - Section 3.1.1.3. Block_Size is the length of Block_Content, - namely the compressed data. The decompressed size is not known, - but its maximum possible value is guaranteed (see below). - - Reserved: This is not a block. This value cannot be used with the - current specification. If such a value is present, it is - considered to be corrupt data. - - - - -Collet & Kucherawy Informational [Page 13] - -RFC 8478 application/zstd October 2018 - - -3.1.1.2.3. Block_Size - - The upper 21 bits of Block_Header represent the Block_Size. - Block_Size is the size of the block excluding the header. A block - can contain any number of bytes (even zero), up to - Block_Maximum_Decompressed_Size, which is the smallest of: - - o Window_Size - - o 128 KB - - A Compressed_Block has the extra restriction that Block_Size is - always strictly less than the decompressed size. If this condition - cannot be respected, the block must be sent uncompressed instead - (i.e., treated as a Raw_Block). - -3.1.1.3. Compressed Blocks - - To decompress a compressed block, the compressed size must be - provided from the Block_Size field within Block_Header. - - A compressed block consists of two sections: a Literals - Section (Section 3.1.1.3.1) and a - Sequences_Section (Section 3.1.1.3.2). The results of the two - sections are then combined to produce the decompressed data in - Sequence Execution (Section 3.1.1.4). - - To decode a compressed block, the following elements are necessary: - - o Previous decoded data, up to a distance of Window_Size, or the - beginning of the Frame, whichever is smaller. Single_Segment_Flag - will be set in the latter case. - - o List of "recent offsets" from the previous Compressed_Block. - - o The previous Huffman tree, required by Treeless_Literals_Block - type. - - o Previous Finite State Entropy (FSE) decoding tables, required by - Repeat_Mode, for each symbol type (literals lengths, match - lengths, offsets). - - Note that decoding tables are not always from the previous - Compressed_Block: - - o Every decoding table can come from a dictionary. - - - - - -Collet & Kucherawy Informational [Page 14] - -RFC 8478 application/zstd October 2018 - - - o The Huffman tree comes from the previous - Compressed_Literals_Block. - -3.1.1.3.1. Literals_Section_Header - - All literals are regrouped in the first part of the block. They can - be decoded first and then copied during Sequence Execution (see - Section 3.1.1.4), or they can be decoded on the flow during Sequence - Execution. - - Literals can be stored uncompressed or compressed using Huffman - prefix codes. When compressed, an optional tree description can be - present, followed by 1 or 4 streams. - - +----------------------------+ - | Literals_Section_Header | - +----------------------------+ - | [Huffman_Tree_Description] | - +----------------------------+ - | [Jump_Table] | - +----------------------------+ - | Stream_1 | - +----------------------------+ - | [Stream_2] | - +----------------------------+ - | [Stream_3] | - +----------------------------+ - | [Stream_4] | - +----------------------------+ - -3.1.1.3.1.1. Literals_Section_Header - - This field describes how literals are packed. It's a byte-aligned - variable-size bit field, ranging from 1 to 5 bytes, using little- - endian convention. - - +---------------------+-----------+ - | Literals_Block_Type | 2 bits | - +---------------------+-----------+ - | Size_Format | 1-2 bits | - +---------------------+-----------+ - | Regenerated_Size | 5-20 bits | - +---------------------+-----------+ - | [Compressed_Size] | 0-18 bits | - +---------------------+-----------+ - - In this representation, bits at the top are the lowest bits. - - - - -Collet & Kucherawy Informational [Page 15] - -RFC 8478 application/zstd October 2018 - - - The Literals_Block_Type field uses the two lowest bits of the first - byte, describing four different block types: - - +---------------------------+-------+ - | Literals_Block_Type | Value | - +---------------------------+-------+ - | Raw_Literals_Block | 0 | - +---------------------------+-------+ - | RLE_Literals_Block | 1 | - +---------------------------+-------+ - | Compressed_Literals_Block | 2 | - +---------------------------+-------+ - | Treeless_Literals_Block | 3 | - +---------------------------+-------+ - - Raw_Literals_Block: Literals are stored uncompressed. - Literals_Section_Content is Regenerated_Size. - - RLE_Literals_Block: Literals consist of a single-byte value repeated - Regenerated_Size times. Literals_Section_Content is 1. - - Compressed_Literals_Block: This is a standard Huffman-compressed - block, starting with a Huffman tree description. See details - below. Literals_Section_Content is Compressed_Size. - - Treeless_Literals_Block: This is a Huffman-compressed block, using - the Huffman tree from the previous Compressed_Literals_Block, or a - dictionary if there is no previous Huffman-compressed literals - block. Huffman_Tree_Description will be skipped. Note that if - this mode is triggered without any previous Huffman-table in the - frame (or dictionary, per Section 5), it should be treated as data - corruption. Literals_Section_Content is Compressed_Size. - - The Size_Format is divided into two families: - - o For Raw_Literals_Block and RLE_Literals_Block, it's only necessary - to decode Regenerated_Size. There is no Compressed_Size field. - - o For Compressed_Block and Treeless_Literals_Block, it's required to - decode both Compressed_Size and Regenerated_Size (the decompressed - size). It's also necessary to decode the number of streams (1 or - 4). - - For values spanning several bytes, the convention is little endian. - - Size_Format for Raw_Literals_Block and RLE_Literals_Block uses 1 or 2 - bits. Its value is (Literals_Section_Header[0]>>2) & 0x3. - - - - -Collet & Kucherawy Informational [Page 16] - -RFC 8478 application/zstd October 2018 - - - Size_Format == 00 or 10: Size_Format uses 1 bit. Regenerated_Size - uses 5 bits (value 0-31). Literals_Section_Header uses 1 byte. - Regenerated_Size = Literal_Section_Header[0]>>3. - - Size_Format == 01: Size_Format uses 2 bits. Regenerated_Size uses - 12 bits (values 0-4095). Literals_Section_Header uses 2 bytes. - Regenerated_Size = (Literals_Section_Header[0]>>4) + - (Literals_Section_Header[1]<<4). - - Size_Format == 11: Size_Format uses 2 bits. Regenerated_Size uses - 20 bits (values 0-1048575). Literals_Section_Header uses 3 bytes. - Regenerated_Size = (Literals_Section_Header[0]>>4) + - (Literals_Section_Header[1]<<4) + (Literals_Section_Header[2]<<12) - - Only Stream_1 is present for these cases. Note that it is permitted - to represent a short value (for example, 13) using a long format, - even if it's less efficient. - - Size_Format for Compressed_Literals_Block and Treeless_Literals_Block - always uses 2 bits. - - Size_Format == 00: A single stream. Both Regenerated_Size and - Compressed_Size use 10 bits (values 0-1023). - Literals_Section_Header uses 3 bytes. - - Size_Format == 01: 4 streams. Both Regenerated_Size and - Compressed_Size use 10 bits (values 0-1023). - Literals_Section_Header uses 3 bytes. - - Size_Format == 10: 4 streams. Both Regenerated_Size and - Compressed_Size use 14 bits (values 0-16383). - Literals_Section_Header uses 4 bytes. - - Size_Format == 11: 4 streams. Both Regenerated_Size and - Compressed_Size use 18 bits (values 0-262143). - Literals_Section_Header uses 5 bytes. - - Both the Compressed_Size and Regenerated_Size fields follow little- - endian convention. Note that Compressed_Size includes the size of - the Huffman_Tree_Description when it is present. - -3.1.1.3.1.2. Raw_Literals_Block - - The data in Stream_1 is Regenerated_Size bytes long. It contains the - raw literals data to be used during Sequence Execution - (Section 3.1.1.3.2). - - - - - -Collet & Kucherawy Informational [Page 17] - -RFC 8478 application/zstd October 2018 - - -3.1.1.3.1.3. RLE_Literals_Block - - Stream_1 consists of a single byte that should be repeated - Regenerated_Size times to generate the decoded literals. - -3.1.1.3.1.4. Compressed_Literals_Block and Treeless_Literals_Block - - Both of these modes contain Huffman-encoded data. For - Treeless_Literals_Block, the Huffman table comes from the previously - compressed literals block, or from a dictionary; see Section 5. - -3.1.1.3.1.5. Huffman_Tree_Description - - This section is only present when the Literals_Block_Type type is - Compressed_Literals_Block (2). The format of - Huffman_Tree_Description can be found in Section 4.2.1. The size of - Huffman_Tree_Description is determined during the decoding process. - It must be used to determine where streams begin. - - Total_Streams_Size = Compressed_Size - - Huffman_Tree_Description_Size - -3.1.1.3.1.6. Jump_Table - - The Jump_Table is only present when there are 4 Huffman-coded - streams. - - (Reminder: Huffman-compressed data consists of either 1 or 4 Huffman- - coded streams.) - - If only 1 stream is present, it is a single bitstream occupying the - entire remaining portion of the literals block, encoded as described - within Section 4.2.2. - - If there are 4 streams, Literals_Section_Header only provides enough - information to know the decompressed and compressed sizes of all 4 - streams combined. The decompressed size of each stream is equal to - (Regenerated_Size+3)/4, except for the last stream, which may be up - to 3 bytes smaller, to reach a total decompressed size as specified - in Regenerated_Size. - - The compressed size of each stream is provided explicitly in the - Jump_Table. The Jump_Table is 6 bytes long and consists of three - 2-byte little-endian fields, describing the compressed sizes of the - first 3 streams. Stream4_Size is computed from Total_Streams_Size - minus sizes of other streams. - - - - - -Collet & Kucherawy Informational [Page 18] - -RFC 8478 application/zstd October 2018 - - - Stream4_Size = Total_Streams_Size - 6 - - Stream1_Size - Stream2_Size - - Stream3_Size - - Note that if Stream1_Size + Stream2_Size + Stream3_Size exceeds - Total_Streams_Size, the data are considered corrupted. - - Each of these 4 bitstreams is then decoded independently as a - Huffman-Coded stream, as described in Section 4.2.2. - -3.1.1.3.2. Sequences_Section - - A compressed block is a succession of sequences. A sequence is a - literal copy command, followed by a match copy command. A literal - copy command specifies a length. It is the number of bytes to be - copied (or extracted) from the Literals Section. A match copy - command specifies an offset and a length. - - When all sequences are decoded, if there are literals left in the - literals section, these bytes are added at the end of the block. - - This is described in more detail in Section 3.1.1.4. - - The Sequences_Section regroups all symbols required to decode - commands. There are three symbol types: literals lengths, offsets, - and match lengths. They are encoded together, interleaved, in a - single "bitstream". - - The Sequences_Section starts by a header, followed by optional - probability tables for each symbol type, followed by the bitstream. - - Sequences_Section_Header - [Literals_Length_Table] - [Offset_Table] - [Match_Length_Table] - bitStream - - To decode the Sequences_Section, it's necessary to know its size. - This size is deduced from the size of the Literals_Section: - Sequences_Section_Size = Block_Size - Literals_Section_Header - - Literals_Section_Content - - - - - - - - - - -Collet & Kucherawy Informational [Page 19] - -RFC 8478 application/zstd October 2018 - - -3.1.1.3.2.1. Sequences_Section_Header - - This header consists of two items: - - o Number_of_Sequences - - o Symbol_Compression_Modes - - Number_of_Sequences is a variable size field using between 1 and 3 - bytes. If the first byte is "byte0": - - o if (byte0 == 0): there are no sequences. The sequence section - stops here. Decompressed content is defined entirely as Literals - Section content. The FSE tables used in Repeat_Mode are not - updated. - - o if (byte0 < 128): Number_of_Sequences = byte0. Uses 1 byte. - - o if (byte0 < 255): Number_of_Sequences = ((byte0 - 128) << 8) + - byte1. Uses 2 bytes. - - o if (byte0 == 255): Number_of_Sequences = byte1 + (byte2 << 8) + - 0x7F00. Uses 3 bytes. - - Symbol_Compression_Modes is a single byte, defining the compression - mode of each symbol type. - - +-------------+----------------------+ - | Bit Number | Field Name | - +-------------+----------------------+ - | 7-6 | Literal_Lengths_Mode | - +-------------+----------------------+ - | 5-4 | Offsets_Mode | - +-------------+----------------------+ - | 3-2 | Match_Lengths_Mode | - +-------------+----------------------+ - | 1-0 | Reserved | - +-------------+----------------------+ - - The last field, Reserved, must be all zeroes. - - - - - - - - - - - -Collet & Kucherawy Informational [Page 20] - -RFC 8478 application/zstd October 2018 - - - Literals_Lengths_Mode, Offsets_Mode, and Match_Lengths_Mode define - the Compression_Mode of literals lengths, offsets, and match lengths - symbols, respectively. They follow the same enumeration: - - +-------+---------------------+ - | Value | Compression_Mode | - +-------+---------------------+ - | 0 | Predefined_Mode | - +-------+---------------------+ - | 1 | RLE_Mode | - +-------+---------------------+ - | 2 | FSE_Compressed_Mode | - +-------+---------------------+ - | 3 | Repeat_Mode | - +-------+---------------------+ - - Predefined_Mode: A predefined FSE (see Section 4.1) distribution - table is used, as defined in Section 3.1.1.3.2.2. No distribution - table will be present. - - RLE_Mode: The table description consists of a single byte, which - contains the symbol's value. This symbol will be used for all - sequences. - - FSE_Compressed_Mode: Standard FSE compression. A distribution table - will be present. The format of this distribution table is - described in Section 4.1.1. Note that the maximum allowed - accuracy log for literals length and match length tables is 9, and - the maximum accuracy log for the offsets table is 8. This mode - must not be used when only one symbol is present; RLE_Mode should - be used instead (although any other mode will work). - - Repeat_Mode: The table used in the previous Compressed_Block with - Number_Of_Sequences > 0 will be used again, or if this is the - first block, the table in the dictionary will be used. Note that - this includes RLE_Mode, so if Repeat_Mode follows RLE_Mode, the - same symbol will be repeated. It also includes Predefined_Mode, - in which case Repeat_Mode will have the same outcome as - Predefined_Mode. No distribution table will be present. If this - mode is used without any previous sequence table in the frame (or - dictionary; see Section 5) to repeat, this should be treated as - corruption. - - - - - - - - - -Collet & Kucherawy Informational [Page 21] - -RFC 8478 application/zstd October 2018 - - -3.1.1.3.2.1.1. Sequence Codes for Lengths and Offsets - - Each symbol is a code in its own context, which specifies Baseline - and Number_of_Bits to add. Codes are FSE compressed and interleaved - with raw additional bits in the same bitstream. - - Literals length codes are values ranging from 0 to 35 inclusive. - They define lengths from 0 to 131071 bytes. The literals length is - equal to the decoded Baseline plus the result of reading - Number_of_Bits bits from the bitstream, as a little-endian value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 22] - -RFC 8478 application/zstd October 2018 - - - +----------------------+----------+----------------+ - | Literals_Length_Code | Baseline | Number_of_Bits | - +----------------------+----------+----------------+ - | 0-15 | length | 0 | - +----------------------+----------+----------------+ - | 16 | 16 | 1 | - +----------------------+----------+----------------+ - | 17 | 18 | 1 | - +----------------------+----------+----------------+ - | 18 | 20 | 1 | - +----------------------+----------+----------------+ - | 19 | 22 | 1 | - +----------------------+----------+----------------+ - | 20 | 24 | 2 | - +----------------------+----------+----------------+ - | 21 | 28 | 2 | - +----------------------+----------+----------------+ - | 22 | 32 | 3 | - +----------------------+----------+----------------+ - | 23 | 40 | 3 | - +----------------------+----------+----------------+ - | 24 | 48 | 4 | - +----------------------+----------+----------------+ - | 25 | 64 | 6 | - +----------------------+----------+----------------+ - | 26 | 128 | 7 | - +----------------------+----------+----------------+ - | 27 | 256 | 8 | - +----------------------+----------+----------------+ - | 28 | 512 | 9 | - +----------------------+----------+----------------+ - | 29 | 1024 | 10 | - +----------------------+----------+----------------+ - | 30 | 2048 | 11 | - +----------------------+----------+----------------+ - | 31 | 4096 | 12 | - +----------------------+----------+----------------+ - | 32 | 8192 | 13 | - +----------------------+----------+----------------+ - | 33 | 16384 | 14 | - +----------------------+----------+----------------+ - | 34 | 32768 | 15 | - +----------------------+----------+----------------+ - | 35 | 65536 | 16 | - +----------------------+----------+----------------+ - - - - - - -Collet & Kucherawy Informational [Page 23] - -RFC 8478 application/zstd October 2018 - - - Match length codes are values ranging from 0 to 52 inclusive. They - define lengths from 3 to 131074 bytes. The match length is equal to - the decoded Baseline plus the result of reading Number_of_Bits bits - from the bitstream, as a little-endian value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 24] - -RFC 8478 application/zstd October 2018 - - - +-------------------+-----------------------+----------------+ - | Match_Length_Code | Baseline | Number_of_Bits | - +-------------------+-----------------------+----------------+ - | 0-31 | Match_Length_Code + 3 | 0 | - +-------------------+-----------------------+----------------+ - | 32 | 35 | 1 | - +-------------------+-----------------------+----------------+ - | 33 | 37 | 1 | - +-------------------+-----------------------+----------------+ - | 34 | 39 | 1 | - +-------------------+-----------------------+----------------+ - | 35 | 41 | 1 | - +-------------------+-----------------------+----------------+ - | 36 | 43 | 2 | - +-------------------+-----------------------+----------------+ - | 37 | 47 | 2 | - +-------------------+-----------------------+----------------+ - | 38 | 51 | 3 | - +-------------------+-----------------------+----------------+ - | 39 | 59 | 3 | - +-------------------+-----------------------+----------------+ - | 40 | 67 | 4 | - +-------------------+-----------------------+----------------+ - | 41 | 83 | 4 | - +-------------------+-----------------------+----------------+ - | 42 | 99 | 5 | - +-------------------+-----------------------+----------------+ - | 43 | 131 | 7 | - +-------------------+-----------------------+----------------+ - | 44 | 259 | 8 | - +-------------------+-----------------------+----------------+ - | 45 | 515 | 9 | - +-------------------+-----------------------+----------------+ - | 46 | 1027 | 10 | - +-------------------+-----------------------+----------------+ - | 47 | 2051 | 11 | - +-------------------+-----------------------+----------------+ - | 48 | 4099 | 12 | - +-------------------+-----------------------+----------------+ - | 49 | 8195 | 13 | - +-------------------+-----------------------+----------------+ - | 50 | 16387 | 14 | - +-------------------+-----------------------+----------------+ - | 51 | 32771 | 15 | - +-------------------+-----------------------+----------------+ - | 52 | 65539 | 16 | - +-------------------+-----------------------+----------------+ - - - - -Collet & Kucherawy Informational [Page 25] - -RFC 8478 application/zstd October 2018 - - - Offset codes are values ranging from 0 to N. - - A decoder is free to limit its maximum supported value for N. - Support for values of at least 22 is recommended. At the time of - this writing, the reference decoder supports a maximum N value of 31. - - An offset code is also the number of additional bits to read in - little-endian fashion and can be translated into an Offset_Value - using the following formulas: - - Offset_Value = (1 << offsetCode) + readNBits(offsetCode); - if (Offset_Value > 3) Offset = Offset_Value - 3; - - This means that maximum Offset_Value is (2^(N+1))-1, supporting back- - reference distance up to (2^(N+1))-4, but it is limited by the - maximum back-reference distance (see Section 3.1.1.1.2). - - Offset_Value from 1 to 3 are special: they define "repeat codes". - This is described in more detail in Section 3.1.1.5. - -3.1.1.3.2.1.2. Decoding Sequences - - FSE bitstreams are read in reverse of the direction they are written. - In zstd, the compressor writes bits forward into a block, and the - decompressor must read the bitstream backwards. - - To find the start of the bitstream, it is therefore necessary to know - the offset of the last byte of the block, which can be found by - counting Block_Size bytes after the block header. - - After writing the last bit containing information, the compressor - writes a single 1 bit and then fills the byte with 0-7 zero bits of - padding. The last byte of the compressed bitstream cannot be zero - for that reason. - - When decompressing, the last byte containing the padding is the first - byte to read. The decompressor needs to skip 0-7 initial zero bits - until the first 1 bit occurs. Afterwards, the useful part of the - bitstream begins. - - FSE decoding requires a 'state' to be carried from symbol to symbol. - For more explanation on FSE decoding, see Section 4.1. - - For sequence decoding, a separate state keeps track of each literal - lengths, offsets, and match lengths symbols. Some FSE primitives are - also used. For more details on the operation of these primitives, - see Section 4.1. - - - - -Collet & Kucherawy Informational [Page 26] - -RFC 8478 application/zstd October 2018 - - - The bitstream starts with initial FSE state values, each using the - required number of bits in their respective accuracy, decoded - previously from their normalized distribution. It starts with - Literals_Length_State, followed by Offset_State, and finally - Match_Length_State. - - Note that all values are read backward, so the 'start' of the - bitstream is at the highest position in memory, immediately before - the last 1 bit for padding. - - After decoding the starting states, a single sequence is decoded - Number_Of_Sequences times. These sequences are decoded in order from - first to last. Since the compressor writes the bitstream in the - forward direction, this means the compressor must encode the - sequences starting with the last one and ending with the first. - - For each of the symbol types, the FSE state can be used to determine - the appropriate code. The code then defines the Baseline and - Number_of_Bits to read for each type. The description of the codes - for how to determine these values can be found in - Section 3.1.1.3.2.1. - - Decoding starts by reading the Number_of_Bits required to decode - offset. It does the same for Match_Length and then for - Literals_Length. This sequence is then used for Sequence Execution - (see Section 3.1.1.4). - - If it is not the last sequence in the block, the next operation is to - update states. Using the rules pre-calculated in the decoding - tables, Literals_Length_State is updated, followed by - Match_Length_State, and then Offset_State. See Section 4.1 for - details on how to update states from the bitstream. - - This operation will be repeated Number_of_Sequences times. At the - end, the bitstream shall be entirely consumed; otherwise, the - bitstream is considered corrupted. - -3.1.1.3.2.2. Default Distributions - - If Predefined_Mode is selected for a symbol type, its FSE decoding - table is generated from a predefined distribution table defined here. - For details on how to convert this distribution into a decoding - table, see Section 4.1. - - - - - - - - -Collet & Kucherawy Informational [Page 27] - -RFC 8478 application/zstd October 2018 - - -3.1.1.3.2.2.1. Literals Length - - The decoding table uses an accuracy log of 6 bits (64 states). - - short literalsLength_defaultDistribution[36] = - { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, - -1,-1,-1,-1 - }; - -3.1.1.3.2.2.2. Match Length - - The decoding table uses an accuracy log of 6 bits (64 states). - - short matchLengths_defaultDistribution[53] = - { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1, - -1,-1,-1,-1,-1 - }; - -3.1.1.3.2.2.3. Offset Codes - - The decoding table uses an accuracy log of 5 bits (32 states), and - supports a maximum N value of 28, allowing offset values up to - 536,870,908. - - If any sequence in the compressed block requires a larger offset than - this, it's not possible to use the default distribution to represent - it. - - short offsetCodes_defaultDistribution[29] = - { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1 - }; - -3.1.1.4. Sequence Execution - - Once literals and sequences have been decoded, they are combined to - produce the decoded content of a block. - - Each sequence consists of a tuple of (literals_length, offset_value, - match_length), decoded as described in the - Sequences_Section (Section 3.1.1.3.2). To execute a sequence, first - copy literals_length bytes from the decoded literals to the output. - - - - - - -Collet & Kucherawy Informational [Page 28] - -RFC 8478 application/zstd October 2018 - - - Then, match_length bytes are copied from previous decoded data. The - offset to copy from is determined by offset_value: - - o if Offset_Value > 3, then the offset is Offset_Value - 3; - - o if Offset_Value is from 1-3, the offset is a special repeat offset - value. See Section 3.1.1.5 for how the offset is determined in - this case. - - The offset is defined as from the current position (after copying the - literals), so an offset of 6 and a match length of 3 means that 3 - bytes should be copied from 6 bytes back. Note that all offsets - leading to previously decoded data must be smaller than Window_Size - defined in Frame_Header_Descriptor (Section 3.1.1.1.1). - -3.1.1.5. Repeat Offsets - - As seen above, the first three values define a repeated offset; we - will call them Repeated_Offset1, Repeated_Offset2, and - Repeated_Offset3. They are sorted in recency order, with - Repeated_Offset1 meaning "most recent one". - - If offset_value is 1, then the offset used is Repeated_Offset1, etc. - - There is one exception: When the current sequence's literals_length - is 0, repeated offsets are shifted by 1, so an offset_value of 1 - means Repeated_Offset2, an offset_value of 2 means Repeated_Offset3, - and an offset_value of 3 means Repeated_Offset1 - 1_byte. - - For the first block, the starting offset history is populated with - the following values: Repeated_Offset1 (1), Repeated_Offset2 (4), and - Repeated_Offset3 (8), unless a dictionary is used, in which case they - come from the dictionary. - - Then each block gets its starting offset history from the ending - values of the most recent Compressed_Block. Note that blocks that - are not Compressed_Block are skipped; they do not contribute to - offset history. - - The newest offset takes the lead in offset history, shifting others - back (up to its previous place if it was already present). This - means that when Repeated_Offset1 (most recent) is used, history is - unmodified. When Repeated_Offset2 is used, it is swapped with - Repeated_Offset1. If any other offset is used, it becomes - Repeated_Offset1, and the rest are shifted back by 1. - - - - - - -Collet & Kucherawy Informational [Page 29] - -RFC 8478 application/zstd October 2018 - - -3.1.2. Skippable Frames - - +--------------+------------+-----------+ - | Magic_Number | Frame_Size | User_Data | - +--------------+------------+-----------+ - | 4 bytes | 4 bytes | n bytes | - +--------------+------------+-----------+ - - Skippable frames allow the insertion of user-defined metadata into a - flow of concatenated frames. - - Skippable frames defined in this specification are compatible with - skippable frames in [LZ4]. - - From a compliant decoder perspective, skippable frames simply need to - be skipped, and their content ignored, resuming decoding after the - skippable frame. - - It should be noted that a skippable frame can be used to watermark a - stream of concatenated frames embedding any kind of tracking - information (even just a Universally Unique Identifier (UUID)). - Users wary of such possibility should scan the stream of concatenated - frames in an attempt to detect such frames for analysis or removal. - - The fields are: - - Magic_Number: 4 bytes, little-endian format. Value: 0x184D2A5?, - which means any value from 0x184D2A50 to 0x184D2A5F. All 16 - values are valid to identify a skippable frame. This - specification does not detail any specific tagging methods for - skippable frames. - - Frame_Size: This is the size, in bytes, of the following User_Data - (without including the magic number nor the size field itself). - This field is represented using 4 bytes, little-endian format, - unsigned 32 bits. This means User_Data can't be bigger than - (2^32-1) bytes. - - User_Data: This field can be anything. Data will just be skipped by - the decoder. - -4. Entropy Encoding - - Two types of entropy encoding are used by the Zstandard format: FSE - and Huffman coding. Huffman is used to compress literals, while FSE - is used for all other symbols (Literals_Length_Code, - Match_Length_Code, and offset codes) and to compress Huffman headers. - - - - -Collet & Kucherawy Informational [Page 30] - -RFC 8478 application/zstd October 2018 - - -4.1. FSE - - FSE, short for Finite State Entropy, is an entropy codec based on - [ANS]. FSE encoding/decoding involves a state that is carried over - between symbols, so decoding must be done in the opposite direction - as encoding. Therefore, all FSE bitstreams are read from end to - beginning. Note that the order of the bits in the stream is not - reversed; they are simply read in the reverse order from which they - were written. - - For additional details on FSE, see Finite State Entropy [FSE]. - - FSE decoding involves a decoding table that has a power of 2 size and - contains three elements: Symbol, Num_Bits, and Baseline. The base 2 - logarithm of the table size is its Accuracy_Log. An FSE state value - represents an index in this table. - - To obtain the initial state value, consume Accuracy_Log bits from the - stream as a little-endian value. The next symbol in the stream is - the Symbol indicated in the table for that state. To obtain the next - state value, the decoder should consume Num_Bits bits from the stream - as a little-endian value and add it to Baseline. - -4.1.1. FSE Table Description - - To decode FSE streams, it is necessary to construct the decoding - table. The Zstandard format encodes FSE table descriptions as - described here. - - An FSE distribution table describes the probabilities of all symbols - from 0 to the last present one (included) on a normalized scale of - (1 << Accuracy_Log). Note that there must be two or more symbols - with non-zero probability. - - A bitstream is read forward, in little-endian fashion. It is not - necessary to know its exact size, since the size will be discovered - and reported by the decoding process. The bitstream starts by - reporting on which scale it operates. If low4bits designates the - lowest 4 bits of the first byte, then Accuracy_Log = low4bits + 5. - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 31] - -RFC 8478 application/zstd October 2018 - - - This is followed by each symbol value, from 0 to the last present - one. The number of bits used by each field is variable and depends - on: - - Remaining probabilities + 1: For example, presuming an Accuracy_Log - of 8, and presuming 100 probabilities points have already been - distributed, the decoder may read any value from 0 to - (256 - 100 + 1) == 157, inclusive. Therefore, it must read - log2sup(157) == 8 bits. - - Value decoded: Small values use 1 fewer bit. For example, presuming - values from 0 to 157 (inclusive) are possible, 255 - 157 = 98 - values are remaining in an 8-bit field. The first 98 values - (hence from 0 to 97) use only 7 bits, and values from 98 to 157 - use 8 bits. This is achieved through this scheme: - - +------------+---------------+-----------+ - | Value Read | Value Decoded | Bits Used | - +------------+---------------+-----------+ - | 0 - 97 | 0 - 97 | 7 | - +------------+---------------+-----------+ - | 98 - 127 | 98 - 127 | 8 | - +------------+---------------+-----------+ - | 128 - 225 | 0 - 97 | 7 | - +------------+---------------+-----------+ - | 226 - 255 | 128 - 157 | 8 | - +------------+---------------+-----------+ - - Symbol probabilities are read one by one, in order. The probability - is obtained from Value decoded using the formula P = Value - 1. This - means the value 0 becomes the negative probability -1. This is a - special probability that means "less than 1". Its effect on the - distribution table is described below. For the purpose of - calculating total allocated probability points, it counts as 1. - - When a symbol has a probability of zero, it is followed by a 2-bit - repeat flag. This repeat flag tells how many probabilities of zeroes - follow the current one. It provides a number ranging from 0 to 3. - If it is a 3, another 2-bit repeat flag follows, and so on. - - When the last symbol reaches a cumulated total of - (1 << Accuracy_Log), decoding is complete. If the last symbol makes - the cumulated total go above (1 << Accuracy_Log), distribution is - considered corrupted. - - - - - - - -Collet & Kucherawy Informational [Page 32] - -RFC 8478 application/zstd October 2018 - - - Finally, the decoder can tell how many bytes were used in this - process and how many symbols are present. The bitstream consumes a - round number of bytes. Any remaining bit within the last byte is - simply unused. - - The distribution of normalized probabilities is enough to create a - unique decoding table. The table has a size of (1 << Accuracy_Log). - Each cell describes the symbol decoded and instructions to get the - next state. - - Symbols are scanned in their natural order for "less than 1" - probabilities as described above. Symbols with this probability are - being attributed a single cell, starting from the end of the table - and retreating. These symbols define a full state reset, reading - Accuracy_Log bits. - - All remaining symbols are allocated in their natural order. Starting - from symbol 0 and table position 0, each symbol gets allocated as - many cells as its probability. Cell allocation is spread, not - linear; each successor position follows this rule: - - position += (tableSize >> 1) + (tableSize >> 3) + 3; - position &= tableSize - 1; - - A position is skipped if it is already occupied by a "less than 1" - probability symbol. Position does not reset between symbols; it - simply iterates through each position in the table, switching to the - next symbol when enough states have been allocated to the current - one. - - The result is a list of state values. Each state will decode the - current symbol. - - To get the Number_of_Bits and Baseline required for the next state, - it is first necessary to sort all states in their natural order. The - lower states will need 1 more bit than higher ones. The process is - repeated for each symbol. - - For example, presuming a symbol has a probability of 5, it receives - five state values. States are sorted in natural order. The next - power of 2 is 8. The space of probabilities is divided into 8 equal - parts. Presuming the Accuracy_Log is 7, this defines 128 states, and - each share (divided by 8) is 16 in size. In order to reach 8, 8 - 5 - = 3 lowest states will count "double", doubling the number of shares - (32 in width), requiring 1 more bit in the process. - - - - - - -Collet & Kucherawy Informational [Page 33] - -RFC 8478 application/zstd October 2018 - - - Baseline is assigned starting from the higher states using fewer - bits, and proceeding naturally, then resuming at the first state, - each taking its allocated width from Baseline. - - +----------------+-------+-------+--------+------+-------+ - | state order | 0 | 1 | 2 | 3 | 4 | - +----------------+-------+-------+--------+------+-------+ - | width | 32 | 32 | 32 | 16 | 16 | - +----------------+-------+-------+--------+------+-------+ - | Number_of_Bits | 5 | 5 | 5 | 4 | 4 | - +----------------+-------+-------+--------+------+-------+ - | range number | 2 | 4 | 6 | 0 | 1 | - +----------------+-------+-------+--------+------+-------+ - | Baseline | 32 | 64 | 96 | 0 | 16 | - +----------------+-------+-------+--------+------+-------+ - | range | 32-63 | 64-95 | 96-127 | 0-15 | 16-31 | - +----------------+-------+-------+--------+------+-------+ - - The next state is determined from the current state by reading the - required Number_of_Bits and adding the specified Baseline. - - See Appendix A for the results of this process that are applied to - the default distributions. - -4.2. Huffman Coding - - Zstandard Huffman-coded streams are read backwards, similar to the - FSE bitstreams. Therefore, to find the start of the bitstream, it is - necessary to know the offset of the last byte of the Huffman-coded - stream. - - After writing the last bit containing information, the compressor - writes a single 1 bit and then fills the byte with 0-7 0 bits of - padding. The last byte of the compressed bitstream cannot be 0 for - that reason. - - When decompressing, the last byte containing the padding is the first - byte to read. The decompressor needs to skip 0-7 initial 0 bits and - the first 1 bit that occurs. Afterwards, the useful part of the - bitstream begins. - - The bitstream contains Huffman-coded symbols in little-endian order, - with the codes defined by the method below. - - - - - - - - -Collet & Kucherawy Informational [Page 34] - -RFC 8478 application/zstd October 2018 - - -4.2.1. Huffman Tree Description - - Prefix coding represents symbols from an a priori known alphabet by - bit sequences (codewords), one codeword for each symbol, in a manner - such that different symbols may be represented by bit sequences of - different lengths, but a parser can always parse an encoded string - unambiguously symbol by symbol. - - Given an alphabet with known symbol frequencies, the Huffman - algorithm allows the construction of an optimal prefix code using the - fewest bits of any possible prefix codes for that alphabet. - - The prefix code must not exceed a maximum code length. More bits - improve accuracy but yield a larger header size and require more - memory or more complex decoding operations. This specification - limits the maximum code length to 11 bits. - - All literal values from zero (included) to the last present one - (excluded) are represented by Weight with values from 0 to - Max_Number_of_Bits. Transformation from Weight to Number_of_Bits - follows this pseudocode: - - if Weight == 0 - Number_of_Bits = 0 - else - Number_of_Bits = Max_Number_of_Bits + 1 - Weight - - The last symbol's Weight is deduced from previously decoded ones, by - completing to the nearest power of 2. This power of 2 gives - Max_Number_of_Bits the depth of the current tree. - - For example, presume the following Huffman tree must be described: - - +---------------+----------------+ - | Literal Value | Number_of_Bits | - +---------------+----------------+ - | 0 | 1 | - +---------------+----------------+ - | 1 | 2 | - +---------------+----------------+ - | 2 | 3 | - +---------------+----------------+ - | 3 | 0 | - +---------------+----------------+ - | 4 | 4 | - +---------------+----------------+ - | 5 | 4 | - +---------------+----------------+ - - - -Collet & Kucherawy Informational [Page 35] - -RFC 8478 application/zstd October 2018 - - - The tree depth is 4, since its longest element uses 4 bits. (The - longest elements are those with the smallest frequencies.) Value 5 - will not be listed as it can be determined from the values for 0-4, - nor will values above 5 as they are all 0. Values from 0 to 4 will - be listed using Weight instead of Number_of_Bits. The pseudocode to - determine Weight is: - - if Number_of_Bits == 0 - Weight = 0 - else - Weight = Max_Number_of_Bits + 1 - Number_of_Bits - - It gives the following series of weights: - - +---------------+--------+ - | Literal Value | Weight | - +---------------+--------+ - | 0 | 4 | - +---------------+--------+ - | 1 | 3 | - +---------------+--------+ - | 2 | 2 | - +---------------+--------+ - | 3 | 0 | - +---------------+--------+ - | 4 | 1 | - +---------------+--------+ - - The decoder will do the inverse operation: having collected weights - of literals from 0 to 4, it knows the last literal, 5, is present - with a non-zero Weight. The Weight of 5 can be determined by - advancing to the next power of 2. The sum of 2^(Weight-1) (excluding - 0's) is 15. The nearest power of 2 is 16. Therefore, - Max_Number_of_Bits = 4 and Weight[5] = 16 - 15 = 1. - -4.2.1.1. Huffman Tree Header - - This is a single byte value (0-255), which describes how the series - of weights is encoded. - - headerByte < 128: The series of weights is compressed using FSE (see - below). The length of the FSE-compressed series is equal to - headerByte (0-127). - - - - - - - - -Collet & Kucherawy Informational [Page 36] - -RFC 8478 application/zstd October 2018 - - - headerByte >= 128: This is a direct representation, where each - Weight is written directly as a 4-bit field (0-15). They are - encoded forward, 2 weights to a byte with the first weight taking - the top 4 bits and the second taking the bottom 4; for example, - the following operations could be used to read the weights: - - Weight[0] = (Byte[0] >> 4) - Weight[1] = (Byte[0] & 0xf), - etc. - - The full representation occupies ceiling(Number_of_Symbols/2) - bytes, meaning it uses only full bytes even if Number_of_Symbols - is odd. Number_of_Symbols = headerByte - 127. Note that maximum - Number_of_Symbols is 255 - 127 = 128. If any literal has a value - over 128, raw header mode is not possible, and it is necessary to - use FSE compression. - -4.2.1.2. FSE Compression of Huffman Weights - - In this case, the series of Huffman weights is compressed using FSE - compression. It is a single bitstream with two interleaved states, - sharing a single distribution table. - - To decode an FSE bitstream, it is necessary to know its compressed - size. Compressed size is provided by headerByte. It's also - necessary to know its maximum possible decompressed size, which is - 255, since literal values span from 0 to 255, and the last symbol's - Weight is not represented. - - An FSE bitstream starts by a header, describing probabilities - distribution. It will create a decoding table. For a list of - Huffman weights, the maximum accuracy log is 6 bits. For more - details, see Section 4.1.1. - - The Huffman header compression uses two states, which share the same - FSE distribution table. The first state (State1) encodes the even- - numbered index symbols, and the second (State2) encodes the odd- - numbered index symbols. State1 is initialized first, and then - State2, and they take turns decoding a single symbol and updating - their state. For more details on these FSE operations, see - Section 4.1. - - The number of symbols to be decoded is determined by tracking the - bitStream overflow condition: If updating state after decoding a - symbol would require more bits than remain in the stream, it is - assumed that extra bits are zero. Then, symbols for each of the - final states are decoded and the process is complete. - - - - -Collet & Kucherawy Informational [Page 37] - -RFC 8478 application/zstd October 2018 - - -4.2.1.3. Conversion from Weights to Huffman Prefix Codes - - All present symbols will now have a Weight value. It is possible to - transform weights into Number_of_Bits, using this formula: - - if Weight > 0 - Number_of_Bits = Max_Number_of_Bits + 1 - Weight - else - Number_of_Bits = 0 - - Symbols are sorted by Weight. Within the same Weight, symbols keep - natural sequential order. Symbols with a Weight of zero are removed. - Then, starting from the lowest Weight, prefix codes are distributed - in sequential order. - - For example, assume the following list of weights has been decoded: - - +---------+--------+ - | Literal | Weight | - +---------+--------+ - | 0 | 4 | - +---------+--------+ - | 1 | 3 | - +---------+--------+ - | 2 | 2 | - +---------+--------+ - | 3 | 0 | - +---------+--------+ - | 4 | 1 | - +---------+--------+ - | 5 | 1 | - +---------+--------+ - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 38] - -RFC 8478 application/zstd October 2018 - - - Sorting by weight and then the natural sequential order yields the - following distribution: - - +---------+--------+----------------+--------------+ - | Literal | Weight | Number_Of_Bits | Prefix Codes | - +---------+--------+----------------|--------------+ - | 3 | 0 | 0 | N/A | - +---------+--------+----------------|--------------+ - | 4 | 1 | 4 | 0000 | - +---------+--------+----------------|--------------+ - | 5 | 1 | 4 | 0001 | - +---------+--------+----------------|--------------+ - | 2 | 2 | 3 | 001 | - +---------+--------+----------------|--------------+ - | 1 | 3 | 2 | 01 | - +---------+--------+----------------|--------------+ - | 0 | 4 | 1 | 1 | - +---------+--------+----------------|--------------+ - -4.2.2. Huffman-Coded Streams - - Given a Huffman decoding table, it is possible to decode a Huffman- - coded stream. - - Each bitstream must be read backward, which starts from the end and - goes up to the beginning. Therefore, it is necessary to know the - size of each bitstream. - - It is also necessary to know exactly which bit is the last. This is - detected by a final bit flag: the highest bit of the last byte is a - final-bit-flag. Consequently, a last byte of 0 is not possible. And - the final-bit-flag itself is not part of the useful bitstream. - Hence, the last byte contains between 0 and 7 useful bits. - - Starting from the end, it is possible to read the bitstream in a - little-endian fashion, keeping track of already used bits. Since the - bitstream is encoded in reverse order, starting from the end, read - symbols in forward order. - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 39] - -RFC 8478 application/zstd October 2018 - - - For example, if the literal sequence "0145" was encoded using the - above prefix code, it would be encoded (in reverse order) as: - - +---------+----------+ - | Symbol | Encoding | - +---------+----------+ - | 5 | 0000 | - +---------+----------+ - | 4 | 0001 | - +---------+----------+ - | 1 | 01 | - +---------+----------+ - | 0 | 1 | - +---------+----------+ - | Padding | 00001 | - +---------+----------+ - - This results in the following 2-byte bitstream: - - 00010000 00001101 - - Here is an alternative representation with the symbol codes separated - by underscores: - - 0001_0000 00001_1_01 - - Reading the highest Max_Number_of_Bits bits, it's possible to compare - the extracted value to the decoding table, determining the symbol to - decode and number of bits to discard. - - The process continues reading up to the required number of symbols - per stream. If a bitstream is not entirely and exactly consumed, - hence reaching exactly its beginning position with all bits consumed, - the decoding process is considered faulty. - -5. Dictionary Format - - Zstandard is compatible with "raw content" dictionaries, free of any - format restriction, except that they must be at least 8 bytes. These - dictionaries function as if they were just the content part of a - formatted dictionary. - - However, dictionaries created by "zstd --train" in the reference - implementation follow a specific format, described here. - - Dictionaries are not included in the compressed content but rather - are provided out of band. That is, the Dictionary_ID identifies - which should be used, but this specification does not describe the - - - -Collet & Kucherawy Informational [Page 40] - -RFC 8478 application/zstd October 2018 - - - mechanism by which the dictionary is obtained prior to use during - compression or decompression. - - A dictionary has a size, defined either by a buffer limit or a file - size. The general format is: - - +--------------+---------------+----------------+---------+ - | Magic_Number | Dictionary_ID | Entropy_Tables | Content | - +--------------+---------------+----------------+---------+ - - Magic_Number: 4 bytes ID, value 0xEC30A437, little-endian format. - - Dictionary_ID: 4 bytes, stored in little-endian format. - Dictionary_ID can be any value, except 0 (which means no - Dictionary_ID). It is used by decoders to check if they use the - correct dictionary. If the frame is going to be distributed in a - private environment, any Dictionary_ID can be used. However, for - public distribution of compressed frames, the following ranges are - reserved and shall not be used: - - low range: <= 32767 - high range: >= (2^31) - - Entropy_Tables: Follow the same format as the tables in compressed - blocks. See the relevant FSE and Huffman sections for how to - decode these tables. They are stored in the following order: - Huffman table for literals, FSE table for offsets, FSE table for - match lengths, and FSE table for literals lengths. These tables - populate the Repeat Stats literals mode and Repeat distribution - mode for sequence decoding. It is finally followed by 3 offset - values, populating repeat offsets (instead of using {1,4,8}), - stored in order, 4-bytes little-endian each, for a total of 12 - bytes. Each repeat offset must have a value less than the - dictionary size. - - Content: The rest of the dictionary is its content. The content - acts as a "past" in front of data to be compressed or - decompressed, so it can be referenced in sequence commands. As - long as the amount of data decoded from this frame is less than or - equal to Window_Size, sequence commands may specify offsets longer - than the total length of decoded output so far to reference back - to the dictionary, even parts of the dictionary with offsets - larger than Window_Size. After the total output has surpassed - Window_Size, however, this is no longer allowed, and the - dictionary is no longer accessible. - - - - - - -Collet & Kucherawy Informational [Page 41] - -RFC 8478 application/zstd October 2018 - - -6. IANA Considerations - - IANA has made two registrations, as described below. - -6.1. The 'application/zstd' Media Type - - The 'application/zstd' media type identifies a block of data that is - compressed using zstd compression. The data is a stream of bytes as - described in this document. IANA has added the following to the - "Media Types" registry: - - Type name: application - - Subtype name: zstd - - Required parameters: N/A - - Optional parameters: N/A - - Encoding considerations: binary - - Security considerations: See Section 7 of RFC 8478 - - Interoperability considerations: N/A - - Published specification: RFC 8478 - - Applications that use this media type: anywhere data size is an - issue - - Additional information: - - Magic number(s): 4 bytes, little-endian format. - Value: 0xFD2FB528 - - File extension(s): zst - - Macintosh file type code(s): N/A - - For further information: See [ZSTD] - - Intended usage: common - - Restrictions on usage: N/A - - Author: Murray S. Kucherawy - - Change Controller: IETF - - - -Collet & Kucherawy Informational [Page 42] - -RFC 8478 application/zstd October 2018 - - - Provisional registration: no - -6.2. Content Encoding - - IANA has added the following entry to the "HTTP Content Coding - Registry" within the "Hypertext Transfer Protocol (HTTP) Parameters" - registry: - - Name: zstd - - Description: A stream of bytes compressed using the Zstandard - protocol - - Pointer to specification text: RFC 8478 - -6.3. Dictionaries - - Work in progress includes development of dictionaries that will - optimize compression and decompression of particular types of data. - Specification of such dictionaries for public use will necessitate - registration of a code point from the reserved range described in - Section 3.1.1.1.3 and its association with a specific dictionary. - - However, there are at present no such dictionaries published for - public use, so this document makes no immediate request of IANA to - create such a registry. - -7. Security Considerations - - Any data compression method involves the reduction of redundancy in - the data. Zstandard is no exception, and the usual precautions - apply. - - One should never compress a message whose content must remain secret - with a message generated by a third party. Such a compression can be - used to guess the content of the secret message through analysis of - entropy reduction. This was demonstrated in the Compression Ratio - Info-leak Made Easy (CRIME) attack [CRIME], for example. - - A decoder has to demonstrate capabilities to detect and prevent any - kind of data tampering in the compressed frame from triggering system - faults, such as reading or writing beyond allowed memory ranges. - This can be guaranteed by either the implementation language or - careful bound checkings. Of particular note is the encoding of - Number_of_Sequences values that cause the decoder to read into the - block header (and beyond), as well as the indication of a - Frame_Content_Size that is smaller than the actual decompressed data, - in an attempt to trigger a buffer overflow. It is highly recommended - - - -Collet & Kucherawy Informational [Page 43] - -RFC 8478 application/zstd October 2018 - - - to fuzz-test (i.e., provide invalid, unexpected, or random input and - verify safe operation of) decoder implementations to test and harden - their capability to detect bad frames and deal with them without any - adverse system side effect. - - An attacker may provide correctly formed compressed frames with - unreasonable memory requirements. A decoder must always control - memory requirements and enforce some (system-specific) limits in - order to protect memory usage from such scenarios. - - Compression can be optimized by training a dictionary on a variety of - related content payloads. This dictionary must then be available at - the decoder for decompression of the payload to be possible. While - this document does not specify how to acquire a dictionary for a - given compressed payload, it is worth noting that third-party - dictionaries may interact unexpectedly with a decoder, leading to - possible memory or other resource exhaustion attacks. We expect such - topics to be discussed in further detail in the Security - Considerations section of a forthcoming RFC for dictionary - acquisition and transmission, but highlight this issue now out of an - abundance of caution. - - As discussed in Section 3.1.2, it is possible to store arbitrary user - metadata in skippable frames. While such frames are ignored during - decompression of the data, they can be used as a watermark to track - the path of the compressed payload. - -8. Implementation Status - - Source code for a C language implementation of a Zstandard-compliant - library is available at [ZSTD-GITHUB]. This implementation is - considered to be the reference implementation and is production - ready; it implements the full range of the specification. It is - routinely tested against security hazards and widely deployed within - Facebook infrastructure. - - The reference version is optimized for speed and is highly portable. - It has been proven to run safely on multiple architectures (e.g., - x86, x64, ARM, MIPS, PowerPC, IA64) featuring 32- or 64-bit - addressing schemes, a little- or big-endian storage scheme, a number - of different operating systems (e.g., UNIX (including Linux, BSD, - OS-X, and Solaris) and Windows), and a number of compilers (e.g., - gcc, clang, visual, and icc). - - - - - - - - -Collet & Kucherawy Informational [Page 44] - -RFC 8478 application/zstd October 2018 - - -9. References - -9.1. Normative References - - [ZSTD] "Zstandard", . - -9.2. Informative References - - [ANS] Duda, J., "Asymmetric numeral systems: entropy coding - combining speed of Huffman coding with compression rate of - arithmetic coding", January 2014, - . - - [CRIME] "CRIME", June 2018, . - - [FSE] "FiniteStateEntropy", commit 6efa78a, June 2018, - . - - [LZ4] "LZ4 Frame Format Description", commit d03224b, January - 2018, . - - [RFC1952] Deutsch, P., "GZIP file format specification version 4.3", - RFC 1952, DOI 10.17487/RFC1952, May 1996, - . - - [XXHASH] "XXHASH Algorithm", . - - [ZSTD-GITHUB] - "zstd", commit 8514bd8, August 2018, - . - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 45] - -RFC 8478 application/zstd October 2018 - - -Appendix A. Decoding Tables for Predefined Codes - - This appendix contains FSE decoding tables for the predefined literal - length, match length, and offset codes. The tables have been - constructed using the algorithm as given above in Section 4.1.1. The - tables here can be used as examples to crosscheck that an - implementation has built its decoding tables correctly. - -A.1. Literal Length Code Table - - +-------+--------+----------------+------+ - | State | Symbol | Number_Of_Bits | Base | - +-------+--------+----------------+------+ - | 0 | 0 | 0 | 0 | - +-------+--------+----------------+------+ - | 0 | 0 | 4 | 0 | - +-------+--------+----------------+------+ - | 1 | 0 | 4 | 16 | - +-------+--------+----------------+------+ - | 2 | 1 | 5 | 32 | - +-------+--------+----------------+------+ - | 3 | 3 | 5 | 0 | - +-------+--------+----------------+------+ - | 4 | 4 | 5 | 0 | - +-------+--------+----------------+------+ - | 5 | 6 | 5 | 0 | - +-------+--------+----------------+------+ - | 6 | 7 | 5 | 0 | - +-------+--------+----------------+------+ - | 7 | 9 | 5 | 0 | - +-------+--------+----------------+------+ - | 8 | 10 | 5 | 0 | - +-------+--------+----------------+------+ - | 9 | 12 | 5 | 0 | - +-------+--------+----------------+------+ - | 10 | 14 | 6 | 0 | - +-------+--------+----------------+------+ - | 11 | 16 | 5 | 0 | - +-------+--------+----------------+------+ - | 12 | 18 | 5 | 0 | - +-------+--------+----------------+------+ - | 13 | 19 | 5 | 0 | - +-------+--------+----------------+------+ - | 14 | 21 | 5 | 0 | - +-------+--------+----------------+------+ - | 15 | 22 | 5 | 0 | - +-------+--------+----------------+------+ - | 16 | 24 | 5 | 0 | - - - -Collet & Kucherawy Informational [Page 46] - -RFC 8478 application/zstd October 2018 - - - +-------+--------+----------------+------+ - | 17 | 25 | 5 | 32 | - +-------+--------+----------------+------+ - | 18 | 26 | 5 | 0 | - +-------+--------+----------------+------+ - | 19 | 27 | 6 | 0 | - +-------+--------+----------------+------+ - | 20 | 29 | 6 | 0 | - +-------+--------+----------------+------+ - | 21 | 31 | 6 | 0 | - +-------+--------+----------------+------+ - | 22 | 0 | 4 | 32 | - +-------+--------+----------------+------+ - | 23 | 1 | 4 | 0 | - +-------+--------+----------------+------+ - | 24 | 2 | 5 | 0 | - +-------+--------+----------------+------+ - | 25 | 4 | 5 | 32 | - +-------+--------+----------------+------+ - | 26 | 5 | 5 | 0 | - +-------+--------+----------------+------+ - | 27 | 7 | 5 | 32 | - +-------+--------+----------------+------+ - | 28 | 8 | 5 | 0 | - +-------+--------+----------------+------+ - | 29 | 10 | 5 | 32 | - +-------+--------+----------------+------+ - | 30 | 11 | 5 | 0 | - +-------+--------+----------------+------+ - | 31 | 13 | 6 | 0 | - +-------+--------+----------------+------+ - | 32 | 16 | 5 | 32 | - +-------+--------+----------------+------+ - | 33 | 17 | 5 | 0 | - +-------+--------+----------------+------+ - | 34 | 19 | 5 | 32 | - +-------+--------+----------------+------+ - | 35 | 20 | 5 | 0 | - +-------+--------+----------------+------+ - | 36 | 22 | 5 | 32 | - +-------+--------+----------------+------+ - | 37 | 23 | 5 | 0 | - +-------+--------+----------------+------+ - | 38 | 25 | 4 | 0 | - +-------+--------+----------------+------+ - | 39 | 25 | 4 | 16 | - +-------+--------+----------------+------+ - | 40 | 26 | 5 | 32 | - - - -Collet & Kucherawy Informational [Page 47] - -RFC 8478 application/zstd October 2018 - - - +-------+--------+----------------+------+ - | 41 | 28 | 6 | 0 | - +-------+--------+----------------+------+ - | 42 | 30 | 6 | 0 | - +-------+--------+----------------+------+ - | 43 | 0 | 4 | 48 | - +-------+--------+----------------+------+ - | 44 | 1 | 4 | 16 | - +-------+--------+----------------+------+ - | 45 | 2 | 5 | 32 | - +-------+--------+----------------+------+ - | 46 | 3 | 5 | 32 | - +-------+--------+----------------+------+ - | 47 | 5 | 5 | 32 | - +-------+--------+----------------+------+ - | 48 | 6 | 5 | 32 | - +-------+--------+----------------+------+ - | 49 | 8 | 5 | 32 | - +-------+--------+----------------+------+ - | 50 | 9 | 5 | 32 | - +-------+--------+----------------+------+ - | 51 | 11 | 5 | 32 | - +-------+--------+----------------+------+ - | 52 | 12 | 5 | 32 | - +-------+--------+----------------+------+ - | 53 | 15 | 6 | 0 | - +-------+--------+----------------+------+ - | 54 | 17 | 5 | 32 | - +-------+--------+----------------+------+ - | 55 | 18 | 5 | 32 | - +-------+--------+----------------+------+ - | 56 | 20 | 5 | 32 | - +-------+--------+----------------+------+ - | 57 | 21 | 5 | 32 | - +-------+--------+----------------+------+ - | 58 | 23 | 5 | 32 | - +-------+--------+----------------+------+ - | 59 | 24 | 5 | 32 | - +-------+--------+----------------+------+ - | 60 | 35 | 6 | 0 | - +-------+--------+----------------+------+ - | 61 | 34 | 6 | 0 | - +-------+--------+----------------+------+ - | 62 | 33 | 6 | 0 | - +-------+--------+----------------+------+ - | 63 | 32 | 6 | 0 | - +-------+--------+----------------+------+ - - - - -Collet & Kucherawy Informational [Page 48] - -RFC 8478 application/zstd October 2018 - - -A.2. Match Length Code Table - - +-------+--------+----------------+------+ - | State | Symbol | Number_Of_Bits | Base | - +-------+--------+----------------+------+ - | 0 | 0 | 0 | 0 | - +-------+--------+----------------+------+ - | 0 | 0 | 6 | 0 | - +-------+--------+----------------+------+ - | 1 | 1 | 4 | 0 | - +-------+--------+----------------+------+ - | 2 | 2 | 5 | 32 | - +-------+--------+----------------+------+ - | 3 | 3 | 5 | 0 | - +-------+--------+----------------+------+ - | 4 | 5 | 5 | 0 | - +-------+--------+----------------+------+ - | 5 | 6 | 5 | 0 | - +-------+--------+----------------+------+ - | 6 | 8 | 5 | 0 | - +-------+--------+----------------+------+ - | 7 | 10 | 6 | 0 | - +-------+--------+----------------+------+ - | 8 | 13 | 6 | 0 | - +-------+--------+----------------+------+ - | 9 | 16 | 6 | 0 | - +-------+--------+----------------+------+ - | 10 | 19 | 6 | 0 | - +-------+--------+----------------+------+ - | 11 | 22 | 6 | 0 | - +-------+--------+----------------+------+ - | 12 | 25 | 6 | 0 | - +-------+--------+----------------+------+ - | 13 | 28 | 6 | 0 | - +-------+--------+----------------+------+ - | 14 | 31 | 6 | 0 | - +-------+--------+----------------+------+ - | 15 | 33 | 6 | 0 | - +-------+--------+----------------+------+ - | 16 | 35 | 6 | 0 | - +-------+--------+----------------+------+ - | 17 | 37 | 6 | 0 | - +-------+--------+----------------+------+ - | 18 | 39 | 6 | 0 | - +-------+--------+----------------+------+ - | 19 | 41 | 6 | 0 | - +-------+--------+----------------+------+ - | 20 | 43 | 6 | 0 | - - - -Collet & Kucherawy Informational [Page 49] - -RFC 8478 application/zstd October 2018 - - - +-------+--------+----------------+------+ - | 21 | 45 | 6 | 0 | - +-------+--------+----------------+------+ - | 22 | 1 | 4 | 16 | - +-------+--------+----------------+------+ - | 23 | 2 | 4 | 0 | - +-------+--------+----------------+------+ - | 24 | 3 | 5 | 32 | - +-------+--------+----------------+------+ - | 25 | 4 | 5 | 0 | - +-------+--------+----------------+------+ - | 26 | 6 | 5 | 32 | - +-------+--------+----------------+------+ - | 27 | 7 | 5 | 0 | - +-------+--------+----------------+------+ - | 28 | 9 | 6 | 0 | - +-------+--------+----------------+------+ - | 29 | 12 | 6 | 0 | - +-------+--------+----------------+------+ - | 30 | 15 | 6 | 0 | - +-------+--------+----------------+------+ - | 31 | 18 | 6 | 0 | - +-------+--------+----------------+------+ - | 32 | 21 | 6 | 0 | - +-------+--------+----------------+------+ - | 33 | 24 | 6 | 0 | - +-------+--------+----------------+------+ - | 34 | 27 | 6 | 0 | - +-------+--------+----------------+------+ - | 35 | 30 | 6 | 0 | - +-------+--------+----------------+------+ - | 36 | 32 | 6 | 0 | - +-------+--------+----------------+------+ - | 37 | 34 | 6 | 0 | - +-------+--------+----------------+------+ - | 38 | 36 | 6 | 0 | - +-------+--------+----------------+------+ - | 39 | 38 | 6 | 0 | - +-------+--------+----------------+------+ - | 40 | 40 | 6 | 0 | - +-------+--------+----------------+------+ - | 41 | 42 | 6 | 0 | - +-------+--------+----------------+------+ - | 42 | 44 | 6 | 0 | - +-------+--------+----------------+------+ - | 43 | 1 | 4 | 32 | - +-------+--------+----------------+------+ - | 44 | 1 | 4 | 48 | - - - -Collet & Kucherawy Informational [Page 50] - -RFC 8478 application/zstd October 2018 - - - +-------+--------+----------------+------+ - | 45 | 2 | 4 | 16 | - +-------+--------+----------------+------+ - | 46 | 4 | 5 | 32 | - +-------+--------+----------------+------+ - | 47 | 5 | 5 | 32 | - +-------+--------+----------------+------+ - | 48 | 7 | 5 | 32 | - +-------+--------+----------------+------+ - | 49 | 8 | 5 | 32 | - +-------+--------+----------------+------+ - | 50 | 11 | 6 | 0 | - +-------+--------+----------------+------+ - | 51 | 14 | 6 | 0 | - +-------+--------+----------------+------+ - | 52 | 17 | 6 | 0 | - +-------+--------+----------------+------+ - | 53 | 20 | 6 | 0 | - +-------+--------+----------------+------+ - | 54 | 23 | 6 | 0 | - +-------+--------+----------------+------+ - | 55 | 26 | 6 | 0 | - +-------+--------+----------------+------+ - | 56 | 29 | 6 | 0 | - +-------+--------+----------------+------+ - | 57 | 52 | 6 | 0 | - +-------+--------+----------------+------+ - | 58 | 51 | 6 | 0 | - +-------+--------+----------------+------+ - | 59 | 50 | 6 | 0 | - +-------+--------+----------------+------+ - | 60 | 49 | 6 | 0 | - +-------+--------+----------------+------+ - | 61 | 48 | 6 | 0 | - +-------+--------+----------------+------+ - | 62 | 47 | 6 | 0 | - +-------+--------+----------------+------+ - | 63 | 46 | 6 | 0 | - +-------+--------+----------------+------+ - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 51] - -RFC 8478 application/zstd October 2018 - - -A.3. Offset Code Table - - +-------+--------+----------------+------+ - | State | Symbol | Number_Of_Bits | Base | - +-------+--------+----------------+------+ - | 0 | 0 | 0 | 0 | - +-------+--------+----------------+------+ - | 0 | 0 | 5 | 0 | - +-------+--------+----------------+------+ - | 1 | 6 | 4 | 0 | - +-------+--------+----------------+------+ - | 2 | 9 | 5 | 0 | - +-------+--------+----------------+------+ - | 3 | 15 | 5 | 0 | - +-------+--------+----------------+------+ - | 4 | 21 | 5 | 0 | - +-------+--------+----------------+------+ - | 5 | 3 | 5 | 0 | - +-------+--------+----------------+------+ - | 6 | 7 | 4 | 0 | - +-------+--------+----------------+------+ - | 7 | 12 | 5 | 0 | - +-------+--------+----------------+------+ - | 8 | 18 | 5 | 0 | - +-------+--------+----------------+------+ - | 9 | 23 | 5 | 0 | - +-------+--------+----------------+------+ - | 10 | 5 | 5 | 0 | - +-------+--------+----------------+------+ - | 11 | 8 | 4 | 0 | - +-------+--------+----------------+------+ - | 12 | 14 | 5 | 0 | - +-------+--------+----------------+------+ - | 13 | 20 | 5 | 0 | - +-------+--------+----------------+------+ - | 14 | 2 | 5 | 0 | - +-------+--------+----------------+------+ - | 15 | 7 | 4 | 16 | - +-------+--------+----------------+------+ - | 16 | 11 | 5 | 0 | - +-------+--------+----------------+------+ - | 17 | 17 | 5 | 0 | - +-------+--------+----------------+------+ - | 18 | 22 | 5 | 0 | - +-------+--------+----------------+------+ - | 19 | 4 | 5 | 0 | - +-------+--------+----------------+------+ - | 20 | 8 | 4 | 16 | - - - -Collet & Kucherawy Informational [Page 52] - -RFC 8478 application/zstd October 2018 - - - +-------+--------+----------------+------+ - | 21 | 13 | 5 | 0 | - +-------+--------+----------------+------+ - | 22 | 19 | 5 | 0 | - +-------+--------+----------------+------+ - | 23 | 1 | 5 | 0 | - +-------+--------+----------------+------+ - | 24 | 6 | 4 | 16 | - +-------+--------+----------------+------+ - | 25 | 10 | 5 | 0 | - +-------+--------+----------------+------+ - | 26 | 16 | 5 | 0 | - +-------+--------+----------------+------+ - | 27 | 28 | 5 | 0 | - +-------+--------+----------------+------+ - | 28 | 27 | 5 | 0 | - +-------+--------+----------------+------+ - | 29 | 26 | 5 | 0 | - +-------+--------+----------------+------+ - | 30 | 25 | 5 | 0 | - +-------+--------+----------------+------+ - | 31 | 24 | 5 | 0 | - +-------+--------+----------------+------+ - -Acknowledgments - - zstd was developed by Yann Collet. - - Bobo Bose-Kolanu, Felix Handte, Kyle Nekritz, Nick Terrell, and David - Schleimer provided helpful feedback during the development of this - document. - - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 53] - -RFC 8478 application/zstd October 2018 - - -Authors' Addresses - - Yann Collet - Facebook - 1 Hacker Way - Menlo Park, CA 94025 - United States of America - - Email: cyan@fb.com - - - Murray S. Kucherawy (editor) - Facebook - 1 Hacker Way - Menlo Park, CA 94025 - United States of America - - Email: msk@fb.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Collet & Kucherawy Informational [Page 54] - diff --git a/lib/std/compress/testdata/rfc8478.txt.zst.19 b/lib/std/compress/testdata/rfc8478.txt.zst.19 deleted file mode 100644 index e0cf325af238aaf25c2d4ec05107381a28bd481f..0000000000000000000000000000000000000000 Binary files a/lib/std/compress/testdata/rfc8478.txt.zst.19 and /dev/null differ diff --git a/lib/std/compress/testdata/rfc8478.txt.zst.3 b/lib/std/compress/testdata/rfc8478.txt.zst.3 deleted file mode 100644 index 781601a8a2c9150aad00ee56d7997d2a96396404..0000000000000000000000000000000000000000 Binary files a/lib/std/compress/testdata/rfc8478.txt.zst.3 and /dev/null differ diff --git a/lib/std/compress/xz/Decompress.zig b/lib/std/compress/xz/Decompress.zig index 2fff561c73862a382eb5ff30e3d0a8418ad2bec6..5fc5a6068eb41137c604a6ba26e7fe35ed5ab7d3 100644 --- a/lib/std/compress/xz/Decompress.zig +++ b/lib/std/compress/xz/Decompress.zig @@ -2,8 +2,8 @@ const Decompress = @This(); const std = @import("../../std.zig"); const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; -const Crc32 = std.hash.Crc32; -const Crc64 = std.hash.crc.Crc64Xz; +const Crc32 = std.hash.crc.@"CRC-32/ISO-HDLC"; +const Crc64 = std.hash.crc.@"CRC-64/XZ"; const Sha256 = std.crypto.hash.sha2.Sha256; const lzma2 = std.compress.lzma2; const Writer = std.Io.Writer; diff --git a/lib/std/compress/zstd.zig b/lib/std/compress/zstd.zig index 51168889c6355b7952e9fe54576c7b74edc6d197..8471f38ba2e87bfb05ae08663e836cfc5339b853 100644 --- a/lib/std/compress/zstd.zig +++ b/lib/std/compress/zstd.zig @@ -121,17 +121,6 @@ fn testExpectDecompressError(err: anyerror, compressed: []const u8) !void { try std.testing.expectError(err, zstd_stream.err orelse {}); } -test Decompress { - const uncompressed = @embedFile("testdata/rfc8478.txt"); - const compressed3 = @embedFile("testdata/rfc8478.txt.zst.3"); - const compressed19 = @embedFile("testdata/rfc8478.txt.zst.19"); - - try testExpectDecompress(uncompressed, compressed3); - try testExpectDecompress(uncompressed, compressed19); - try std.testing.expectEqual(uncompressed.len, testDiscard(std.testing.allocator, compressed3)); - try std.testing.expectEqual(uncompressed.len, testDiscard(std.testing.allocator, compressed19)); -} - test "partial magic number" { const input_raw = "\x28\xb5\x2f"; // 3 bytes of the 4-byte zstandard frame magic number diff --git a/lib/std/crypto/argon2.zig b/lib/std/crypto/argon2.zig index 9add038b95bb5d46432fcaaeacf59a2f077185fb..e3550abe1d7cfcad3cdc738ac5f2f01e2606e0a5 100644 --- a/lib/std/crypto/argon2.zig +++ b/lib/std/crypto/argon2.zig @@ -609,10 +609,8 @@ pub fn strHash( } /// Options for hash verification. -/// -/// Allocator is required for argon2. pub const VerifyOptions = struct { - allocator: ?mem.Allocator, + allocator: mem.Allocator, }; /// Verify that a previously computed hash is valid for a given password. @@ -622,8 +620,7 @@ pub fn strVerify( options: VerifyOptions, io: Io, ) Error!void { - const allocator = options.allocator orelse return Error.AllocatorRequired; - return PhcFormatHasher.verify(allocator, str, password, io); + return PhcFormatHasher.verify(options.allocator, str, password, io); } test "argon2d" { diff --git a/lib/std/crypto/scrypt.zig b/lib/std/crypto/scrypt.zig index 913feb4b380e909b816924a95131df14ef97cf69..9939188ebff47ad0a631255d7a2bf4be49c30e57 100644 --- a/lib/std/crypto/scrypt.zig +++ b/lib/std/crypto/scrypt.zig @@ -566,10 +566,8 @@ pub fn strHashWithSalt( } /// Options for hash verification. -/// -/// Allocator is required for scrypt. pub const VerifyOptions = struct { - allocator: ?mem.Allocator, + allocator: mem.Allocator, }; /// Verify that a previously computed hash is valid for a given password. @@ -578,11 +576,10 @@ pub fn strVerify( password: []const u8, options: VerifyOptions, ) Error!void { - const allocator = options.allocator orelse return Error.AllocatorRequired; if (mem.startsWith(u8, str, crypt_format.prefix)) { - return CryptFormatHasher.verify(allocator, str, password); + return CryptFormatHasher.verify(options.allocator, str, password); } else { - return PhcFormatHasher.verify(allocator, str, password); + return PhcFormatHasher.verify(options.allocator, str, password); } } @@ -693,7 +690,7 @@ test "strHash and strVerify" { const password = "testpass"; const params = Params.interactive; - const verify_options = VerifyOptions{ .allocator = alloc }; + const verify_options: VerifyOptions = .{ .allocator = alloc }; var buf: [128]u8 = undefined; { diff --git a/lib/std/crypto/tls/Client.zig b/lib/std/crypto/tls/Client.zig index 4a0a8c6ddaf1c9231a89dce253c01c4eef8bf2fa..11eb30f226f217f9f28771f01aa53b8ccb21ccc0 100644 --- a/lib/std/crypto/tls/Client.zig +++ b/lib/std/crypto/tls/Client.zig @@ -376,7 +376,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client const nonce = nonce: { const V = @Vector(P.AEAD.nonce_length, u8); const pad: [P.AEAD.nonce_length - 8]u8 = @splat(0); - const operand: V = pad ++ @as([8]u8, @bitCast(big(read_seq))); + const operand: V = pad ++ @as([8]u8, @bitCast(@byteSwap(read_seq))); break :nonce @as(V, pv.server_handshake_iv) ^ operand; }; P.AEAD.decrypt(cleartext, ciphertext, auth_tag, record_header, nonce, pv.server_handshake_key) catch @@ -416,7 +416,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client const nonce: [P.AEAD.nonce_length]u8 = nonce: { const V = @Vector(P.AEAD.nonce_length, u8); const pad: [P.AEAD.nonce_length - 8]u8 = @splat(0); - const operand: V = pad ++ @as([8]u8, @bitCast(big(masked_read_seq))); + const operand: V = pad ++ @as([8]u8, @bitCast(@byteSwap(masked_read_seq))); break :nonce @as(V, pv.app_cipher.server_write_IV ++ record_iv) ^ operand; }; const ciphertext = record_decoder.slice(message_len); @@ -792,7 +792,7 @@ pub fn init(input: *Reader, output: *Writer, options: Options) InitError!Client const nonce: [P.AEAD.nonce_length]u8 = nonce: { const V = @Vector(P.AEAD.nonce_length, u8); const pad: [P.AEAD.nonce_length - 8]u8 = @splat(0); - const operand: V = pad ++ @as([8]u8, @bitCast(big(write_seq))); + const operand: V = pad ++ @as([8]u8, @bitCast(@byteSwap(write_seq))); break :nonce @as(V, pv.app_cipher.client_write_IV ++ pv.app_cipher.client_salt) ^ operand; }; var client_verify_msg = .{@intFromEnum(tls.ContentType.handshake)} ++ @@ -1105,7 +1105,7 @@ fn prepareCiphertextRecord( const nonce: [P.AEAD.nonce_length]u8 = nonce: { const V = @Vector(P.AEAD.nonce_length, u8); const pad: [P.AEAD.nonce_length - 8]u8 = @splat(0); - const operand: V = pad ++ @as([8]u8, @bitCast(big(c.write_seq))); + const operand: V = pad ++ @as([8]u8, @bitCast(@byteSwap(c.write_seq))); break :nonce @as(V, pv.client_write_IV ++ pv.client_salt) ^ operand; }; record_iv.* = nonce[P.fixed_iv_length..].*; @@ -1214,7 +1214,7 @@ fn readIndirect(c: *Client) Reader.Error!usize { const nonce: [P.AEAD.nonce_length]u8 = nonce: { const V = @Vector(P.AEAD.nonce_length, u8); const pad: [P.AEAD.nonce_length - 8]u8 = @splat(0); - const operand: V = pad ++ @as([8]u8, @bitCast(big(masked_read_seq))); + const operand: V = pad ++ @as([8]u8, @bitCast(@byteSwap(masked_read_seq))); break :nonce @as(V, pv.server_write_IV ++ record_iv) ^ operand; }; const ciphertext = input.take(message_len) catch unreachable; // already peeked diff --git a/lib/std/debug.zig b/lib/std/debug.zig index dd6de989cbff6b9a6f0c12a8b3e857b765b03a9b..578d06fd3f5ddefdf64d8ea3af2e6b510a7513d3 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -63,16 +63,22 @@ pub const cpu_context = @import("debug/cpu_context.zig"); /// ``` pub const SelfInfo = if (@hasDecl(root, "debug") and @hasDecl(root.debug, "SelfInfo")) root.debug.SelfInfo -else switch (std.Target.ObjectFormat.default(native_os, native_arch)) { - .coff => if (native_os == .windows) @import("debug/SelfInfo/Windows.zig") else void, - .elf => switch (native_os) { - .freestanding, .other => void, - else => @import("debug/SelfInfo/Elf.zig"), - }, - .macho => @import("debug/SelfInfo/MachO.zig"), - .plan9, .spirv, .wasm => void, - .c, .hex, .raw => unreachable, -}; +else + TargetInfo(native_os, native_arch); + +/// Returns the default `SelfInfo` for the given `os` and `arch`. +pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type { + return switch (std.Target.ObjectFormat.default(os, arch)) { + .coff => if (os == .windows) @import("debug/SelfInfo/Windows.zig") else void, + .elf => switch (os) { + .freestanding, .other => void, + else => @import("debug/SelfInfo/Elf.zig"), + }, + .macho => @import("debug/SelfInfo/MachO.zig"), + .plan9, .spirv, .wasm => void, + .c, .hex, .raw => unreachable, + }; +} pub const SelfInfoError = error{ /// The required debug info is invalid or corrupted. @@ -308,6 +314,9 @@ pub fn unlockStderr() void { /// Alternatively, use the higher-level `std.log` or `Io.lockStderr` to /// integrate with the application's chosen `Io` implementation. pub fn print(comptime fmt: []const u8, args: anytype) void { + const io = std.Options.debug_io; + const prev = io.swapCancelProtection(.blocked); + defer _ = io.swapCancelProtection(prev); var buffer: [64]u8 = undefined; const stderr = lockStderr(&buffer); defer unlockStderr(); @@ -326,6 +335,9 @@ pub inline fn getSelfDebugInfo() !*SelfInfo { /// Tries to print a hexadecimal view of the bytes, unbuffered, and ignores any error returned. /// Obtains the stderr mutex while dumping. pub fn dumpHex(bytes: []const u8) void { + const io = std.Options.debug_io; + const prev = io.swapCancelProtection(.blocked); + defer _ = io.swapCancelProtection(prev); const stderr = lockStderr(&.{}).terminal(); defer unlockStderr(); dumpHexFallible(stderr, bytes) catch {}; @@ -495,7 +507,16 @@ pub fn defaultPanic(msg: []const u8, first_trace_addr: ?usize) noreturn { if (use_trap_panic) @trap(); switch (builtin.os.tag) { - .freestanding, .other, .@"3ds", .psp, .vita => { + .freestanding, + .other, + + .@"3ds", + .wiiu, + + .psx, + .psp, + .vita, + => { @trap(); }, .uefi => { @@ -789,6 +810,9 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin } /// A thin wrapper around `writeCurrentStackTrace` which writes to stderr and ignores write errors. pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void { + const io = std.Options.debug_io; + const prev = io.swapCancelProtection(.blocked); + defer _ = io.swapCancelProtection(prev); const stderr = lockStderr(&.{}).terminal(); defer unlockStderr(); writeCurrentStackTrace(.{ @@ -879,6 +903,9 @@ fn writeTrace( } /// A thin wrapper around `writeStackTrace` which writes to stderr and ignores write errors. pub fn dumpStackTrace(st: *const StackTrace) void { + const io = std.Options.debug_io; + const prev = io.swapCancelProtection(.blocked); + defer _ = io.swapCancelProtection(prev); const stderr = lockStderr(&.{}).terminal(); defer unlockStderr(); writeStackTrace(st, stderr) catch |err| switch (err) { @@ -888,6 +915,9 @@ pub fn dumpStackTrace(st: *const StackTrace) void { /// A thin wrapper around `writeErrorReturnTrace` which writes to stderr and ignores write errors. pub fn dumpErrorReturnTrace(et: *const std.builtin.StackTrace) void { + const io = std.Options.debug_io; + const prev = io.swapCancelProtection(.blocked); + defer _ = io.swapCancelProtection(prev); const stderr = lockStderr(&.{}).terminal(); defer unlockStderr(); writeErrorReturnTrace(et, stderr) catch |err| switch (err) { diff --git a/lib/std/debug/Coverage.zig b/lib/std/debug/Coverage.zig index b3e16382cc45dff17d34b9bf57f7accb63d918e5..7bbc58a5b71f541734aafd75d75fdfb2c3858efb 100644 --- a/lib/std/debug/Coverage.zig +++ b/lib/std/debug/Coverage.zig @@ -15,13 +15,13 @@ const assert = std.debug.assert; /// String memory references the memory-mapped debug information. /// /// Protected by `mutex`. -directories: std.ArrayHashMapUnmanaged(String, void, String.MapContext, false), +directories: std.array_hash_map.Custom(String, void, String.MapContext, false), /// Provides a globally-scoped integer index for files. /// /// String memory references the memory-mapped debug information. /// /// Protected by `mutex`. -files: std.ArrayHashMapUnmanaged(File, void, File.MapContext, false), +files: std.array_hash_map.Custom(File, void, File.MapContext, false), string_bytes: std.ArrayList(u8), /// Protects the other fields. mutex: Io.Mutex, diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig index 439e590daed71cf16c70d1ebea2a6943978f719f..a5f290039f4c57138832360a7fecf4183ecc04b5 100644 --- a/lib/std/debug/Dwarf.zig +++ b/lib/std/debug/Dwarf.zig @@ -134,7 +134,7 @@ pub const CompileUnit = struct { files: []FileEntry, version: u16, - pub const LineTable = std.AutoArrayHashMapUnmanaged(u64, LineEntry); + pub const LineTable = std.array_hash_map.Auto(u64, LineEntry); pub const LineEntry = struct { line: u32, diff --git a/lib/std/debug/Dwarf/SelfUnwinder.zig b/lib/std/debug/Dwarf/SelfUnwinder.zig index 0f5253844de3cdcd97d57e18c8d0ca6c4ed231c8..6eef056e86866d66b94564dae6b94d71484829ac 100644 --- a/lib/std/debug/Dwarf/SelfUnwinder.zig +++ b/lib/std/debug/Dwarf/SelfUnwinder.zig @@ -168,7 +168,7 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE .none => return error.InvalidDebugInfo, .reg_off => |ro| cfa: { const ptr = try regNative(&unwinder.cpu_state, ro.register); - break :cfa try applyOffset(ptr.*, ro.offset); + break :cfa try applyOffset(@intCast(ptr.*), ro.offset); }, .expression => |expr| cfa: { // On most implemented architectures, the CFA is defined to be the previous frame's SP. @@ -181,7 +181,7 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE const value = try unwinder.expr_vm.run(expr, gpa, .{ .format = format, .cpu_context = &unwinder.cpu_state, - }, prev_cfa_val) orelse return error.InvalidDebugInfo; + }, @intCast(prev_cfa_val)) orelse return error.InvalidDebugInfo; switch (value) { .generic => |g| break :cfa g, else => return error.InvalidDebugInfo, @@ -203,7 +203,7 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE const new_val: union(enum) { same, undefined, - val: usize, + val: std.debug.cpu_context.Native.Gpr, bytes: []const u8, } = switch (rule) { .default => val: { @@ -219,7 +219,7 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE .undefined => .undefined, .same_value => .same, .offset => |offset| val: { - const ptr: *const usize = @ptrFromInt(try applyOffset(cfa, offset)); + const ptr: *const std.debug.cpu_context.Native.Gpr = @ptrFromInt(try applyOffset(cfa, offset)); break :val .{ .val = ptr.* }; }, .val_offset => |offset| .{ .val = try applyOffset(cfa, offset) }, @@ -260,12 +260,7 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE has_return_address = false; } }, - .val => |val| { - const dest = try new_cpu_state.dwarfRegisterBytes(@intCast(register)); - if (dest.len != @sizeOf(usize)) return error.InvalidDebugInfo; - const dest_ptr: *align(1) usize = @ptrCast(dest); - dest_ptr.* = val; - }, + .val => |val| (try regNative(&new_cpu_state, register)).* = val, .bytes => |src| { const dest = try new_cpu_state.dwarfRegisterBytes(@intCast(register)); if (dest.len != src.len) return error.InvalidDebugInfo; @@ -275,7 +270,7 @@ fn nextInner(unwinder: *SelfUnwinder, gpa: Allocator, cache_entry: *const CacheE } const return_address = if (has_return_address) - stripInstructionPtrAuthCode((try regNative(&new_cpu_state, return_address_register)).*) + stripInstructionPtrAuthCode(@intCast((try regNative(&new_cpu_state, return_address_register)).*)) else 0; @@ -303,9 +298,9 @@ pub fn regNative(ctx: *std.debug.cpu_context.Native, num: u16) error{ InvalidRegister, UnsupportedRegister, IncompatibleRegisterSize, -}!*align(1) usize { +}!*align(1) std.debug.cpu_context.Native.Gpr { const bytes = try ctx.dwarfRegisterBytes(num); - if (bytes.len != @sizeOf(usize)) return error.IncompatibleRegisterSize; + if (bytes.len != @sizeOf(std.debug.cpu_context.Native.Gpr)) return error.IncompatibleRegisterSize; return @ptrCast(bytes); } diff --git a/lib/std/debug/Dwarf/expression.zig b/lib/std/debug/Dwarf/expression.zig index 626af96d4a8391f031e17a5ca5e2003910481897..9b506dd4da0c1dff4d47711e6b4f367d662edca0 100644 --- a/lib/std/debug/Dwarf/expression.zig +++ b/lib/std/debug/Dwarf/expression.zig @@ -387,7 +387,7 @@ pub fn StackMachine(comptime options: Options) type { .regval_type = .{ .type_offset = rt.type_offset, .type_size = @sizeOf(addr_type), - .value = (try regNative(cpu_context, rt.register)).*, + .value = @intCast((try regNative(cpu_context, rt.register)).*), }, }); }, @@ -738,7 +738,7 @@ pub fn StackMachine(comptime options: Options) type { var block_stream: std.Io.Reader = .fixed(block); const register = (try readOperand(&block_stream, block[0], context)).?.register; const value = (try regNative(cpu_context, register)).*; - try self.stack.append(allocator, .{ .generic = value }); + try self.stack.append(allocator, .{ .generic = @intCast(value) }); } else { var stack_machine: Self = .{}; defer stack_machine.deinit(allocator); @@ -1158,7 +1158,7 @@ test "basics" { // TODO: Test fbreg (once implemented): mock a DIE and point compile_unit.frame_base at it - mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian); + mem.writeInt(std.debug.cpu_context.Native.Gpr, reg_bytes[0..@sizeOf(std.debug.cpu_context.Native.Gpr)], 0xee, native_endian); (try regNative(&cpu_context, fp_reg_num)).* = 1; (try regNative(&cpu_context, ip_reg_num)).* = 2; @@ -1566,7 +1566,7 @@ test "basics" { context = .{ .cpu_context = &cpu_context }; const reg_bytes = try cpu_context.dwarfRegisterBytes(0); - mem.writeInt(usize, reg_bytes[0..@sizeOf(usize)], 0xee, native_endian); + mem.writeInt(std.debug.cpu_context.Native.Gpr, reg_bytes[0..@sizeOf(std.debug.cpu_context.Native.Gpr)], 0xee, native_endian); var sub_program: std.Io.Writer.Allocating = .init(allocator); defer sub_program.deinit(); diff --git a/lib/std/debug/ElfFile.zig b/lib/std/debug/ElfFile.zig index 22ea71af4443d78f05f45ae90b13708c0ceb5610..0ea4207c3521830ca4a1b9b1a1a0567cb97b5201 100644 --- a/lib/std/debug/ElfFile.zig +++ b/lib/std/debug/ElfFile.zig @@ -455,7 +455,7 @@ fn loadInner( }; if (opt_crc) |crc| { - if (std.hash.crc.Crc32.hash(mapped_mem) != crc) { + if (std.hash.Crc32.hash(mapped_mem) != crc) { return error.CrcMismatch; } } diff --git a/lib/std/debug/MachOFile.zig b/lib/std/debug/MachOFile.zig index 4b2fb524bcdab99802e9001b0d340d484e6f86e2..369ee8c4bc41bf87ac8f9c3356a7ab1c532bfdad 100644 --- a/lib/std/debug/MachOFile.zig +++ b/lib/std/debug/MachOFile.zig @@ -4,7 +4,7 @@ strings: []const u8, text_vmaddr: u64, /// Key is index into `strings` of the file path. -ofiles: std.AutoArrayHashMapUnmanaged(u32, Error!OFile), +ofiles: std.array_hash_map.Auto(u32, Error!OFile), pub const Error = error{ InvalidMachO, @@ -115,7 +115,7 @@ pub fn load(gpa: Allocator, io: Io, path: []const u8, arch: std.Target.Cpu.Arch) // necessary because we prefer to use STAB ("symbolic debugging table") symbols, // but they might not be present, so we track normal symbols too. // Indices match 1-1 with those of `symbols`. - var symbol_names: std.StringArrayHashMapUnmanaged(void) = .empty; + var symbol_names: std.array_hash_map.String(void) = .empty; defer symbol_names.deinit(gpa); try symbol_names.ensureUnusedCapacity(gpa, symtab.nsyms); @@ -305,7 +305,7 @@ const OFile = struct { symtab_raw: []align(1) const macho.nlist_64, /// All named symbols in `symtab_raw`. Stored `u32` key is the index into `symtab_raw`. Accessed /// through `SymbolAdapter`, so that the symbol name is used as the logical key. - symbols_by_name: std.ArrayHashMapUnmanaged(u32, void, void, true), + symbols_by_name: std.array_hash_map.Custom(u32, void, void, true), const SymbolAdapter = struct { strtab: []const u8, @@ -380,7 +380,7 @@ test { fn appendStabSymbol( symbols: *std.ArrayList(Symbol), - symbol_names: *std.StringArrayHashMapUnmanaged(void), + symbol_names: *std.array_hash_map.String(void), strings: []const u8, last_sym: Symbol, ) void { @@ -476,7 +476,7 @@ fn loadOFile(gpa: Allocator, io: Io, o_file_name: []const u8) !OFile { const symtab_raw: []align(1) const macho.nlist_64 = @ptrCast(mapped_ofile[symtab_cmd.symoff..][0..n_sym_bytes]); // TODO handle tentative (common) symbols - var symbols_by_name: std.ArrayHashMapUnmanaged(u32, void, void, true) = .empty; + var symbols_by_name: std.array_hash_map.Custom(u32, void, void, true) = .empty; defer symbols_by_name.deinit(gpa); try symbols_by_name.ensureUnusedCapacity(gpa, @intCast(symtab_raw.len)); for (symtab_raw, 0..) |sym_raw, sym_index| { diff --git a/lib/std/debug/SelfInfo/Elf.zig b/lib/std/debug/SelfInfo/Elf.zig index c3124902008f0b45347b939b0d49aff7164c5c34..9e8153555f4a68dfde3996328263aee2dd39d582 100644 --- a/lib/std/debug/SelfInfo/Elf.zig +++ b/lib/std/debug/SelfInfo/Elf.zig @@ -92,16 +92,6 @@ pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) Error!usize { } pub const can_unwind: bool = s: { - // The DWARF code can't deal with ILP32 ABIs yet: https://github.com/ziglang/zig/issues/25447 - switch (builtin.target.abi) { - .gnuabin32, - .muslabin32, - .gnux32, - .muslx32, - => break :s false, - else => {}, - } - // Notably, we are yet to support unwinding on ARM. There, unwinding is not done through // `.eh_frame`, but instead with the `.ARM.exidx` section, which has a different format. const archs: []const std.Target.Cpu.Arch = switch (builtin.target.os.tag) { diff --git a/lib/std/debug/SelfInfo/MachO.zig b/lib/std/debug/SelfInfo/MachO.zig index 431108cd3f6164769359902f1abccdec720516df..e771d7a9f5e45b3b5c217053f3394fd7b713a029 100644 --- a/lib/std/debug/SelfInfo/MachO.zig +++ b/lib/std/debug/SelfInfo/MachO.zig @@ -1,6 +1,6 @@ mutex: Io.Mutex, /// Accessed through `Module.Adapter`. -modules: std.ArrayHashMapUnmanaged(Module, void, Module.Context, false), +modules: std.array_hash_map.Custom(Module, void, Module.Context, false), pub const init: SelfInfo = .{ .mutex = .init, diff --git a/lib/std/debug/cpu_context.zig b/lib/std/debug/cpu_context.zig index 6f6a07a86ffc0a867da5534b440966e6f12451bc..36be9fe60e0ebe084ab2e045702bc91628ff9bf6 100644 --- a/lib/std/debug/cpu_context.zig +++ b/lib/std/debug/cpu_context.zig @@ -240,9 +240,11 @@ pub fn fromWindowsContext(ctx: *const std.os.windows.CONTEXT) Native { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Aarch64 = extern struct { /// The numbered general-purpose registers X0 - X30. - x: [31]u64, - sp: u64, - pc: u64, + x: [31]Gpr, + sp: Gpr, + pc: Gpr, + + pub const Gpr = u64; pub inline fn current() Aarch64 { var ctx: Aarch64 = undefined; @@ -273,10 +275,10 @@ const Aarch64 = extern struct { return ctx; } - pub fn getFp(ctx: *const Aarch64) u64 { + pub fn getFp(ctx: *const Aarch64) usize { return ctx.x[29]; } - pub fn getPc(ctx: *const Aarch64) u64 { + pub fn getPc(ctx: *const Aarch64) usize { return ctx.pc; } @@ -308,8 +310,10 @@ const Aarch64 = extern struct { const Alpha = extern struct { /// The numbered general-purpose registers R0 - R31. - r: [32]u64, - pc: u64, + r: [32]Gpr, + pc: Gpr, + + pub const Gpr = u64; pub inline fn current() Alpha { var ctx: Alpha = undefined; @@ -355,10 +359,10 @@ const Alpha = extern struct { return ctx; } - pub fn getFp(ctx: *const Alpha) u64 { + pub fn getFp(ctx: *const Alpha) usize { return ctx.r[15]; } - pub fn getPc(ctx: *const Alpha) u64 { + pub fn getPc(ctx: *const Alpha) usize { return ctx.pc; } @@ -378,8 +382,10 @@ const Alpha = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Arc = extern struct { /// The numbered general-purpose registers r0 - r31. - r: [32]u32, - pcl: u32, + r: [32]Gpr, + pcl: Gpr, + + pub const Gpr = u32; pub inline fn current() Arc { var ctx: Arc = undefined; @@ -423,10 +429,10 @@ const Arc = extern struct { return ctx; } - pub fn getFp(ctx: *const Arc) u32 { + pub fn getFp(ctx: *const Arc) usize { return ctx.r[27]; } - pub fn getPc(ctx: *const Arc) u32 { + pub fn getPc(ctx: *const Arc) usize { return ctx.pcl; } @@ -446,7 +452,9 @@ const Arc = extern struct { const Arm = struct { /// The numbered general-purpose registers R0 - R15. - r: [16]u32, + r: [16]Gpr, + + pub const Gpr = u32; pub inline fn current() Arm { var ctx: Arm = undefined; @@ -462,10 +470,10 @@ const Arm = struct { return ctx; } - pub fn getFp(ctx: *const Arm) u32 { + pub fn getFp(ctx: *const Arm) usize { return ctx.r[11]; } - pub fn getPc(ctx: *const Arm) u32 { + pub fn getPc(ctx: *const Arm) usize { return ctx.r[15]; } @@ -512,8 +520,10 @@ const Arm = struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Csky = extern struct { /// The numbered general-purpose registers r0 - r31. - r: [32]u32, - pc: u32, + r: [32]Gpr, + pc: Gpr, + + pub const Gpr = u32; pub inline fn current() Csky { var ctx: Csky = undefined; @@ -528,10 +538,10 @@ const Csky = extern struct { return ctx; } - pub fn getFp(ctx: *const Csky) u32 { + pub fn getFp(ctx: *const Csky) usize { return ctx.r[14]; } - pub fn getPc(ctx: *const Csky) u32 { + pub fn getPc(ctx: *const Csky) usize { return ctx.pc; } @@ -550,8 +560,10 @@ const Csky = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Hexagon = extern struct { /// The numbered general-purpose registers r0 - r31. - r: [32]u32, - pc: u32, + r: [32]Gpr, + pc: Gpr, + + pub const Gpr = u32; pub inline fn current() Hexagon { var ctx: Hexagon = undefined; @@ -596,10 +608,10 @@ const Hexagon = extern struct { return ctx; } - pub fn getFp(ctx: *const Hexagon) u32 { + pub fn getFp(ctx: *const Hexagon) usize { return ctx.r[30]; } - pub fn getPc(ctx: *const Hexagon) u32 { + pub fn getPc(ctx: *const Hexagon) usize { return ctx.pc; } @@ -623,9 +635,11 @@ const Hexagon = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Kvx = extern struct { - r: [64]u64, - ra: u64, - pc: u64, + r: [64]Gpr, + ra: Gpr, + pc: Gpr, + + pub const Gpr = u64; pub inline fn current() Kvx { var ctx: Kvx = undefined; @@ -671,10 +685,10 @@ const Kvx = extern struct { return ctx; } - pub fn getFp(ctx: *const Kvx) u64 { + pub fn getFp(ctx: *const Kvx) usize { return ctx.r[14]; } - pub fn getPc(ctx: *const Kvx) u64 { + pub fn getPc(ctx: *const Kvx) usize { return ctx.pc; } @@ -695,7 +709,9 @@ const Kvx = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Lanai = extern struct { - r: [32]u32, + r: [32]Gpr, + + pub const Gpr = u32; pub inline fn current() Lanai { var ctx: Lanai = undefined; @@ -738,10 +754,10 @@ const Lanai = extern struct { return ctx; } - pub fn getFp(ctx: *const Lanai) u32 { + pub fn getFp(ctx: *const Lanai) usize { return ctx.r[5]; } - pub fn getPc(ctx: *const Lanai) u32 { + pub fn getPc(ctx: *const Lanai) usize { return ctx.r[2]; } @@ -842,10 +858,10 @@ const LoongArch = extern struct { return ctx; } - pub fn getFp(ctx: *const LoongArch) Gpr { + pub fn getFp(ctx: *const LoongArch) usize { return ctx.r[22]; } - pub fn getPc(ctx: *const LoongArch) Gpr { + pub fn getPc(ctx: *const LoongArch) usize { return ctx.pc; } @@ -864,10 +880,12 @@ const LoongArch = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const M68k = extern struct { /// The numbered data registers d0 - d7. - d: [8]u32, + d: [8]Gpr, /// The numbered address registers a0 - a7. - a: [8]u32, - pc: u32, + a: [8]Gpr, + pc: Gpr, + + pub const Gpr = u32; pub inline fn current() M68k { var ctx: M68k = undefined; @@ -881,10 +899,10 @@ const M68k = extern struct { return ctx; } - pub fn getFp(ctx: *const M68k) u32 { + pub fn getFp(ctx: *const M68k) usize { return ctx.a[6]; } - pub fn getPc(ctx: *const M68k) u32 { + pub fn getPc(ctx: *const M68k) usize { return ctx.pc; } @@ -905,8 +923,10 @@ const M68k = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const M88k = extern struct { /// The numbered general-purpose registers r0 - r31. - r: [32]u32, - xip: u32, + r: [32]Gpr, + xip: Gpr, + + pub const Gpr = u32; pub inline fn current() M88k { var ctx: M88k = undefined; @@ -952,10 +972,10 @@ const M88k = extern struct { return ctx; } - pub fn getFp(ctx: *const M88k) u32 { + pub fn getFp(ctx: *const M88k) usize { return ctx.r[30]; } - pub fn getPc(ctx: *const M88k) u32 { + pub fn getPc(ctx: *const M88k) usize { return ctx.xip; } @@ -1103,8 +1123,10 @@ const Mips = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Or1k = extern struct { /// The numbered general-purpose registers r0 - r31. - r: [32]u32, - pc: u32, + r: [32]Gpr, + pc: Gpr, + + pub const Gpr = u32; pub inline fn current() Or1k { var ctx: Or1k = undefined; @@ -1150,10 +1172,10 @@ const Or1k = extern struct { return ctx; } - pub fn getFp(ctx: *const Or1k) u32 { + pub fn getFp(ctx: *const Or1k) usize { return ctx.r[2]; } - pub fn getPc(ctx: *const Or1k) u32 { + pub fn getPc(ctx: *const Or1k) usize { return ctx.pc; } @@ -1262,10 +1284,10 @@ const Powerpc = extern struct { return ctx; } - pub fn getFp(ctx: *const Powerpc) Gpr { + pub fn getFp(ctx: *const Powerpc) usize { return ctx.r[1]; } - pub fn getPc(ctx: *const Powerpc) Gpr { + pub fn getPc(ctx: *const Powerpc) usize { return ctx.pc; } @@ -1415,10 +1437,10 @@ const Riscv = extern struct { return ctx; } - pub fn getFp(ctx: *const Riscv) Gpr { + pub fn getFp(ctx: *const Riscv) usize { return ctx.x[8]; } - pub fn getPc(ctx: *const Riscv) Gpr { + pub fn getPc(ctx: *const Riscv) usize { return ctx.pc; } @@ -1441,13 +1463,15 @@ const Riscv = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const S390x = extern struct { /// The numbered general-purpose registers r0 - r15. - r: [16]u64, + r: [16]Gpr, /// The program counter. psw: extern struct { - mask: u64, - addr: u64, + mask: Gpr, + addr: Gpr, }, + pub const Gpr = u64; + pub inline fn current() S390x { var ctx: S390x = undefined; asm volatile ( @@ -1462,10 +1486,10 @@ const S390x = extern struct { return ctx; } - pub fn getFp(ctx: *const S390x) u64 { + pub fn getFp(ctx: *const S390x) usize { return ctx.r[11]; } - pub fn getPc(ctx: *const S390x) u64 { + pub fn getPc(ctx: *const S390x) usize { return ctx.psw.addr; } @@ -1571,10 +1595,10 @@ const Sparc = extern struct { asm volatile ("ta 3" ::: .{ .memory = true }); // ST_FLUSH_WINDOWS } - pub fn getFp(ctx: *const Sparc) Gpr { + pub fn getFp(ctx: *const Sparc) usize { return ctx.i[6]; } - pub fn getPc(ctx: *const Sparc) Gpr { + pub fn getPc(ctx: *const Sparc) usize { return ctx.pc; } @@ -1593,8 +1617,10 @@ const Sparc = extern struct { /// This is an `extern struct` so that inline assembly in `current` can use field offsets. const Ve = extern struct { - s: [64]u64, - ic: u64, + s: [64]Gpr, + ic: Gpr, + + pub const Gpr = u64; pub inline fn current() Ve { var ctx: Ve = undefined; @@ -1672,10 +1698,10 @@ const Ve = extern struct { return ctx; } - pub fn getFp(ctx: *const Ve) u64 { + pub fn getFp(ctx: *const Ve) usize { return ctx.s[9]; } - pub fn getPc(ctx: *const Ve) u64 { + pub fn getPc(ctx: *const Ve) usize { return ctx.ic; } @@ -1693,14 +1719,15 @@ const Ve = extern struct { }; const X86_16 = struct { - pub const Register = enum { + regs: std.enums.EnumArray(GprName, Gpr), + + pub const GprName = enum { // zig fmt: off sp, bp, ss, ip, cs, // zig fmt: on }; - - regs: std.enums.EnumArray(Register, u16), + pub const Gpr = u16; pub inline fn current() X86_16 { var ctx: X86_16 = undefined; @@ -1719,10 +1746,10 @@ const X86_16 = struct { return ctx; } - pub fn getFp(ctx: *const X86_16) u16 { + pub fn getFp(ctx: *const X86_16) usize { return ctx.regs.get(.bp); } - pub fn getPc(ctx: *const X86_16) u16 { + pub fn getPc(ctx: *const X86_16) usize { return ctx.regs.get(.ip); } @@ -1740,17 +1767,19 @@ const X86_16 = struct { }; const X86 = struct { + gprs: std.enums.EnumArray(GprName, Gpr), + /// The first 8 registers here intentionally match the order of registers in the x86 instruction /// encoding. This order is inherited by the PUSHA instruction and the DWARF register mappings, /// among other things. - pub const Gpr = enum { + pub const GprName = enum { // zig fmt: off eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, // zig fmt: on }; - gprs: std.enums.EnumArray(Gpr, u32), + pub const Gpr = u32; pub inline fn current() X86 { var ctx: X86 = undefined; @@ -1772,10 +1801,10 @@ const X86 = struct { return ctx; } - pub fn getFp(ctx: *const X86) u32 { + pub fn getFp(ctx: *const X86) usize { return ctx.gprs.get(.ebp); } - pub fn getPc(ctx: *const X86) u32 { + pub fn getPc(ctx: *const X86) usize { return ctx.gprs.get(.eip); } @@ -1806,10 +1835,12 @@ const X86 = struct { }; const X86_64 = struct { + gprs: std.enums.EnumArray(GprName, Gpr), + /// The order here intentionally matches the order of the DWARF register mappings. It's unclear /// where those mappings actually originated from---the ordering of the first 4 registers seems /// quite unusual---but it is currently convenient for us to match DWARF. - pub const Gpr = enum { + pub const GprName = enum { // zig fmt: off rax, rdx, rcx, rbx, rsi, rdi, rbp, rsp, @@ -1818,7 +1849,7 @@ const X86_64 = struct { rip, // zig fmt: on }; - gprs: std.enums.EnumArray(Gpr, u64), + pub const Gpr = u64; pub inline fn current() X86_64 { var ctx: X86_64 = undefined; diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index d7cea3b3cd3699e4e0a4d5700b241fdc4656ac4e..3f39089510ee6ccf85f90625dfcf542cfb11bf70 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -302,27 +302,14 @@ pub const ElfDynLib = struct { const extended_memsz = mem.alignForward(usize, ph.p_memsz + extra_bytes, page_size); const ptr = @as([*]align(std.heap.page_size_min) u8, @ptrFromInt(aligned_addr)); const prot = elfToProt(ph.p_flags); - if ((ph.p_flags & elf.PF_W) == 0) { - // If it does not need write access, it can be mapped from the fd. - _ = try posix.mmap( - ptr, - extended_memsz, - prot, - .{ .TYPE = .PRIVATE, .FIXED = true }, - file.handle, - ph.p_offset - extra_bytes, - ); - } else { - const sect_mem = try posix.mmap( - ptr, - extended_memsz, - prot, - .{ .TYPE = .PRIVATE, .FIXED = true, .ANONYMOUS = true }, - -1, - 0, - ); - @memcpy(sect_mem[0..ph.p_filesz], file_bytes[0..ph.p_filesz]); - } + _ = try posix.mmap( + ptr, + extended_memsz, + prot, + .{ .TYPE = .PRIVATE, .FIXED = true }, + file.handle, + ph.p_offset - extra_bytes, + ); }, else => {}, } diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 81de3f7f501d4c54e3f9048921a6a9a90cc21a77..d3215291852537cd82a03abf0f8b33fc1e2a6ea6 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -3001,6 +3001,141 @@ pub const R_PPC64 = enum(u32) { _, }; +/// LoongArch relocations, as of v2.50 of the ABI specs. +pub const R_LARCH = enum(u32) { + NONE = 0, + @"32" = 1, + @"64" = 2, + RELATIVE = 3, + COPY = 4, + JUMP_SLOT = 5, + TLS_DTPMOD32 = 6, + TLS_DTPMOD64 = 7, + TLS_DTPREL32 = 8, + TLS_DTPREL64 = 9, + TLS_TPREL32 = 10, + TLS_TPREL64 = 11, + IRELATIVE = 12, + TLS_DESC32 = 13, + TLS_DESC64 = 14, + MARK_LA = 20, + MARK_PCREL = 21, + SOP_PUSH_PCREL = 22, + SOP_PUSH_ABSOLUTE = 23, + SOP_PUSH_DUP = 24, + SOP_PUSH_GPREL = 25, + SOP_PUSH_TLS_TPREL = 26, + SOP_PUSH_TLS_GOT = 27, + SOP_PUSH_TLS_GD = 28, + SOP_PUSH_PLT_PCREL = 29, + SOP_ASSERT = 30, + SOP_NOT = 31, + SOP_SUB = 32, + SOP_SL = 33, + SOP_SR = 34, + SOP_ADD = 35, + SOP_AND = 36, + SOP_IF_ELSE = 37, + SOP_POP_32_S_10_5 = 38, + SOP_POP_32_U_10_12 = 39, + SOP_POP_32_S_10_12 = 40, + SOP_POP_32_S_10_16 = 41, + SOP_POP_32_S_10_16_S2 = 42, + SOP_POP_32_S_5_20 = 43, + SOP_POP_32_S_0_5_10_16_S2 = 44, + SOP_POP_32_S_0_10_10_16_S2 = 45, + SOP_POP_32_U = 46, + ADD8 = 47, + ADD16 = 48, + ADD24 = 49, + ADD32 = 50, + ADD64 = 51, + SUB8 = 52, + SUB16 = 53, + SUB24 = 54, + SUB32 = 55, + SUB64 = 56, + GNU_VTINHERIT = 57, + GNU_VTENTRY = 58, + B16 = 64, + B21 = 65, + B26 = 66, + ABS_HI20 = 67, + ABS_LO12 = 68, + ABS64_LO20 = 69, + ABS64_HI12 = 70, + PCALA_HI20 = 71, + PCALA_LO12 = 72, + PCALA64_LO20 = 73, + PCALA64_HI12 = 74, + GOT_PC_HI20 = 75, + GOT_PC_LO12 = 76, + GOT64_PC_LO20 = 77, + GOT64_PC_HI12 = 78, + GOT_HI20 = 79, + GOT_LO12 = 80, + GOT64_LO20 = 81, + GOT64_HI12 = 82, + TLS_LE_HI20 = 83, + TLS_LE_LO12 = 84, + TLS_LE64_LO20 = 85, + TLS_LE64_HI12 = 86, + TLS_IE_PC_HI20 = 87, + TLS_IE_PC_LO12 = 88, + TLS_IE64_PC_LO20 = 89, + TLS_IE64_PC_HI12 = 90, + TLS_IE_HI20 = 91, + TLS_IE_LO12 = 92, + TLS_IE64_LO20 = 93, + TLS_IE64_HI12 = 94, + TLS_LD_PC_HI20 = 95, + TLS_LD_HI20 = 96, + TLS_GD_PC_HI20 = 97, + TLS_GD_HI20 = 98, + @"32_PCREL" = 99, + RELAX = 100, + DELETE = 101, + ALIGN = 102, + PCREL20_S2 = 103, + CFA = 104, + ADD6 = 105, + SUB6 = 106, + ADD_ULEB128 = 107, + SUB_ULEB128 = 108, + @"64_PCREL" = 109, + CALL36 = 110, + TLS_DESC_PC_HI20 = 111, + TLS_DESC_PC_LO12 = 112, + TLS_DESC64_PC_LO20 = 113, + TLS_DESC64_PC_HI12 = 114, + TLS_DESC_HI20 = 115, + TLS_DESC_LO12 = 116, + TLS_DESC64_LO20 = 117, + TLS_DESC64_HI12 = 118, + TLS_DESC_LD = 119, + TLS_DESC_CALL = 120, + TLS_LE_HI20_R = 121, + TLS_LE_ADD_R = 122, + TLS_LE_LO12_R = 123, + TLS_LD_PCREL20_S2 = 124, + TLS_GD_PCREL20_S2 = 125, + TLS_DESC_PCREL20_S2 = 126, + CALL30 = 127, + PCADD_HI20 = 128, + PCADD_LO12 = 129, + GOT_PCADD_HI20 = 130, + GOT_PCADD_LO12 = 131, + TLS_IE_PCADD_HI20 = 132, + TLS_IE_PCADD_LO12 = 133, + TLS_LD_PCADD_HI20 = 134, + TLS_LD_PCADD_LO12 = 135, + TLS_GD_PCADD_HI20 = 136, + TLS_GD_PCADD_LO12 = 137, + TLS_DESC_PCADD_HI20 = 138, + TLS_DESC_PCADD_LO12 = 139, + _, +}; + pub const ar_hdr = extern struct { /// Member file name, sometimes / terminated. ar_name: [16]u8, @@ -3128,3 +3263,21 @@ pub const gnu_hash = struct { try std.testing.expectEqual(0x8ae9f18e, calculate("flapenguin.me")); } }; + +pub const loongarch = struct { + /// Ehdr.e_flags bits of LoongArch + pub const EFlags = packed struct(Word) { + base_abi_modifier: BaseAbiModifier, + abi_extension: AbiExtension, + abi_version: u2, + reserved: u24 = 0, + + pub const BaseAbiModifier = enum(u3) { + s = 1, + f = 2, + d = 3, + _, + }; + pub const AbiExtension = enum(u3) { base = 0, _ }; + }; +}; diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index df762e8fbe7a170ea62820a45a97f148c30d5811..edb1de18fc27228353d8fccea3227893c3eeeac3 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -6,8 +6,6 @@ const std = @import("std.zig"); const math = std.math; const assert = std.debug.assert; const mem = std.mem; -const meta = std.meta; -const lossyCast = math.lossyCast; const expectFmt = std.testing.expectFmt; const testing = std.testing; const Allocator = std.mem.Allocator; @@ -254,6 +252,13 @@ pub fn printInt(buffer: []u8, value: anytype, base: u8, case: Case, options: Opt return w.end; } +test printInt { + const x: i32 = -3; + var buffer: [64]u8 = undefined; + const s = buffer[0..printInt(&buffer, x, 10, .lower, .{})]; + try testing.expectEqualStrings("-3", s); +} + /// Converts values in the range [0, 100) to a base 10 string. pub fn digits2(value: u8) [2]u8 { if (builtin.mode == .ReleaseSmall) { @@ -332,63 +337,63 @@ pub fn parseIntWithGenericCharacter( } test parseInt { - try std.testing.expectEqual(-10, try parseInt(i32, "-10", 10)); - try std.testing.expectEqual(10, try parseInt(i32, "+10", 10)); - try std.testing.expectEqual(10, try parseInt(u32, "+10", 10)); - try std.testing.expectError(error.Overflow, parseInt(u32, "-10", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, " 10", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "10 ", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "_10_", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x_10_", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x10_", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x_10", 10)); - try std.testing.expectEqual(255, try parseInt(u8, "255", 10)); - try std.testing.expectError(error.Overflow, parseInt(u8, "256", 10)); + try testing.expectEqual(-10, try parseInt(i32, "-10", 10)); + try testing.expectEqual(10, try parseInt(i32, "+10", 10)); + try testing.expectEqual(10, try parseInt(u32, "+10", 10)); + try testing.expectError(error.Overflow, parseInt(u32, "-10", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, " 10", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "10 ", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "_10_", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "0x_10_", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "0x10_", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "0x_10", 10)); + try testing.expectEqual(255, try parseInt(u8, "255", 10)); + try testing.expectError(error.Overflow, parseInt(u8, "256", 10)); // +0 and -0 should work for unsigned - try std.testing.expectEqual(0, try parseInt(u8, "-0", 10)); - try std.testing.expectEqual(0, try parseInt(u8, "+0", 10)); + try testing.expectEqual(0, try parseInt(u8, "-0", 10)); + try testing.expectEqual(0, try parseInt(u8, "+0", 10)); // ensure minInt is parsed correctly - try std.testing.expectEqual(math.minInt(i1), try parseInt(i1, "-1", 10)); - try std.testing.expectEqual(math.minInt(i8), try parseInt(i8, "-128", 10)); - try std.testing.expectEqual(math.minInt(i43), try parseInt(i43, "-4398046511104", 10)); + try testing.expectEqual(math.minInt(i1), try parseInt(i1, "-1", 10)); + try testing.expectEqual(math.minInt(i8), try parseInt(i8, "-128", 10)); + try testing.expectEqual(math.minInt(i43), try parseInt(i43, "-4398046511104", 10)); // empty string or bare +- is invalid - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(i32, "", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "+", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(i32, "+", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "-", 10)); - try std.testing.expectError(error.InvalidCharacter, parseInt(i32, "-", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(i32, "", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "+", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(i32, "+", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "-", 10)); + try testing.expectError(error.InvalidCharacter, parseInt(i32, "-", 10)); // autodectect the base - try std.testing.expectEqual(111, try parseInt(i32, "111", 0)); - try std.testing.expectEqual(111, try parseInt(i32, "1_1_1", 0)); - try std.testing.expectEqual(111, try parseInt(i32, "1_1_1", 0)); - try std.testing.expectEqual(7, try parseInt(i32, "+0b111", 0)); - try std.testing.expectEqual(7, try parseInt(i32, "+0B111", 0)); - try std.testing.expectEqual(7, try parseInt(i32, "+0b1_11", 0)); - try std.testing.expectEqual(73, try parseInt(i32, "+0o111", 0)); - try std.testing.expectEqual(73, try parseInt(i32, "+0O111", 0)); - try std.testing.expectEqual(73, try parseInt(i32, "+0o11_1", 0)); - try std.testing.expectEqual(273, try parseInt(i32, "+0x111", 0)); - try std.testing.expectEqual(-7, try parseInt(i32, "-0b111", 0)); - try std.testing.expectEqual(-7, try parseInt(i32, "-0b11_1", 0)); - try std.testing.expectEqual(-73, try parseInt(i32, "-0o111", 0)); - try std.testing.expectEqual(-273, try parseInt(i32, "-0x111", 0)); - try std.testing.expectEqual(-273, try parseInt(i32, "-0X111", 0)); - try std.testing.expectEqual(-273, try parseInt(i32, "-0x1_11", 0)); + try testing.expectEqual(111, try parseInt(i32, "111", 0)); + try testing.expectEqual(111, try parseInt(i32, "1_1_1", 0)); + try testing.expectEqual(111, try parseInt(i32, "1_1_1", 0)); + try testing.expectEqual(7, try parseInt(i32, "+0b111", 0)); + try testing.expectEqual(7, try parseInt(i32, "+0B111", 0)); + try testing.expectEqual(7, try parseInt(i32, "+0b1_11", 0)); + try testing.expectEqual(73, try parseInt(i32, "+0o111", 0)); + try testing.expectEqual(73, try parseInt(i32, "+0O111", 0)); + try testing.expectEqual(73, try parseInt(i32, "+0o11_1", 0)); + try testing.expectEqual(273, try parseInt(i32, "+0x111", 0)); + try testing.expectEqual(-7, try parseInt(i32, "-0b111", 0)); + try testing.expectEqual(-7, try parseInt(i32, "-0b11_1", 0)); + try testing.expectEqual(-73, try parseInt(i32, "-0o111", 0)); + try testing.expectEqual(-273, try parseInt(i32, "-0x111", 0)); + try testing.expectEqual(-273, try parseInt(i32, "-0X111", 0)); + try testing.expectEqual(-273, try parseInt(i32, "-0x1_11", 0)); // bare binary/octal/decimal prefix is invalid - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0b", 0)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0o", 0)); - try std.testing.expectError(error.InvalidCharacter, parseInt(u32, "0x", 0)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "0b", 0)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "0o", 0)); + try testing.expectError(error.InvalidCharacter, parseInt(u32, "0x", 0)); // edge cases which previously errored due to base overflowing T - try std.testing.expectEqual(@as(i2, -2), try std.fmt.parseInt(i2, "-10", 2)); - try std.testing.expectEqual(@as(i4, -8), try std.fmt.parseInt(i4, "-10", 8)); - try std.testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16)); + try testing.expectEqual(@as(i2, -2), try std.fmt.parseInt(i2, "-10", 2)); + try testing.expectEqual(@as(i4, -8), try std.fmt.parseInt(i4, "-10", 8)); + try testing.expectEqual(@as(i5, -16), try std.fmt.parseInt(i5, "-10", 16)); } fn parseIntWithSign( @@ -475,39 +480,39 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, base: u8) ParseIntError! } test parseUnsigned { - try std.testing.expectEqual(50124, try parseUnsigned(u16, "050124", 10)); - try std.testing.expectEqual(65535, try parseUnsigned(u16, "65535", 10)); - try std.testing.expectEqual(65535, try parseUnsigned(u16, "65_535", 10)); - try std.testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); + try testing.expectEqual(50124, try parseUnsigned(u16, "050124", 10)); + try testing.expectEqual(65535, try parseUnsigned(u16, "65535", 10)); + try testing.expectEqual(65535, try parseUnsigned(u16, "65_535", 10)); + try testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); - try std.testing.expectEqual(0xffffffffffffffff, try parseUnsigned(u64, "0ffffffffffffffff", 16)); - try std.testing.expectEqual(0xffffffffffffffff, try parseUnsigned(u64, "0f_fff_fff_fff_fff_fff", 16)); - try std.testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); + try testing.expectEqual(0xffffffffffffffff, try parseUnsigned(u64, "0ffffffffffffffff", 16)); + try testing.expectEqual(0xffffffffffffffff, try parseUnsigned(u64, "0f_fff_fff_fff_fff_fff", 16)); + try testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); - try std.testing.expectEqual(0xDEADBEEF, try parseUnsigned(u32, "DeadBeef", 16)); + try testing.expectEqual(0xDEADBEEF, try parseUnsigned(u32, "DeadBeef", 16)); - try std.testing.expectEqual(1, try parseUnsigned(u7, "1", 10)); - try std.testing.expectEqual(8, try parseUnsigned(u7, "1000", 2)); + try testing.expectEqual(1, try parseUnsigned(u7, "1", 10)); + try testing.expectEqual(8, try parseUnsigned(u7, "1000", 2)); - try std.testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10)); - try std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8)); + try testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10)); + try testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8)); - try std.testing.expectEqual(1442151747, try parseUnsigned(u32, "NUMBER", 36)); + try testing.expectEqual(1442151747, try parseUnsigned(u32, "NUMBER", 36)); // these numbers should fit even though the base itself doesn't fit in the destination type - try std.testing.expectEqual(0, try parseUnsigned(u1, "0", 10)); - try std.testing.expectEqual(1, try parseUnsigned(u1, "1", 10)); - try std.testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10)); - try std.testing.expectEqual(1, try parseUnsigned(u1, "001", 16)); - try std.testing.expectEqual(3, try parseUnsigned(u2, "3", 16)); - try std.testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16)); + try testing.expectEqual(0, try parseUnsigned(u1, "0", 10)); + try testing.expectEqual(1, try parseUnsigned(u1, "1", 10)); + try testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10)); + try testing.expectEqual(1, try parseUnsigned(u1, "001", 16)); + try testing.expectEqual(3, try parseUnsigned(u2, "3", 16)); + try testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16)); // parseUnsigned does not expect a sign - try std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "+0", 10)); - try std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "-0", 10)); + try testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "+0", 10)); + try testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "-0", 10)); // test empty string error - try std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "", 10)); + try testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "", 10)); } /// Parses a number like '2G', '2Gi', or '2GiB'. @@ -549,15 +554,15 @@ pub fn parseIntSizeSuffix(buf: []const u8, digit_base: u8) ParseIntError!usize { } test parseIntSizeSuffix { - try std.testing.expectEqual(2, try parseIntSizeSuffix("2", 10)); - try std.testing.expectEqual(2, try parseIntSizeSuffix("2B", 10)); - try std.testing.expectEqual(2000, try parseIntSizeSuffix("2kB", 10)); - try std.testing.expectEqual(2000, try parseIntSizeSuffix("2k", 10)); - try std.testing.expectEqual(2048, try parseIntSizeSuffix("2KiB", 10)); - try std.testing.expectEqual(2048, try parseIntSizeSuffix("2Ki", 10)); - try std.testing.expectEqual(10240, try parseIntSizeSuffix("aKiB", 16)); - try std.testing.expectError(error.InvalidCharacter, parseIntSizeSuffix("", 10)); - try std.testing.expectError(error.InvalidCharacter, parseIntSizeSuffix("2iB", 10)); + try testing.expectEqual(2, try parseIntSizeSuffix("2", 10)); + try testing.expectEqual(2, try parseIntSizeSuffix("2B", 10)); + try testing.expectEqual(2000, try parseIntSizeSuffix("2kB", 10)); + try testing.expectEqual(2000, try parseIntSizeSuffix("2k", 10)); + try testing.expectEqual(2048, try parseIntSizeSuffix("2KiB", 10)); + try testing.expectEqual(2048, try parseIntSizeSuffix("2Ki", 10)); + try testing.expectEqual(10240, try parseIntSizeSuffix("aKiB", 16)); + try testing.expectError(error.InvalidCharacter, parseIntSizeSuffix("", 10)); + try testing.expectError(error.InvalidCharacter, parseIntSizeSuffix("2iB", 10)); } pub const parseFloat = @import("fmt/parse_float.zig").parseFloat; @@ -588,28 +593,22 @@ pub fn digitToChar(digit: u8, case: Case) u8 { }; } -pub const BufPrintError = error{ - /// As much as possible was written to the buffer, but it was too small to fit all the printed bytes. - NoSpaceLeft, -}; +/// Deprecated in favor of `mem.PrintError`. +pub const BufPrintError = mem.PrintError; -/// Print a format string into `buf`. Returns a slice of the bytes printed. +/// Deprecated in favor of `mem.print`. pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: anytype) BufPrintError![]u8 { - var w: Writer = .fixed(buf); - w.print(fmt, args) catch |err| switch (err) { - error.WriteFailed => return error.NoSpaceLeft, - }; - return w.buffered(); + return mem.print(buf, fmt, args); } +/// Deprecated in favor of `mem.printSentinel`. pub fn bufPrintSentinel( buf: []u8, comptime fmt: []const u8, args: anytype, comptime sentinel: u8, ) BufPrintError![:sentinel]u8 { - const result = try bufPrint(buf, fmt ++ [_]u8{sentinel}, args); - return result[0 .. result.len - 1 :sentinel]; + return mem.printSentinel(buf, fmt, args, sentinel); } /// Count the characters needed for format. @@ -622,33 +621,25 @@ pub fn count(comptime fmt: []const u8, args: anytype) usize { return @intCast(dw.count + dw.writer.end); } +/// Deprecated in favor of `Allocator.print`. pub fn allocPrint(gpa: Allocator, comptime fmt: []const u8, args: anytype) Allocator.Error![]u8 { - var aw = try Writer.Allocating.initCapacity(gpa, fmt.len); - defer aw.deinit(); - aw.writer.print(fmt, args) catch |err| switch (err) { - error.WriteFailed => return error.OutOfMemory, - }; - return aw.toOwnedSlice(); + return gpa.print(fmt, args); } +/// Deprecated in favor of `Allocator.printSentinel`. pub fn allocPrintSentinel( gpa: Allocator, comptime fmt: []const u8, args: anytype, comptime sentinel: u8, ) Allocator.Error![:sentinel]u8 { - var aw = try Writer.Allocating.initCapacity(gpa, fmt.len); - defer aw.deinit(); - aw.writer.print(fmt, args) catch |err| switch (err) { - error.WriteFailed => return error.OutOfMemory, - }; - return aw.toOwnedSliceSentinel(sentinel); + return gpa.printSentinel(fmt, args, sentinel); } pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 { comptime { var buf: [count(fmt, args):0]u8 = undefined; - _ = bufPrint(&buf, fmt, args) catch unreachable; + _ = mem.print(&buf, fmt, args) catch unreachable; buf[buf.len] = 0; const final = buf; return &final; @@ -657,12 +648,12 @@ pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [cou test comptimePrint { @setEvalBranchQuota(2000); - try std.testing.expectEqual(*const [3:0]u8, @TypeOf(comptimePrint("{}", .{100}))); - try std.testing.expectEqualSlices(u8, "100", comptimePrint("{}", .{100})); - try std.testing.expectEqualStrings("30", comptimePrint("{d}", .{30.0})); - try std.testing.expectEqualStrings("30.0", comptimePrint("{d:3.1}", .{30.0})); - try std.testing.expectEqualStrings("0.05", comptimePrint("{d}", .{0.05})); - try std.testing.expectEqualStrings("5e-2", comptimePrint("{e}", .{0.05})); + try testing.expectEqual(*const [3:0]u8, @TypeOf(comptimePrint("{}", .{100}))); + try testing.expectEqualSlices(u8, "100", comptimePrint("{}", .{100})); + try testing.expectEqualStrings("30", comptimePrint("{d}", .{30.0})); + try testing.expectEqualStrings("30.0", comptimePrint("{d:3.1}", .{30.0})); + try testing.expectEqualStrings("0.05", comptimePrint("{d}", .{0.05})); + try testing.expectEqualStrings("5e-2", comptimePrint("{e}", .{0.05})); } test "parse u64 digit too big" { @@ -675,7 +666,7 @@ test "parse u64 digit too big" { test "parse unsigned comptime" { comptime { - try std.testing.expectEqual(2, try parseUnsigned(usize, "2", 10)); + try testing.expectEqual(2, try parseUnsigned(usize, "2", 10)); } } @@ -780,15 +771,15 @@ test "buffer" { var buf1: [32]u8 = undefined; var w: Writer = .fixed(&buf1); try w.printValue("", .{}, 1234, std.options.fmt_max_depth); - try std.testing.expectEqualStrings("1234", w.buffered()); + try testing.expectEqualStrings("1234", w.buffered()); w = .fixed(&buf1); try w.printValue("c", .{}, 'a', std.options.fmt_max_depth); - try std.testing.expectEqualStrings("a", w.buffered()); + try testing.expectEqualStrings("a", w.buffered()); w = .fixed(&buf1); try w.printValue("b", .{}, 0b1100, std.options.fmt_max_depth); - try std.testing.expectEqualStrings("1100", w.buffered()); + try testing.expectEqualStrings("1100", w.buffered()); } } @@ -809,7 +800,7 @@ test "array" { var buf: [100]u8 = undefined; try expectFmt( - try bufPrint(buf[0..], "array: [3]u8@{x}\n", .{@intFromPtr(&value)}), + try mem.print(buf[0..], "array: [3]u8@{x}\n", .{@intFromPtr(&value)}), "array: {*}\n", .{&value}, ); @@ -1185,7 +1176,7 @@ test bytesToHex { const input = "input slice"; const encoded = bytesToHex(input, .lower); var decoded: [input.len]u8 = undefined; - try std.testing.expectEqualSlices(u8, input, try hexToBytes(&decoded, &encoded)); + try testing.expectEqualSlices(u8, input, try hexToBytes(&decoded, &encoded)); } test hexToBytes { @@ -1197,9 +1188,9 @@ test hexToBytes { try expectFmt(repeated, "{X}", .{try hexToBytes(&buf, repeated)}); try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")}); try expectFmt("", "{X}", .{try hexToBytes(&buf, "")}); - try std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z")); - try std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA")); - try std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB")); + try testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z")); + try testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA")); + try testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB")); } test "positional" { @@ -1234,12 +1225,12 @@ test "vector" { const vop: @Vector(4, ?*const u64) = [_]?*const u64{ &x[0], null, null, &x[3] }; var expect_buffer: [@sizeOf(usize) * 2 * 4 + 64]u8 = undefined; - try expectFmt(try bufPrint( + try expectFmt(try mem.print( &expect_buffer, "{{ {}, {}, {}, {} }}", .{ &x[0], &x[1], &x[2], &x[3] }, ), "{}", .{vp}); - try expectFmt(try bufPrint( + try expectFmt(try mem.print( &expect_buffer, "{{ {?}, null, null, {?} }}", .{ &x[0], &x[3] }, @@ -1356,18 +1347,18 @@ pub fn hex(x: anytype) [@typeInfo(@TypeOf(x)).int.bits / 4]u8 { test hex { { const x = hex(@as(u32, 0xdeadbeef)); - try std.testing.expect(x.len == 8); - try std.testing.expectEqualStrings("efbeadde", &x); + try testing.expect(x.len == 8); + try testing.expectEqualStrings("efbeadde", &x); } { const s = "[" ++ hex(@as(u48, 0x12345678_abcd)) ++ "]"; - try std.testing.expect(s.len == 14); - try std.testing.expectEqualStrings("[cdab78563412]", s); + try testing.expect(s.len == 14); + try testing.expectEqualStrings("[cdab78563412]", s); } { const s = "[" ++ hex(@as(u64, 0x12345678_abcdef00)) ++ "]"; - try std.testing.expect(s.len == 18); - try std.testing.expectEqualStrings("[00efcdab78563412]", s); + try testing.expect(s.len == 18); + try testing.expectEqualStrings("[00efcdab78563412]", s); } } diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index d9d8f011e381cd9c345af49878530968e02cf871..bf16a7c216b4f9087195c7a98160e6b765687960 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -1096,8 +1096,10 @@ test "Dir.renamePreserve onto existing" { // file -> dir try expectError(error.PathAlreadyExists, ctx.dir.renamePreserve(test_file_path, ctx.dir, target_dir_path, io)); - // TODO: fix dir renaming on non-Linux, non-Windows systems, see https://codeberg.org/ziglang/zig/issues/35340 - if (native_os != .windows and native_os != .linux) return; + // TODO: fix dir renaming on other systems, see https://codeberg.org/ziglang/zig/issues/35340 + if (native_os != .windows and native_os != .linux and !native_os.isDarwin()) { + return; + } // dir -> file try expectError(error.PathAlreadyExists, ctx.dir.renamePreserve(test_dir_path, ctx.dir, target_file_path, io)); diff --git a/lib/std/gpu.zig b/lib/std/gpu.zig deleted file mode 100644 index 0e00eccb62f74979c42b704f57ada7ff24668731..0000000000000000000000000000000000000000 --- a/lib/std/gpu.zig +++ /dev/null @@ -1,104 +0,0 @@ -const std = @import("std.zig"); - -pub const position_in = @extern(*addrspace(.input) @Vector(4, f32), .{ .name = "position" }); -pub const position_out = @extern(*addrspace(.output) @Vector(4, f32), .{ .name = "position" }); -pub const point_size_in = @extern(*addrspace(.input) f32, .{ .name = "point_size" }); -pub const point_size_out = @extern(*addrspace(.output) f32, .{ .name = "point_size" }); -pub extern const invocation_id: u32 addrspace(.input); -pub extern const frag_coord: @Vector(4, f32) addrspace(.input); -pub extern const point_coord: @Vector(2, f32) addrspace(.input); -// TODO: direct/indirect values -// pub extern const front_facing: bool addrspace(.input); -// TODO: runtime array -// pub extern const sample_mask; -pub extern var frag_depth: f32 addrspace(.output); -pub extern const num_workgroups: @Vector(3, u32) addrspace(.input); -pub extern const workgroup_size: @Vector(3, u32) addrspace(.input); -pub extern const workgroup_id: @Vector(3, u32) addrspace(.input); -pub extern const local_invocation_id: @Vector(3, u32) addrspace(.input); -pub extern const global_invocation_id: @Vector(3, u32) addrspace(.input); -pub extern const vertex_index: u32 addrspace(.input); -pub extern const instance_index: u32 addrspace(.input); - -pub const ExecutionMode = union(Tag) { - /// Sets origin of the framebuffer to the upper-left corner - origin_upper_left, - /// Sets origin of the framebuffer to the lower-left corner - origin_lower_left, - /// Indicates that the fragment shader writes to `frag_depth`, - /// replacing the fixed-function depth value. - depth_replacing, - /// Indicates that per-fragment tests may assume that - /// any `frag_depth` built in-decorated value written by the shader is - /// greater-than-or-equal to the fragment’s interpolated depth value - depth_greater, - /// Indicates that per-fragment tests may assume that - /// any `frag_depth` built in-decorated value written by the shader is - /// less-than-or-equal to the fragment’s interpolated depth value - depth_less, - /// Indicates that per-fragment tests may assume that - /// any `frag_depth` built in-decorated value written by the shader is - /// the same as the fragment’s interpolated depth value - depth_unchanged, - /// Indicates the workgroup size in the x, y, and z dimensions. - local_size: LocalSize, - - pub const Tag = enum(u32) { - origin_upper_left = 7, - origin_lower_left = 8, - depth_replacing = 12, - depth_greater = 14, - depth_less = 15, - depth_unchanged = 16, - local_size = 17, - }; - - pub const LocalSize = struct { x: u32, y: u32, z: u32 }; -}; - -/// Declare the mode entry point executes in. -pub fn executionMode(comptime entry_point: anytype, comptime mode: ExecutionMode) void { - const cc = @typeInfo(@TypeOf(entry_point)).@"fn".attrs.@"callconv"; - switch (mode) { - .origin_upper_left, - .origin_lower_left, - .depth_replacing, - .depth_greater, - .depth_less, - .depth_unchanged, - => { - if (cc != .spirv_fragment) { - @compileError( - \\invalid execution mode ' - ++ @tagName(mode) ++ - \\' for function with ' - ++ @tagName(cc) ++ - \\' calling convention - ); - } - asm volatile ( - \\OpExecutionMode %entry_point $mode - : - : [entry_point] "" (entry_point), - [mode] "c" (@intFromEnum(mode)), - ); - }, - .local_size => |size| { - if (cc != .spirv_kernel) { - @compileError( - \\invalid execution mode 'local_size' for function with ' - ++ @tagName(cc) ++ - \\' calling convention - ); - } - asm volatile ( - \\OpExecutionMode %entry_point LocalSize $x $y $z - : - : [entry_point] "" (entry_point), - [x] "c" (size.x), - [y] "c" (size.y), - [z] "c" (size.z), - ); - }, - } -} diff --git a/lib/std/hash.zig b/lib/std/hash.zig index e8d2aa85b13e7dbec1ffbc541bcbeb95a9264261..5ae3734ad2d8c30837b4c69f30866658016f8698 100644 --- a/lib/std/hash.zig +++ b/lib/std/hash.zig @@ -5,9 +5,8 @@ pub const autoHash = auto_hash.autoHash; pub const autoHashStrat = auto_hash.hash; pub const Strategy = auto_hash.HashStrategy; -// pub for polynomials + generic crc32 construction pub const crc = @import("hash/crc.zig"); -pub const Crc32 = crc.Crc32; +pub const Crc32 = crc.@"CRC-32/ISO-HDLC"; const fnv = @import("hash/fnv.zig"); pub const Fnv1a_32 = fnv.Fnv1a_32; diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index edfe870f27099104cc3b4f589a5cd94c9e373be0..2562c5157355aa312b3fdd5a89e652a131035d61 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -76,6 +76,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { switch (@typeInfo(Key)) { .noreturn, .@"opaque", + .spirv, .undefined, .null, .comptime_float, diff --git a/lib/std/hash/benchmark.zig b/lib/std/hash/benchmark.zig index e5467f421154747181b0d14c1bada7ac28a462ee..3f5b763d9b0f2eb207b597c8e41098f272a090d0 100644 --- a/lib/std/hash/benchmark.zig +++ b/lib/std/hash/benchmark.zig @@ -61,7 +61,7 @@ const hashes = [_]Hash{ .init_default = true, }, Hash{ - .ty = hash.crc.Crc32, + .ty = hash.Crc32, .name = "crc32", }, Hash{ diff --git a/lib/std/hash/crc.zig b/lib/std/hash/crc.zig index c0a418a0c2cd236e89df6eeec979dddd33537b8a..795f6a5f5e61ba60b3cbb33efd6605848a91cff8 100644 --- a/lib/std/hash/crc.zig +++ b/lib/std/hash/crc.zig @@ -1,19 +1,8 @@ //! This file is auto-generated by tools/update_crc_catalog.zig. -const impl = @import("crc/impl.zig"); +const builtin = @import("builtin"); -pub const Crc = impl.Crc; -pub const Polynomial = impl.Polynomial; -pub const Crc32WithPoly = impl.Crc32WithPoly; -pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly; - -pub const Crc32 = Crc32IsoHdlc; - -test { - _ = @import("crc/test.zig"); -} - -pub const Crc3Gsm = Crc(u3, .{ +pub const @"CRC-3/GSM" = Generic(u3, .{ .polynomial = 0x3, .initial = 0x0, .reflect_input = false, @@ -21,7 +10,7 @@ pub const Crc3Gsm = Crc(u3, .{ .xor_output = 0x7, }); -pub const Crc3Rohc = Crc(u3, .{ +pub const @"CRC-3/ROHC" = Generic(u3, .{ .polynomial = 0x3, .initial = 0x7, .reflect_input = true, @@ -29,7 +18,7 @@ pub const Crc3Rohc = Crc(u3, .{ .xor_output = 0x0, }); -pub const Crc4G704 = Crc(u4, .{ +pub const @"CRC-4/G-704" = Generic(u4, .{ .polynomial = 0x3, .initial = 0x0, .reflect_input = true, @@ -37,7 +26,7 @@ pub const Crc4G704 = Crc(u4, .{ .xor_output = 0x0, }); -pub const Crc4Interlaken = Crc(u4, .{ +pub const @"CRC-4/INTERLAKEN" = Generic(u4, .{ .polynomial = 0x3, .initial = 0xf, .reflect_input = false, @@ -45,7 +34,7 @@ pub const Crc4Interlaken = Crc(u4, .{ .xor_output = 0xf, }); -pub const Crc5EpcC1g2 = Crc(u5, .{ +pub const @"CRC-5/EPC-C1G2" = Generic(u5, .{ .polynomial = 0x09, .initial = 0x09, .reflect_input = false, @@ -53,7 +42,7 @@ pub const Crc5EpcC1g2 = Crc(u5, .{ .xor_output = 0x00, }); -pub const Crc5G704 = Crc(u5, .{ +pub const @"CRC-5/G-704" = Generic(u5, .{ .polynomial = 0x15, .initial = 0x00, .reflect_input = true, @@ -61,7 +50,7 @@ pub const Crc5G704 = Crc(u5, .{ .xor_output = 0x00, }); -pub const Crc5Usb = Crc(u5, .{ +pub const @"CRC-5/USB" = Generic(u5, .{ .polynomial = 0x05, .initial = 0x1f, .reflect_input = true, @@ -69,7 +58,7 @@ pub const Crc5Usb = Crc(u5, .{ .xor_output = 0x1f, }); -pub const Crc6Cdma2000A = Crc(u6, .{ +pub const @"CRC-6/CDMA2000-A" = Generic(u6, .{ .polynomial = 0x27, .initial = 0x3f, .reflect_input = false, @@ -77,7 +66,7 @@ pub const Crc6Cdma2000A = Crc(u6, .{ .xor_output = 0x00, }); -pub const Crc6Cdma2000B = Crc(u6, .{ +pub const @"CRC-6/CDMA2000-B" = Generic(u6, .{ .polynomial = 0x07, .initial = 0x3f, .reflect_input = false, @@ -85,7 +74,7 @@ pub const Crc6Cdma2000B = Crc(u6, .{ .xor_output = 0x00, }); -pub const Crc6Darc = Crc(u6, .{ +pub const @"CRC-6/DARC" = Generic(u6, .{ .polynomial = 0x19, .initial = 0x00, .reflect_input = true, @@ -93,7 +82,7 @@ pub const Crc6Darc = Crc(u6, .{ .xor_output = 0x00, }); -pub const Crc6G704 = Crc(u6, .{ +pub const @"CRC-6/G-704" = Generic(u6, .{ .polynomial = 0x03, .initial = 0x00, .reflect_input = true, @@ -101,7 +90,7 @@ pub const Crc6G704 = Crc(u6, .{ .xor_output = 0x00, }); -pub const Crc6Gsm = Crc(u6, .{ +pub const @"CRC-6/GSM" = Generic(u6, .{ .polynomial = 0x2f, .initial = 0x00, .reflect_input = false, @@ -109,7 +98,7 @@ pub const Crc6Gsm = Crc(u6, .{ .xor_output = 0x3f, }); -pub const Crc7Mmc = Crc(u7, .{ +pub const @"CRC-7/MMC" = Generic(u7, .{ .polynomial = 0x09, .initial = 0x00, .reflect_input = false, @@ -117,7 +106,7 @@ pub const Crc7Mmc = Crc(u7, .{ .xor_output = 0x00, }); -pub const Crc7Rohc = Crc(u7, .{ +pub const @"CRC-7/ROHC" = Generic(u7, .{ .polynomial = 0x4f, .initial = 0x7f, .reflect_input = true, @@ -125,7 +114,7 @@ pub const Crc7Rohc = Crc(u7, .{ .xor_output = 0x00, }); -pub const Crc7Umts = Crc(u7, .{ +pub const @"CRC-7/UMTS" = Generic(u7, .{ .polynomial = 0x45, .initial = 0x00, .reflect_input = false, @@ -133,7 +122,7 @@ pub const Crc7Umts = Crc(u7, .{ .xor_output = 0x00, }); -pub const Crc8Autosar = Crc(u8, .{ +pub const @"CRC-8/AUTOSAR" = Generic(u8, .{ .polynomial = 0x2f, .initial = 0xff, .reflect_input = false, @@ -141,7 +130,7 @@ pub const Crc8Autosar = Crc(u8, .{ .xor_output = 0xff, }); -pub const Crc8Bluetooth = Crc(u8, .{ +pub const @"CRC-8/BLUETOOTH" = Generic(u8, .{ .polynomial = 0xa7, .initial = 0x00, .reflect_input = true, @@ -149,7 +138,7 @@ pub const Crc8Bluetooth = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Cdma2000 = Crc(u8, .{ +pub const @"CRC-8/CDMA2000" = Generic(u8, .{ .polynomial = 0x9b, .initial = 0xff, .reflect_input = false, @@ -157,7 +146,7 @@ pub const Crc8Cdma2000 = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Darc = Crc(u8, .{ +pub const @"CRC-8/DARC" = Generic(u8, .{ .polynomial = 0x39, .initial = 0x00, .reflect_input = true, @@ -165,7 +154,7 @@ pub const Crc8Darc = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8DvbS2 = Crc(u8, .{ +pub const @"CRC-8/DVB-S2" = Generic(u8, .{ .polynomial = 0xd5, .initial = 0x00, .reflect_input = false, @@ -173,7 +162,7 @@ pub const Crc8DvbS2 = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8GsmA = Crc(u8, .{ +pub const @"CRC-8/GSM-A" = Generic(u8, .{ .polynomial = 0x1d, .initial = 0x00, .reflect_input = false, @@ -181,7 +170,7 @@ pub const Crc8GsmA = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8GsmB = Crc(u8, .{ +pub const @"CRC-8/GSM-B" = Generic(u8, .{ .polynomial = 0x49, .initial = 0x00, .reflect_input = false, @@ -189,7 +178,7 @@ pub const Crc8GsmB = Crc(u8, .{ .xor_output = 0xff, }); -pub const Crc8Hitag = Crc(u8, .{ +pub const @"CRC-8/HITAG" = Generic(u8, .{ .polynomial = 0x1d, .initial = 0xff, .reflect_input = false, @@ -197,7 +186,7 @@ pub const Crc8Hitag = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8I4321 = Crc(u8, .{ +pub const @"CRC-8/I-432-1" = Generic(u8, .{ .polynomial = 0x07, .initial = 0x00, .reflect_input = false, @@ -205,7 +194,7 @@ pub const Crc8I4321 = Crc(u8, .{ .xor_output = 0x55, }); -pub const Crc8ICode = Crc(u8, .{ +pub const @"CRC-8/I-CODE" = Generic(u8, .{ .polynomial = 0x1d, .initial = 0xfd, .reflect_input = false, @@ -213,7 +202,7 @@ pub const Crc8ICode = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Lte = Crc(u8, .{ +pub const @"CRC-8/LTE" = Generic(u8, .{ .polynomial = 0x9b, .initial = 0x00, .reflect_input = false, @@ -221,7 +210,7 @@ pub const Crc8Lte = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8MaximDow = Crc(u8, .{ +pub const @"CRC-8/MAXIM-DOW" = Generic(u8, .{ .polynomial = 0x31, .initial = 0x00, .reflect_input = true, @@ -229,7 +218,7 @@ pub const Crc8MaximDow = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8MifareMad = Crc(u8, .{ +pub const @"CRC-8/MIFARE-MAD" = Generic(u8, .{ .polynomial = 0x1d, .initial = 0xc7, .reflect_input = false, @@ -237,7 +226,7 @@ pub const Crc8MifareMad = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Nrsc5 = Crc(u8, .{ +pub const @"CRC-8/NRSC-5" = Generic(u8, .{ .polynomial = 0x31, .initial = 0xff, .reflect_input = false, @@ -245,7 +234,7 @@ pub const Crc8Nrsc5 = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Opensafety = Crc(u8, .{ +pub const @"CRC-8/OPENSAFETY" = Generic(u8, .{ .polynomial = 0x2f, .initial = 0x00, .reflect_input = false, @@ -253,7 +242,7 @@ pub const Crc8Opensafety = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Rohc = Crc(u8, .{ +pub const @"CRC-8/ROHC" = Generic(u8, .{ .polynomial = 0x07, .initial = 0xff, .reflect_input = true, @@ -261,7 +250,7 @@ pub const Crc8Rohc = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8SaeJ1850 = Crc(u8, .{ +pub const @"CRC-8/SAE-J1850" = Generic(u8, .{ .polynomial = 0x1d, .initial = 0xff, .reflect_input = false, @@ -269,7 +258,7 @@ pub const Crc8SaeJ1850 = Crc(u8, .{ .xor_output = 0xff, }); -pub const Crc8Smbus = Crc(u8, .{ +pub const @"CRC-8/SMBUS" = Generic(u8, .{ .polynomial = 0x07, .initial = 0x00, .reflect_input = false, @@ -277,7 +266,7 @@ pub const Crc8Smbus = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Tech3250 = Crc(u8, .{ +pub const @"CRC-8/TECH-3250" = Generic(u8, .{ .polynomial = 0x1d, .initial = 0xff, .reflect_input = true, @@ -285,7 +274,7 @@ pub const Crc8Tech3250 = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc8Wcdma = Crc(u8, .{ +pub const @"CRC-8/WCDMA" = Generic(u8, .{ .polynomial = 0x9b, .initial = 0x00, .reflect_input = true, @@ -293,7 +282,7 @@ pub const Crc8Wcdma = Crc(u8, .{ .xor_output = 0x00, }); -pub const Crc10Atm = Crc(u10, .{ +pub const @"CRC-10/ATM" = Generic(u10, .{ .polynomial = 0x233, .initial = 0x000, .reflect_input = false, @@ -301,7 +290,7 @@ pub const Crc10Atm = Crc(u10, .{ .xor_output = 0x000, }); -pub const Crc10Cdma2000 = Crc(u10, .{ +pub const @"CRC-10/CDMA2000" = Generic(u10, .{ .polynomial = 0x3d9, .initial = 0x3ff, .reflect_input = false, @@ -309,7 +298,7 @@ pub const Crc10Cdma2000 = Crc(u10, .{ .xor_output = 0x000, }); -pub const Crc10Gsm = Crc(u10, .{ +pub const @"CRC-10/GSM" = Generic(u10, .{ .polynomial = 0x175, .initial = 0x000, .reflect_input = false, @@ -317,7 +306,7 @@ pub const Crc10Gsm = Crc(u10, .{ .xor_output = 0x3ff, }); -pub const Crc11Flexray = Crc(u11, .{ +pub const @"CRC-11/FLEXRAY" = Generic(u11, .{ .polynomial = 0x385, .initial = 0x01a, .reflect_input = false, @@ -325,7 +314,7 @@ pub const Crc11Flexray = Crc(u11, .{ .xor_output = 0x000, }); -pub const Crc11Umts = Crc(u11, .{ +pub const @"CRC-11/UMTS" = Generic(u11, .{ .polynomial = 0x307, .initial = 0x000, .reflect_input = false, @@ -333,7 +322,7 @@ pub const Crc11Umts = Crc(u11, .{ .xor_output = 0x000, }); -pub const Crc12Cdma2000 = Crc(u12, .{ +pub const @"CRC-12/CDMA2000" = Generic(u12, .{ .polynomial = 0xf13, .initial = 0xfff, .reflect_input = false, @@ -341,7 +330,7 @@ pub const Crc12Cdma2000 = Crc(u12, .{ .xor_output = 0x000, }); -pub const Crc12Dect = Crc(u12, .{ +pub const @"CRC-12/DECT" = Generic(u12, .{ .polynomial = 0x80f, .initial = 0x000, .reflect_input = false, @@ -349,7 +338,7 @@ pub const Crc12Dect = Crc(u12, .{ .xor_output = 0x000, }); -pub const Crc12Gsm = Crc(u12, .{ +pub const @"CRC-12/GSM" = Generic(u12, .{ .polynomial = 0xd31, .initial = 0x000, .reflect_input = false, @@ -357,7 +346,7 @@ pub const Crc12Gsm = Crc(u12, .{ .xor_output = 0xfff, }); -pub const Crc12Umts = Crc(u12, .{ +pub const @"CRC-12/UMTS" = Generic(u12, .{ .polynomial = 0x80f, .initial = 0x000, .reflect_input = false, @@ -365,7 +354,7 @@ pub const Crc12Umts = Crc(u12, .{ .xor_output = 0x000, }); -pub const Crc13Bbc = Crc(u13, .{ +pub const @"CRC-13/BBC" = Generic(u13, .{ .polynomial = 0x1cf5, .initial = 0x0000, .reflect_input = false, @@ -373,7 +362,7 @@ pub const Crc13Bbc = Crc(u13, .{ .xor_output = 0x0000, }); -pub const Crc14Darc = Crc(u14, .{ +pub const @"CRC-14/DARC" = Generic(u14, .{ .polynomial = 0x0805, .initial = 0x0000, .reflect_input = true, @@ -381,7 +370,7 @@ pub const Crc14Darc = Crc(u14, .{ .xor_output = 0x0000, }); -pub const Crc14Gsm = Crc(u14, .{ +pub const @"CRC-14/GSM" = Generic(u14, .{ .polynomial = 0x202d, .initial = 0x0000, .reflect_input = false, @@ -389,7 +378,7 @@ pub const Crc14Gsm = Crc(u14, .{ .xor_output = 0x3fff, }); -pub const Crc15Can = Crc(u15, .{ +pub const @"CRC-15/CAN" = Generic(u15, .{ .polynomial = 0x4599, .initial = 0x0000, .reflect_input = false, @@ -397,7 +386,7 @@ pub const Crc15Can = Crc(u15, .{ .xor_output = 0x0000, }); -pub const Crc15Mpt1327 = Crc(u15, .{ +pub const @"CRC-15/MPT1327" = Generic(u15, .{ .polynomial = 0x6815, .initial = 0x0000, .reflect_input = false, @@ -405,7 +394,7 @@ pub const Crc15Mpt1327 = Crc(u15, .{ .xor_output = 0x0001, }); -pub const Crc16Arc = Crc(u16, .{ +pub const @"CRC-16/ARC" = Generic(u16, .{ .polynomial = 0x8005, .initial = 0x0000, .reflect_input = true, @@ -413,7 +402,7 @@ pub const Crc16Arc = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Cdma2000 = Crc(u16, .{ +pub const @"CRC-16/CDMA2000" = Generic(u16, .{ .polynomial = 0xc867, .initial = 0xffff, .reflect_input = false, @@ -421,7 +410,7 @@ pub const Crc16Cdma2000 = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Cms = Crc(u16, .{ +pub const @"CRC-16/CMS" = Generic(u16, .{ .polynomial = 0x8005, .initial = 0xffff, .reflect_input = false, @@ -429,7 +418,7 @@ pub const Crc16Cms = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Dds110 = Crc(u16, .{ +pub const @"CRC-16/DDS-110" = Generic(u16, .{ .polynomial = 0x8005, .initial = 0x800d, .reflect_input = false, @@ -437,7 +426,7 @@ pub const Crc16Dds110 = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16DectR = Crc(u16, .{ +pub const @"CRC-16/DECT-R" = Generic(u16, .{ .polynomial = 0x0589, .initial = 0x0000, .reflect_input = false, @@ -445,7 +434,7 @@ pub const Crc16DectR = Crc(u16, .{ .xor_output = 0x0001, }); -pub const Crc16DectX = Crc(u16, .{ +pub const @"CRC-16/DECT-X" = Generic(u16, .{ .polynomial = 0x0589, .initial = 0x0000, .reflect_input = false, @@ -453,7 +442,7 @@ pub const Crc16DectX = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Dnp = Crc(u16, .{ +pub const @"CRC-16/DNP" = Generic(u16, .{ .polynomial = 0x3d65, .initial = 0x0000, .reflect_input = true, @@ -461,7 +450,7 @@ pub const Crc16Dnp = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16En13757 = Crc(u16, .{ +pub const @"CRC-16/EN-13757" = Generic(u16, .{ .polynomial = 0x3d65, .initial = 0x0000, .reflect_input = false, @@ -469,7 +458,7 @@ pub const Crc16En13757 = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16Genibus = Crc(u16, .{ +pub const @"CRC-16/GENIBUS" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0xffff, .reflect_input = false, @@ -477,7 +466,7 @@ pub const Crc16Genibus = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16Gsm = Crc(u16, .{ +pub const @"CRC-16/GSM" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0x0000, .reflect_input = false, @@ -485,7 +474,7 @@ pub const Crc16Gsm = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16Ibm3740 = Crc(u16, .{ +pub const @"CRC-16/IBM-3740" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0xffff, .reflect_input = false, @@ -493,7 +482,7 @@ pub const Crc16Ibm3740 = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16IbmSdlc = Crc(u16, .{ +pub const @"CRC-16/IBM-SDLC" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0xffff, .reflect_input = true, @@ -501,7 +490,7 @@ pub const Crc16IbmSdlc = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16IsoIec144433A = Crc(u16, .{ +pub const @"CRC-16/ISO-IEC-14443-3-A" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0xc6c6, .reflect_input = true, @@ -509,7 +498,7 @@ pub const Crc16IsoIec144433A = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Kermit = Crc(u16, .{ +pub const @"CRC-16/KERMIT" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0x0000, .reflect_input = true, @@ -517,7 +506,7 @@ pub const Crc16Kermit = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Lj1200 = Crc(u16, .{ +pub const @"CRC-16/LJ1200" = Generic(u16, .{ .polynomial = 0x6f63, .initial = 0x0000, .reflect_input = false, @@ -525,7 +514,7 @@ pub const Crc16Lj1200 = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16M17 = Crc(u16, .{ +pub const @"CRC-16/M17" = Generic(u16, .{ .polynomial = 0x5935, .initial = 0xffff, .reflect_input = false, @@ -533,7 +522,7 @@ pub const Crc16M17 = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16MaximDow = Crc(u16, .{ +pub const @"CRC-16/MAXIM-DOW" = Generic(u16, .{ .polynomial = 0x8005, .initial = 0x0000, .reflect_input = true, @@ -541,7 +530,7 @@ pub const Crc16MaximDow = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16Mcrf4xx = Crc(u16, .{ +pub const @"CRC-16/MCRF4XX" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0xffff, .reflect_input = true, @@ -549,7 +538,7 @@ pub const Crc16Mcrf4xx = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Modbus = Crc(u16, .{ +pub const @"CRC-16/MODBUS" = Generic(u16, .{ .polynomial = 0x8005, .initial = 0xffff, .reflect_input = true, @@ -557,7 +546,7 @@ pub const Crc16Modbus = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Nrsc5 = Crc(u16, .{ +pub const @"CRC-16/NRSC-5" = Generic(u16, .{ .polynomial = 0x080b, .initial = 0xffff, .reflect_input = true, @@ -565,7 +554,7 @@ pub const Crc16Nrsc5 = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16OpensafetyA = Crc(u16, .{ +pub const @"CRC-16/OPENSAFETY-A" = Generic(u16, .{ .polynomial = 0x5935, .initial = 0x0000, .reflect_input = false, @@ -573,7 +562,7 @@ pub const Crc16OpensafetyA = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16OpensafetyB = Crc(u16, .{ +pub const @"CRC-16/OPENSAFETY-B" = Generic(u16, .{ .polynomial = 0x755b, .initial = 0x0000, .reflect_input = false, @@ -581,7 +570,7 @@ pub const Crc16OpensafetyB = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Profibus = Crc(u16, .{ +pub const @"CRC-16/PROFIBUS" = Generic(u16, .{ .polynomial = 0x1dcf, .initial = 0xffff, .reflect_input = false, @@ -589,7 +578,7 @@ pub const Crc16Profibus = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16Riello = Crc(u16, .{ +pub const @"CRC-16/RIELLO" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0xb2aa, .reflect_input = true, @@ -597,7 +586,7 @@ pub const Crc16Riello = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16SpiFujitsu = Crc(u16, .{ +pub const @"CRC-16/SPI-FUJITSU" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0x1d0f, .reflect_input = false, @@ -605,7 +594,7 @@ pub const Crc16SpiFujitsu = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16T10Dif = Crc(u16, .{ +pub const @"CRC-16/T10-DIF" = Generic(u16, .{ .polynomial = 0x8bb7, .initial = 0x0000, .reflect_input = false, @@ -613,7 +602,7 @@ pub const Crc16T10Dif = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Teledisk = Crc(u16, .{ +pub const @"CRC-16/TELEDISK" = Generic(u16, .{ .polynomial = 0xa097, .initial = 0x0000, .reflect_input = false, @@ -621,7 +610,7 @@ pub const Crc16Teledisk = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Tms37157 = Crc(u16, .{ +pub const @"CRC-16/TMS37157" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0x89ec, .reflect_input = true, @@ -629,7 +618,7 @@ pub const Crc16Tms37157 = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Umts = Crc(u16, .{ +pub const @"CRC-16/UMTS" = Generic(u16, .{ .polynomial = 0x8005, .initial = 0x0000, .reflect_input = false, @@ -637,7 +626,7 @@ pub const Crc16Umts = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc16Usb = Crc(u16, .{ +pub const @"CRC-16/USB" = Generic(u16, .{ .polynomial = 0x8005, .initial = 0xffff, .reflect_input = true, @@ -645,7 +634,7 @@ pub const Crc16Usb = Crc(u16, .{ .xor_output = 0xffff, }); -pub const Crc16Xmodem = Crc(u16, .{ +pub const @"CRC-16/XMODEM" = Generic(u16, .{ .polynomial = 0x1021, .initial = 0x0000, .reflect_input = false, @@ -653,7 +642,7 @@ pub const Crc16Xmodem = Crc(u16, .{ .xor_output = 0x0000, }); -pub const Crc17CanFd = Crc(u17, .{ +pub const @"CRC-17/CAN-FD" = Generic(u17, .{ .polynomial = 0x1685b, .initial = 0x00000, .reflect_input = false, @@ -661,7 +650,7 @@ pub const Crc17CanFd = Crc(u17, .{ .xor_output = 0x00000, }); -pub const Crc21CanFd = Crc(u21, .{ +pub const @"CRC-21/CAN-FD" = Generic(u21, .{ .polynomial = 0x102899, .initial = 0x000000, .reflect_input = false, @@ -669,7 +658,7 @@ pub const Crc21CanFd = Crc(u21, .{ .xor_output = 0x000000, }); -pub const Crc24Ble = Crc(u24, .{ +pub const @"CRC-24/BLE" = Generic(u24, .{ .polynomial = 0x00065b, .initial = 0x555555, .reflect_input = true, @@ -677,7 +666,7 @@ pub const Crc24Ble = Crc(u24, .{ .xor_output = 0x000000, }); -pub const Crc24FlexrayA = Crc(u24, .{ +pub const @"CRC-24/FLEXRAY-A" = Generic(u24, .{ .polynomial = 0x5d6dcb, .initial = 0xfedcba, .reflect_input = false, @@ -685,7 +674,7 @@ pub const Crc24FlexrayA = Crc(u24, .{ .xor_output = 0x000000, }); -pub const Crc24FlexrayB = Crc(u24, .{ +pub const @"CRC-24/FLEXRAY-B" = Generic(u24, .{ .polynomial = 0x5d6dcb, .initial = 0xabcdef, .reflect_input = false, @@ -693,7 +682,7 @@ pub const Crc24FlexrayB = Crc(u24, .{ .xor_output = 0x000000, }); -pub const Crc24Interlaken = Crc(u24, .{ +pub const @"CRC-24/INTERLAKEN" = Generic(u24, .{ .polynomial = 0x328b63, .initial = 0xffffff, .reflect_input = false, @@ -701,7 +690,7 @@ pub const Crc24Interlaken = Crc(u24, .{ .xor_output = 0xffffff, }); -pub const Crc24LteA = Crc(u24, .{ +pub const @"CRC-24/LTE-A" = Generic(u24, .{ .polynomial = 0x864cfb, .initial = 0x000000, .reflect_input = false, @@ -709,7 +698,7 @@ pub const Crc24LteA = Crc(u24, .{ .xor_output = 0x000000, }); -pub const Crc24LteB = Crc(u24, .{ +pub const @"CRC-24/LTE-B" = Generic(u24, .{ .polynomial = 0x800063, .initial = 0x000000, .reflect_input = false, @@ -717,7 +706,7 @@ pub const Crc24LteB = Crc(u24, .{ .xor_output = 0x000000, }); -pub const Crc24Openpgp = Crc(u24, .{ +pub const @"CRC-24/OPENPGP" = Generic(u24, .{ .polynomial = 0x864cfb, .initial = 0xb704ce, .reflect_input = false, @@ -725,7 +714,7 @@ pub const Crc24Openpgp = Crc(u24, .{ .xor_output = 0x000000, }); -pub const Crc24Os9 = Crc(u24, .{ +pub const @"CRC-24/OS-9" = Generic(u24, .{ .polynomial = 0x800063, .initial = 0xffffff, .reflect_input = false, @@ -733,7 +722,7 @@ pub const Crc24Os9 = Crc(u24, .{ .xor_output = 0xffffff, }); -pub const Crc30Cdma = Crc(u30, .{ +pub const @"CRC-30/CDMA" = Generic(u30, .{ .polynomial = 0x2030b9c7, .initial = 0x3fffffff, .reflect_input = false, @@ -741,7 +730,7 @@ pub const Crc30Cdma = Crc(u30, .{ .xor_output = 0x3fffffff, }); -pub const Crc31Philips = Crc(u31, .{ +pub const @"CRC-31/PHILIPS" = Generic(u31, .{ .polynomial = 0x04c11db7, .initial = 0x7fffffff, .reflect_input = false, @@ -749,7 +738,7 @@ pub const Crc31Philips = Crc(u31, .{ .xor_output = 0x7fffffff, }); -pub const Crc32Aixm = Crc(u32, .{ +pub const @"CRC-32/AIXM" = Generic(u32, .{ .polynomial = 0x814141ab, .initial = 0x00000000, .reflect_input = false, @@ -757,7 +746,7 @@ pub const Crc32Aixm = Crc(u32, .{ .xor_output = 0x00000000, }); -pub const Crc32Autosar = Crc(u32, .{ +pub const @"CRC-32/AUTOSAR" = Generic(u32, .{ .polynomial = 0xf4acfb13, .initial = 0xffffffff, .reflect_input = true, @@ -765,7 +754,7 @@ pub const Crc32Autosar = Crc(u32, .{ .xor_output = 0xffffffff, }); -pub const Crc32Base91D = Crc(u32, .{ +pub const @"CRC-32/BASE91-D" = Generic(u32, .{ .polynomial = 0xa833982b, .initial = 0xffffffff, .reflect_input = true, @@ -773,7 +762,7 @@ pub const Crc32Base91D = Crc(u32, .{ .xor_output = 0xffffffff, }); -pub const Crc32Bzip2 = Crc(u32, .{ +pub const @"CRC-32/BZIP2" = Generic(u32, .{ .polynomial = 0x04c11db7, .initial = 0xffffffff, .reflect_input = false, @@ -781,7 +770,7 @@ pub const Crc32Bzip2 = Crc(u32, .{ .xor_output = 0xffffffff, }); -pub const Crc32CdRomEdc = Crc(u32, .{ +pub const @"CRC-32/CD-ROM-EDC" = Generic(u32, .{ .polynomial = 0x8001801b, .initial = 0x00000000, .reflect_input = true, @@ -789,7 +778,7 @@ pub const Crc32CdRomEdc = Crc(u32, .{ .xor_output = 0x00000000, }); -pub const Crc32Cksum = Crc(u32, .{ +pub const @"CRC-32/CKSUM" = Generic(u32, .{ .polynomial = 0x04c11db7, .initial = 0x00000000, .reflect_input = false, @@ -797,15 +786,18 @@ pub const Crc32Cksum = Crc(u32, .{ .xor_output = 0xffffffff, }); -pub const Crc32Iscsi = Crc(u32, .{ - .polynomial = 0x1edc6f41, - .initial = 0xffffffff, - .reflect_input = true, - .reflect_output = true, - .xor_output = 0xffffffff, -}); +pub const @"CRC-32/ISCSI" = if (builtin.cpu.hasAll(.x86, &.{ .@"64bit", .crc32 })) + @import("crc/Crc32c.zig") +else + Generic(u32, .{ + .polynomial = 0x1edc6f41, + .initial = 0xffffffff, + .reflect_input = true, + .reflect_output = true, + .xor_output = 0xffffffff, + }); -pub const Crc32IsoHdlc = Crc(u32, .{ +pub const @"CRC-32/ISO-HDLC" = Generic(u32, .{ .polynomial = 0x04c11db7, .initial = 0xffffffff, .reflect_input = true, @@ -813,7 +805,7 @@ pub const Crc32IsoHdlc = Crc(u32, .{ .xor_output = 0xffffffff, }); -pub const Crc32Jamcrc = Crc(u32, .{ +pub const @"CRC-32/JAMCRC" = Generic(u32, .{ .polynomial = 0x04c11db7, .initial = 0xffffffff, .reflect_input = true, @@ -821,7 +813,7 @@ pub const Crc32Jamcrc = Crc(u32, .{ .xor_output = 0x00000000, }); -pub const Crc32Koopman = Crc(u32, .{ +pub const @"CRC-32/KOOPMAN" = Generic(u32, .{ .polynomial = 0x741b8cd7, .initial = 0xffffffff, .reflect_input = true, @@ -829,7 +821,7 @@ pub const Crc32Koopman = Crc(u32, .{ .xor_output = 0xffffffff, }); -pub const Crc32Mef = Crc(u32, .{ +pub const @"CRC-32/MEF" = Generic(u32, .{ .polynomial = 0x741b8cd7, .initial = 0xffffffff, .reflect_input = true, @@ -837,7 +829,7 @@ pub const Crc32Mef = Crc(u32, .{ .xor_output = 0x00000000, }); -pub const Crc32Mpeg2 = Crc(u32, .{ +pub const @"CRC-32/MPEG-2" = Generic(u32, .{ .polynomial = 0x04c11db7, .initial = 0xffffffff, .reflect_input = false, @@ -845,7 +837,7 @@ pub const Crc32Mpeg2 = Crc(u32, .{ .xor_output = 0x00000000, }); -pub const Crc32Xfer = Crc(u32, .{ +pub const @"CRC-32/XFER" = Generic(u32, .{ .polynomial = 0x000000af, .initial = 0x00000000, .reflect_input = false, @@ -853,7 +845,7 @@ pub const Crc32Xfer = Crc(u32, .{ .xor_output = 0x00000000, }); -pub const Crc40Gsm = Crc(u40, .{ +pub const @"CRC-40/GSM" = Generic(u40, .{ .polynomial = 0x0004820009, .initial = 0x0000000000, .reflect_input = false, @@ -861,7 +853,7 @@ pub const Crc40Gsm = Crc(u40, .{ .xor_output = 0xffffffffff, }); -pub const Crc64Ecma182 = Crc(u64, .{ +pub const @"CRC-64/ECMA-182" = Generic(u64, .{ .polynomial = 0x42f0e1eba9ea3693, .initial = 0x0000000000000000, .reflect_input = false, @@ -869,7 +861,7 @@ pub const Crc64Ecma182 = Crc(u64, .{ .xor_output = 0x0000000000000000, }); -pub const Crc64GoIso = Crc(u64, .{ +pub const @"CRC-64/GO-ISO" = Generic(u64, .{ .polynomial = 0x000000000000001b, .initial = 0xffffffffffffffff, .reflect_input = true, @@ -877,7 +869,7 @@ pub const Crc64GoIso = Crc(u64, .{ .xor_output = 0xffffffffffffffff, }); -pub const Crc64Ms = Crc(u64, .{ +pub const @"CRC-64/MS" = Generic(u64, .{ .polynomial = 0x259c84cba6426349, .initial = 0xffffffffffffffff, .reflect_input = true, @@ -885,7 +877,7 @@ pub const Crc64Ms = Crc(u64, .{ .xor_output = 0x0000000000000000, }); -pub const Crc64Redis = Crc(u64, .{ +pub const @"CRC-64/REDIS" = Generic(u64, .{ .polynomial = 0xad93d23594c935a9, .initial = 0x0000000000000000, .reflect_input = true, @@ -893,7 +885,7 @@ pub const Crc64Redis = Crc(u64, .{ .xor_output = 0x0000000000000000, }); -pub const Crc64We = Crc(u64, .{ +pub const @"CRC-64/WE" = Generic(u64, .{ .polynomial = 0x42f0e1eba9ea3693, .initial = 0xffffffffffffffff, .reflect_input = false, @@ -901,7 +893,7 @@ pub const Crc64We = Crc(u64, .{ .xor_output = 0xffffffffffffffff, }); -pub const Crc64Xz = Crc(u64, .{ +pub const @"CRC-64/XZ" = Generic(u64, .{ .polynomial = 0x42f0e1eba9ea3693, .initial = 0xffffffffffffffff, .reflect_input = true, @@ -909,10 +901,109 @@ pub const Crc64Xz = Crc(u64, .{ .xor_output = 0xffffffffffffffff, }); -pub const Crc82Darc = Crc(u82, .{ +pub const @"CRC-82/DARC" = Generic(u82, .{ .polynomial = 0x0308c0111011401440411, .initial = 0x000000000000000000000, .reflect_input = true, .reflect_output = true, .xor_output = 0x000000000000000000000, }); + +pub fn Algorithm(comptime W: type) type { + return struct { + polynomial: W, + initial: W, + reflect_input: bool, + reflect_output: bool, + xor_output: W, + }; +} + +pub fn Generic(comptime W: type, comptime algorithm: Algorithm(W)) type { + return struct { + const Self = @This(); + const I = if (@bitSizeOf(W) < 8) u8 else W; + const lookup_table = blk: { + @setEvalBranchQuota(2500); + const poly = reflect(algorithm.polynomial); + var table: [256]I = undefined; + for (&table, 0..) |*e, i| { + var crc: I = i; + if (algorithm.reflect_input) { + var j: usize = 0; + while (j < 8) : (j += 1) { + crc = (crc >> 1) ^ ((crc & 1) * poly); + } + } else { + crc <<= @bitSizeOf(I) - 8; + var j: usize = 0; + while (j < 8) : (j += 1) { + crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly); + } + } + e.* = crc; + } + break :blk table; + }; + + crc: I, + + pub fn init() Self { + const initial = reflect(algorithm.initial); + return .{ .crc = initial }; + } + + inline fn tableEntry(index: I) I { + const short: u8 = @truncate(index); + return lookup_table[short]; + } + + pub fn update(self: *Self, bytes: []const u8) void { + var i: usize = 0; + if (@bitSizeOf(I) <= 8) { + while (i < bytes.len) : (i += 1) { + self.crc = tableEntry(self.crc ^ bytes[i]); + } + } else if (algorithm.reflect_input) { + while (i < bytes.len) : (i += 1) { + const table_index = self.crc ^ bytes[i]; + self.crc = tableEntry(table_index) ^ (self.crc >> 8); + } + } else { + while (i < bytes.len) : (i += 1) { + const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i]; + self.crc = tableEntry(table_index) ^ (self.crc << 8); + } + } + } + + pub fn final(self: Self) W { + var c = self.crc; + if (algorithm.reflect_input != algorithm.reflect_output) { + c = @bitReverse(c); + } + if (!algorithm.reflect_output) { + c >>= @bitSizeOf(I) - @bitSizeOf(W); + } + return @intCast(c ^ algorithm.xor_output); + } + + pub fn hash(bytes: []const u8) W { + var c = Self.init(); + c.update(bytes); + return c.final(); + } + + fn reflect(x: I) I { + const offset = @bitSizeOf(I) - @bitSizeOf(W); + if (algorithm.reflect_input) + return @bitReverse(x) >> offset + else + return x << offset; + } + }; +} + +test { + _ = @import("crc/test.zig"); +} diff --git a/lib/std/hash/crc/Crc32c.zig b/lib/std/hash/crc/Crc32c.zig new file mode 100644 index 0000000000000000000000000000000000000000..7405dc949d1f80abb01b94500c0b3613763fc62c --- /dev/null +++ b/lib/std/hash/crc/Crc32c.zig @@ -0,0 +1,238 @@ +//! Implements CRC-32C (Castagnoli) using the SSE4.2 Intel CRC32 instruction. +//! +//! A couple useful links for understanding the approach taken here: +//! - https://github.com/madler/brotli/blob/1d428d3a9baade233ebc3ac108293256bcb813d1/crc32c.c +//! - https://github.com/madler/zlib/blob/5a82f71ed1dfc0bec044d9702463dbdf84ea3b71/crc32.c +//! - http://www.ross.net/crc/download/crc_v3.txt + +// Reflected CRC-32C polynomial in binary form. +const POLY = 0x82f63b78; + +const LONG = 8192; +const SHORT = 256; +const long_lookup_table = genTable(LONG); +const short_lookup_table = genTable(SHORT); + +const Wrapper = @This(); + +crc: u32, + +pub fn init() Wrapper { + return .{ .crc = 0 }; +} + +pub fn update(w: *Wrapper, bytes: []const u8) void { + w.crc = crc32(w.crc, bytes); +} + +pub fn final(w: Wrapper) u32 { + return w.crc; +} + +pub fn hash(bytes: []const u8) u32 { + var c = init(); + c.update(bytes); + return c.final(); +} + +/// Generates the lookup table for efficiently combining CRCs over a block of a given length `length`. +/// This works by building an operator that advances the CRC state as if `length` zero-bytes were appended. +/// We pre-compute 4 tables of 256 entries each (one per byte offset). +/// +/// +/// The idea behind this table is quite interesting. The CRC state is equivalent to the +/// remainder of dividing the message polynomial (over GF(2)) by the CRC polynomial. +/// +/// Advancing the CRC register by `k` zero bits is equivalent to multiplying the current +/// CRC state by `x^k` modulo the CRC polynomial. This operation can be represented +/// as a linear transformation in GF(2), i.e, a matrix. +/// +/// We build up this matrix via repeated squaring: +/// - odd represents the operator for 1 zero bit (i.e, multiplication by `x^1 mod POLY`) +/// - even represents the operator for 2 zero bits (`x^2 mod POLY`) +/// - squaring again gives `x^4 mod POLY`, and so on until we get to the right size. +/// +/// By squaring the shifting `len`, we build the operator for `x^l mod POLY`. +fn genTable(length: usize) [4][256]u32 { + @setEvalBranchQuota(250000); + + var even: [32]u32 = undefined; + zeroes: { + var odd: [32]u32 = undefined; + + // Initialize our `odd` array with the operator for a single zero bit: + // - odd[0] is the polynomial itself (acts on the MSB). + // - odd[1..32] represent shifting a single bit through 31 positions. + odd[0] = POLY; + var row: u32 = 1; + for (1..32) |n| { + odd[n] = row; + row <<= 1; + } + + // even = odd squared: even represents `x^2 mod POLY`. + square(&even, &odd); + // odd = even squared: odd now represents `x^4 mod POLY`. + square(&odd, &even); + + // Continue squaring to double the number of zeroes encoded each time: + // + // At each point in the process: + // - square(even, odd): even gets the operator for twice the current length. + // - square(odd, even): odd gets the operator for 4 times the original length. + var len = length; + while (true) { + square(&even, &odd); + len >>= 1; + if (len == 0) break :zeroes; + square(&odd, &even); + len >>= 1; + if (len == 0) break; + } + + @memcpy(&even, &odd); + } + + var zeroes: [4][256]u32 = undefined; + for (0..256) |n| { + zeroes[0][n] = times(&even, n); + zeroes[1][n] = times(&even, n << 8); + zeroes[2][n] = times(&even, n << 16); + zeroes[3][n] = times(&even, n << 24); + } + return zeroes; +} + +/// Computes `mat * vec` over `GF(2)`, where `mat` is a 32x32 binary matrix and `vec` +/// is a 32-bit vector. This somewhat "simulates" how bits propagate through the CRC register +/// during shifting. +/// +/// - In GF(2) (aka a field where the only values are 0 and 1, aka binary), multiplication is +/// an `AND`, and addition is `XOR`. +/// - This dot product determines how each bit in the input vector "contributes" to +/// the final CRC state, by XORing (adding) rows of the matrix where `vec` has 1s. +fn times(mat: *const [32]u32, vec: u32) u32 { + var sum: u32 = 0; + var v = vec; + var i: u32 = 0; + while (v != 0) { + if (v & 1 != 0) sum ^= mat[i]; + v >>= 1; + i += 1; + } + return sum; +} + +/// Computes the square of a matrix in GF(2), i.e `dst = dst x src`. +/// +/// This produces the operator for doubling the number of zeroes: +/// if `src` represents advancing the CRC by `k` zeroes, then `dest` will +/// represent advancing by 2k zeroes. +/// +/// Since polynomial multiplication mod POLY is linear, `mat(mat(x)) = mat^2(x)` +/// gives the effect of two sequential applications of the operator. +fn square(dst: *[32]u32, src: *const [32]u32) void { + for (dst, src) |*d, s| { + d.* = times(src, s); + } +} + +fn shift(table: *const [4][256]u32, crc: u32) u32 { + return table[0][crc & 0xFF] ^ table[1][(crc >> 8) & 0xFF] ^ table[2][(crc >> 16) & 0xFF] ^ table[3][crc >> 24]; +} + +fn crc32(crc: u32, input: []const u8) u32 { + var crc0: u64 = ~crc; + + // Compute the CRC for up to seven leading bytes to bring the + // `next` pointer to an eight-byte boundary. + var next = input; + while (next.len > 0 and @intFromPtr(next.ptr) & 7 != 0) { + asm volatile ("crc32b %[out], %[in]" + : [in] "+r" (crc0), + : [out] "rm" (next[0]), + ); + next = next[1..]; + } + + // Compute the CRC on sets of LONG * 3 bytes, executing three independent + // CRC instructions, each on LONG bytes. This is an optimization for + // targets where the CRC instruction has a throughput of one CRC per + // cycle, but a latency of three cycles. + while (next.len >= LONG * 3) { + var crc1: u64 = 0; + var crc2: u64 = 0; + + const start = next.len; + while (true) { + // Safe @alignCast(), since we've aligned the pointer to 8 bytes before this loop. + const long: [*]const u64 = @ptrCast(@alignCast(next)); + asm volatile ( + \\crc32q %[out0], %[in0] + \\crc32q %[out1], %[in1] + \\crc32q %[out2], %[in2] + : [in0] "+r" (crc0), + [in1] "+r" (crc1), + [in2] "+r" (crc2), + : [out0] "rm" (long[0 * LONG / 8]), + [out1] "rm" (long[1 * LONG / 8]), + [out2] "rm" (long[2 * LONG / 8]), + ); + next = next[8..]; + if (next.len <= start - LONG) break; + } + + crc0 = shift(&long_lookup_table, @truncate(crc0)) ^ crc1; + crc0 = shift(&long_lookup_table, @truncate(crc0)) ^ crc2; + next = next[LONG * 2 ..]; + } + + // Same thing as above, but for smaller chunks of SHORT bytes. + while (next.len >= SHORT * 3) { + var crc1: u64 = 0; + var crc2: u64 = 0; + + const start = next.len; + while (true) { + const long: [*]const u64 = @ptrCast(@alignCast(next)); + asm volatile ( + \\crc32q %[out0], %[in0] + \\crc32q %[out1], %[in1] + \\crc32q %[out2], %[in2] + : [in0] "+r" (crc0), + [in1] "+r" (crc1), + [in2] "+r" (crc2), + : [out0] "rm" (long[0 * SHORT / 8]), + [out1] "rm" (long[1 * SHORT / 8]), + [out2] "rm" (long[2 * SHORT / 8]), + ); + next = next[8..]; + if (next.len <= start - SHORT) break; + } + + crc0 = shift(&short_lookup_table, @truncate(crc0)) ^ crc1; + crc0 = shift(&short_lookup_table, @truncate(crc0)) ^ crc2; + next = next[SHORT * 2 ..]; + } + + // Compute via 8-byte chunks, until we're left with less than 8 bytes. + while (next.len >= 8) { + const long: [*]const u64 = @ptrCast(@alignCast(next)); + asm volatile ("crc32q %[out], %[in]" + : [in] "+r" (crc0), + : [out] "rm" (long[0]), + ); + next = next[8..]; + } + + // Finish the last bytes with just single instructions. + while (next.len > 0) { + asm volatile ("crc32b %[out], %[in]" + : [in] "+r" (crc0), + : [out] "rm" (next[0]), + ); + next = next[1..]; + } + + return @truncate(~crc0); +} diff --git a/lib/std/hash/crc/impl.zig b/lib/std/hash/crc/impl.zig deleted file mode 100644 index 6638d13d806bb51e1ff4f4f3c48221130a1bab38..0000000000000000000000000000000000000000 --- a/lib/std/hash/crc/impl.zig +++ /dev/null @@ -1,102 +0,0 @@ -// There is a generic CRC implementation "Crc()" which can be parameterized via -// the Algorithm struct for a plethora of uses. -// -// The primary interface for all of the standard CRC algorithms is the -// generated file "crc.zig", which uses the implementation code here to define -// many standard CRCs. - -const std = @import("std"); - -pub fn Algorithm(comptime W: type) type { - return struct { - polynomial: W, - initial: W, - reflect_input: bool, - reflect_output: bool, - xor_output: W, - }; -} - -pub fn Crc(comptime W: type, comptime algorithm: Algorithm(W)) type { - return struct { - const Self = @This(); - const I = if (@bitSizeOf(W) < 8) u8 else W; - const lookup_table = blk: { - @setEvalBranchQuota(2500); - - const poly = if (algorithm.reflect_input) - @bitReverse(@as(I, algorithm.polynomial)) >> (@bitSizeOf(I) - @bitSizeOf(W)) - else - @as(I, algorithm.polynomial) << (@bitSizeOf(I) - @bitSizeOf(W)); - - var table: [256]I = undefined; - for (&table, 0..) |*e, i| { - var crc: I = i; - if (algorithm.reflect_input) { - var j: usize = 0; - while (j < 8) : (j += 1) { - crc = (crc >> 1) ^ ((crc & 1) * poly); - } - } else { - crc <<= @bitSizeOf(I) - 8; - var j: usize = 0; - while (j < 8) : (j += 1) { - crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly); - } - } - e.* = crc; - } - break :blk table; - }; - - crc: I, - - pub fn init() Self { - const initial = if (algorithm.reflect_input) - @bitReverse(@as(I, algorithm.initial)) >> (@bitSizeOf(I) - @bitSizeOf(W)) - else - @as(I, algorithm.initial) << (@bitSizeOf(I) - @bitSizeOf(W)); - return Self{ .crc = initial }; - } - - inline fn tableEntry(index: I) I { - return lookup_table[@as(u8, @intCast(index & 0xFF))]; - } - - pub fn update(self: *Self, bytes: []const u8) void { - var i: usize = 0; - if (@bitSizeOf(I) <= 8) { - while (i < bytes.len) : (i += 1) { - self.crc = tableEntry(self.crc ^ bytes[i]); - } - } else if (algorithm.reflect_input) { - while (i < bytes.len) : (i += 1) { - const table_index = self.crc ^ bytes[i]; - self.crc = tableEntry(table_index) ^ (self.crc >> 8); - } - } else { - while (i < bytes.len) : (i += 1) { - const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i]; - self.crc = tableEntry(table_index) ^ (self.crc << 8); - } - } - } - - pub fn final(self: Self) W { - var c = self.crc; - if (algorithm.reflect_input != algorithm.reflect_output) { - c = @bitReverse(c); - } - if (!algorithm.reflect_output) { - c >>= @bitSizeOf(I) - @bitSizeOf(W); - } - return @as(W, @intCast(c ^ algorithm.xor_output)); - } - - pub fn hash(bytes: []const u8) W { - var c = Self.init(); - c.update(bytes); - return c.final(); - } - }; -} diff --git a/lib/std/hash/crc/test.zig b/lib/std/hash/crc/test.zig index a6c2641853e01b0653f86a1202ba701adb8bd30b..68183d1050b37133d19663971357f32f53284267 100644 --- a/lib/std/hash/crc/test.zig +++ b/lib/std/hash/crc/test.zig @@ -6,1264 +6,1264 @@ const verify = @import("../verify.zig"); const crc = @import("../crc.zig"); test "crc32 ieee regression" { - const crc32 = crc.Crc32IsoHdlc; - try testing.expectEqual(crc32.hash(""), 0x00000000); - try testing.expectEqual(crc32.hash("a"), 0xe8b7be43); - try testing.expectEqual(crc32.hash("abc"), 0x352441c2); + const Crc = crc.@"CRC-32/ISO-HDLC"; + try testing.expectEqual(Crc.hash(""), 0x00000000); + try testing.expectEqual(Crc.hash("a"), 0xe8b7be43); + try testing.expectEqual(Crc.hash("abc"), 0x352441c2); } test "crc32 castagnoli regression" { - const crc32 = crc.Crc32Iscsi; - try testing.expectEqual(crc32.hash(""), 0x00000000); - try testing.expectEqual(crc32.hash("a"), 0xc1d04330); - try testing.expectEqual(crc32.hash("abc"), 0x364b3fb7); + const Crc = crc.@"CRC-32/ISCSI"; + try testing.expectEqual(Crc.hash(""), 0x00000000); + try testing.expectEqual(Crc.hash("a"), 0xc1d04330); + try testing.expectEqual(Crc.hash("abc"), 0x364b3fb7); } test "crc32 koopman regression" { - const crc32 = crc.Crc32Koopman; - try testing.expectEqual(crc32.hash(""), 0x00000000); - try testing.expectEqual(crc32.hash("a"), 0x0da2aa8a); - try testing.expectEqual(crc32.hash("abc"), 0xba2322ac); + const Crc = crc.@"CRC-32/KOOPMAN"; + try testing.expectEqual(Crc.hash(""), 0x00000000); + try testing.expectEqual(Crc.hash("a"), 0x0da2aa8a); + try testing.expectEqual(Crc.hash("abc"), 0xba2322ac); } test "CRC-3/GSM" { - const Crc3Gsm = crc.Crc3Gsm; + const Crc = crc.@"CRC-3/GSM"; - try testing.expectEqual(@as(u3, 0x4), Crc3Gsm.hash("123456789")); + try testing.expectEqual(@as(u3, 0x4), Crc.hash("123456789")); - var c = Crc3Gsm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u3, 0x4), c.final()); } test "CRC-3/ROHC" { - const Crc3Rohc = crc.Crc3Rohc; + const Crc = crc.@"CRC-3/ROHC"; - try testing.expectEqual(@as(u3, 0x6), Crc3Rohc.hash("123456789")); + try testing.expectEqual(@as(u3, 0x6), Crc.hash("123456789")); - var c = Crc3Rohc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u3, 0x6), c.final()); } test "CRC-4/G-704" { - const Crc4G704 = crc.Crc4G704; + const Crc = crc.@"CRC-4/G-704"; - try testing.expectEqual(@as(u4, 0x7), Crc4G704.hash("123456789")); + try testing.expectEqual(@as(u4, 0x7), Crc.hash("123456789")); - var c = Crc4G704.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u4, 0x7), c.final()); } test "CRC-4/INTERLAKEN" { - const Crc4Interlaken = crc.Crc4Interlaken; + const Crc = crc.@"CRC-4/INTERLAKEN"; - try testing.expectEqual(@as(u4, 0xb), Crc4Interlaken.hash("123456789")); + try testing.expectEqual(@as(u4, 0xb), Crc.hash("123456789")); - var c = Crc4Interlaken.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u4, 0xb), c.final()); } test "CRC-5/EPC-C1G2" { - const Crc5EpcC1g2 = crc.Crc5EpcC1g2; + const Crc = crc.@"CRC-5/EPC-C1G2"; - try testing.expectEqual(@as(u5, 0x00), Crc5EpcC1g2.hash("123456789")); + try testing.expectEqual(@as(u5, 0x00), Crc.hash("123456789")); - var c = Crc5EpcC1g2.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u5, 0x00), c.final()); } test "CRC-5/G-704" { - const Crc5G704 = crc.Crc5G704; + const Crc = crc.@"CRC-5/G-704"; - try testing.expectEqual(@as(u5, 0x07), Crc5G704.hash("123456789")); + try testing.expectEqual(@as(u5, 0x07), Crc.hash("123456789")); - var c = Crc5G704.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u5, 0x07), c.final()); } test "CRC-5/USB" { - const Crc5Usb = crc.Crc5Usb; + const Crc = crc.@"CRC-5/USB"; - try testing.expectEqual(@as(u5, 0x19), Crc5Usb.hash("123456789")); + try testing.expectEqual(@as(u5, 0x19), Crc.hash("123456789")); - var c = Crc5Usb.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u5, 0x19), c.final()); } test "CRC-6/CDMA2000-A" { - const Crc6Cdma2000A = crc.Crc6Cdma2000A; + const Crc = crc.@"CRC-6/CDMA2000-A"; - try testing.expectEqual(@as(u6, 0x0d), Crc6Cdma2000A.hash("123456789")); + try testing.expectEqual(@as(u6, 0x0d), Crc.hash("123456789")); - var c = Crc6Cdma2000A.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u6, 0x0d), c.final()); } test "CRC-6/CDMA2000-B" { - const Crc6Cdma2000B = crc.Crc6Cdma2000B; + const Crc = crc.@"CRC-6/CDMA2000-B"; - try testing.expectEqual(@as(u6, 0x3b), Crc6Cdma2000B.hash("123456789")); + try testing.expectEqual(@as(u6, 0x3b), Crc.hash("123456789")); - var c = Crc6Cdma2000B.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u6, 0x3b), c.final()); } test "CRC-6/DARC" { - const Crc6Darc = crc.Crc6Darc; + const Crc = crc.@"CRC-6/DARC"; - try testing.expectEqual(@as(u6, 0x26), Crc6Darc.hash("123456789")); + try testing.expectEqual(@as(u6, 0x26), Crc.hash("123456789")); - var c = Crc6Darc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u6, 0x26), c.final()); } test "CRC-6/G-704" { - const Crc6G704 = crc.Crc6G704; + const Crc = crc.@"CRC-6/G-704"; - try testing.expectEqual(@as(u6, 0x06), Crc6G704.hash("123456789")); + try testing.expectEqual(@as(u6, 0x06), Crc.hash("123456789")); - var c = Crc6G704.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u6, 0x06), c.final()); } test "CRC-6/GSM" { - const Crc6Gsm = crc.Crc6Gsm; + const Crc = crc.@"CRC-6/GSM"; - try testing.expectEqual(@as(u6, 0x13), Crc6Gsm.hash("123456789")); + try testing.expectEqual(@as(u6, 0x13), Crc.hash("123456789")); - var c = Crc6Gsm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u6, 0x13), c.final()); } test "CRC-7/MMC" { - const Crc7Mmc = crc.Crc7Mmc; + const Crc = crc.@"CRC-7/MMC"; - try testing.expectEqual(@as(u7, 0x75), Crc7Mmc.hash("123456789")); + try testing.expectEqual(@as(u7, 0x75), Crc.hash("123456789")); - var c = Crc7Mmc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u7, 0x75), c.final()); } test "CRC-7/ROHC" { - const Crc7Rohc = crc.Crc7Rohc; + const Crc = crc.@"CRC-7/ROHC"; - try testing.expectEqual(@as(u7, 0x53), Crc7Rohc.hash("123456789")); + try testing.expectEqual(@as(u7, 0x53), Crc.hash("123456789")); - var c = Crc7Rohc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u7, 0x53), c.final()); } test "CRC-7/UMTS" { - const Crc7Umts = crc.Crc7Umts; + const Crc = crc.@"CRC-7/UMTS"; - try testing.expectEqual(@as(u7, 0x61), Crc7Umts.hash("123456789")); + try testing.expectEqual(@as(u7, 0x61), Crc.hash("123456789")); - var c = Crc7Umts.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u7, 0x61), c.final()); } test "CRC-8/AUTOSAR" { - const Crc8Autosar = crc.Crc8Autosar; + const Crc = crc.@"CRC-8/AUTOSAR"; - try testing.expectEqual(@as(u8, 0xdf), Crc8Autosar.hash("123456789")); + try testing.expectEqual(@as(u8, 0xdf), Crc.hash("123456789")); - var c = Crc8Autosar.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xdf), c.final()); } test "CRC-8/BLUETOOTH" { - const Crc8Bluetooth = crc.Crc8Bluetooth; + const Crc = crc.@"CRC-8/BLUETOOTH"; - try testing.expectEqual(@as(u8, 0x26), Crc8Bluetooth.hash("123456789")); + try testing.expectEqual(@as(u8, 0x26), Crc.hash("123456789")); - var c = Crc8Bluetooth.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x26), c.final()); } test "CRC-8/CDMA2000" { - const Crc8Cdma2000 = crc.Crc8Cdma2000; + const Crc = crc.@"CRC-8/CDMA2000"; - try testing.expectEqual(@as(u8, 0xda), Crc8Cdma2000.hash("123456789")); + try testing.expectEqual(@as(u8, 0xda), Crc.hash("123456789")); - var c = Crc8Cdma2000.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xda), c.final()); } test "CRC-8/DARC" { - const Crc8Darc = crc.Crc8Darc; + const Crc = crc.@"CRC-8/DARC"; - try testing.expectEqual(@as(u8, 0x15), Crc8Darc.hash("123456789")); + try testing.expectEqual(@as(u8, 0x15), Crc.hash("123456789")); - var c = Crc8Darc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x15), c.final()); } test "CRC-8/DVB-S2" { - const Crc8DvbS2 = crc.Crc8DvbS2; + const Crc = crc.@"CRC-8/DVB-S2"; - try testing.expectEqual(@as(u8, 0xbc), Crc8DvbS2.hash("123456789")); + try testing.expectEqual(@as(u8, 0xbc), Crc.hash("123456789")); - var c = Crc8DvbS2.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xbc), c.final()); } test "CRC-8/GSM-A" { - const Crc8GsmA = crc.Crc8GsmA; + const Crc = crc.@"CRC-8/GSM-A"; - try testing.expectEqual(@as(u8, 0x37), Crc8GsmA.hash("123456789")); + try testing.expectEqual(@as(u8, 0x37), Crc.hash("123456789")); - var c = Crc8GsmA.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x37), c.final()); } test "CRC-8/GSM-B" { - const Crc8GsmB = crc.Crc8GsmB; + const Crc = crc.@"CRC-8/GSM-B"; - try testing.expectEqual(@as(u8, 0x94), Crc8GsmB.hash("123456789")); + try testing.expectEqual(@as(u8, 0x94), Crc.hash("123456789")); - var c = Crc8GsmB.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x94), c.final()); } test "CRC-8/HITAG" { - const Crc8Hitag = crc.Crc8Hitag; + const Crc = crc.@"CRC-8/HITAG"; - try testing.expectEqual(@as(u8, 0xb4), Crc8Hitag.hash("123456789")); + try testing.expectEqual(@as(u8, 0xb4), Crc.hash("123456789")); - var c = Crc8Hitag.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xb4), c.final()); } test "CRC-8/I-432-1" { - const Crc8I4321 = crc.Crc8I4321; + const Crc = crc.@"CRC-8/I-432-1"; - try testing.expectEqual(@as(u8, 0xa1), Crc8I4321.hash("123456789")); + try testing.expectEqual(@as(u8, 0xa1), Crc.hash("123456789")); - var c = Crc8I4321.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xa1), c.final()); } test "CRC-8/I-CODE" { - const Crc8ICode = crc.Crc8ICode; + const Crc = crc.@"CRC-8/I-CODE"; - try testing.expectEqual(@as(u8, 0x7e), Crc8ICode.hash("123456789")); + try testing.expectEqual(@as(u8, 0x7e), Crc.hash("123456789")); - var c = Crc8ICode.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x7e), c.final()); } test "CRC-8/LTE" { - const Crc8Lte = crc.Crc8Lte; + const Crc = crc.@"CRC-8/LTE"; - try testing.expectEqual(@as(u8, 0xea), Crc8Lte.hash("123456789")); + try testing.expectEqual(@as(u8, 0xea), Crc.hash("123456789")); - var c = Crc8Lte.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xea), c.final()); } test "CRC-8/MAXIM-DOW" { - const Crc8MaximDow = crc.Crc8MaximDow; + const Crc = crc.@"CRC-8/MAXIM-DOW"; - try testing.expectEqual(@as(u8, 0xa1), Crc8MaximDow.hash("123456789")); + try testing.expectEqual(@as(u8, 0xa1), Crc.hash("123456789")); - var c = Crc8MaximDow.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xa1), c.final()); } test "CRC-8/MIFARE-MAD" { - const Crc8MifareMad = crc.Crc8MifareMad; + const Crc = crc.@"CRC-8/MIFARE-MAD"; - try testing.expectEqual(@as(u8, 0x99), Crc8MifareMad.hash("123456789")); + try testing.expectEqual(@as(u8, 0x99), Crc.hash("123456789")); - var c = Crc8MifareMad.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x99), c.final()); } test "CRC-8/NRSC-5" { - const Crc8Nrsc5 = crc.Crc8Nrsc5; + const Crc = crc.@"CRC-8/NRSC-5"; - try testing.expectEqual(@as(u8, 0xf7), Crc8Nrsc5.hash("123456789")); + try testing.expectEqual(@as(u8, 0xf7), Crc.hash("123456789")); - var c = Crc8Nrsc5.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xf7), c.final()); } test "CRC-8/OPENSAFETY" { - const Crc8Opensafety = crc.Crc8Opensafety; + const Crc = crc.@"CRC-8/OPENSAFETY"; - try testing.expectEqual(@as(u8, 0x3e), Crc8Opensafety.hash("123456789")); + try testing.expectEqual(@as(u8, 0x3e), Crc.hash("123456789")); - var c = Crc8Opensafety.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x3e), c.final()); } test "CRC-8/ROHC" { - const Crc8Rohc = crc.Crc8Rohc; + const Crc = crc.@"CRC-8/ROHC"; - try testing.expectEqual(@as(u8, 0xd0), Crc8Rohc.hash("123456789")); + try testing.expectEqual(@as(u8, 0xd0), Crc.hash("123456789")); - var c = Crc8Rohc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xd0), c.final()); } test "CRC-8/SAE-J1850" { - const Crc8SaeJ1850 = crc.Crc8SaeJ1850; + const Crc = crc.@"CRC-8/SAE-J1850"; - try testing.expectEqual(@as(u8, 0x4b), Crc8SaeJ1850.hash("123456789")); + try testing.expectEqual(@as(u8, 0x4b), Crc.hash("123456789")); - var c = Crc8SaeJ1850.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x4b), c.final()); } test "CRC-8/SMBUS" { - const Crc8Smbus = crc.Crc8Smbus; + const Crc = crc.@"CRC-8/SMBUS"; - try testing.expectEqual(@as(u8, 0xf4), Crc8Smbus.hash("123456789")); + try testing.expectEqual(@as(u8, 0xf4), Crc.hash("123456789")); - var c = Crc8Smbus.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0xf4), c.final()); } test "CRC-8/TECH-3250" { - const Crc8Tech3250 = crc.Crc8Tech3250; + const Crc = crc.@"CRC-8/TECH-3250"; - try testing.expectEqual(@as(u8, 0x97), Crc8Tech3250.hash("123456789")); + try testing.expectEqual(@as(u8, 0x97), Crc.hash("123456789")); - var c = Crc8Tech3250.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x97), c.final()); } test "CRC-8/WCDMA" { - const Crc8Wcdma = crc.Crc8Wcdma; + const Crc = crc.@"CRC-8/WCDMA"; - try testing.expectEqual(@as(u8, 0x25), Crc8Wcdma.hash("123456789")); + try testing.expectEqual(@as(u8, 0x25), Crc.hash("123456789")); - var c = Crc8Wcdma.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u8, 0x25), c.final()); } test "CRC-10/ATM" { - const Crc10Atm = crc.Crc10Atm; + const Crc = crc.@"CRC-10/ATM"; - try testing.expectEqual(@as(u10, 0x199), Crc10Atm.hash("123456789")); + try testing.expectEqual(@as(u10, 0x199), Crc.hash("123456789")); - var c = Crc10Atm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u10, 0x199), c.final()); } test "CRC-10/CDMA2000" { - const Crc10Cdma2000 = crc.Crc10Cdma2000; + const Crc = crc.@"CRC-10/CDMA2000"; - try testing.expectEqual(@as(u10, 0x233), Crc10Cdma2000.hash("123456789")); + try testing.expectEqual(@as(u10, 0x233), Crc.hash("123456789")); - var c = Crc10Cdma2000.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u10, 0x233), c.final()); } test "CRC-10/GSM" { - const Crc10Gsm = crc.Crc10Gsm; + const Crc = crc.@"CRC-10/GSM"; - try testing.expectEqual(@as(u10, 0x12a), Crc10Gsm.hash("123456789")); + try testing.expectEqual(@as(u10, 0x12a), Crc.hash("123456789")); - var c = Crc10Gsm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u10, 0x12a), c.final()); } test "CRC-11/FLEXRAY" { - const Crc11Flexray = crc.Crc11Flexray; + const Crc = crc.@"CRC-11/FLEXRAY"; - try testing.expectEqual(@as(u11, 0x5a3), Crc11Flexray.hash("123456789")); + try testing.expectEqual(@as(u11, 0x5a3), Crc.hash("123456789")); - var c = Crc11Flexray.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u11, 0x5a3), c.final()); } test "CRC-11/UMTS" { - const Crc11Umts = crc.Crc11Umts; + const Crc = crc.@"CRC-11/UMTS"; - try testing.expectEqual(@as(u11, 0x061), Crc11Umts.hash("123456789")); + try testing.expectEqual(@as(u11, 0x061), Crc.hash("123456789")); - var c = Crc11Umts.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u11, 0x061), c.final()); } test "CRC-12/CDMA2000" { - const Crc12Cdma2000 = crc.Crc12Cdma2000; + const Crc = crc.@"CRC-12/CDMA2000"; - try testing.expectEqual(@as(u12, 0xd4d), Crc12Cdma2000.hash("123456789")); + try testing.expectEqual(@as(u12, 0xd4d), Crc.hash("123456789")); - var c = Crc12Cdma2000.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u12, 0xd4d), c.final()); } test "CRC-12/DECT" { - const Crc12Dect = crc.Crc12Dect; + const Crc = crc.@"CRC-12/DECT"; - try testing.expectEqual(@as(u12, 0xf5b), Crc12Dect.hash("123456789")); + try testing.expectEqual(@as(u12, 0xf5b), Crc.hash("123456789")); - var c = Crc12Dect.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u12, 0xf5b), c.final()); } test "CRC-12/GSM" { - const Crc12Gsm = crc.Crc12Gsm; + const Crc = crc.@"CRC-12/GSM"; - try testing.expectEqual(@as(u12, 0xb34), Crc12Gsm.hash("123456789")); + try testing.expectEqual(@as(u12, 0xb34), Crc.hash("123456789")); - var c = Crc12Gsm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u12, 0xb34), c.final()); } test "CRC-12/UMTS" { - const Crc12Umts = crc.Crc12Umts; + const Crc = crc.@"CRC-12/UMTS"; - try testing.expectEqual(@as(u12, 0xdaf), Crc12Umts.hash("123456789")); + try testing.expectEqual(@as(u12, 0xdaf), Crc.hash("123456789")); - var c = Crc12Umts.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u12, 0xdaf), c.final()); } test "CRC-13/BBC" { - const Crc13Bbc = crc.Crc13Bbc; + const Crc = crc.@"CRC-13/BBC"; - try testing.expectEqual(@as(u13, 0x04fa), Crc13Bbc.hash("123456789")); + try testing.expectEqual(@as(u13, 0x04fa), Crc.hash("123456789")); - var c = Crc13Bbc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u13, 0x04fa), c.final()); } test "CRC-14/DARC" { - const Crc14Darc = crc.Crc14Darc; + const Crc = crc.@"CRC-14/DARC"; - try testing.expectEqual(@as(u14, 0x082d), Crc14Darc.hash("123456789")); + try testing.expectEqual(@as(u14, 0x082d), Crc.hash("123456789")); - var c = Crc14Darc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u14, 0x082d), c.final()); } test "CRC-14/GSM" { - const Crc14Gsm = crc.Crc14Gsm; + const Crc = crc.@"CRC-14/GSM"; - try testing.expectEqual(@as(u14, 0x30ae), Crc14Gsm.hash("123456789")); + try testing.expectEqual(@as(u14, 0x30ae), Crc.hash("123456789")); - var c = Crc14Gsm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u14, 0x30ae), c.final()); } test "CRC-15/CAN" { - const Crc15Can = crc.Crc15Can; + const Crc = crc.@"CRC-15/CAN"; - try testing.expectEqual(@as(u15, 0x059e), Crc15Can.hash("123456789")); + try testing.expectEqual(@as(u15, 0x059e), Crc.hash("123456789")); - var c = Crc15Can.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u15, 0x059e), c.final()); } test "CRC-15/MPT1327" { - const Crc15Mpt1327 = crc.Crc15Mpt1327; + const Crc = crc.@"CRC-15/MPT1327"; - try testing.expectEqual(@as(u15, 0x2566), Crc15Mpt1327.hash("123456789")); + try testing.expectEqual(@as(u15, 0x2566), Crc.hash("123456789")); - var c = Crc15Mpt1327.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u15, 0x2566), c.final()); } test "CRC-16/ARC" { - const Crc16Arc = crc.Crc16Arc; + const Crc = crc.@"CRC-16/ARC"; - try testing.expectEqual(@as(u16, 0xbb3d), Crc16Arc.hash("123456789")); + try testing.expectEqual(@as(u16, 0xbb3d), Crc.hash("123456789")); - var c = Crc16Arc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xbb3d), c.final()); } test "CRC-16/CDMA2000" { - const Crc16Cdma2000 = crc.Crc16Cdma2000; + const Crc = crc.@"CRC-16/CDMA2000"; - try testing.expectEqual(@as(u16, 0x4c06), Crc16Cdma2000.hash("123456789")); + try testing.expectEqual(@as(u16, 0x4c06), Crc.hash("123456789")); - var c = Crc16Cdma2000.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x4c06), c.final()); } test "CRC-16/CMS" { - const Crc16Cms = crc.Crc16Cms; + const Crc = crc.@"CRC-16/CMS"; - try testing.expectEqual(@as(u16, 0xaee7), Crc16Cms.hash("123456789")); + try testing.expectEqual(@as(u16, 0xaee7), Crc.hash("123456789")); - var c = Crc16Cms.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xaee7), c.final()); } test "CRC-16/DDS-110" { - const Crc16Dds110 = crc.Crc16Dds110; + const Crc = crc.@"CRC-16/DDS-110"; - try testing.expectEqual(@as(u16, 0x9ecf), Crc16Dds110.hash("123456789")); + try testing.expectEqual(@as(u16, 0x9ecf), Crc.hash("123456789")); - var c = Crc16Dds110.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x9ecf), c.final()); } test "CRC-16/DECT-R" { - const Crc16DectR = crc.Crc16DectR; + const Crc = crc.@"CRC-16/DECT-R"; - try testing.expectEqual(@as(u16, 0x007e), Crc16DectR.hash("123456789")); + try testing.expectEqual(@as(u16, 0x007e), Crc.hash("123456789")); - var c = Crc16DectR.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x007e), c.final()); } test "CRC-16/DECT-X" { - const Crc16DectX = crc.Crc16DectX; + const Crc = crc.@"CRC-16/DECT-X"; - try testing.expectEqual(@as(u16, 0x007f), Crc16DectX.hash("123456789")); + try testing.expectEqual(@as(u16, 0x007f), Crc.hash("123456789")); - var c = Crc16DectX.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x007f), c.final()); } test "CRC-16/DNP" { - const Crc16Dnp = crc.Crc16Dnp; + const Crc = crc.@"CRC-16/DNP"; - try testing.expectEqual(@as(u16, 0xea82), Crc16Dnp.hash("123456789")); + try testing.expectEqual(@as(u16, 0xea82), Crc.hash("123456789")); - var c = Crc16Dnp.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xea82), c.final()); } test "CRC-16/EN-13757" { - const Crc16En13757 = crc.Crc16En13757; + const Crc = crc.@"CRC-16/EN-13757"; - try testing.expectEqual(@as(u16, 0xc2b7), Crc16En13757.hash("123456789")); + try testing.expectEqual(@as(u16, 0xc2b7), Crc.hash("123456789")); - var c = Crc16En13757.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xc2b7), c.final()); } test "CRC-16/GENIBUS" { - const Crc16Genibus = crc.Crc16Genibus; + const Crc = crc.@"CRC-16/GENIBUS"; - try testing.expectEqual(@as(u16, 0xd64e), Crc16Genibus.hash("123456789")); + try testing.expectEqual(@as(u16, 0xd64e), Crc.hash("123456789")); - var c = Crc16Genibus.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xd64e), c.final()); } test "CRC-16/GSM" { - const Crc16Gsm = crc.Crc16Gsm; + const Crc = crc.@"CRC-16/GSM"; - try testing.expectEqual(@as(u16, 0xce3c), Crc16Gsm.hash("123456789")); + try testing.expectEqual(@as(u16, 0xce3c), Crc.hash("123456789")); - var c = Crc16Gsm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xce3c), c.final()); } test "CRC-16/IBM-3740" { - const Crc16Ibm3740 = crc.Crc16Ibm3740; + const Crc = crc.@"CRC-16/IBM-3740"; - try testing.expectEqual(@as(u16, 0x29b1), Crc16Ibm3740.hash("123456789")); + try testing.expectEqual(@as(u16, 0x29b1), Crc.hash("123456789")); - var c = Crc16Ibm3740.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x29b1), c.final()); } test "CRC-16/IBM-SDLC" { - const Crc16IbmSdlc = crc.Crc16IbmSdlc; + const Crc = crc.@"CRC-16/IBM-SDLC"; - try testing.expectEqual(@as(u16, 0x906e), Crc16IbmSdlc.hash("123456789")); + try testing.expectEqual(@as(u16, 0x906e), Crc.hash("123456789")); - var c = Crc16IbmSdlc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x906e), c.final()); } test "CRC-16/ISO-IEC-14443-3-A" { - const Crc16IsoIec144433A = crc.Crc16IsoIec144433A; + const Crc = crc.@"CRC-16/ISO-IEC-14443-3-A"; - try testing.expectEqual(@as(u16, 0xbf05), Crc16IsoIec144433A.hash("123456789")); + try testing.expectEqual(@as(u16, 0xbf05), Crc.hash("123456789")); - var c = Crc16IsoIec144433A.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xbf05), c.final()); } test "CRC-16/KERMIT" { - const Crc16Kermit = crc.Crc16Kermit; + const Crc = crc.@"CRC-16/KERMIT"; - try testing.expectEqual(@as(u16, 0x2189), Crc16Kermit.hash("123456789")); + try testing.expectEqual(@as(u16, 0x2189), Crc.hash("123456789")); - var c = Crc16Kermit.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x2189), c.final()); } test "CRC-16/LJ1200" { - const Crc16Lj1200 = crc.Crc16Lj1200; + const Crc = crc.@"CRC-16/LJ1200"; - try testing.expectEqual(@as(u16, 0xbdf4), Crc16Lj1200.hash("123456789")); + try testing.expectEqual(@as(u16, 0xbdf4), Crc.hash("123456789")); - var c = Crc16Lj1200.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xbdf4), c.final()); } test "CRC-16/M17" { - const Crc16M17 = crc.Crc16M17; + const Crc = crc.@"CRC-16/M17"; - try testing.expectEqual(@as(u16, 0x772b), Crc16M17.hash("123456789")); + try testing.expectEqual(@as(u16, 0x772b), Crc.hash("123456789")); - var c = Crc16M17.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x772b), c.final()); } test "CRC-16/MAXIM-DOW" { - const Crc16MaximDow = crc.Crc16MaximDow; + const Crc = crc.@"CRC-16/MAXIM-DOW"; - try testing.expectEqual(@as(u16, 0x44c2), Crc16MaximDow.hash("123456789")); + try testing.expectEqual(@as(u16, 0x44c2), Crc.hash("123456789")); - var c = Crc16MaximDow.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x44c2), c.final()); } test "CRC-16/MCRF4XX" { - const Crc16Mcrf4xx = crc.Crc16Mcrf4xx; + const Crc = crc.@"CRC-16/MCRF4XX"; - try testing.expectEqual(@as(u16, 0x6f91), Crc16Mcrf4xx.hash("123456789")); + try testing.expectEqual(@as(u16, 0x6f91), Crc.hash("123456789")); - var c = Crc16Mcrf4xx.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x6f91), c.final()); } test "CRC-16/MODBUS" { - const Crc16Modbus = crc.Crc16Modbus; + const Crc = crc.@"CRC-16/MODBUS"; - try testing.expectEqual(@as(u16, 0x4b37), Crc16Modbus.hash("123456789")); + try testing.expectEqual(@as(u16, 0x4b37), Crc.hash("123456789")); - var c = Crc16Modbus.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x4b37), c.final()); } test "CRC-16/NRSC-5" { - const Crc16Nrsc5 = crc.Crc16Nrsc5; + const Crc = crc.@"CRC-16/NRSC-5"; - try testing.expectEqual(@as(u16, 0xa066), Crc16Nrsc5.hash("123456789")); + try testing.expectEqual(@as(u16, 0xa066), Crc.hash("123456789")); - var c = Crc16Nrsc5.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xa066), c.final()); } test "CRC-16/OPENSAFETY-A" { - const Crc16OpensafetyA = crc.Crc16OpensafetyA; + const Crc = crc.@"CRC-16/OPENSAFETY-A"; - try testing.expectEqual(@as(u16, 0x5d38), Crc16OpensafetyA.hash("123456789")); + try testing.expectEqual(@as(u16, 0x5d38), Crc.hash("123456789")); - var c = Crc16OpensafetyA.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x5d38), c.final()); } test "CRC-16/OPENSAFETY-B" { - const Crc16OpensafetyB = crc.Crc16OpensafetyB; + const Crc = crc.@"CRC-16/OPENSAFETY-B"; - try testing.expectEqual(@as(u16, 0x20fe), Crc16OpensafetyB.hash("123456789")); + try testing.expectEqual(@as(u16, 0x20fe), Crc.hash("123456789")); - var c = Crc16OpensafetyB.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x20fe), c.final()); } test "CRC-16/PROFIBUS" { - const Crc16Profibus = crc.Crc16Profibus; + const Crc = crc.@"CRC-16/PROFIBUS"; - try testing.expectEqual(@as(u16, 0xa819), Crc16Profibus.hash("123456789")); + try testing.expectEqual(@as(u16, 0xa819), Crc.hash("123456789")); - var c = Crc16Profibus.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xa819), c.final()); } test "CRC-16/RIELLO" { - const Crc16Riello = crc.Crc16Riello; + const Crc = crc.@"CRC-16/RIELLO"; - try testing.expectEqual(@as(u16, 0x63d0), Crc16Riello.hash("123456789")); + try testing.expectEqual(@as(u16, 0x63d0), Crc.hash("123456789")); - var c = Crc16Riello.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x63d0), c.final()); } test "CRC-16/SPI-FUJITSU" { - const Crc16SpiFujitsu = crc.Crc16SpiFujitsu; + const Crc = crc.@"CRC-16/SPI-FUJITSU"; - try testing.expectEqual(@as(u16, 0xe5cc), Crc16SpiFujitsu.hash("123456789")); + try testing.expectEqual(@as(u16, 0xe5cc), Crc.hash("123456789")); - var c = Crc16SpiFujitsu.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xe5cc), c.final()); } test "CRC-16/T10-DIF" { - const Crc16T10Dif = crc.Crc16T10Dif; + const Crc = crc.@"CRC-16/T10-DIF"; - try testing.expectEqual(@as(u16, 0xd0db), Crc16T10Dif.hash("123456789")); + try testing.expectEqual(@as(u16, 0xd0db), Crc.hash("123456789")); - var c = Crc16T10Dif.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xd0db), c.final()); } test "CRC-16/TELEDISK" { - const Crc16Teledisk = crc.Crc16Teledisk; + const Crc = crc.@"CRC-16/TELEDISK"; - try testing.expectEqual(@as(u16, 0x0fb3), Crc16Teledisk.hash("123456789")); + try testing.expectEqual(@as(u16, 0x0fb3), Crc.hash("123456789")); - var c = Crc16Teledisk.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x0fb3), c.final()); } test "CRC-16/TMS37157" { - const Crc16Tms37157 = crc.Crc16Tms37157; + const Crc = crc.@"CRC-16/TMS37157"; - try testing.expectEqual(@as(u16, 0x26b1), Crc16Tms37157.hash("123456789")); + try testing.expectEqual(@as(u16, 0x26b1), Crc.hash("123456789")); - var c = Crc16Tms37157.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x26b1), c.final()); } test "CRC-16/UMTS" { - const Crc16Umts = crc.Crc16Umts; + const Crc = crc.@"CRC-16/UMTS"; - try testing.expectEqual(@as(u16, 0xfee8), Crc16Umts.hash("123456789")); + try testing.expectEqual(@as(u16, 0xfee8), Crc.hash("123456789")); - var c = Crc16Umts.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xfee8), c.final()); } test "CRC-16/USB" { - const Crc16Usb = crc.Crc16Usb; + const Crc = crc.@"CRC-16/USB"; - try testing.expectEqual(@as(u16, 0xb4c8), Crc16Usb.hash("123456789")); + try testing.expectEqual(@as(u16, 0xb4c8), Crc.hash("123456789")); - var c = Crc16Usb.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0xb4c8), c.final()); } test "CRC-16/XMODEM" { - const Crc16Xmodem = crc.Crc16Xmodem; + const Crc = crc.@"CRC-16/XMODEM"; - try testing.expectEqual(@as(u16, 0x31c3), Crc16Xmodem.hash("123456789")); + try testing.expectEqual(@as(u16, 0x31c3), Crc.hash("123456789")); - var c = Crc16Xmodem.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u16, 0x31c3), c.final()); } test "CRC-17/CAN-FD" { - const Crc17CanFd = crc.Crc17CanFd; + const Crc = crc.@"CRC-17/CAN-FD"; - try testing.expectEqual(@as(u17, 0x04f03), Crc17CanFd.hash("123456789")); + try testing.expectEqual(@as(u17, 0x04f03), Crc.hash("123456789")); - var c = Crc17CanFd.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u17, 0x04f03), c.final()); } test "CRC-21/CAN-FD" { - const Crc21CanFd = crc.Crc21CanFd; + const Crc = crc.@"CRC-21/CAN-FD"; - try testing.expectEqual(@as(u21, 0x0ed841), Crc21CanFd.hash("123456789")); + try testing.expectEqual(@as(u21, 0x0ed841), Crc.hash("123456789")); - var c = Crc21CanFd.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u21, 0x0ed841), c.final()); } test "CRC-24/BLE" { - const Crc24Ble = crc.Crc24Ble; + const Crc = crc.@"CRC-24/BLE"; - try testing.expectEqual(@as(u24, 0xc25a56), Crc24Ble.hash("123456789")); + try testing.expectEqual(@as(u24, 0xc25a56), Crc.hash("123456789")); - var c = Crc24Ble.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0xc25a56), c.final()); } test "CRC-24/FLEXRAY-A" { - const Crc24FlexrayA = crc.Crc24FlexrayA; + const Crc = crc.@"CRC-24/FLEXRAY-A"; - try testing.expectEqual(@as(u24, 0x7979bd), Crc24FlexrayA.hash("123456789")); + try testing.expectEqual(@as(u24, 0x7979bd), Crc.hash("123456789")); - var c = Crc24FlexrayA.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0x7979bd), c.final()); } test "CRC-24/FLEXRAY-B" { - const Crc24FlexrayB = crc.Crc24FlexrayB; + const Crc = crc.@"CRC-24/FLEXRAY-B"; - try testing.expectEqual(@as(u24, 0x1f23b8), Crc24FlexrayB.hash("123456789")); + try testing.expectEqual(@as(u24, 0x1f23b8), Crc.hash("123456789")); - var c = Crc24FlexrayB.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0x1f23b8), c.final()); } test "CRC-24/INTERLAKEN" { - const Crc24Interlaken = crc.Crc24Interlaken; + const Crc = crc.@"CRC-24/INTERLAKEN"; - try testing.expectEqual(@as(u24, 0xb4f3e6), Crc24Interlaken.hash("123456789")); + try testing.expectEqual(@as(u24, 0xb4f3e6), Crc.hash("123456789")); - var c = Crc24Interlaken.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0xb4f3e6), c.final()); } test "CRC-24/LTE-A" { - const Crc24LteA = crc.Crc24LteA; + const Crc = crc.@"CRC-24/LTE-A"; - try testing.expectEqual(@as(u24, 0xcde703), Crc24LteA.hash("123456789")); + try testing.expectEqual(@as(u24, 0xcde703), Crc.hash("123456789")); - var c = Crc24LteA.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0xcde703), c.final()); } test "CRC-24/LTE-B" { - const Crc24LteB = crc.Crc24LteB; + const Crc = crc.@"CRC-24/LTE-B"; - try testing.expectEqual(@as(u24, 0x23ef52), Crc24LteB.hash("123456789")); + try testing.expectEqual(@as(u24, 0x23ef52), Crc.hash("123456789")); - var c = Crc24LteB.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0x23ef52), c.final()); } test "CRC-24/OPENPGP" { - const Crc24Openpgp = crc.Crc24Openpgp; + const Crc = crc.@"CRC-24/OPENPGP"; - try testing.expectEqual(@as(u24, 0x21cf02), Crc24Openpgp.hash("123456789")); + try testing.expectEqual(@as(u24, 0x21cf02), Crc.hash("123456789")); - var c = Crc24Openpgp.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0x21cf02), c.final()); } test "CRC-24/OS-9" { - const Crc24Os9 = crc.Crc24Os9; + const Crc = crc.@"CRC-24/OS-9"; - try testing.expectEqual(@as(u24, 0x200fa5), Crc24Os9.hash("123456789")); + try testing.expectEqual(@as(u24, 0x200fa5), Crc.hash("123456789")); - var c = Crc24Os9.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u24, 0x200fa5), c.final()); } test "CRC-30/CDMA" { - const Crc30Cdma = crc.Crc30Cdma; + const Crc = crc.@"CRC-30/CDMA"; - try testing.expectEqual(@as(u30, 0x04c34abf), Crc30Cdma.hash("123456789")); + try testing.expectEqual(@as(u30, 0x04c34abf), Crc.hash("123456789")); - var c = Crc30Cdma.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u30, 0x04c34abf), c.final()); } test "CRC-31/PHILIPS" { - const Crc31Philips = crc.Crc31Philips; + const Crc = crc.@"CRC-31/PHILIPS"; - try testing.expectEqual(@as(u31, 0x0ce9e46c), Crc31Philips.hash("123456789")); + try testing.expectEqual(@as(u31, 0x0ce9e46c), Crc.hash("123456789")); - var c = Crc31Philips.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u31, 0x0ce9e46c), c.final()); } test "CRC-32/AIXM" { - const Crc32Aixm = crc.Crc32Aixm; + const Crc = crc.@"CRC-32/AIXM"; - try testing.expectEqual(@as(u32, 0x3010bf7f), Crc32Aixm.hash("123456789")); + try testing.expectEqual(@as(u32, 0x3010bf7f), Crc.hash("123456789")); - var c = Crc32Aixm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x3010bf7f), c.final()); } test "CRC-32/AUTOSAR" { - const Crc32Autosar = crc.Crc32Autosar; + const Crc = crc.@"CRC-32/AUTOSAR"; - try testing.expectEqual(@as(u32, 0x1697d06a), Crc32Autosar.hash("123456789")); + try testing.expectEqual(@as(u32, 0x1697d06a), Crc.hash("123456789")); - var c = Crc32Autosar.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x1697d06a), c.final()); } test "CRC-32/BASE91-D" { - const Crc32Base91D = crc.Crc32Base91D; + const Crc = crc.@"CRC-32/BASE91-D"; - try testing.expectEqual(@as(u32, 0x87315576), Crc32Base91D.hash("123456789")); + try testing.expectEqual(@as(u32, 0x87315576), Crc.hash("123456789")); - var c = Crc32Base91D.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x87315576), c.final()); } test "CRC-32/BZIP2" { - const Crc32Bzip2 = crc.Crc32Bzip2; + const Crc = crc.@"CRC-32/BZIP2"; - try testing.expectEqual(@as(u32, 0xfc891918), Crc32Bzip2.hash("123456789")); + try testing.expectEqual(@as(u32, 0xfc891918), Crc.hash("123456789")); - var c = Crc32Bzip2.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0xfc891918), c.final()); } test "CRC-32/CD-ROM-EDC" { - const Crc32CdRomEdc = crc.Crc32CdRomEdc; + const Crc = crc.@"CRC-32/CD-ROM-EDC"; - try testing.expectEqual(@as(u32, 0x6ec2edc4), Crc32CdRomEdc.hash("123456789")); + try testing.expectEqual(@as(u32, 0x6ec2edc4), Crc.hash("123456789")); - var c = Crc32CdRomEdc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x6ec2edc4), c.final()); } test "CRC-32/CKSUM" { - const Crc32Cksum = crc.Crc32Cksum; + const Crc = crc.@"CRC-32/CKSUM"; - try testing.expectEqual(@as(u32, 0x765e7680), Crc32Cksum.hash("123456789")); + try testing.expectEqual(@as(u32, 0x765e7680), Crc.hash("123456789")); - var c = Crc32Cksum.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x765e7680), c.final()); } test "CRC-32/ISCSI" { - const Crc32Iscsi = crc.Crc32Iscsi; + const Crc = crc.@"CRC-32/ISCSI"; - try testing.expectEqual(@as(u32, 0xe3069283), Crc32Iscsi.hash("123456789")); + try testing.expectEqual(@as(u32, 0xe3069283), Crc.hash("123456789")); - var c = Crc32Iscsi.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0xe3069283), c.final()); } test "CRC-32/ISO-HDLC" { - const Crc32IsoHdlc = crc.Crc32IsoHdlc; + const Crc = crc.@"CRC-32/ISO-HDLC"; - try testing.expectEqual(@as(u32, 0xcbf43926), Crc32IsoHdlc.hash("123456789")); + try testing.expectEqual(@as(u32, 0xcbf43926), Crc.hash("123456789")); - var c = Crc32IsoHdlc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0xcbf43926), c.final()); } test "CRC-32/JAMCRC" { - const Crc32Jamcrc = crc.Crc32Jamcrc; + const Crc = crc.@"CRC-32/JAMCRC"; - try testing.expectEqual(@as(u32, 0x340bc6d9), Crc32Jamcrc.hash("123456789")); + try testing.expectEqual(@as(u32, 0x340bc6d9), Crc.hash("123456789")); - var c = Crc32Jamcrc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x340bc6d9), c.final()); } test "CRC-32/KOOPMAN" { - const Crc32Koopman = crc.Crc32Koopman; + const Crc = crc.@"CRC-32/KOOPMAN"; - try testing.expectEqual(@as(u32, 0x2d3dd0ae), Crc32Koopman.hash("123456789")); + try testing.expectEqual(@as(u32, 0x2d3dd0ae), Crc.hash("123456789")); - var c = Crc32Koopman.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x2d3dd0ae), c.final()); } test "CRC-32/MEF" { - const Crc32Mef = crc.Crc32Mef; + const Crc = crc.@"CRC-32/MEF"; - try testing.expectEqual(@as(u32, 0xd2c22f51), Crc32Mef.hash("123456789")); + try testing.expectEqual(@as(u32, 0xd2c22f51), Crc.hash("123456789")); - var c = Crc32Mef.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0xd2c22f51), c.final()); } test "CRC-32/MPEG-2" { - const Crc32Mpeg2 = crc.Crc32Mpeg2; + const Crc = crc.@"CRC-32/MPEG-2"; - try testing.expectEqual(@as(u32, 0x0376e6e7), Crc32Mpeg2.hash("123456789")); + try testing.expectEqual(@as(u32, 0x0376e6e7), Crc.hash("123456789")); - var c = Crc32Mpeg2.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0x0376e6e7), c.final()); } test "CRC-32/XFER" { - const Crc32Xfer = crc.Crc32Xfer; + const Crc = crc.@"CRC-32/XFER"; - try testing.expectEqual(@as(u32, 0xbd0be338), Crc32Xfer.hash("123456789")); + try testing.expectEqual(@as(u32, 0xbd0be338), Crc.hash("123456789")); - var c = Crc32Xfer.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u32, 0xbd0be338), c.final()); } test "CRC-40/GSM" { - const Crc40Gsm = crc.Crc40Gsm; + const Crc = crc.@"CRC-40/GSM"; - try testing.expectEqual(@as(u40, 0xd4164fc646), Crc40Gsm.hash("123456789")); + try testing.expectEqual(@as(u40, 0xd4164fc646), Crc.hash("123456789")); - var c = Crc40Gsm.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u40, 0xd4164fc646), c.final()); } test "CRC-64/ECMA-182" { - const Crc64Ecma182 = crc.Crc64Ecma182; + const Crc = crc.@"CRC-64/ECMA-182"; - try testing.expectEqual(@as(u64, 0x6c40df5f0b497347), Crc64Ecma182.hash("123456789")); + try testing.expectEqual(@as(u64, 0x6c40df5f0b497347), Crc.hash("123456789")); - var c = Crc64Ecma182.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u64, 0x6c40df5f0b497347), c.final()); } test "CRC-64/GO-ISO" { - const Crc64GoIso = crc.Crc64GoIso; + const Crc = crc.@"CRC-64/GO-ISO"; - try testing.expectEqual(@as(u64, 0xb90956c775a41001), Crc64GoIso.hash("123456789")); + try testing.expectEqual(@as(u64, 0xb90956c775a41001), Crc.hash("123456789")); - var c = Crc64GoIso.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u64, 0xb90956c775a41001), c.final()); } test "CRC-64/MS" { - const Crc64Ms = crc.Crc64Ms; + const Crc = crc.@"CRC-64/MS"; - try testing.expectEqual(@as(u64, 0x75d4b74f024eceea), Crc64Ms.hash("123456789")); + try testing.expectEqual(@as(u64, 0x75d4b74f024eceea), Crc.hash("123456789")); - var c = Crc64Ms.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u64, 0x75d4b74f024eceea), c.final()); } test "CRC-64/REDIS" { - const Crc64Redis = crc.Crc64Redis; + const Crc = crc.@"CRC-64/REDIS"; - try testing.expectEqual(@as(u64, 0xe9c6d914c4b8d9ca), Crc64Redis.hash("123456789")); + try testing.expectEqual(@as(u64, 0xe9c6d914c4b8d9ca), Crc.hash("123456789")); - var c = Crc64Redis.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u64, 0xe9c6d914c4b8d9ca), c.final()); } test "CRC-64/WE" { - const Crc64We = crc.Crc64We; + const Crc = crc.@"CRC-64/WE"; - try testing.expectEqual(@as(u64, 0x62ec59e3f1a4f00a), Crc64We.hash("123456789")); + try testing.expectEqual(@as(u64, 0x62ec59e3f1a4f00a), Crc.hash("123456789")); - var c = Crc64We.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u64, 0x62ec59e3f1a4f00a), c.final()); } test "CRC-64/XZ" { - const Crc64Xz = crc.Crc64Xz; + const Crc = crc.@"CRC-64/XZ"; - try testing.expectEqual(@as(u64, 0x995dc9bbdf1939fa), Crc64Xz.hash("123456789")); + try testing.expectEqual(@as(u64, 0x995dc9bbdf1939fa), Crc.hash("123456789")); - var c = Crc64Xz.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u64, 0x995dc9bbdf1939fa), c.final()); } test "CRC-82/DARC" { - const Crc82Darc = crc.Crc82Darc; + const Crc = crc.@"CRC-82/DARC"; - try testing.expectEqual(@as(u82, 0x09ea83f625023801fd612), Crc82Darc.hash("123456789")); + try testing.expectEqual(@as(u82, 0x09ea83f625023801fd612), Crc.hash("123456789")); - var c = Crc82Darc.init(); + var c = Crc.init(); c.update("1234"); c.update("56789"); try testing.expectEqual(@as(u82, 0x09ea83f625023801fd612), c.final()); diff --git a/lib/std/hash/xxhash.zig b/lib/std/hash/xxhash.zig index 107b608006c2f8c23c6ba85077b24304138429b4..27f2701443cc919a9cd2686165ecc8ae087ae002 100644 --- a/lib/std/hash/xxhash.zig +++ b/lib/std/hash/xxhash.zig @@ -2,7 +2,6 @@ const std = @import("std"); const builtin = @import("builtin"); const mem = std.mem; const expectEqual = std.testing.expectEqual; -const native_endian = builtin.cpu.arch.endian(); const rotl = std.math.rotl; @@ -421,7 +420,18 @@ pub const XxHash32 = struct { }; pub const XxHash3 = struct { + const block_bytes = 64; const Block = @Vector(8, u64); + const InputBlock = extern struct { + raw: [block_bytes]u8, + inline fn load(ptr: *const InputBlock) Block { + return @bitCast(ptr.raw); + } + inline fn store(ptr: *InputBlock, val: Block) void { + ptr.raw = @bitCast(val); + } + }; + const default_secret: [192]u8 = .{ 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, @@ -464,10 +474,6 @@ pub const XxHash3 = struct { return wide[0] ^ wide[1]; } - inline fn swap(x: anytype) @TypeOf(x) { - return if (native_endian == .big) @byteSwap(x) else x; - } - inline fn disableAutoVectorization(x: anytype) void { if (!@inComptime()) asm volatile ("" : @@ -476,20 +482,20 @@ pub const XxHash3 = struct { } inline fn mix16(seed: u64, input: []const u8, secret: []const u8) u64 { - const blk: [4]u64 = @bitCast([_][16]u8{ input[0..16].*, secret[0..16].* }); + const blk: [4]u64 = @bitCast([2][16]u8{ input[0..16].*, secret[0..16].* }); disableAutoVectorization(seed); return fold( - swap(blk[0]) ^ (swap(blk[2]) +% seed), - swap(blk[1]) ^ (swap(blk[3]) -% seed), + blk[0] ^ (blk[2] +% seed), + blk[1] ^ (blk[3] -% seed), ); } - const Accumulator = extern struct { + const Accumulator = struct { consumed: usize = 0, seed: u64, - secret: [192]u8 = undefined, - state: Block = Block{ + secret: [192]u8, + state: Block = .{ XxHash32.prime_3, XxHash64.prime_1, XxHash64.prime_2, @@ -501,33 +507,35 @@ pub const XxHash3 = struct { }, inline fn init(seed: u64) Accumulator { - var self = Accumulator{ .seed = seed }; - for ( - std.mem.bytesAsSlice(Block, &self.secret), - std.mem.bytesAsSlice(Block, &default_secret), - ) |*dst, src| { - dst.* = swap(swap(src) +% Block{ - seed, @as(u64, 0) -% seed, - seed, @as(u64, 0) -% seed, - seed, @as(u64, 0) -% seed, - seed, @as(u64, 0) -% seed, - }); + const seed_block: Block = .{ + seed, @as(u64, 0) -% seed, + seed, @as(u64, 0) -% seed, + seed, @as(u64, 0) -% seed, + seed, @as(u64, 0) -% seed, + }; + + var secret: [192]u8 = undefined; + const secret_blocks: []InputBlock = @ptrCast(&secret); + const default_secret_blocks: []const InputBlock = @ptrCast(&default_secret); + for (secret_blocks, default_secret_blocks) |*dst, *src| { + dst.store(src.load() +% seed_block); } - return self; + + return .{ .seed = seed, .secret = secret }; } inline fn round( noalias state: *Block, - noalias input_block: *align(1) const Block, - noalias secret_block: *align(1) const Block, + noalias input_block: *const InputBlock, + noalias secret_block: *const InputBlock, ) void { - const data = swap(input_block.*); - const mixed = data ^ swap(secret_block.*); + const data = input_block.load(); + const mixed = data ^ secret_block.load(); state.* +%= (mixed & @as(Block, @splat(0xffffffff))) *% (mixed >> @splat(32)); state.* +%= @shuffle(u64, data, undefined, [_]i32{ 1, 0, 3, 2, 5, 4, 7, 6 }); } - fn accumulate(noalias self: *Accumulator, blocks: []align(1) const Block) void { + fn accumulate(noalias self: *Accumulator, blocks: []const InputBlock) void { const secret = std.mem.bytesAsSlice(u64, self.secret[self.consumed * 8 ..]); for (blocks, secret[0..blocks.len]) |*input_block, *secret_block| { @prefetch(@as([*]const u8, @ptrCast(input_block)) + 320, .{}); @@ -536,14 +544,14 @@ pub const XxHash3 = struct { } fn scramble(self: *Accumulator) void { - const secret_block: Block = @bitCast(self.secret[192 - @sizeOf(Block) .. 192].*); + const secret_block: Block = @bitCast(self.secret[192 - block_bytes .. 192].*); self.state ^= self.state >> @splat(47); - self.state ^= swap(secret_block); + self.state ^= secret_block; self.state *%= @as(Block, @splat(XxHash32.prime_1)); } - fn consume(noalias self: *Accumulator, input_blocks: []align(1) const Block) void { - const blocks_per_scramble = 1024 / @sizeOf(Block); + fn consume(noalias self: *Accumulator, input_blocks: []const InputBlock) void { + const blocks_per_scramble = 1024 / block_bytes; std.debug.assert(self.consumed <= blocks_per_scramble); var blocks = input_blocks; @@ -561,12 +569,12 @@ pub const XxHash3 = struct { self.consumed += blocks.len; } - fn digest(noalias self: *Accumulator, total_len: u64, noalias last_block: *align(1) const Block) u64 { - const secret_block = self.secret[192 - @sizeOf(Block) - 7 ..][0..@sizeOf(Block)]; + fn digest(noalias self: *Accumulator, total_len: u64, noalias last_block: *const InputBlock) u64 { + const secret_block = self.secret[192 - block_bytes - 7 ..][0..block_bytes]; round(&self.state, last_block, @ptrCast(secret_block)); - const merge_block: Block = @bitCast(self.secret[11 .. 11 + @sizeOf(Block)].*); - self.state ^= swap(merge_block); + const merge_block: Block = @bitCast(self.secret[11 .. 11 + block_bytes].*); + self.state ^= merge_block; var result = XxHash64.prime_1 *% total_len; inline for (0..4) |i| { @@ -588,7 +596,7 @@ pub const XxHash3 = struct { if (input.len > 0) return hash3(seed, input, secret); const flip: [2]u64 = @bitCast(secret[56..72].*); - const key = swap(flip[0]) ^ swap(flip[1]); + const key = flip[0] ^ flip[1]; return avalanche(.h64, seed ^ key); } @@ -604,8 +612,8 @@ pub const XxHash3 = struct { input[input.len / 2], }); - const key = @as(u64, swap(flip[0]) ^ swap(flip[1])) +% seed; - return avalanche(.h64, key ^ swap(blk)); + const key = @as(u64, flip[0] ^ flip[1]) +% seed; + return avalanche(.h64, key ^ blk); } fn hash8(seed: u64, input: anytype, noalias secret: *const [192]u8) u64 { @@ -619,8 +627,8 @@ pub const XxHash3 = struct { }); const mixed = seed ^ (@as(u64, @byteSwap(@as(u32, @truncate(seed)))) << 32); - const key = (swap(flip[0]) ^ swap(flip[1])) -% mixed; - const combined = (@as(u64, swap(blk[0])) << 32) +% swap(blk[1]); + const key = (flip[0] ^ flip[1]) -% mixed; + const combined = (@as(u64, blk[0]) << 32) +% blk[1]; return avalanche(.{ .rrmxmx = input.len }, key ^ combined); } @@ -634,8 +642,8 @@ pub const XxHash3 = struct { input[input.len - 8 ..][0..8].*, }); - const lo = swap(blk[0]) ^ ((swap(flip[0]) ^ swap(flip[1])) +% seed); - const hi = swap(blk[1]) ^ ((swap(flip[2]) ^ swap(flip[3])) -% seed); + const lo = blk[0] ^ ((flip[0] ^ flip[1]) +% seed); + const hi = blk[1] ^ ((flip[2] ^ flip[3]) -% seed); const combined = @as(u64, input.len) +% @byteSwap(lo) +% hi +% fold(lo, hi); return avalanche(.h3, combined); } @@ -679,11 +687,11 @@ pub const XxHash3 = struct { @branchHint(.unlikely); std.debug.assert(input.len >= 240); - const block_count = ((input.len - 1) / @sizeOf(Block)) * @sizeOf(Block); - const last_block = input[input.len - @sizeOf(Block) ..][0..@sizeOf(Block)]; + const block_count = ((input.len - 1) / block_bytes) * block_bytes; + const last_block = input[input.len - block_bytes ..][0..block_bytes]; var acc = Accumulator.init(seed); - acc.consume(std.mem.bytesAsSlice(Block, input[0..block_count])); + acc.consume(std.mem.bytesAsSlice(InputBlock, input[0..block_count])); return acc.digest(input.len, @ptrCast(last_block)); } @@ -716,21 +724,21 @@ pub const XxHash3 = struct { @memcpy(self.buffer[self.buffered..], consumable[0..remaining]); consumable = consumable[remaining..]; - self.accumulator.consume(std.mem.bytesAsSlice(Block, &self.buffer)); + self.accumulator.consume(std.mem.bytesAsSlice(InputBlock, &self.buffer)); self.buffered = 0; } // The input isn't small enough to fit in the buffer. Consume it directly. if (consumable.len > self.buffer.len) { - const block_count = ((consumable.len - 1) / @sizeOf(Block)) * @sizeOf(Block); - self.accumulator.consume(std.mem.bytesAsSlice(Block, consumable[0..block_count])); + const block_count = ((consumable.len - 1) / block_bytes) * block_bytes; + self.accumulator.consume(std.mem.bytesAsSlice(InputBlock, consumable[0..block_count])); consumable = consumable[block_count..]; // In case we consume all remaining input, write the last block to end of the buffer // to populate the last_block_copy in final() similar to hashLong()'s last_block. @memcpy( - self.buffer[self.buffer.len - @sizeOf(Block) .. self.buffer.len], - (consumable.ptr - @sizeOf(Block))[0..@sizeOf(Block)], + self.buffer[self.buffer.len - block_bytes .. self.buffer.len], + (consumable.ptr - block_bytes)[0..block_bytes], ); } @@ -751,16 +759,16 @@ pub const XxHash3 = struct { // Make a copy of the Accumulator state in case `self` needs to update() / be used later. var accumulator_copy = self.accumulator; - var last_block_copy: [@sizeOf(Block)]u8 = undefined; + var last_block_copy: [block_bytes]u8 = undefined; // Digest the last block onthe Accumulator copy. return accumulator_copy.digest(self.total_len, last_block: { - if (self.buffered >= @sizeOf(Block)) { - const block_count = ((self.buffered - 1) / @sizeOf(Block)) * @sizeOf(Block); - accumulator_copy.consume(std.mem.bytesAsSlice(Block, self.buffer[0..block_count])); - break :last_block @ptrCast(self.buffer[self.buffered - @sizeOf(Block) ..][0..@sizeOf(Block)]); + if (self.buffered >= block_bytes) { + const block_count = ((self.buffered - 1) / block_bytes) * block_bytes; + accumulator_copy.consume(std.mem.bytesAsSlice(InputBlock, self.buffer[0..block_count])); + break :last_block @ptrCast(self.buffer[self.buffered - block_bytes ..][0..block_bytes]); } else { - const remaining = @sizeOf(Block) - self.buffered; + const remaining = block_bytes - self.buffered; @memcpy(last_block_copy[0..remaining], self.buffer[self.buffer.len - remaining ..][0..remaining]); @memcpy(last_block_copy[remaining..][0..self.buffered], self.buffer[0..self.buffered]); break :last_block @ptrCast(&last_block_copy); @@ -780,6 +788,7 @@ 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); @@ -811,6 +820,7 @@ 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); @@ -822,6 +832,7 @@ 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 5ba6aadc9ed418611482075e7daf0c6edaf775ea..a6562bc5ea1ab479963b308beae24fb303d98c6d 100644 --- a/lib/std/hash_map.zig +++ b/lib/std/hash_map.zig @@ -593,8 +593,8 @@ fn Custom( fingerprint: FingerPrint = free, used: u1 = 0, - const slot_free = @as(u8, @bitCast(Metadata{ .fingerprint = free })); - const slot_tombstone = @as(u8, @bitCast(Metadata{ .fingerprint = tombstone })); + const slot_free: u8 = @bitCast(Metadata{ .fingerprint = free }); + const slot_tombstone: u8 = @bitCast(Metadata{ .fingerprint = tombstone }); pub fn isUsed(self: Metadata) bool { return self.used == 1; diff --git a/lib/std/http/HeadParser.zig b/lib/std/http/HeadParser.zig index 7b9ca6d2c58f4dce7be24cd4db7e225a1d8bc13a..4c7f1779043b0b0f809cef4f39553fe049e1b53d 100644 --- a/lib/std/http/HeadParser.zig +++ b/lib/std/http/HeadParser.zig @@ -116,11 +116,8 @@ pub fn feed(p: *HeadParser, bytes: []const u8) usize { const chunk = bytes[index..][0..vector_len]; const v: Vector = chunk.*; - // depends on https://github.com/ziglang/zig/issues/19755 - // const matches_r: BitVector = @bitCast(v == @as(Vector, @splat('\r'))); - // const matches_n: BitVector = @bitCast(v == @as(Vector, @splat('\n'))); - const matches_r: BitVector = @select(u1, v == @as(Vector, @splat('\r')), @as(Vector, @splat(1)), @as(Vector, @splat(0))); - const matches_n: BitVector = @select(u1, v == @as(Vector, @splat('\n')), @as(Vector, @splat(1)), @as(Vector, @splat(0))); + const matches_r: BitVector = @bitCast(v == @as(Vector, @splat('\r'))); + const matches_n: BitVector = @bitCast(v == @as(Vector, @splat('\n'))); const matches_or: SizeVector = matches_r | matches_n; const matches = @reduce(.Add, matches_or); @@ -331,15 +328,15 @@ pub fn feed(p: *HeadParser, bytes: []const u8) usize { } inline fn int16(array: *const [2]u8) u16 { - return @bitCast(array.*); + return std.mem.toNative(u16, @bitCast(array.*), .little); } inline fn int24(array: *const [3]u8) u24 { - return @bitCast(array.*); + return std.mem.toNative(u24, @bitCast(array.*), .little); } inline fn int32(array: *const [4]u8) u32 { - return @bitCast(array.*); + return std.mem.toNative(u32, @bitCast(array.*), .little); } inline fn intShift(comptime T: type, x: anytype) T { diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig index 7820ad6d0dc2db532f2c1f7bebc58cb50bce0a04..3d56f59da31ce69377e8886a62245cc8f6612c7c 100644 --- a/lib/std/http/Server.zig +++ b/lib/std/http/Server.zig @@ -726,7 +726,7 @@ pub const WebSocket = struct { else => @intFromEnum(h1.payload_len), }; if (len > in.buffer.len) return error.MessageOversize; - const mask: u32 = @bitCast((try in.takeArray(4)).*); + const mask: [4]u8 = (try in.takeArray(4)).*; const payload = try in.take(len); // Skip pongs. @@ -734,11 +734,16 @@ pub const WebSocket = struct { // The last item may contain a partial word of unused data. const floored_len = (payload.len / 4) * 4; - const u32_payload: []align(1) u32 = @ptrCast(payload[0..floored_len]); - for (u32_payload) |*elem| elem.* ^= mask; - const mask_bytes: []const u8 = @ptrCast(&mask); - for (payload[floored_len..], mask_bytes[0 .. payload.len - floored_len]) |*leftover, m| + + const payload_chunks: [][4]u8 = @ptrCast(payload[0..floored_len]); + for (payload_chunks) |*chunk| { + const mask_i: u32 = @bitCast(mask); + const chunk_i: u32 = @bitCast(chunk.*); + chunk.* = @bitCast(chunk_i ^ mask_i); + } + for (payload[floored_len..], mask[0 .. payload.len - floored_len]) |*leftover, m| { leftover.* ^= m; + } return .{ .opcode = h0.opcode, diff --git a/lib/std/json/hashmap.zig b/lib/std/json/hashmap.zig index be4e9bd2dd5a4359c6ed2a0b6be704369fc314e9..7a88f6ea0d3a2ae1d40f2a9a522ebd0bc0ec63f4 100644 --- a/lib/std/json/hashmap.zig +++ b/lib/std/json/hashmap.zig @@ -6,20 +6,20 @@ const innerParse = @import("static.zig").innerParse; const innerParseFromValue = @import("static.zig").innerParseFromValue; const Value = @import("dynamic.zig").Value; -/// A thin wrapper around `std.StringArrayHashMapUnmanaged` that implements +/// A thin wrapper around `std.array_hash_map.String` that implements /// `jsonParse`, `jsonParseFromValue`, and `jsonStringify`. /// This is useful when your JSON schema has an object with arbitrary data keys /// instead of comptime-known struct field names. pub fn ArrayHashMap(comptime T: type) type { return struct { - map: std.StringArrayHashMapUnmanaged(T) = .empty, + map: std.array_hash_map.String(T) = .empty, pub fn deinit(self: *@This(), allocator: Allocator) void { self.map.deinit(allocator); } pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) !@This() { - var map: std.StringArrayHashMapUnmanaged(T) = .empty; + var map: std.array_hash_map.String(T) = .empty; errdefer map.deinit(allocator); if (.object_begin != try source.next()) return error.UnexpectedToken; @@ -52,7 +52,7 @@ pub fn ArrayHashMap(comptime T: type) type { pub fn jsonParseFromValue(allocator: Allocator, source: Value, options: ParseOptions) !@This() { if (source != .object) return error.UnexpectedToken; - var map: std.StringArrayHashMapUnmanaged(T) = .empty; + var map: std.array_hash_map.String(T) = .empty; errdefer map.deinit(allocator); var it = source.object.iterator(); diff --git a/lib/std/lang.zig b/lib/std/lang.zig index 9fdf35ae3fab87b6e70043a9c09a3726576bfd49..21a4fdae87a59afb4a63cbfe106558a0d1a0281d 100644 --- a/lib/std/lang.zig +++ b/lib/std/lang.zig @@ -140,7 +140,7 @@ pub const CallingConvention = union(enum(u8)) { pub const kernel: CallingConvention = switch (builtin.target.cpu.arch) { .amdgcn => .amdgcn_kernel, .nvptx, .nvptx64 => .nvptx_kernel, - .spirv32, .spirv64 => .spirv_kernel, + .spirv32, .spirv64 => .{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }, else => unreachable, }; @@ -337,11 +337,13 @@ pub const CallingConvention = union(enum(u8)) { nvptx_device, nvptx_kernel, - // Calling conventions for kernels and shaders on the `spirv`, `spirv32`, and `spirv64` architectures. + // Calling conventions for kernels and shaders on the `spirv32` and `spirv64` architectures. spirv_device, - spirv_kernel, - spirv_fragment, spirv_vertex, + spirv_kernel: SpirvKernelOptions, + spirv_fragment: SpirvFragmentOptions, + spirv_task: SpirvKernelOptions, + spirv_mesh: SpirvMeshOptions, // Calling conventions for the `ez80` architecture. ez80_cet, @@ -473,6 +475,36 @@ pub const CallingConvention = union(enum(u8)) { }; }; + pub const SpirvKernelOptions = struct { + x: u32, + y: u32, + z: u32, + }; + + pub const SpirvFragmentOptions = struct { + pub const DepthAssumption = enum(u2) { + none = 0, + greater = 1, + less = 2, + unchanged = 3, + }; + + pixel_centered_integer: bool = false, + depth_assumption: DepthAssumption = .none, + }; + + pub const SpirvMeshOptions = struct { + pub const StageOutput = enum(u2) { + output_points = 0, + output_lines = 1, + output_triangles = 2, + }; + + stage_output: StageOutput = .output_triangles, + max_primitives: u32 = 1, + max_vertices: u32 = 3, + }; + /// Returns the array of `std.Target.Cpu.Arch` to which this `CallingConvention` applies. /// Asserts that `cc` is not `.auto`, `.@"async"`, `.naked`, or `.@"inline"`. pub fn archs(cc: CallingConvention) []const std.Target.Cpu.Arch { @@ -535,6 +567,10 @@ pub const AddressSpace = enum(u5) { /// This address space only addresses the "lookup" ram lut, + + // Web Assembly + externref, + funcref, }; /// This data structure is used by the Zig language code generation and @@ -578,6 +614,7 @@ pub const Type = union(enum) { @"anyframe": AnyFrame, vector: Vector, enum_literal, + spirv: Spirv, /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -781,6 +818,59 @@ pub const Type = union(enum) { }; }; + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Spirv = union(enum(u2)) { + sampler, + image: Image, + sampled_image: type, + runtime_array: type, + + pub const Image = struct { + usage: Usage, + format: Format, + dim: Dimensionality, + depth: Depth, + access: Access, + arrayed: bool, + multisampled: bool, + + pub const Usage = union(enum(u2)) { + unknown: type, + sampled: type, + storage: type, + }; + + pub const Format = enum(u4) { + unknown, + rgba32f, + rgba32i, + rgba32u, + rgba16f, + rgba16i, + rgba16u, + rgba8unorm, + rgba8snorm, + rgba8i, + rgba8u, + r32f, + r32i, + r32u, + }; + + pub const Dimensionality = enum(u2) { + @"1d", + @"2d", + @"3d", + cube, + }; + + pub const Depth = enum(u2) { unknown, depth, not_depth }; + + pub const Access = enum(u2) { unknown, read_only, write_only, read_write }; + }; + }; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Opaque = struct { @@ -914,10 +1004,9 @@ pub const VaListArm = extern struct { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const VaListHexagon = extern struct { - __gpr: c_long, - __fpr: c_long, - __overflow_arg_area: *anyopaque, - __reg_save_area: *anyopaque, + __current_saved_reg_area_pointer: *anyopaque, + __saved_reg_area_end_pointer: *anyopaque, + __overflow_area_pointer: *anyopaque, }; /// This data structure is used by the Zig language code generation and @@ -933,9 +1022,10 @@ pub const VaListPowerPc = extern struct { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const VaListS390x = extern struct { - __current_saved_reg_area_pointer: *anyopaque, - __saved_reg_area_end_pointer: *anyopaque, - __overflow_area_pointer: *anyopaque, + __gpr: c_long, + __fpr: c_long, + __overflow_arg_area: *anyopaque, + __reg_save_area: *anyopaque, }; /// This data structure is used by the Zig language code generation and @@ -1083,11 +1173,12 @@ pub const ExternOptions = struct { pub const Decoration = union(enum) { location: u32, + flat: u32, descriptor: Descriptor, pub const Descriptor = struct { - binding: u32, set: u32, + binding: u32, }; }; diff --git a/lib/std/math.zig b/lib/std/math.zig index 5487e0cb37520ec415f7db1a712c88a8e1f2e9c1..aec6f03ce0d4d8d7b4407c6be5bf241db47b0371 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -1875,3 +1875,39 @@ test sign { try testSign(); try comptime testSign(); } + +/// Increases the bit width of an integer by copying the most significant bit. +/// This results in the input and output having the same arithmetic value, when +/// interpreted as two's complement integers. +fn signExtend(To: type, n: anytype) To { + const From = @TypeOf(n); + if (From == u0) return 0; + const FromSigned = @Int(.signed, @typeInfo(From).int.bits); + const ToSigned = @Int(.signed, @typeInfo(To).int.bits); + + return @bitCast(@as(ToSigned, @as(FromSigned, @bitCast(n)))); +} + +test signExtend { + const number: u8 = 0x86; + try testing.expectEqual(0xff86, signExtend(u16, number)); + + try testing.expectEqual(0, signExtend(u1, @as(u0, 0))); + try testing.expectEqual(0, signExtend(u16, @as(u0, 0))); + + try testing.expectEqual(0x0000, signExtend(u16, @as(u1, 0b0))); + try testing.expectEqual(0xffff, signExtend(u16, @as(u1, 0b1))); + + try testing.expectEqual(0b000, signExtend(u3, @as(u2, 0b00))); + try testing.expectEqual(0b001, signExtend(u3, @as(u2, 0b01))); + try testing.expectEqual(0b110, signExtend(u3, @as(u2, 0b10))); + try testing.expectEqual(0b111, signExtend(u3, @as(u2, 0b11))); + try testing.expectEqual(0b0000_0001, signExtend(u8, @as(u2, 0b01))); + try testing.expectEqual(0b1111_1110, signExtend(u8, @as(u2, 0b10))); + + try testing.expectEqual(0x0039, signExtend(u16, @as(u8, 0x39))); + try testing.expectEqual(0xff93, signExtend(u16, @as(u8, 0x93))); + + try testing.expectEqual(5, signExtend(i32, @as(i8, 5))); + try testing.expectEqual(-123, signExtend(i16, @as(i8, -123))); +} diff --git a/lib/std/mem.zig b/lib/std/mem.zig index ba8602e90b458e3425fd03c2d0fd75469483053f..2e0f3cb0ccee44adabf55ff740bd247ad762a5a6 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -1,12 +1,14 @@ -const std = @import("std.zig"); +const mem = @This(); + const builtin = @import("builtin"); +const native_endian = builtin.cpu.arch.endian(); + +const std = @import("std.zig"); const debug = std.debug; const assert = debug.assert; const math = std.math; -const mem = @This(); const testing = std.testing; -const Endian = std.builtin.Endian; -const native_endian = builtin.cpu.arch.endian(); +const Endian = std.lang.Endian; /// The standard library currently thoroughly depends on byte size /// being 8 bits. (see the use of u8 throughout allocation code as @@ -352,6 +354,7 @@ pub fn zeroes(comptime T: type) T { .noreturn, .undefined, .@"opaque", + .spirv, .frame, .@"anyframe", => { @@ -1847,18 +1850,18 @@ pub fn readVarPackedInt( if (@bitSizeOf(T) <= 8) { // These are the same shifts/masks we perform below, but adds `@truncate`/`@intCast` // where needed since int is smaller than a byte. - const value = if (read_size == 1) b: { - break :b @as(uN, @truncate(read_bytes[0] >> bit_shift)); + const value: uN = if (read_size == 1) b: { + break :b @truncate(read_bytes[0] >> bit_shift); } else b: { const i: u1 = @intFromBool(endian == .big); - const head = @as(uN, @truncate(read_bytes[i] >> bit_shift)); - const tail_shift = @as(Log2N, @intCast(@as(u4, 8) - bit_shift)); - const tail = @as(uN, @truncate(read_bytes[1 - i])); + const head: uN = @truncate(read_bytes[i] >> bit_shift); + const tail_shift: Log2N = @intCast(@as(u4, 8) - bit_shift); + const tail: uN = @truncate(read_bytes[1 - i]); break :b (tail << tail_shift) | head; }; switch (signedness) { - .signed => return @as(T, @intCast((@as(iN, @bitCast(value)) << pad) >> pad)), - .unsigned => return @as(T, @intCast((@as(uN, @bitCast(value)) << pad) >> pad)), + .signed => return @intCast((@as(iN, @bitCast(value)) << pad) >> pad), + .unsigned => return @intCast((value << pad) >> pad), } } @@ -1879,8 +1882,8 @@ pub fn readVarPackedInt( }, } switch (signedness) { - .signed => return @as(T, @intCast((@as(iN, @bitCast(int)) << pad) >> pad)), - .unsigned => return @as(T, @intCast((@as(uN, @bitCast(int)) << pad) >> pad)), + .signed => return @intCast((@as(iN, @bitCast(int)) << pad) >> pad), + .unsigned => return @intCast((int << pad) >> pad), } } @@ -1895,8 +1898,13 @@ test readVarPackedInt { /// The bit count of T must be evenly divisible by 8. /// This function cannot fail and cannot cause undefined behavior. pub inline fn readInt(comptime T: type, buffer: *const [@divExact(@typeInfo(T).int.bits, 8)]u8, endian: Endian) T { - const value: T = @bitCast(buffer.*); - return if (endian == native_endian) value else @byteSwap(value); + // Zig's logical bit order aligns with a little-endian byte array, so when reading in big-endian + // we must `@byteSwap` the int after we `@bitCast` to it. + const little_val: T = @bitCast(buffer.*); + return switch (endian) { + .little => little_val, + .big => @byteSwap(little_val), + }; } test readInt { @@ -1939,13 +1947,15 @@ fn readPackedIntLittle(comptime T: type, bytes: []const u8, bit_offset: usize) T // Read by loading a LoadInt, and then follow it up with a 1-byte read // of the tail if bit_offset pushed us over a byte boundary. const read_bytes = bytes[bit_offset / 8 ..]; - const val = @as(uN, @truncate(readInt(LoadInt, read_bytes[0..load_size], .little) >> bit_shift)); + const val: uN = @truncate(readInt(LoadInt, read_bytes[0..load_size], .little) >> bit_shift); if (bit_shift > load_tail_bits) { const tail_bits = @as(Log2N, @intCast(bit_shift - load_tail_bits)); const tail_byte = read_bytes[load_size]; const tail_truncated = if (bit_count < 8) @as(uN, @truncate(tail_byte)) else @as(uN, tail_byte); - return @as(T, @bitCast(val | (tail_truncated << (@as(Log2N, @truncate(bit_count)) -% tail_bits)))); - } else return @as(T, @bitCast(val)); + return @bitCast(val | (tail_truncated << (@as(Log2N, @truncate(bit_count)) -% tail_bits))); + } else { + return @bitCast(val); + } } fn readPackedIntBig(comptime T: type, bytes: []const u8, bit_offset: usize) T { @@ -1971,8 +1981,10 @@ fn readPackedIntBig(comptime T: type, bytes: []const u8, bit_offset: usize) T { if (bit_shift > load_tail_bits) { const tail_bits = @as(Log2N, @intCast(bit_shift - load_tail_bits)); const tail_byte = if (bit_count < 8) @as(uN, @truncate(read_bytes[0])) else @as(uN, read_bytes[0]); - return @as(T, @bitCast(val | (tail_byte << (@as(Log2N, @truncate(bit_count)) -% tail_bits)))); - } else return @as(T, @bitCast(val)); + return @bitCast(val | (tail_byte << (@as(Log2N, @truncate(bit_count)) -% tail_bits))); + } else { + return @bitCast(val); + } } /// Loads an integer from packed memory. @@ -2010,7 +2022,12 @@ test "comptime read/write int" { /// This function always succeeds, has defined behavior for all inputs, but /// the integer bit width must be divisible by 8. pub inline fn writeInt(comptime T: type, buffer: *[@divExact(@typeInfo(T).int.bits, 8)]u8, value: T, endian: Endian) void { - buffer.* = @bitCast(if (endian == native_endian) value else @byteSwap(value)); + // Zig's logical bit order aligns with a little-endian byte array, so when writing in big-endian + // we must `@byteSwap` the int before we `@bitCast` to an array. + buffer.* = switch (endian) { + .little => @bitCast(value), + .big => @bitCast(@byteSwap(value)), + }; } test writeInt { @@ -2208,10 +2225,10 @@ pub fn byteSwapAllFields(comptime S: type, ptr: *S) void { /// (Changing their endianness) pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *align(a.toByteUnits()) S) void { switch (@typeInfo(S)) { - .@"struct" => |struct_info| { - if (struct_info.backing_integer) |Int| { + .@"struct" => |@"struct"| { + if (@"struct".backing_integer) |Int| { ptr.* = @bitCast(@byteSwap(@as(Int, @bitCast(ptr.*)))); - } else inline for (struct_info.field_types, struct_info.field_names, struct_info.field_attrs) |f_type, f_name, f_attr| { + } 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)), @@ -2219,8 +2236,8 @@ pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *a @field(ptr, f_name) = @enumFromInt(@byteSwap(@intFromEnum(@field(ptr, f_name)))); }, .bool => {}, - .float => |float_info| { - @field(ptr, f_name) = @bitCast(@byteSwap(@as(@Int(.unsigned, float_info.bits), @bitCast(@field(ptr, f_name))))); + .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)); @@ -2228,23 +2245,26 @@ pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *a } } }, - .@"union" => |union_info| { - if (union_info.tag_type != null) { - @compileError("byteSwapAllFields expects an untagged union"); + .@"union" => |@"union"| if (@"union".backing_integer) |Int| { + ptr.* = @bitCast(@byteSwap(@as(Int, @bitCast(ptr.*)))); + } else { + if (@"union".layout != .@"extern") { + @compileError("byteSwapAllFields expects a packed or extern union"); } - const first_size = @bitSizeOf(union_info.field_types[0]); - inline for (union_info.field_types) |field_type| { + const first_size = @bitSizeOf(@"union".field_types[0]); + inline for (@"union".field_types) |field_type| { if (@bitSizeOf(field_type) != first_size) { @compileError("Unable to byte-swap unions with varying field sizes"); } } - const BackingInt = @Int(.unsigned, @bitSizeOf(S)); - ptr.* = @bitCast(@byteSwap(@as(BackingInt, @bitCast(ptr.*)))); + const FieldInt = @Int(.unsigned, first_size); + const field_ptr = &@field(ptr, @"union".field_names[0]); + field_ptr.* = @bitCast(@byteSwap(@as(FieldInt, @bitCast(field_ptr.*)))); }, - .array => |info| { - byteSwapAllElements(info.child, ptr); + .array => |array| { + byteSwapAllElements(array.child, ptr); }, else => { ptr.* = @byteSwap(ptr.*); @@ -2290,7 +2310,7 @@ test byteSwapAllFields { .f2 = 0x12345678, .f3 = .{0x12}, .f4 = true, - .f5 = @as(f32, @bitCast(@as(u32, 0x4640e400))), + .f5 = @bitCast(@as(u32, 0x4640e400)), .f6 = .{ .f0 = 0x1234 }, }; var k = K{ @@ -2299,7 +2319,7 @@ test byteSwapAllFields { .f2 = 0x1234, .f3 = .{0x12}, .f4 = false, - .f5 = @as(f32, @bitCast(@as(u32, 0x45d42800))), + .f5 = @bitCast(@as(u32, 0x45d42800)), }; var p: P = @bitCast(@as(u32, 0x01234567)); var a: A = A{ @@ -2317,7 +2337,7 @@ test byteSwapAllFields { .f2 = 0x78563412, .f3 = .{0x12}, .f4 = true, - .f5 = @as(f32, @bitCast(@as(u32, 0x00e44046))), + .f5 = @bitCast(@as(u32, 0x00e44046)), .f6 = .{ .f0 = 0x3412 }, }, s); try std.testing.expectEqual(K{ @@ -2326,7 +2346,7 @@ test byteSwapAllFields { .f2 = 0x3412, .f3 = .{0x12}, .f4 = false, - .f5 = @as(f32, @bitCast(@as(u32, 0x0028d445))), + .f5 = @bitCast(@as(u32, 0x0028d445)), }, k); try std.testing.expectEqual(@as(P, @bitCast(@as(u32, 0x67452301))), p); try std.testing.expectEqual(A{ @@ -2347,8 +2367,9 @@ pub fn byteSwapAllElements(comptime Elem: type, slice: []Elem) void { elem.* = @enumFromInt(@byteSwap(@intFromEnum(elem.*))); }, .bool => {}, - .float => |float_info| { - elem.* = @bitCast(@byteSwap(@as(@Int(.unsigned, float_info.bits), @bitCast(elem.*)))); + .float => |float| { + const int_repr: @Int(.unsigned, float.bits) = @bitCast(elem.*); + elem.* = @bitCast(@byteSwap(int_repr)); }, else => { elem.* = @byteSwap(elem.*); @@ -3869,25 +3890,29 @@ inline fn reverseVector(comptime N: usize, comptime T: type, a: []T) [N]T { pub fn reverse(comptime T: type, items: []T) void { var i: usize = 0; const end = items.len / 2; - if (use_vectors and - !@inComptime() and - @bitSizeOf(T) > 0 and - std.math.isPowerOfTwo(@bitSizeOf(T))) - { - if (std.simd.suggestVectorLength(T)) |simd_size| { - if (simd_size <= end) { - const simd_end = end - (simd_size - 1); - while (i < simd_end) : (i += simd_size) { - const left_slice = items[i .. i + simd_size]; - const right_slice = items[items.len - i - simd_size .. items.len - i]; - const left_shuffled: [simd_size]T = reverseVector(simd_size, T, left_slice); - const right_shuffled: [simd_size]T = reverseVector(simd_size, T, right_slice); + vec: { + if (!use_vectors) break :vec; + if (@inComptime()) break :vec; + switch (@typeInfo(T)) { + .int, .float => {}, + .pointer => |pointer| if (pointer.size == .slice) break :vec, + else => break :vec, + } + if (@bitSizeOf(T) == 0 or !comptime std.math.isPowerOfTwo(@bitSizeOf(T))) break :vec; + const simd_size = std.simd.suggestVectorLength(T) orelse break :vec; + if (simd_size > end) break :vec; - @memcpy(right_slice, &left_shuffled); - @memcpy(left_slice, &right_shuffled); - } - } + const simd_end = end - (simd_size - 1); + while (i < simd_end) : (i += simd_size) { + const left_slice = items[i .. i + simd_size]; + const right_slice = items[items.len - i - simd_size .. items.len - i]; + + const left_shuffled: [simd_size]T = reverseVector(simd_size, T, left_slice); + const right_shuffled: [simd_size]T = reverseVector(simd_size, T, right_slice); + + @memcpy(right_slice, &left_shuffled); + @memcpy(left_slice, &right_shuffled); } } @@ -5008,8 +5033,8 @@ test "read/write(Var)PackedInt" { for ([_]PackedType{ ~@as(PackedType, 0), // all ones: -1 iN / maxInt uN @as(PackedType, 0), // all zeros: 0 iN / 0 uN - @as(PackedType, @bitCast(@as(iPackedType, math.maxInt(iPackedType)))), // maxInt iN - @as(PackedType, @bitCast(@as(iPackedType, math.minInt(iPackedType)))), // maxInt iN + @bitCast(@as(iPackedType, math.maxInt(iPackedType))), // maxInt iN + @bitCast(@as(iPackedType, math.minInt(iPackedType))), // maxInt iN random.int(PackedType), // random random.int(PackedType), // random }) |write_value| { @@ -5129,3 +5154,50 @@ test "read/write(Var)PackedInt" { } } } + +pub const PrintError = error{ + /// As much as possible was written to the buffer, but it was too small to + /// fit all the printed bytes. + NoSpaceLeft, +}; + +/// Render a formatted string into `buffer`. Returns a slice of `buffer` +/// starting at index 0 containing the result, or `error.NoSpaceLeft` if one or +/// more bytes were truncated. +/// +/// See `std.Io.Writer.print`. +pub fn print(buffer: []u8, comptime format: []const u8, args: anytype) PrintError![]u8 { + var w: std.Io.Writer = .fixed(buffer); + w.print(format, args) catch |err| switch (err) { + error.WriteFailed => return error.NoSpaceLeft, + }; + return w.buffered(); +} + +test print { + const x: i32 = -1; + const y: []const u8 = "hi"; + var buffer: [64]u8 = undefined; + const s = try print(&buffer, "{d}={s}", .{ x, y }); + try testing.expectEqualStrings("-1=hi", s); +} + +/// Like `print` but returned slice has the provided sentinel. +pub fn printSentinel( + buffer: []u8, + comptime format: []const u8, + args: anytype, + comptime sentinel: u8, +) PrintError![:sentinel]u8 { + const result = try print(buffer, format ++ [1]u8{sentinel}, args); + return result[0 .. result.len - 1 :sentinel]; +} + +test printSentinel { + const x: i32 = -1; + const y: []const u8 = "hi"; + var buffer: [64]u8 = undefined; + const s = try printSentinel(&buffer, "{d}={s}", .{ x, y }, 0); + try testing.expectEqualStrings("-1=hi", s); + try testing.expectEqual(0, s[s.len]); +} diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index 76e5d11cc46e76cd90aa83601735138367b9d4dd..80341ecc2fa30523ef26bf7f1f68087fea18b925 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -1,11 +1,12 @@ //! The standard memory allocation interface. +const Allocator = @This(); + +const builtin = @import("builtin"); const std = @import("../std.zig"); const assert = std.debug.assert; const math = std.math; const mem = std.mem; -const Allocator = @This(); -const builtin = @import("builtin"); const Alignment = std.mem.Alignment; pub const Error = error{OutOfMemory}; @@ -444,7 +445,10 @@ pub fn reallocAdvanced( /// To free a single item, see `destroy`. pub fn free(self: Allocator, memory: anytype) void { const slice_info = @typeInfo(@TypeOf(memory)).pointer; - comptime assert(slice_info.size == .slice); + 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))); if (bytes.len == 0) return; @memset(bytes, undefined); @@ -471,6 +475,61 @@ pub fn dupeSentinel( return new_buf[0..m.len :sentinel]; } +/// Allocates a formatted string which is returned on success. +/// +/// Returned slice can be deallocated with `free`. If an arena-style allocator +/// is used instead, such as `std.heap.ArenaAllocator`, then no call to `free` +/// is necessary. +/// +/// See `std.Io.Writer.print`. +pub fn print(a: Allocator, comptime format: []const u8, args: anytype) Error![]u8 { + var aw = try std.Io.Writer.Allocating.initCapacity(a, format.len); + defer aw.deinit(); + aw.writer.print(format, args) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return aw.toOwnedSlice(); +} + +test print { + const x: i32 = -1; + const y: []const u8 = "hi"; + const a = std.testing.allocator; + const s = try print(a, "{d}={s}", .{ x, y }); + defer free(a, s); + try std.testing.expectEqualStrings("-1=hi", s); +} + +/// Like `print` but returned slice has the provided sentinel. +/// +/// Returned slice can be deallocated with `free`. If an arena-style allocator +/// is used instead, such as `std.heap.ArenaAllocator`, then no call to `free` +/// is necessary. Illegal behavior occurs if the returned slice is type-coerced +/// to a slice without the sentinel and then passed to `free`. +pub fn printSentinel( + a: Allocator, + comptime format: []const u8, + args: anytype, + comptime sentinel: u8, +) Allocator.Error![:sentinel]u8 { + var aw = try std.Io.Writer.Allocating.initCapacity(a, format.len); + defer aw.deinit(); + aw.writer.print(format, args) catch |err| switch (err) { + error.WriteFailed => return error.OutOfMemory, + }; + return aw.toOwnedSliceSentinel(sentinel); +} + +test printSentinel { + const x: i32 = -1; + const y: []const u8 = "hi"; + const a = std.testing.allocator; + const s = try printSentinel(a, "{d}={s}", .{ x, y }, 0); + defer free(a, s); + try std.testing.expectEqualStrings("-1=hi", s); + try std.testing.expectEqual(0, s[s.len]); +} + /// An allocator that always fails to allocate. pub const failing: Allocator = .{ .ptr = undefined, diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 2012f8cafe7c94647ff1bb992d91fc3dc22efc7f..14270ba9d86763f72a5a75eb5f846dee00759954 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -14,31 +14,14 @@ test { _ = TrailerFlags; } -/// Returns the variant of an enum type, `T`, which is named `str`, or `null` if no such variant exists. +/// Returns the variant of an enum type corresponding to the provided tag name, +/// or `null` if no such variant exists. pub fn stringToEnum(comptime T: type, tag_name: []const u8) ?T { - // Using StaticStringMap here is more performant, but it will start to take too - // long to compile if the enum is large enough, due to the current limits of comptime - // performance when doing things like constructing lookup maps at comptime. - // TODO The '100' here is arbitrary and should be increased when possible: - // - https://github.com/ziglang/zig/issues/4055 - // - https://github.com/ziglang/zig/issues/3863 - if (@typeInfo(T).@"enum".field_names.len <= 100) { - return std.StaticStringMap(T).initEnum().get(tag_name); - } else { - inline for (@typeInfo(T).@"enum".field_names) |name| { - if (mem.eql(u8, tag_name, name)) { - return @field(T, name); - } - } - return null; - } + return std.StaticStringMap(T).initEnum().get(tag_name); } test stringToEnum { - const E1 = enum { - A, - B, - }; + const E1 = enum { A, B }; try testing.expect(E1.A == stringToEnum(E1, "A").?); try testing.expect(E1.B == stringToEnum(E1, "B").?); try testing.expect(null == stringToEnum(E1, "C")); @@ -516,6 +499,15 @@ test DeclEnum { try expectEqualEnum(enum {}, DeclEnum(D)); } +pub fn BareUnion(comptime T: type) type { + const u = switch (@typeInfo(T)) { + .@"union" => |u| u, + else => @compileError("expected union type, found '" ++ @typeName(T) ++ "'"), + }; + + return @Union(u.layout, null, u.field_names, u.field_types[0..], u.field_attrs[0..]); +} + pub fn Tag(comptime T: type) type { return switch (@typeInfo(T)) { .@"enum" => |info| info.tag_type, @@ -917,6 +909,15 @@ pub inline fn hasUniqueRepresentation(comptime T: type) bool { return @sizeOf(T) == sum_size; }, + .@"union" => |info| { + if (info.layout == .@"packed") return @sizeOf(T) * 8 == @bitSizeOf(T); + inline for (info.field_types) |field_type| { + if (@sizeOf(field_type) != @sizeOf(T)) return false; + if (!hasUniqueRepresentation(field_type)) return false; + } + return true; + }, + .vector => |info| hasUniqueRepresentation(info.child) and @sizeOf(T) == @sizeOf(info.child) * info.len, }; @@ -986,6 +987,27 @@ test hasUniqueRepresentation { try testing.expect(!hasUniqueRepresentation(TestUnion4)); + const TestUnion5 = extern union { + a: u32, + b: i32, + }; + + try testing.expect(hasUniqueRepresentation(TestUnion5)); + + const TestUnion6 = packed union(u7) { + a: u7, + b: i7, + }; + + try testing.expect(!hasUniqueRepresentation(TestUnion6)); + + const TestUnion7 = packed union(u8) { + a: u8, + b: i8, + }; + + try testing.expect(hasUniqueRepresentation(TestUnion7)); + inline for ([_]type{ u8, i16, u32, i64 }) |T| { try testing.expect(hasUniqueRepresentation(T)); try testing.expect(hasUniqueRepresentation(enum(T) { _ })); diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index 7b99eeb63e1185c0466527b42a99770819a28f46..95404a3288e8459ff334c6e0c0558c71d3d563f6 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -44,7 +44,7 @@ pub fn MultiArrayList(comptime T: type) type { const Elem = switch (@typeInfo(T)) { .@"struct" => T, .@"union" => |u| struct { - pub const Bare = @Union(u.layout, null, u.field_names, u.field_types[0..], u.field_attrs[0..]); + pub const Bare = std.meta.BareUnion(T); pub const Tag = u.tag_type orelse @compileError("MultiArrayList does not support untagged unions"); tags: Tag, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index aeaf6f2a53eb961078106775ecb4aad7b89addef..dc22fc6db21bdcf83d929ace73f37594fc0d5982 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -43,7 +43,7 @@ const arch_bits = switch (native_arch) { .microblaze, .microblazeel => @import("linux/microblaze.zig"), .mips, .mipsel => @import("linux/mips.zig"), .mips64, .mips64el => switch (builtin.abi) { - .gnuabin32, .muslabin32 => @import("linux/mipsn32.zig"), + .gnuabin32, .muslabin32, .abin32 => @import("linux/mipsn32.zig"), else => @import("linux/mips64.zig"), }, .or1k => @import("linux/or1k.zig"), @@ -57,7 +57,7 @@ const arch_bits = switch (native_arch) { .sparc64 => @import("linux/sparc64.zig"), .x86 => @import("linux/x86.zig"), .x86_64 => switch (builtin.abi) { - .gnux32, .muslx32 => @import("linux/x32.zig"), + .gnux32, .muslx32, .x32 => @import("linux/x32.zig"), else => @import("linux/x86_64.zig"), }, .xtensa, .xtensaeb => @import("linux/xtensa.zig"), @@ -80,6 +80,7 @@ pub const restore_rt = syscall_bits.restore_rt; pub const socketcall = syscall_bits.socketcall; pub const syscall_pipe = syscall_bits.syscall_pipe; pub const syscall_fork = syscall_bits.syscall_fork; +pub const syscall_lseek = syscall_bits.syscall_lseek; pub fn clone( func: *const fn (arg: usize) callconv(.c) u8, @@ -143,7 +144,7 @@ pub const SYS = switch (native_arch) { .microblaze, .microblazeel => syscalls.Microblaze, .mips, .mipsel => syscalls.MipsO32, .mips64, .mips64el => switch (builtin.abi) { - .gnuabin32, .muslabin32 => syscalls.MipsN32, + .gnuabin32, .muslabin32, .abin32 => syscalls.MipsN32, else => syscalls.MipsN64, }, .or1k => syscalls.OpenRisc, @@ -157,7 +158,7 @@ pub const SYS = switch (native_arch) { .sparc64 => syscalls.Sparc64, .x86 => syscalls.X86, .x86_64 => switch (builtin.abi) { - .gnux32, .muslx32 => syscalls.X32, + .gnux32, .muslx32, .x32 => syscalls.X32, else => syscalls.X64, }, .xtensa, .xtensaeb => syscalls.Xtensa, @@ -751,8 +752,8 @@ fn splitValue64(val: i64) [2]u32 { } /// Get the errno from a syscall return value. SUCCESS means no error. -pub fn errno(r: usize) E { - const signed_r: isize = @bitCast(r); +pub fn errno(r: u64) E { + const signed_r: i32 = @bitCast(@as(u32, @truncate(r))); const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0; return @enumFromInt(int); } @@ -1809,7 +1810,7 @@ pub fn fchmodat2(fd: fd_t, path: [*:0]const u8, mode: mode_t, flags: u32) usize } /// Can only be called on 32 bit systems. For 64 bit see `lseek`. -pub fn llseek(fd: fd_t, offset: off_t, result: ?*off_t, whence: u32) usize { +pub fn llseek(fd: fd_t, offset: off_t, result: ?*off_t, whence: u32) u32 { // NOTE: The offset parameter splitting is independent from the target // endianness. return syscall5( @@ -1823,8 +1824,17 @@ pub fn llseek(fd: fd_t, offset: off_t, result: ?*off_t, whence: u32) usize { } /// Can only be called on 64 bit systems. For 32 bit see `llseek`. -pub fn lseek(fd: fd_t, offset: off_t, whence: u32) usize { - return syscall3(.lseek, @as(u32, @bitCast(fd)), @as(u64, @bitCast(offset)), whence); +pub fn lseek(fd: fd_t, offset: off_t, whence: u32) u64 { + return switch (builtin.abi) { + .gnuabin32, + .muslabin32, + .abin32, + .gnux32, + .muslx32, + .x32, + => syscall_lseek(fd, offset, whence), + else => syscall3(.lseek, @as(u32, @bitCast(fd)), @as(u64, @bitCast(offset)), whence), + }; } pub fn exit(status: i32) noreturn { @@ -1998,7 +2008,7 @@ pub const F = struct { const SETLKW = 35; }, .mips64, .mips64el => switch (native_abi) { - .gnuabin32, .muslabin32 => struct { + .gnuabin32, .muslabin32, .abin32 => struct { const GETLK = 33; const SETLK = 34; const SETLKW = 35; @@ -3179,7 +3189,7 @@ pub fn tee(src: fd_t, dest: fd_t, len: usize, flags: u32) usize { } pub const Sysinfo = switch (native_abi) { - .gnux32, .muslx32 => extern struct { + .gnux32, .muslx32, .x32 => extern struct { /// Seconds since boot uptime: i64, /// 1, 5, and 15 minute load averages @@ -9450,7 +9460,11 @@ pub const UTIME = struct { }; // https://github.com/ziglang/zig/issues/4726#issuecomment-2190337877 -pub const timespec = if (native_arch == .hexagon or native_arch == .riscv32) kernel_timespec else extern struct { +const use_kernel_timespec = native_arch == .hexagon or native_arch == .riscv32 or switch (native_abi) { + .gnux32, .muslx32, .x32 => true, + else => false, +}; +pub const timespec = if (use_kernel_timespec) kernel_timespec else extern struct { sec: isize, nsec: isize, }; @@ -10745,11 +10759,11 @@ pub const AUDIT = struct { .mips => .MIPS, .mipsel => .MIPSEL, .mips64 => switch (native_abi) { - .gnuabin32, .muslabin32 => .MIPS64N32, + .gnuabin32, .muslabin32, .abin32 => .MIPS64N32, else => .MIPS64, }, .mips64el => switch (native_abi) { - .gnuabin32, .muslabin32 => .MIPSEL64N32, + .gnuabin32, .muslabin32, .abin32 => .MIPSEL64N32, else => .MIPSEL64, }, .or1k => .OPENRISC, diff --git a/lib/std/os/linux/IoUring/test.zig b/lib/std/os/linux/IoUring/test.zig index add4f30f8512e1c0c470cba0f253a7ff80159cf1..27925c81fb138ec20efbb6bc05acfff5a4a09879 100644 --- a/lib/std/os/linux/IoUring/test.zig +++ b/lib/std/os/linux/IoUring/test.zig @@ -526,7 +526,9 @@ test "sendmsg/recvmsg" { var address_server: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; const server = try socket(address_server.family, posix.SOCK.DGRAM, 0); @@ -1028,7 +1030,9 @@ test "shutdown" { var address: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; // Socket bound, expect shutdown to work @@ -1740,7 +1744,9 @@ test "accept multishot" { var address: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; const listener_socket = try createListenerSocket(&address); defer _ = linux.close(listener_socket); @@ -1842,7 +1848,9 @@ test "accept_direct" { defer ring.deinit(); var address: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; // register direct file descriptors @@ -1931,7 +1939,9 @@ test "accept_multishot_direct" { var address: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; var registered_fds: [2]linux.fd_t = @splat(-1); @@ -2041,7 +2051,9 @@ test "socket_direct/socket_direct_alloc/close_direct" { // use sockets from registered_fds in connect operation var address: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; const listener_socket = try createListenerSocket(&address); defer _ = linux.close(listener_socket); @@ -2426,7 +2438,9 @@ test "bind/listen/connect" { var addr: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; const proto: u32 = if (addr.family == linux.AF.UNIX) 0 else linux.IPPROTO.TCP; @@ -2614,7 +2628,9 @@ pub fn createSocketTestHarness(ring: *IoUring) !SocketTestHarness { // Create a TCP server socket var address: linux.sockaddr.in = .{ .port = 0, - .addr = @bitCast([4]u8{ 127, 0, 0, 1 }), + .addr = @as(*align(1) const u32, @ptrCast( + &@as([4]u8, .{ 127, 0, 0, 1 }), + )).*, }; const listener_socket = try createListenerSocket(&address); errdefer _ = linux.close(listener_socket); diff --git a/lib/std/os/linux/mipsn32.zig b/lib/std/os/linux/mipsn32.zig index 04b240af9fa7631a635024cc7847a62fd691023a..fcaebaa9189e5d005d8026febad952fe29e8ba7d 100644 --- a/lib/std/os/linux/mipsn32.zig +++ b/lib/std/os/linux/mipsn32.zig @@ -163,6 +163,25 @@ pub fn syscall_pipe( : .{ .r1 = true, .r3 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true }); } +pub fn syscall_lseek( + fd: std.os.linux.fd_t, + offset: std.os.linux.off_t, + whence: u32, +) u64 { + return asm volatile ( + \\ syscall + \\ beq $a3, $zero, 1f + \\ blez $v0, 1f + \\ dsubu $v0, $zero, $v0 + \\1: + : [ret] "={$2}" (-> u64), + : [number] "{$2}" (@intFromEnum(SYS.lseek)), + [fd] "{$4}" (@as(u32, @bitCast(fd))), + [offset] "{$5}" (@as(u64, @bitCast(offset))), + [whence] "{$6}" (whence), + : .{ .r1 = true, .r3 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true }); +} + pub fn clone() callconv(.naked) u32 { // __clone(func, stack, flags, arg, ptid, tls, ctid) // a0, a1, a2, a3, a4, a5, a6 @@ -200,8 +219,8 @@ pub fn clone() callconv(.naked) u32 { \\ move $fp, $zero \\ move $ra, $zero \\ - \\ ld $t9, 0($sp) - \\ ld $a0, 4($sp) + \\ lw $t9, 0($sp) + \\ lw $a0, 4($sp) \\ jalr $t9 \\ \\ move $a0, $v0 diff --git a/lib/std/os/linux/syscalls.zig b/lib/std/os/linux/syscalls.zig index 226081bf4d6e5942559eef906ee1fb71b8b3a597..4182eb4e46ce497efc9aebba7435835deb8d916c 100644 --- a/lib/std/os/linux/syscalls.zig +++ b/lib/std/os/linux/syscalls.zig @@ -1,5 +1,5 @@ // This file is automatically generated by tools/generate_linux_syscalls.zig -// This list current as of kernel: 7.0.0 +// This list current as of kernel: 7.1.0 pub const X86 = enum(usize) { restart_syscall = 0, @@ -9929,7 +9929,6 @@ pub const Hppa64 = enum(usize) { personality = 136, setfsuid = 138, setfsgid = 139, - llseek = 140, getdents = 141, newselect = 142, flock = 143, diff --git a/lib/std/os/linux/x32.zig b/lib/std/os/linux/x32.zig index d26833d9a17bdf40bd76d6477068152fc676dbb2..3b10612786a6d256775c3f3dbe068b1ced5e352b 100644 --- a/lib/std/os/linux/x32.zig +++ b/lib/std/os/linux/x32.zig @@ -109,6 +109,20 @@ pub fn syscall6( : .{ .rcx = true, .r11 = true, .memory = true }); } +pub fn syscall_lseek( + fd: std.os.linux.fd_t, + offset: std.os.linux.off_t, + whence: u32, +) u64 { + return asm volatile ("syscall" + : [ret] "={rax}" (-> u64), + : [number] "{rax}" (@intFromEnum(SYS.lseek)), + [fd] "{rdi}" (@as(u32, @bitCast(fd))), + [offset] "{rsi}" (@as(u64, @bitCast(offset))), + [whence] "{rdx}" (whence), + : .{ .rcx = true, .r11 = true, .memory = true }); +} + pub fn clone() callconv(.naked) u32 { asm volatile ( \\ movl $0x40000038,%%eax // SYS_clone @@ -116,7 +130,7 @@ pub fn clone() callconv(.naked) u32 { \\ mov %%rdx,%%rdi \\ mov %%r8,%%rdx \\ mov %%r9,%%r8 - \\ mov 8(%%rsp),%%r10 + \\ mov 8(%%rsp),%%r10d \\ mov %%r11,%%r9 \\ and $-16,%%rsi \\ sub $8,%%rsi @@ -161,7 +175,7 @@ pub fn restore_rt() callconv(.naked) noreturn { } } -pub const time_t = i32; +pub const time_t = i64; pub const VDSO = struct { pub const CGT_SYM = "__vdso_clock_gettime"; diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig index cc2dac949e31d6c5a0bda855079f234f0ae7e181..e48ec85fe32bc7af9c7dce101ebf5d2d6a9fbd28 100644 --- a/lib/std/os/uefi.zig +++ b/lib/std/os/uefi.zig @@ -218,7 +218,7 @@ pub const TimeCapabilities = extern struct { pub const FileHandle = *opaque {}; test "GUID formatting" { - const bytes = [_]u8{ 137, 60, 203, 50, 128, 128, 124, 66, 186, 19, 80, 73, 135, 59, 194, 135 }; + const bytes: [16]u8 = .{ 137, 60, 203, 50, 128, 128, 124, 66, 186, 19, 80, 73, 135, 59, 194, 135 }; const guid: Guid = @bitCast(bytes); const str = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{guid}); diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 89105b673602a7c5d13439100a4426082b7c3b0f..7a3c134e2a3416f35aed6cbff592105f0cd95109 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -4189,19 +4189,11 @@ pub const GUID = extern struct { Data3: u16, Data4: [8]u8, - const hex_offsets = switch (builtin.target.cpu.arch.endian()) { - .big => [16]u6{ - 0, 2, 4, 6, - 9, 11, 14, 16, - 19, 21, 24, 26, - 28, 30, 32, 34, - }, - .little => [16]u6{ - 6, 4, 2, 0, - 11, 9, 16, 14, - 19, 21, 24, 26, - 28, 30, 32, 34, - }, + const hex_offsets: [16]u6 = .{ + 6, 4, 2, 0, + 11, 9, 16, 14, + 19, 21, 24, 26, + 28, 30, 32, 34, }; pub fn parse(s: []const u8) GUID { @@ -4216,12 +4208,21 @@ pub const GUID = extern struct { assert(s[13] == '-'); assert(s[18] == '-'); assert(s[23] == '-'); - var bytes: [16]u8 = undefined; - for (hex_offsets, 0..) |hex_offset, i| { - bytes[i] = (try std.fmt.charToDigit(s[hex_offset], 16)) << 4 | - try std.fmt.charToDigit(s[hex_offset + 1], 16); - } - return @as(GUID, @bitCast(bytes)); + var raw1: [4]u8 = undefined; + var raw2: [2]u8 = undefined; + var raw3: [2]u8 = undefined; + var raw4: [8]u8 = undefined; + assert((try std.fmt.hexToBytes(&raw1, s[0..8])).len == raw1.len); + assert((try std.fmt.hexToBytes(&raw2, s[9..13])).len == raw2.len); + assert((try std.fmt.hexToBytes(&raw3, s[14..18])).len == raw3.len); + assert((try std.fmt.hexToBytes(raw4[0..2], s[19..23])).len == 2); + assert((try std.fmt.hexToBytes(raw4[2..8], s[24..36])).len == 6); + return .{ + .Data1 = @byteSwap(@as(u32, @bitCast(raw1))), + .Data2 = @byteSwap(@as(u16, @bitCast(raw2))), + .Data3 = @byteSwap(@as(u16, @bitCast(raw3))), + .Data4 = raw4, + }; } pub fn format(self: GUID, w: *std.Io.Writer) std.Io.Writer.Error!void { @@ -4233,28 +4234,28 @@ pub const GUID = extern struct { self.Data4[2..8], }); } -}; -test GUID { - try std.testing.expectEqual( - GUID{ + test parse { + const expected: GUID = .{ .Data1 = 0x01234567, .Data2 = 0x89ab, .Data3 = 0xef10, .Data4 = "\x32\x54\x76\x98\xba\xdc\xfe\x91".*, - }, - GUID.parse("{01234567-89AB-EF10-3254-7698badcfe91}"), - ); - try std.testing.expectFmt( - "{01234567-89ab-ef10-3254-7698badcfe91}", - "{f}", - .{GUID.parse("{01234567-89AB-EF10-3254-7698badcfe91}")}, - ); - try std.testing.expectFmt( - "{00000001-0001-0001-0001-000000000001}", - "{f}", - .{GUID{ .Data1 = 1, .Data2 = 1, .Data3 = 1, .Data4 = [_]u8{ 0, 1, 0, 0, 0, 0, 0, 1 } }}, - ); + }; + try std.testing.expectEqual(expected, GUID.parse("{01234567-89AB-EF10-3254-7698badcfe91}")); + } + + test format { + const guid0: GUID = .{ .Data1 = 1, .Data2 = 1, .Data3 = 1, .Data4 = .{ 0, 1, 0, 0, 0, 0, 0, 1 } }; + try std.testing.expectFmt("{00000001-0001-0001-0001-000000000001}", "{f}", .{guid0}); + + const guid1: GUID = .parse("{01234567-89AB-EF10-3254-7698badcfe91}"); + try std.testing.expectFmt("{01234567-89ab-ef10-3254-7698badcfe91}", "{f}", .{guid1}); + } +}; + +test { + _ = GUID; } pub const COORD = extern struct { diff --git a/lib/std/pie.zig b/lib/std/pie.zig index 8d7ac3fa7c447ed7f73a616a982daa321bc87960..0252cde9e8f0161ae5a3767723c3853f94ec82f0 100644 --- a/lib/std/pie.zig +++ b/lib/std/pie.zig @@ -162,7 +162,7 @@ inline fn getDynamicSymbol() [*]const elf.Dyn { : : .{ .lr = true }), .mips64, .mips64el => switch (builtin.abi) { - .gnuabin32, .muslabin32 => asm volatile ( + .gnuabin32, .muslabin32, .abin32 => asm volatile ( \\ .weak _DYNAMIC \\ .hidden _DYNAMIC \\ bal 1f diff --git a/lib/std/process.zig b/lib/std/process.zig index bcee558a65eef07afab17b484cc012326bb5004c..f3ef291763d642426770883e886c8a5a50aeae41 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -315,7 +315,15 @@ pub fn replacePath(io: Io, dir: Io.Dir, options: ReplaceOptions) ReplaceError { pub const ArgExpansion = enum { expand, no_expand }; /// File name extensions supported natively by `CreateProcess()` on Windows. -pub const WindowsExtension = enum { bat, cmd, com, exe }; +pub const WindowsExtension = enum { + bat, + cmd, + com, + exe, + + /// Length of the longest supported extension (in ASCII characters) + pub const max_len = 3; +}; pub const SpawnError = error{ /// The operating system does not support creating child processes. diff --git a/lib/std/process/Environ.zig b/lib/std/process/Environ.zig index bf0408c31ddc4eebf48a08dea54b6391a524e012..a2b2f4110f499171a09ffb42c3d631f7e48faee7 100644 --- a/lib/std/process/Environ.zig +++ b/lib/std/process/Environ.zig @@ -101,7 +101,7 @@ pub const Map = struct { array_hash_map: ArrayHashMap, allocator: Allocator, - const ArrayHashMap = std.ArrayHashMapUnmanaged([]const u8, []const u8, EnvNameHashContext, false); + const ArrayHashMap = std.array_hash_map.Custom([]const u8, []const u8, EnvNameHashContext, false); pub const Size = usize; diff --git a/lib/std/process/Preopens.zig b/lib/std/process/Preopens.zig index 3baf696ee9a5d95dbf2bed352ea4867e8c3fde8c..6a7337a31e9bcaf207af9d2ab501448a95649cc3 100644 --- a/lib/std/process/Preopens.zig +++ b/lib/std/process/Preopens.zig @@ -16,7 +16,7 @@ pub const empty: Preopens = switch (native_os) { pub const Map = switch (native_os) { // Indexed by file descriptor number. - .wasi => std.StringArrayHashMapUnmanaged(void), + .wasi => std.array_hash_map.String(void), else => void, }; diff --git a/lib/std/sort/pdq.zig b/lib/std/sort/pdq.zig index 85d3a62c9c5233441edb013b6f6d611d7159b9b9..5b0da14156ae1365f7a677c84453d0b07d84a774 100644 --- a/lib/std/sort/pdq.zig +++ b/lib/std/sort/pdq.zig @@ -44,12 +44,11 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { // slices of up to this length get sorted using insertion sort. const max_insertion = 24; // number of allowed imbalanced partitions before switching to heap sort. - const max_limit = std.math.floorPowerOfTwo(usize, b - a) + 1; + const max_limit = if (b > a) math.log2_int(usize, b - a) else 0; // set upper bound on stack memory usage. const Range = struct { a: usize, b: usize, limit: usize, leftmost: bool }; - const stack_size = math.log2(math.maxInt(usize) + 1); - var stack: [stack_size]Range = undefined; + var stack: [2 * @bitSizeOf(usize)]Range = undefined; var range = Range{ .a = a, .b = b, .limit = max_limit, .leftmost = true }; var top: usize = 0; diff --git a/lib/std/spirv.zig b/lib/std/spirv.zig new file mode 100644 index 0000000000000000000000000000000000000000..6f9fd74967053ec295ad14882d4abda7eedccc18 --- /dev/null +++ b/lib/std/spirv.zig @@ -0,0 +1,84 @@ +const std = @import("std.zig"); + +pub const position_in = @extern(*addrspace(.input) @Vector(4, f32), .{ .name = "position" }); +pub const position_out = @extern(*addrspace(.output) @Vector(4, f32), .{ .name = "position" }); +pub const point_size_in = @extern(*addrspace(.input) f32, .{ .name = "point_size" }); +pub const point_size_out = @extern(*addrspace(.output) f32, .{ .name = "point_size" }); +pub extern const invocation_id: u32 addrspace(.input); +pub extern const frag_coord: @Vector(4, f32) addrspace(.input); +pub extern const point_coord: @Vector(2, f32) addrspace(.input); +// TODO: direct/indirect values +// pub extern const front_facing: bool addrspace(.input); +// TODO: runtime array +// pub extern const sample_mask; +pub extern var frag_depth: f32 addrspace(.output); +pub extern const num_workgroups: @Vector(3, u32) addrspace(.input); +pub extern const workgroup_size: @Vector(3, u32) addrspace(.input); +pub extern const workgroup_id: @Vector(3, u32) addrspace(.input); +pub extern const local_invocation_id: @Vector(3, u32) addrspace(.input); +pub extern const global_invocation_id: @Vector(3, u32) addrspace(.input); +pub extern const vertex_index: u32 addrspace(.input); +pub extern const instance_index: u32 addrspace(.input); + +pub const Scope = enum(u32) { + cross_device = 0, + device = 1, + workgroup = 2, + subgroup = 3, + invocation = 4, + queue_family = 5, + shader_call_khr = 6, +}; + +pub const MemorySemantics = packed struct(u32) { + _reserved_bit_0: bool = false, + acquire: bool = false, + release: bool = false, + acquire_release: bool = false, + sequentially_consistent: bool = false, + _reserved_bit_5: bool = false, + uniform_memory: bool = false, + subgroup_memory: bool = false, + workgroup_memory: bool = false, + cross_workgroup_memory: bool = false, + atomic_counter_memory: bool = false, + image_memory: bool = false, + output_memory: bool = false, + make_available: bool = false, + make_visible: bool = false, + @"volatile": bool = false, + _reserved: u16 = 0, + + pub const none: MemorySemantics = .{}; +}; + +pub fn controlBarrier( + comptime execution: Scope, + comptime memory: Scope, + comptime semantics: MemorySemantics, +) void { + asm volatile ( + \\OpControlBarrier %exec %mem %sem + : + : [exec] "" (@as(u32, @intFromEnum(execution))), + [mem] "" (@as(u32, @intFromEnum(memory))), + [sem] "" (@as(u32, @bitCast(semantics))), + ); +} + +pub fn memoryBarrier(comptime memory: Scope, comptime semantics: MemorySemantics) void { + asm volatile ( + \\OpMemoryBarrier %mem %sem + : + : [mem] "" (@as(u32, @intFromEnum(memory))), + [sem] "" (@as(u32, @bitCast(semantics))), + ); +} + +pub fn workgroupBarrier() void { + controlBarrier( + .workgroup, + .workgroup, + .{ .acquire_release = true, .workgroup_memory = true }, + ); +} diff --git a/lib/std/start.zig b/lib/std/start.zig index 6a20adf011ab109115e4365fb9d115ce37d6e0e5..68785b47aed7f36f2bf9dcea941eb12657c7c203 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -70,7 +70,19 @@ comptime { // case it's not required to provide an entrypoint such as main. if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main")) @export(&wasm_freestanding_start, .{ .name = start_sym_name }); } else switch (native_os) { - .other, .freestanding, .@"3ds", .psp, .vita => {}, + .other, + .freestanding, + .vulkan, + .opengl, + .opencl, + + .@"3ds", + .wiiu, + + .psx, + .psp, + .vita, + => {}, else => if (!@hasDecl(root, start_sym_name)) @export(&_start, .{ .name = start_sym_name }), } } @@ -81,7 +93,7 @@ fn DllMainCRTStartup( fdwReason: std.os.windows.DWORD, lpReserved: std.os.windows.LPVOID, ) callconv(.winapi) std.os.windows.BOOL { - if (!builtin.single_threaded and !builtin.link_libc) { + if (!builtin.single_threaded) { _ = @import("os/windows/tls.zig"); } @@ -373,7 +385,7 @@ fn _start() callconv(.naked) noreturn { \\ jalr $t9 , .mips64, .mips64el => switch (builtin.abi) { - .gnuabin32, .muslabin32 => + .gnuabin32, .muslabin32, .abin32 => \\ move $fp, $zero \\ bal 1f \\ .gpword . diff --git a/lib/std/static_string_map.zig b/lib/std/static_string_map.zig index f0bfc2adb75cb7b4852d2c0719b8761db0e38cf4..950468fd5162d427c73811c5561e0e020d72b9e6 100644 --- a/lib/std/static_string_map.zig +++ b/lib/std/static_string_map.zig @@ -241,7 +241,10 @@ pub fn StaticStringMapWithEql( return self.kvs.values[self.getIndex(str) orelse return null]; } - fn getIndex(self: Self, str: []const u8) ?usize { + /// Returns the index corresponding to the `str` within the + /// generated `kvs`, or `null` if `str` was not found. + /// The returned index is unrelated to the input `kvs_list`. + pub fn getIndex(self: Self, str: []const u8) ?usize { const kvs = self.kvs.*; if (kvs.len == 0) return null; @@ -279,6 +282,14 @@ pub fn StaticStringMapWithEql( }; } + /// Returns the index within the generated `kvs` corresponding to the + /// key-value pair where key is the longest prefix of `str`, or `null` + /// if no such key-value pair was found. The returned index is unrelated + /// to the input `kvs_list`. + /// + /// This is effectively an O(N) algorithm which loops from `max_len` to + /// `min_len` and calls `getIndex()` to check all keys with the given + /// len. pub fn getLongestPrefixIndex(self: Self, str: []const u8) ?usize { if (self.kvs.len == 0) return null; @@ -294,11 +305,15 @@ pub fn StaticStringMapWithEql( return null; } + /// Returns the slice of keys from the generated `kvs`, which may + /// be in a different order than the input `kvs_list`. pub fn keys(self: Self) []const []const u8 { const kvs = self.kvs.*; return kvs.keys[0..kvs.len]; } + /// Returns the slice of values from the generated `kvs`, which may + /// be in a different order than the input `kvs_list`. pub fn values(self: Self) []const V { const kvs = self.kvs.*; return kvs.values[0..kvs.len]; @@ -504,6 +519,20 @@ test "comptime-only value" { try testing.expect(map.get("d") == null); } +test "getIndex" { + const slice = [_]TestKV{ + .{ "longer", .A }, + .{ "short", .B }, + }; + const map = TestMap.initComptime(slice); + + // This index can be different than the index of the "short" KV in `slice` + const short_index = map.getIndex("short").?; + try testing.expectEqualStrings("short", map.keys()[short_index]); + try testing.expectEqual(.B, map.values()[short_index]); + try testing.expectEqual(null, map.getIndex("missing")); +} + test "getLongestPrefix" { const slice = [_]TestKV{ .{ "a", .A }, diff --git a/lib/std/std.zig b/lib/std/std.zig index 3f2fb1d62d0fb91d048c251c5c9ca569cccd4263..e7c50a946091a47dccf4cf1301d2982189ff8589 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -81,7 +81,7 @@ pub const elf = @import("elf.zig"); pub const enums = @import("enums.zig"); pub const fmt = @import("fmt.zig"); pub const fs = @import("fs.zig"); -pub const gpu = @import("gpu.zig"); +pub const spirv = @import("spirv.zig"); pub const hash = @import("hash.zig"); pub const hash_map = @import("hash_map.zig"); pub const heap = @import("heap.zig"); diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 9f00c270d4e59152eeeab8c761de32f2c847109e..46c7fe938b22300c23dcedc3570cb329090d3d3a 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -79,6 +79,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { switch (@typeInfo(@TypeOf(actual))) { .noreturn, .@"opaque", + .spirv, .frame, .@"anyframe", => @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"), @@ -140,39 +141,45 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { try expectEqualSlices(info.child, &expect_array, &actual_array); }, - .@"struct" => |structType| { - inline for (structType.field_names) |field_name| { + .@"struct" => |@"struct"| { + inline for (@"struct".field_names) |field_name| { try expectEqual(@field(expected, field_name), @field(actual, field_name)); } }, - .@"union" => |union_info| { - if (union_info.tag_type == null) { - const first_size = @bitSizeOf(union_info.field_types[0]); - inline for (union_info.field_types) |field_type| { + .@"union" => |@"union"| if (@"union".backing_integer) |Int| { + try expectEqual(@as(Int, @bitCast(expected)), @as(Int, @bitCast(actual))); + } else switch (@"union".layout) { + .@"packed" => { + const Int = @Int(.unsigned, @bitSizeOf(T)); + try expectEqual(@as(Int, @bitCast(expected)), @as(Int, @bitCast(actual))); + }, + .@"extern" => { + const first_size = @bitSizeOf(@"union".field_types[0]); + inline for (@"union".field_types) |field_type| { if (@bitSizeOf(field_type) != first_size) { - @compileError("Unable to compare untagged unions with varying field sizes for type " ++ @typeName(@TypeOf(actual))); + @compileError("Unable to compare extern unions with varying field sizes for type " ++ @typeName(T)); } } - - const BackingInt = @Int(.unsigned, @bitSizeOf(T)); + const FieldInt = @Int(.unsigned, first_size); + const expected_field = @field(expected, @"union".field_names[0]); + const actual_field = @field(actual, @"union".field_names[0]); return expectEqual( - @as(BackingInt, @bitCast(expected)), - @as(BackingInt, @bitCast(actual)), + @as(FieldInt, @bitCast(expected_field)), + @as(FieldInt, @bitCast(actual_field)), ); - } - - const Tag = std.meta.Tag(@TypeOf(expected)); - - const expectedTag = @as(Tag, expected); - const actualTag = @as(Tag, actual); - - try expectEqual(expectedTag, actualTag); - - // we only reach this switch if the tags are equal - switch (expected) { - inline else => |val, tag| try expectEqual(val, @field(actual, @tagName(tag))), - } + }, + .auto => { + const Tag = @"union".tag_type orelse @compileError("byteSwapAllFields expects packed, extern, or tagged union"); + + try expectEqual(@as(Tag, expected), @as(Tag, actual)); + switch (expected) { + inline else => |expected_payload, tag| { + const actual_payload = @field(actual, @tagName(tag)); + try expectEqual(expected_payload, actual_payload); + }, + } + }, }, .optional => { @@ -737,6 +744,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe switch (@typeInfo(@TypeOf(actual))) { .noreturn, .@"opaque", + .spirv, .frame, .@"anyframe", => @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"), diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 6cd6deecb66f0070411926184fd48929eb6c03f0..05891c582e38646da978177e34a3e8b26ac7f0af 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -774,7 +774,7 @@ pub const EnvVar = enum { ZIG_VERBOSE_CC, ZIG_DEBUG_CMD, ZIG_IS_DETECTING_LIBC_PATHS, - ZIG_IS_TRYING_TO_NOT_CALL_ITSELF, + ZIG_IS_AVOIDING_CALLING_ITSELF, // C toolchain integration NIX_CFLAGS_COMPILE, @@ -996,14 +996,11 @@ pub const EmitArtifact = enum { docs, pdb, h, - compiler_rt_dyn_lib, /// If using `Server` to communicate with the compiler, it will place requested artifacts in /// paths under the output directory, where those paths are named according to this function. /// Returned string is allocated with `gpa` and owned by the caller. pub fn cacheName(ea: EmitArtifact, gpa: Allocator, opts: BinNameOptions) Allocator.Error![]const u8 { - // hack for stage2_x86_64 + coff. See Coff.flush. - if (ea == .compiler_rt_dyn_lib) return "compiler_rt.dll"; const suffix: []const u8 = switch (ea) { .bin => return binNameAlloc(gpa, opts), .@"asm" => ".s", @@ -1013,7 +1010,6 @@ pub const EmitArtifact = enum { .docs => "-docs", .pdb => ".pdb", .h => ".h", - .compiler_rt_dyn_lib => unreachable, }; return std.fmt.allocPrint(gpa, "{s}{s}", .{ opts.root_name, suffix }); } diff --git a/lib/std/zig/Ast/Render.zig b/lib/std/zig/Ast/Render.zig index 6c8c0c9143d147b0f2483148f305c7b00c1cf304..8f5b2e2c276f5b8680fb56173154bcbdbf8966e6 100644 --- a/lib/std/zig/Ast/Render.zig +++ b/lib/std/zig/Ast/Render.zig @@ -42,7 +42,7 @@ pub const Fixups = struct { /// These nodes will be replaced with a different node. replace_nodes_with_node: std.AutoHashMapUnmanaged(Ast.Node.Index, Ast.Node.Index) = .empty, /// Change all identifier names matching the key to be value instead. - rename_identifiers: std.StringArrayHashMapUnmanaged([]const u8) = .empty, + rename_identifiers: std.array_hash_map.String([]const u8) = .empty, /// All `@import` builtin calls which refer to a file path will be prefixed /// with this path. diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index b02f4cc05636a19d0922d93ec32791f2315f64db..4adf7d0232804afe4738add9bf7a5307e2f1cdd3 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -52,7 +52,7 @@ within_fn: bool = false, fn_ret_ty: Zir.Inst.Ref = .none, /// Maps string table indexes to the first `@import` ZIR instruction /// that uses this string as the operand. -imports: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, Ast.TokenIndex) = .empty, +imports: std.array_hash_map.Auto(Zir.NullTerminatedString, Ast.TokenIndex) = .empty, /// Used for temporary storage when building payloads. scratch: std.ArrayList(u32) = .empty, /// Whenever a `ref` instruction is needed, it is created and saved in this @@ -927,15 +927,14 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE .deref => { const lhs = try expr(gz, scope, .{ .rl = .none }, tree.nodeData(node).node); - _ = try gz.addUnNode(.validate_deref, lhs, node); switch (ri.rl) { .ref, .ref_coerced_ty, .ref_const, - => return lhs, + => return gz.addUnNode(.ref_deref, lhs, node), else => { - const result = try gz.addUnNode(.load, lhs, node); + const result = try gz.addUnNode(.deref, lhs, node); return rvalue(gz, ri, result, node); }, } @@ -2759,6 +2758,8 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .mulwrap, .mul_sat, .ref, + .deref, + .ref_deref, .shl, .shl_sat, .shr, @@ -2932,7 +2933,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .memcpy, .memset, .memmove, - .validate_deref, .validate_destructure, .save_err_ret_index, .restore_err_ret_index_unconditional, @@ -3130,7 +3130,7 @@ fn varDecl( } const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node.unwrap()) |align_node| - try expr(gz, scope, coerced_align_ri, align_node) + try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align") else .none; @@ -3477,7 +3477,7 @@ fn assignDestructureMaybeDecls( const this_variable_comptime = is_comptime or (is_const and value_is_comptime); const align_inst: Zir.Inst.Ref = if (full_var_decl.ast.align_node.unwrap()) |align_node| - try expr(gz, scope, coerced_align_ri, align_node) + try comptimeExpr(gz, scope, coerced_align_ri, align_node, .@"align") else .none; @@ -8069,14 +8069,6 @@ fn identifier( if (std.mem.eql(u8, ident_name_raw, "i0")) { return astgen.failNode(ident, "signed integer cannot have bit width 0", .{}); } - if (ident_name_raw[1] == '0') { - assert(ident_name_raw.len >= 3); // `u0` and `i0` handled - return astgen.failNode( - ident, - "primitive integer type '{s}' has leading zero", - .{ident_name_raw}, - ); - } const bit_count = parseBitCount(ident_name_raw[1..]) catch |err| switch (err) { error.Overflow => return astgen.failNode( ident, @@ -8085,6 +8077,14 @@ fn identifier( ), error.InvalidCharacter => break :int_type, }; + if (ident_name_raw[1] == '0') { + assert(ident_name_raw.len >= 3); // `u0` and `i0` handled + return astgen.failNode( + ident, + "primitive integer type '{s}' has leading zero", + .{ident_name_raw}, + ); + } const result = try gz.add(.{ .tag = .int_type, .data = .{ .int_type = .{ @@ -9327,6 +9327,16 @@ fn builtinCall( }); return rvalue(gz, ri, result, node); }, + .SpirvType => { + const spirv_type_options_ty = try gz.addStdLangValue(node, .spirv_type_options); + const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = spirv_type_options_ty } }, params[0], .type); + const result = try gz.addExtendedPayload(.reify_spirv_type, Zir.Inst.ReifySpirvType{ + .src_line = gz.astgen.source_line, + .node = node, + .operand = operand, + }); + return rvalue(gz, ri, result, node); + }, .panic => { try emitDbgNode(gz, node); @@ -11153,7 +11163,7 @@ const Scope = struct { declaring_gz: ?*GenZir, /// Set of captures used by this namespace. - captures: std.AutoArrayHashMapUnmanaged(Zir.Inst.Capture, Zir.NullTerminatedString) = .empty, + captures: std.array_hash_map.Auto(Zir.Inst.Capture, Zir.NullTerminatedString) = .empty, fn deinit(self: *Namespace, gpa: Allocator) void { self.decls.deinit(gpa); @@ -12846,9 +12856,9 @@ fn scanContainer( var bfa_state: std.heap.BufferFirstAllocator = .init(&bfa_buf, astgen.gpa); const bfa = bfa_state.allocator(); - var names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .empty; - var test_names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .empty; - var decltest_names: std.AutoArrayHashMapUnmanaged(Zir.NullTerminatedString, NameEntry) = .empty; + var names: std.array_hash_map.Auto(Zir.NullTerminatedString, NameEntry) = .empty; + var test_names: std.array_hash_map.Auto(Zir.NullTerminatedString, NameEntry) = .empty; + var decltest_names: std.array_hash_map.Auto(Zir.NullTerminatedString, NameEntry) = .empty; defer { names.deinit(bfa); test_names.deinit(bfa); diff --git a/lib/std/zig/AstRlAnnotate.zig b/lib/std/zig/AstRlAnnotate.zig index a316ef79784f36686b8385bf38020e0263dad247..a9b680c39b2a9e01e967ab33f3b03fe43999392a 100644 --- a/lib/std/zig/AstRlAnnotate.zig +++ b/lib/std/zig/AstRlAnnotate.zig @@ -1079,6 +1079,10 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. _ = try astrl.expr(args[3], block, ResultInfo.type_only); return false; }, + .SpirvType => { + _ = try astrl.expr(args[0], block, ResultInfo.type_only); + return false; + }, .Vector => { _ = try astrl.expr(args[0], block, ResultInfo.type_only); _ = try astrl.expr(args[1], block, ResultInfo.type_only); diff --git a/lib/std/zig/AstSmith.zig b/lib/std/zig/AstSmith.zig index 033556654cee53b3f2203840fb347e9f85dae7d3..87cfc0ccf25a19890d263c9dd8726ec9c209ed2a 100644 --- a/lib/std/zig/AstSmith.zig +++ b/lib/std/zig/AstSmith.zig @@ -238,9 +238,6 @@ fn pegToken(a: *AstSmith, tag: Token.Tag) SourceError!void { switch (lexeme[0]) { '_', 'a'...'z', 'A'...'Z', '0'...'9' => try a.preservePegEndOfWord(), - '*' => if (a.tokens_len > 0 and a.source_buf[a.source_len - 1] == '*') { - try a.addSourceByte(' '); - }, '.' => if (a.tokens_len > 0 and switch (a.source_buf[a.source_len - 1]) { '.' => true, '0'...'9', 'a'...'z', 'A'...'Z' => a.token_tag_buf[a.tokens_len - 1] == .number_literal, @@ -1810,7 +1807,7 @@ fn pegPrefixTypeOp(a: *AstSmith) SourceError!void { } /// SuffixOp -/// <- LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET +/// <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET /// / DOT IDENTIFIER /// / DOTASTERISK /// / DOTQUESTIONMARK @@ -1820,12 +1817,14 @@ fn pegSuffixOp(a: *AstSmith) SourceError!void { try a.pegToken(.l_bracket); try a.pegExpr(); - const components = a.smith.value(u2); - if (components >= 1) try a.pegToken(.ellipsis2); - if (components >= 2) try a.pegExpr(); - if (components >= 3) { - try a.pegToken(.colon); - try a.pegExpr(); + if (a.smith.value(bool)) { + try a.pegToken(.ellipsis2); + if (a.smith.value(bool)) + try a.pegExpr(); + if (a.smith.value(bool)) { + try a.pegToken(.colon); + try a.pegExpr(); + } } try a.pegToken(.r_bracket); diff --git a/lib/std/zig/BuiltinFn.zig b/lib/std/zig/BuiltinFn.zig index 1a8fe743cae34a36a715ae50b6bb9ec859e33b03..4464d1fa46c93a1170238627dc5fd0b03c32048e 100644 --- a/lib/std/zig/BuiltinFn.zig +++ b/lib/std/zig/BuiltinFn.zig @@ -114,6 +114,7 @@ pub const Tag = enum { Struct, Union, Enum, + SpirvType, type_info, type_name, TypeOf, @@ -971,6 +972,13 @@ pub const list = list: { .param_count = 4, }, }, + .{ + "@SpirvType", + .{ + .tag = .SpirvType, + .param_count = 1, + }, + }, .{ "@typeInfo", .{ diff --git a/lib/std/zig/LibCDirs.zig b/lib/std/zig/LibCDirs.zig index 7ae4061b0d2acd299259acd5bb833a68128860a9..04c61af0bedab6728309db7c00c975ef4229a57d 100644 --- a/lib/std/zig/LibCDirs.zig +++ b/lib/std/zig/LibCDirs.zig @@ -282,6 +282,8 @@ fn libCGenericName(target: *const std.Target) [:0]const u8 { => return "musl", .eabi, .eabihf, + .abin32, + .x32, .ilp32, .android, .androideabi, diff --git a/lib/std/zig/LibCInstallation.zig b/lib/std/zig/LibCInstallation.zig index daf1fb14cb5e502f881348f2dcb118b4b6a6d696..6fa49a0ce985c9115495a16c862e7d6e1a9062d5 100644 --- a/lib/std/zig/LibCInstallation.zig +++ b/lib/std/zig/LibCInstallation.zig @@ -46,7 +46,7 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const const field_names = comptime std.meta.fieldNames(LibCInstallation); const FoundKey = struct { found: bool, - allocated: ?[:0]u8, + allocated: ?[]u8, }; var found_keys: [field_names.len]FoundKey = @splat(.{ .found = false, .allocated = null }); @@ -60,7 +60,7 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const const contents = try Io.Dir.cwd().readFileAlloc(io, libc_file, allocator, .limited(std.math.maxInt(usize))); defer allocator.free(contents); - var it = std.mem.tokenizeScalar(u8, contents, '\n'); + var it = std.mem.tokenizeAny(u8, contents, "\n\r"); while (it.next()) |line| { if (line.len == 0 or line[0] == '#') continue; var line_it = std.mem.splitScalar(u8, line, '='); @@ -72,7 +72,7 @@ pub fn parse(allocator: Allocator, io: Io, libc_file: []const u8, target: *const if (value.len == 0) { @field(self, field_name) = null; } else { - found_keys[i].allocated = try allocator.dupeSentinel(u8, value, 0); + found_keys[i].allocated = try allocator.dupe(u8, value); @field(self, field_name) = found_keys[i].allocated; } break; diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index c41d5441075e751b7f4b65778ddf0a7b78423e7c..d4c6015131d4c612633e3b87f8da61f0faeaf6a4 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -3137,7 +3137,7 @@ fn parsePtrModifiers(p: *Parse) !PtrModifiers { } /// SuffixOp -/// <- LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET +/// <- LBRACKET Expr (DOT2 Expr? (COLON Expr)?)? RBRACKET /// / DOT IDENTIFIER /// / DOTASTERISK /// / DOTQUESTIONMARK diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index b649b7aff06900a27bf19156ae417eeaa5cfd3bf..49897a755f8a08cedc86d421250a887afe03a720 100644 --- a/lib/std/zig/Zir.zig +++ b/lib/std/zig/Zir.zig @@ -567,12 +567,21 @@ pub const Inst = struct { /// Uses the `pl_node` field with payload `Bin`. merge_error_sets, /// Turns an R-Value into a const L-Value. In other words, it takes a value, - /// stores it in a memory location, and returns a const pointer to it. If the value - /// is `comptime`, the memory location is global static constant data. Otherwise, - /// the memory location is in the stack frame, local to the scope containing the - /// instruction. + /// stores it in a memory location, and returns a const single-item pointer to it. + /// If the value is `comptime`, the memory location is global static constant data. + /// Otherwise, the memory location is in the stack frame, local to the scope + /// containing the instruction. /// Uses the `un_tok` union field. ref, + /// Implements the dereference operand (`.*`). Checks that operand is a pointer + /// that supports being directly dereferenced. + /// Uses the `un_node` union field. + deref, + /// Emitted when a dereference (`.*`) with a reference result location occurs. + /// Checks that operand is a pointer that supports being directly dereferenced + /// and returns a single-item pointer to the dereferenced memory location. + /// Uses the `un_node` union field. + ref_deref, /// Sends control flow back to the function's callee. /// Includes an operand as the return value. /// Includes an AST node source location. @@ -717,9 +726,6 @@ pub const Inst = struct { /// - `if (eu) |payload| {...} else |err| {...}`, AST node is the `if`. /// Uses the `pl_node` union field. Payload is `SwitchBlock`. switch_block_err_union, - /// Check that operand type supports the dereference operand (.*). - /// Uses the `un_node` field. - validate_deref, /// Check that the operand's type is an array or tuple with the given number of elements. /// Uses the `pl_node` field. Payload is `ValidateDestructure`. validate_destructure, @@ -1170,6 +1176,8 @@ pub const Inst = struct { .mulwrap, .mul_sat, .ref, + .deref, + .ref_deref, .shl, .shl_sat, .shr, @@ -1213,7 +1221,6 @@ pub const Inst = struct { .switch_block, .switch_block_ref, .switch_block_err_union, - .validate_deref, .validate_destructure, .union_init, .field_type_ref, @@ -1352,7 +1359,6 @@ pub const Inst = struct { .atomic_store, .store_node, .store_to_inferred_ptr, - .validate_deref, .validate_destructure, .@"export", .set_runtime_safety, @@ -1456,6 +1462,8 @@ pub const Inst = struct { .mulwrap, .mul_sat, .ref, + .deref, + .ref_deref, .shl, .shl_sat, .shr, @@ -1708,6 +1716,8 @@ pub const Inst = struct { .merge_error_sets = .pl_node, .mod_rem = .pl_node, .ref = .un_tok, + .deref = .un_node, + .ref_deref = .un_node, .ret_node = .un_node, .ret_load = .un_node, .ret_implicit = .un_tok, @@ -1744,7 +1754,6 @@ pub const Inst = struct { .switch_block = .pl_node, .switch_block_ref = .pl_node, .switch_block_err_union = .pl_node, - .validate_deref = .un_node, .validate_destructure = .pl_node, .field_type_ref = .pl_node, .union_init = .pl_node, @@ -2055,6 +2064,9 @@ pub const Inst = struct { /// `operand` is payload index to `ReifyEnum`. /// `small` contains `NameStrategy`. reify_enum, + /// Implements builtin `@SpirvType`. + /// `operand` is payload index to `ReifyFn`. + reify_spirv_type, /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins. /// `small` 0=>weak 1=>strong /// `operand` is payload index to `Cmpxchg`. @@ -3269,6 +3281,14 @@ pub const Inst = struct { field_values: Ref, }; + pub const ReifySpirvType = struct { + src_line: u32, + /// This node is absolute, because `reify` instructions are tracked across updates, and + /// this simplifies the logic for getting source locations for types. + node: Ast.Node.Index, + operand: Ref, + }; + /// Trailing: /// 0. multi_cases_len: u32, // If has_multi_cases is set. /// 1. payload_capture_placeholder: Inst.Index, // If payload_capture_inst_is_placeholder is set. @@ -3584,6 +3604,7 @@ pub const Inst = struct { fn_attributes, container_layout, enum_mode, + spirv_type_options, // Values calling_convention_c, calling_convention_inline, @@ -4174,6 +4195,8 @@ fn findTrackableInner( .for_len, .merge_error_sets, .ref, + .deref, + .ref_deref, .ret_node, .ret_load, .ret_implicit, @@ -4207,7 +4230,6 @@ fn findTrackableInner( .enum_literal, .decl_literal, .decl_literal_no_coerce, - .validate_deref, .validate_destructure, .field_type_ref, .opt_eu_base_ptr_init, @@ -4389,6 +4411,7 @@ fn findTrackableInner( .reify_enum, .reify_struct, .reify_union, + .reify_spirv_type, => return contents.other.append(gpa, inst), // Type declarations need tracking. @@ -5181,6 +5204,7 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void { .reify_enum, .reify_struct, .reify_union, + .reify_spirv_type, => {}, // tracked in order, as the owner instructions of explicit container types else => unreachable, // assertion failure; not trackable }, diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 27a1532aab387624bb127e6ee5f2ad341f989ea8..f780e28f5c4d897d8a920c890c38933ea8f0ee85 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -21,25 +21,25 @@ data_layout: String, target_triple: String, module_asm: std.ArrayList(u8), -string_map: std.AutoArrayHashMapUnmanaged(void, void), +string_map: std.array_hash_map.Auto(void, void), string_indices: std.ArrayList(u32), string_bytes: std.ArrayList(u8), -types: std.AutoArrayHashMapUnmanaged(String, Type), +types: std.array_hash_map.Auto(String, Type), next_unnamed_type: String, next_unique_type_id: std.AutoHashMapUnmanaged(String, u32), -type_map: std.AutoArrayHashMapUnmanaged(void, void), +type_map: std.array_hash_map.Auto(void, void), type_items: std.ArrayList(Type.Item), type_extra: std.ArrayList(u32), -attributes: std.AutoArrayHashMapUnmanaged(Attribute.Storage, void), -attributes_map: std.AutoArrayHashMapUnmanaged(void, void), +attributes: std.array_hash_map.Auto(Attribute.Storage, void), +attributes_map: std.array_hash_map.Auto(void, void), attributes_indices: std.ArrayList(u32), attributes_extra: std.ArrayList(u32), -function_attributes_set: std.AutoArrayHashMapUnmanaged(FunctionAttributes, void), +function_attributes_set: std.array_hash_map.Auto(FunctionAttributes, void), -globals: std.AutoArrayHashMapUnmanaged(StrtabString, Global), +globals: std.array_hash_map.Auto(StrtabString, Global), next_unnamed_global: StrtabString, next_replaced_global: StrtabString, next_unique_global_id: std.AutoHashMapUnmanaged(StrtabString, u32), @@ -47,28 +47,28 @@ aliases: std.ArrayList(Alias), variables: std.ArrayList(Variable), functions: std.ArrayList(Function), -strtab_string_map: std.AutoArrayHashMapUnmanaged(void, void), +strtab_string_map: std.array_hash_map.Auto(void, void), strtab_string_indices: std.ArrayList(u32), strtab_string_bytes: std.ArrayList(u8), -constant_map: std.AutoArrayHashMapUnmanaged(void, void), +constant_map: std.array_hash_map.Auto(void, void), constant_items: std.MultiArrayList(Constant.Item), constant_extra: std.ArrayList(u32), constant_limbs: std.ArrayList(std.math.big.Limb), alignment_forward_references: std.ArrayList(Alignment), -metadata_map: std.AutoArrayHashMapUnmanaged(void, void), +metadata_map: std.array_hash_map.Auto(void, void), metadata_items: std.MultiArrayList(Metadata.Item), metadata_extra: std.ArrayList(u32), metadata_limbs: std.ArrayList(std.math.big.Limb), metadata_forward_references: std.ArrayList(Metadata.Optional), -metadata_named: std.AutoArrayHashMapUnmanaged(String, struct { +metadata_named: std.array_hash_map.Auto(String, struct { len: u32, index: Metadata.Item.ExtraIndex, }), -metadata_string_map: std.AutoArrayHashMapUnmanaged(void, void), +metadata_string_map: std.array_hash_map.Auto(void, void), metadata_string_indices: std.ArrayList(u32), metadata_string_bytes: std.ArrayList(u8), @@ -1633,7 +1633,7 @@ pub const FunctionAttributes = enum(u32) { pub const Wip = struct { maps: Maps = .empty, - const Map = std.AutoArrayHashMapUnmanaged(Attribute.Kind, Attribute.Index); + const Map = std.array_hash_map.Auto(Attribute.Kind, Attribute.Index); const Maps = std.ArrayList(Map); pub fn deinit(self: *Wip, builder: *const Builder) void { @@ -1816,7 +1816,7 @@ pub const Linkage = enum(u4) { } }; -pub const Preemption = enum { +pub const Preemption = enum(u2) { dso_preemptable, dso_local, implicit_dso_local, @@ -2011,7 +2011,7 @@ pub const AddrSpace = enum(u24) { } }; -pub const ExternallyInitialized = enum { +pub const ExternallyInitialized = enum(u1) { default, externally_initialized, @@ -2061,6 +2061,13 @@ 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 @enumFromInt(@max(@intFromEnum(a), @intFromEnum(b))); + } + pub fn toLlvm(self: Alignment) u6 { return switch (self) { .default => 0, @@ -4314,6 +4321,9 @@ pub const Function = struct { @"tail call", @"tail call fast", trunc, + @"trunc nuw", + @"trunc nsw", + @"trunc nuw nsw", udiv, @"udiv exact", urem, @@ -4377,7 +4387,10 @@ pub const Function = struct { }; } - pub fn toCastOpcode(self: Tag) CastOpcode { + /// Does not accept `.@"trunc nuw"`, `.@"trunc nsw"`, or `.@"trunc nuw nsw"`, because + /// they do not have distinct `CastOpcode` values, and are instead encoded in bitcode + /// using flags on a normal `trunc` operation. + fn toCastOpcode(self: Tag) CastOpcode { return switch (self) { .trunc => .trunc, .zext => .zext, @@ -4572,6 +4585,9 @@ pub const Function = struct { .sext, .sitofp, .trunc, + .@"trunc nuw", + .@"trunc nsw", + .@"trunc nuw nsw", .uitofp, .zext, => wip.extraData(Cast, instruction.data).type, @@ -4758,6 +4774,9 @@ pub const Function = struct { .sext, .sitofp, .trunc, + .@"trunc nuw", + .@"trunc nsw", + .@"trunc nuw nsw", .uitofp, .zext, => function.extraData(Cast, instruction.data).type, @@ -5235,8 +5254,8 @@ pub const WipFunction = struct { instructions: std.MultiArrayList(Instruction), names: std.ArrayList(String), strip: bool, - debug_locations: std.AutoArrayHashMapUnmanaged(Instruction.Index, DebugLocation), - debug_values: std.AutoArrayHashMapUnmanaged(Instruction.Index, void), + debug_locations: std.array_hash_map.Auto(Instruction.Index, DebugLocation), + debug_values: std.array_hash_map.Auto(Instruction.Index, void), extra: std.ArrayList(u32), pub const Cursor = struct { block: Block.Index, instruction: u32 = 0 }; @@ -5975,6 +5994,9 @@ pub const WipFunction = struct { .sext, .sitofp, .trunc, + .@"trunc nuw", + .@"trunc nsw", + .@"trunc nuw nsw", .uitofp, .zext, => {}, @@ -6583,6 +6605,9 @@ pub const WipFunction = struct { .sext, .sitofp, .trunc, + .@"trunc nuw", + .@"trunc nsw", + .@"trunc nuw nsw", .uitofp, .zext, => { @@ -8451,7 +8476,7 @@ pub const Metadata = packed struct(u32) { const Formatter = struct { builder: *Builder, need_comma: bool, - map: std.AutoArrayHashMapUnmanaged(union(enum) { + map: std.array_hash_map.Auto(union(enum) { metadata: Metadata, debug_location: DebugLocation.Location, }, void) = .empty, @@ -9791,7 +9816,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void } } - var attribute_groups: std.AutoArrayHashMapUnmanaged(Attributes, void) = .empty; + var attribute_groups: std.array_hash_map.Auto(Attributes, void) = .empty; defer attribute_groups.deinit(self.gpa); for (0.., self.functions.items) |function_i, function| { @@ -9975,6 +10000,9 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void .sext, .sitofp, .trunc, + .@"trunc nuw", + .@"trunc nsw", + .@"trunc nuw nsw", .uitofp, .zext, => |tag| { @@ -11649,7 +11677,11 @@ fn convTag( .unneeded => unreachable, }, .eq => unreachable, - .gt => .trunc, + .gt => switch (signedness) { + .unsigned => .@"trunc nuw", + .signed => .@"trunc nsw", + .unneeded => .trunc, + }, }, .pointer => .inttoptr, else => unreachable, @@ -13507,7 +13539,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco try type_block.end(); } - var attributes_set: std.AutoArrayHashMapUnmanaged(struct { + var attributes_set: std.array_hash_map.Auto(struct { attributes: Attributes, index: u32, }, void) = .{}; @@ -13743,7 +13775,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco try paramattr_block.end(); } - var globals: std.AutoArrayHashMapUnmanaged(Global.Index, void) = .empty; + var globals: std.array_hash_map.Auto(Global.Index, void) = .empty; defer globals.deinit(self.gpa); try globals.ensureUnusedCapacity( self.gpa, @@ -13784,7 +13816,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco const ConstantAdapter = struct { builder: *const Builder, - globals: *const std.AutoArrayHashMapUnmanaged(Global.Index, void), + globals: *const std.array_hash_map.Auto(Global.Index, void), pub fn get(adapter: @This(), param: anytype) switch (@TypeOf(param)) { Constant => u32, @@ -13815,7 +13847,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco // Globals { - var section_map: std.AutoArrayHashMapUnmanaged(String, void) = .empty; + var section_map: std.array_hash_map.Auto(String, void) = .empty; defer section_map.deinit(self.gpa); try section_map.ensureUnusedCapacity(self.gpa, globals.count()); @@ -14962,6 +14994,20 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco .opcode = kind.toCastOpcode(), }); }, + .@"trunc nuw", + .@"trunc nsw", + .@"trunc nuw nsw", + => |kind| { + const extra = func.extraData(Function.Instruction.Cast, data); + try function_block.writeAbbrev(FunctionBlock.TruncNoWrap{ + .val = adapter.getOffsetValueIndex(extra.val), + .type_index = extra.type, + .flags = .{ + .no_unsigned_wrap = kind == .@"trunc nuw" or kind == .@"trunc nuw nsw", + .no_signed_wrap = kind == .@"trunc nsw" or kind == .@"trunc nuw nsw", + }, + }); + }, .@"fcmp false", .@"fcmp oeq", .@"fcmp oge", diff --git a/lib/std/zig/llvm/ir.zig b/lib/std/zig/llvm/ir.zig index 00c20c3b425a10ea17d09941c5c8ce1b57ac1a39..397ea34b87041fa8223ff8723cb03c87c5a94b6f 100644 --- a/lib/std/zig/llvm/ir.zig +++ b/lib/std/zig/llvm/ir.zig @@ -696,6 +696,7 @@ pub const ModuleBlock = struct { ModuleBlock.FunctionBlock.Select, ModuleBlock.FunctionBlock.SelectFast, ModuleBlock.FunctionBlock.Cast, + ModuleBlock.FunctionBlock.TruncNoWrap, ModuleBlock.FunctionBlock.Alloca, ModuleBlock.FunctionBlock.GetElementPtr, ModuleBlock.FunctionBlock.ExtractValue, @@ -1086,6 +1087,24 @@ pub const ModuleBlock = struct { opcode: CastOpcode, }; + pub const TruncNoWrap = struct { + pub const Flags = packed struct(u2) { + no_unsigned_wrap: bool, + no_signed_wrap: bool, + }; + pub const ops = [_]AbbrevOp{ + .{ .literal = @intFromEnum(ModuleBlock.FunctionBlock.Code.INST_CAST) }, + ValueAbbrev, + .{ .fixed_runtime = Builder.Type }, + .{ .literal = @intFromEnum(Builder.CastOpcode.trunc) }, + .{ .fixed = @bitSizeOf(Flags) }, + }; + + val: u32, + type_index: Builder.Type, + flags: Flags, + }; + pub const Alloca = struct { pub const Flags = packed struct(u11) { align_lower: u5, diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index c2ad638832ea8e5944324e98adcd65ec65b6322e..d40d442ce88198297f183a00e586aba3991d09e7 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -104,7 +104,7 @@ pub fn getExternalExecutor(io: Io, candidate: *const std.Target, options: GetExt => .{ .qemu = switch (t) { .x86 => "qemu-i386", .x86_64 => switch (candidate.abi) { - .gnux32, .muslx32 => return bad_result, + .gnux32, .muslx32, .x32 => return bad_result, else => "qemu-x86_64", }, else => "qemu-" ++ @tagName(t), @@ -146,7 +146,7 @@ pub fn getExternalExecutor(io: Io, candidate: *const std.Target, options: GetExt .powerpc64 => "qemu-ppc64", .powerpc64le => "qemu-ppc64le", .mips64, .mips64el => switch (candidate.abi) { - .gnuabin32, .muslabin32 => if (t == .mips64el) "qemu-mipsn32el" else "qemu-mipsn32", + .gnuabin32, .muslabin32, .abin32 => if (t == .mips64el) "qemu-mipsn32el" else "qemu-mipsn32", else => "qemu-" ++ @tagName(t), }, // TODO: Actually check the SuperH version. diff --git a/lib/std/zip.zig b/lib/std/zip.zig index be2a442f3de66e0cb0f912868de26e07fd180d66..3784605d0227653b8424dbc5345ff55a481878b0 100644 --- a/lib/std/zip.zig +++ b/lib/std/zip.zig @@ -164,50 +164,6 @@ pub const EndRecord = extern struct { } }; -pub const Decompress = struct { - interface: Reader, - state: union { - inflate: flate.Decompress, - store: *Reader, - }, - - pub fn init(reader: *Reader, method: CompressionMethod, buffer: []u8) Reader { - return switch (method) { - .store => .{ - .state = .{ .store = reader }, - .interface = .{ - .context = undefined, - .vtable = &.{ .stream = streamStore }, - .buffer = buffer, - .end = 0, - .seek = 0, - }, - }, - .deflate => .{ - .state = .{ .inflate = .init(reader, .raw) }, - .interface = .{ - .context = undefined, - .vtable = &.{ .stream = streamDeflate }, - .buffer = buffer, - .end = 0, - .seek = 0, - }, - }, - else => unreachable, - }; - } - - fn streamStore(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize { - const d: *Decompress = @fieldParentPtr("interface", r); - return d.store.read(w, limit); - } - - fn streamDeflate(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize { - const d: *Decompress = @fieldParentPtr("interface", r); - return flate.Decompress.read(&d.inflate, w, limit); - } -}; - fn isBadFilename(filename: []const u8) bool { if (filename.len == 0 or filename[0] == '/') return true; @@ -457,15 +413,7 @@ pub const Iterator = struct { uncompressed_size: u64, file_offset: u64, - pub fn extract( - self: Entry, - stream: *File.Reader, - options: ExtractOptions, - filename_buf: []u8, - dest: Io.Dir, - ) !void { - const io = stream.io; - + pub fn getFilename(self: Entry, stream: *File.Reader, filename_buf: []u8, options: ExtractOptions) ![]u8 { if (filename_buf.len < self.filename_len) return error.ZipInsufficientBuffer; switch (self.compression_method) { @@ -478,6 +426,25 @@ pub const Iterator = struct { try stream.interface.readSliceAll(filename); } + if (options.allow_backslashes) { + std.mem.replaceScalar(u8, filename, '\\', '/'); + } else { + if (std.mem.findScalar(u8, filename, '\\')) |_| + return error.ZipFilenameHasBackslash; + } + + if (isBadFilename(filename)) + return error.ZipBadFilename; + + return filename; + } + + pub fn extractTo(self: Entry, stream: *File.Reader, w: *Writer) !void { + switch (self.compression_method) { + .store, .deflate => {}, + else => return error.UnsupportedCompressionMethod, + } + const local_data_header_offset: u64 = local_data_header_offset: { const local_header = blk: { try stream.seekTo(self.file_offset); @@ -540,15 +507,45 @@ pub const Iterator = struct { @as(u64, local_header.extra_len); }; - if (options.allow_backslashes) { - std.mem.replaceScalar(u8, filename, '\\', '/'); - } else { - if (std.mem.findScalar(u8, filename, '\\')) |_| - return error.ZipFilenameHasBackslash; + const local_data_file_offset: u64 = + @as(u64, self.file_offset) + + @as(u64, @sizeOf(LocalFileHeader)) + + local_data_header_offset; + try stream.seekTo(local_data_file_offset); + + // TODO limit based on self.compressed_size + + switch (self.compression_method) { + .store => { + stream.interface.streamExact64(w, self.uncompressed_size) catch |err| switch (err) { + error.ReadFailed => |e| return stream.err orelse e, + error.WriteFailed => |e| return e, + error.EndOfStream => return error.ZipDecompressTruncated, + }; + }, + .deflate => { + var flate_buffer: [flate.max_window_len]u8 = undefined; + var decompress: flate.Decompress = .init(&stream.interface, .raw, &flate_buffer); + decompress.reader.streamExact64(w, self.uncompressed_size) catch |err| switch (err) { + error.ReadFailed => |e| return decompress.err orelse (stream.err orelse e), + error.WriteFailed => |e| return e, + error.EndOfStream => return error.ZipDecompressTruncated, + }; + }, + else => return error.UnsupportedCompressionMethod, } + } - if (isBadFilename(filename)) - return error.ZipBadFilename; + pub fn extract( + self: Entry, + stream: *File.Reader, + options: ExtractOptions, + filename_buf: []u8, + dest: Io.Dir, + ) !void { + const io = stream.io; + + const filename = try self.getFilename(stream, filename_buf, options); // All entries that end in '/' are directories if (filename[filename.len - 1] == '/') { @@ -571,33 +568,10 @@ pub const Iterator = struct { defer out_file.close(io); var out_file_buffer: [1024]u8 = undefined; var file_writer = out_file.writer(io, &out_file_buffer); - const local_data_file_offset: u64 = - @as(u64, self.file_offset) + - @as(u64, @sizeOf(LocalFileHeader)) + - local_data_header_offset; - try stream.seekTo(local_data_file_offset); - - // TODO limit based on self.compressed_size - - switch (self.compression_method) { - .store => { - stream.interface.streamExact64(&file_writer.interface, self.uncompressed_size) catch |err| switch (err) { - error.ReadFailed => return stream.err.?, - error.WriteFailed => return file_writer.err.?, - error.EndOfStream => return error.ZipDecompressTruncated, - }; - }, - .deflate => { - var flate_buffer: [flate.max_window_len]u8 = undefined; - var decompress: flate.Decompress = .init(&stream.interface, .raw, &flate_buffer); - decompress.reader.streamExact64(&file_writer.interface, self.uncompressed_size) catch |err| switch (err) { - error.ReadFailed => return stream.err.?, - error.WriteFailed => return file_writer.err orelse decompress.err.?, - error.EndOfStream => return error.ZipDecompressTruncated, - }; - }, - else => return error.UnsupportedCompressionMethod, - } + self.extractTo(stream, &file_writer.interface) catch |err| switch (err) { + error.WriteFailed => |e| return file_writer.err orelse e, + else => return err, + }; try file_writer.end(); } }; @@ -664,3 +638,85 @@ pub fn extract(dest: Io.Dir, fr: *File.Reader, options: ExtractOptions) !void { } } } + +const testing = std.testing; + +test "extractTo" { + const io = testing.io; + var tmp = testing.tmpDir(.{}); + defer tmp.cleanup(); + + try tmp.dir.writeFile(io, .{ + .sub_path = "test.zip", + .data = @embedFile("zip/testdata/test.zip"), + }); + + var file = try tmp.dir.openFile(io, "test.zip", .{}); + defer file.close(io); + var read_buf: [512]u8 = undefined; + var reader = file.reader(io, &read_buf); + + const Expected = struct { + contents: []const u8, + compression: CompressionMethod, + }; + const expected_map = std.StaticStringMap(Expected).initComptime(.{ + .{ "deflate.txt", Expected{ .contents = "aaaaaaaaaaaaaaaaaaaaaaaa\n", .compression = .deflate } }, + .{ "store.txt", Expected{ .contents = "hello world\n", .compression = .store } }, + .{ "dir/", Expected{ .contents = "", .compression = .store } }, + }); + + var iter = try Iterator.init(&reader); + var num_entries: usize = 0; + while (try iter.next()) |entry| { + var filename_buf: [256]u8 = undefined; + const filename = try entry.getFilename(&reader, &filename_buf, .{}); + const expected = expected_map.get(filename) orelse { + std.debug.print("found unexpected filename: {f}\n", .{std.ascii.hexEscape(filename, .lower)}); + return error.UnexpectedFilename; + }; + var buf: [256]u8 = undefined; + var w: Writer = .fixed(&buf); + try entry.extractTo(&reader, &w); + try testing.expectEqualStrings(expected.contents, w.buffered()); + try testing.expectEqual(expected.compression, entry.compression_method); + num_entries += 1; + } + try testing.expectEqual(expected_map.kvs.len, num_entries); +} + +test "output buffers too small" { + const io = testing.io; + var tmp = testing.tmpDir(.{}); + defer tmp.cleanup(); + + try tmp.dir.writeFile(io, .{ + .sub_path = "test.zip", + .data = @embedFile("zip/testdata/test.zip"), + }); + + var file = try tmp.dir.openFile(io, "test.zip", .{}); + defer file.close(io); + var read_buf: [512]u8 = undefined; + var reader = file.reader(io, &read_buf); + + var iter = try Iterator.init(&reader); + var num_entries: usize = 0; + while (try iter.next()) |entry| { + try testing.expectError( + error.ZipInsufficientBuffer, + entry.getFilename(&reader, &.{}, .{}), + ); + + if (entry.uncompressed_size <= 1) continue; + + var buf: [1]u8 = undefined; + var w: Writer = .fixed(&buf); + try testing.expectError( + error.WriteFailed, + entry.extractTo(&reader, &w), + ); + num_entries += 1; + } + try std.testing.expect(num_entries > 0); +} diff --git a/lib/std/zip/testdata/test.zip b/lib/std/zip/testdata/test.zip new file mode 100644 index 0000000000000000000000000000000000000000..48127af3be38d314f7195e3b4aea166ee3a55805 Binary files /dev/null and b/lib/std/zip/testdata/test.zip differ diff --git a/lib/std/zon/Serializer.zig b/lib/std/zon/Serializer.zig index c9809e30838f4b790ce1a9e7969dfbc4859ccec9..ec8456bcc964e6724862fce7392a13e01220dc1a 100644 --- a/lib/std/zon/Serializer.zig +++ b/lib/std/zon/Serializer.zig @@ -854,6 +854,7 @@ fn canSerializeTypeInner( .frame, .@"anyframe", .@"opaque", + .spirv, => false, .@"enum" => |@"enum"| @"enum".mode == .exhaustive, diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index 49ea45e03420e75bbafce4be577b8b93877f04d2..249dc9b644ce80553568bfd5dfb77291ec6bf60c 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -1173,7 +1173,9 @@ const Parser = struct { }; fn intFromFloatExact(T: type, value: anytype) ?T { - if (value > std.math.maxInt(T) or value < std.math.minInt(T)) { + const max: @TypeOf(value) = @floatFromInt(std.math.maxInt(T)); + const min: @TypeOf(value) = @floatFromInt(std.math.minInt(T)); + if (value > max or value < min) { return null; } @@ -1213,6 +1215,7 @@ fn canParseTypeInner( .frame, .@"anyframe", .@"opaque", + .spirv, .comptime_int, .comptime_float, .enum_literal, @@ -2447,6 +2450,7 @@ test "std.zon intFromFloatExact" { try std.testing.expectEqual(@as(u8, 10), intFromFloatExact(u8, @as(f32, 10.0)).?); try std.testing.expectEqual(@as(i8, -123), intFromFloatExact(i8, @as(f64, @as(f64, -123.0))).?); try std.testing.expectEqual(@as(i16, 45), intFromFloatExact(i16, @as(f128, @as(f128, 45.0))).?); + try std.testing.expectEqual(@as(u128, 67), intFromFloatExact(u128, @as(f128, @as(f128, 67.0))).?); // Out of range try std.testing.expectEqual(@as(?u4, null), intFromFloatExact(u4, @as(f32, 16.0))); @@ -2489,6 +2493,10 @@ test "std.zon parse int" { @as(u65, 36893488147419103231), try fromSlice(u65, gpa, "368934_881_474191032_31", null, .{}), ); + try std.testing.expectEqual( + @as(u128, 340282366920938463463374607431768211455), + try fromSlice(u128, gpa, "340282366920938463463374607431768211455", null, .{}), + ); // Test big integer limits try std.testing.expectEqual( diff --git a/lib/zig.h b/lib/zig.h index 4f8b2da1d7de0ddcbd6d7df8c1b85d563349d7c1..34b56286a508b2707f4498f49612d9d625ee7c86 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -4557,9 +4557,12 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a #include #endif +static inline void* zig_e_zig_windows_teb(void) zig_mangled(zig_e_zig_windows_teb, "zig_windows_teb"); +static inline void* zig_e_zig_windows_peb(void) zig_mangled(zig_e_zig_windows_peb, "zig_windows_peb"); + #if defined(zig_thumb) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); @@ -4571,7 +4574,7 @@ static inline void* zig_windows_teb(void) { #elif defined(zig_aarch64) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readx18qword(0x0); @@ -4583,7 +4586,7 @@ static inline void* zig_windows_teb(void) { #elif defined(zig_x86_32) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readfsdword(0x18); @@ -4593,7 +4596,7 @@ static inline void* zig_windows_teb(void) { return teb; } -static inline void* zig_windows_peb(void) { +static inline void* zig_e_zig_windows_peb(void) { void* peb = 0; #if defined(zig_msvc) peb = (void*)__readfsdword(0x30); @@ -4605,7 +4608,7 @@ static inline void* zig_windows_peb(void) { #elif defined(zig_x86_64) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readgsqword(0x30); @@ -4615,7 +4618,7 @@ static inline void* zig_windows_teb(void) { return teb; } -static inline void* zig_windows_peb(void) { +static inline void* zig_e_zig_windows_peb(void) { void* peb = 0; #if defined(zig_msvc) peb = (void*)__readgsqword(0x60); @@ -4629,7 +4632,9 @@ static inline void* zig_windows_peb(void) { #if defined(zig_loongarch) -static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { +static inline void zig_e_zig_loongarch_cpucfg(uint32_t word, uint32_t* result) zig_mangled(zig_e_zig_loongarch_cpucfg, "zig_loongarch_cpucfg"); + +static inline void zig_e_zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { #if defined(zig_gnuc_asm) __asm__("cpucfg %[result], %[word]" : [result] "=r" (result) : [word] "r" (word)); #else @@ -4639,7 +4644,10 @@ static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { #elif defined(zig_x86) && !defined(zig_x86_16) -static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { +static inline void zig_e_zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) zig_mangled(zig_e_zig_x86_cpuid, "zig_x86_cpuid"); +static inline uint32_t zig_e_zig_x86_get_xcr0(void) zig_mangled(zig_e_zig_x86_get_xcr0, "zig_x86_get_xcr0"); + +static inline void zig_e_zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { #if defined(zig_msvc) int cpu_info[4]; __cpuidex(cpu_info, leaf_id, subid); @@ -4657,7 +4665,7 @@ static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax #endif } -static inline uint32_t zig_x86_get_xcr0(void) { +static inline uint32_t zig_e_zig_x86_get_xcr0(void) { #if defined(zig_msvc) return (uint32_t)_xgetbv(0); #elif defined(zig_gnuc_asm) diff --git a/src/Air.zig b/src/Air.zig index fd551de1a5195e3b46c13bd76e42160647104919..baaa70d7e2230274ac91508f4e04e2e7b7ad82d6 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -17,6 +17,7 @@ const print = @import("Air/print.zig"); pub const Legalize = @import("Air/Legalize.zig"); pub const Liveness = @import("Air/Liveness.zig"); +pub const Verify = @import("Air/Verify.zig"); instructions: std.MultiArrayList(Inst).Slice, /// The meaning of this data is determined by `Inst.Tag` value. @@ -276,10 +277,50 @@ pub const Inst = struct { /// Boolean or binary NOT. /// Uses the `ty_op` field. not, - /// Reinterpret the bits of a value as a different type. This is like `@bitCast` but - /// also supports enums and pointers. + /// Implements `@bitCast`. + /// /// Uses the `ty_op` field. - bitcast, + bit_cast, + /// Cast a pointer to a different pointer type. The result type is a slice iff the operand + /// type is a slice (the length of the slice does not change). All other pointer attributes + /// except for the address space may change. + /// + /// Supports vectors of pointers. + /// + /// Uses the `ty_op` field. + ptr_cast, + /// Cast an integer to a pointer (not a slice). Operand type is always `usize`. + /// + /// Supports vectors of integers. + /// + /// Uses the `ty_op` field. + ptr_from_int, + /// Cast a pointer (not a slice) to an integer. Result type is always `usize`. + /// + /// Supports vectors of pointers. + /// + /// Uses the `ty_op` field. + int_from_ptr, + /// Cast an error set `E1` to a different error set `E2`, or cast an error union `E1!T` to + /// an error union `E2!T` with the same payload type but a different error set type. + /// + /// Uses the `ty_op` field. + error_cast, + /// Cast an integer to an error set type. The integer operand type is unsigned and has bit + /// width equal to `zcu.errorSetBits()`. + /// + /// Uses the `ty_op` field. + error_from_int, + /// Cast an error set to an integer type. The integer destination type is unsigned and has + /// bit width equal to `zcu.errorSetBits()`. + /// + /// Uses the `ty_op` field. + int_from_error, + /// Cast an enum value to a tagged union, whose tag type is that enum, and which has no + /// payload bits (i.e. all payloads are equivalent to `void`). + /// + /// Uses the `ty_op` field. + union_from_enum, /// A block runs its body which always ends with a `noreturn` instruction, /// so the only way to proceed to the code after the `block` is to encounter a `br` /// that targets this `block`. If the `block` type is `noreturn`, @@ -589,13 +630,13 @@ pub const Inst = struct { /// the integer tag type of the enum. /// See `trunc` for integer truncation. /// Uses the `ty_op` field. - intcast, - /// Like `intcast`, but includes two safety checks: + int_cast, + /// Like `int_cast`, but includes two safety checks: /// * triggers a safety panic if the cast truncates bits /// * triggers a safety panic if the destination type is an exhaustive enum /// and the operand is not a valid value of this type; i.e. equivalent to /// a safety check based on `.is_named_enum_value` - intcast_safe, + int_cast_safe, /// Truncate higher bits from an integer, resulting in an integer type with the same /// sign but an equal or smaller number of bits. /// Uses the `ty_op` field. @@ -918,6 +959,11 @@ pub const Inst = struct { /// Uses the `ty` field. c_va_start, + /// Implements `.len` field for `@SpirvType(.{ .runtime_array = T })`. + /// Result type is always `u32`. + /// Uses the `ty_pl` field, payload is `StructField`. + spirv_runtime_array_len, + /// Implements @workItemId builtin. /// Result type is always `u32` /// Uses the `pl_op` field, payload is the dimension to get the work item id for. @@ -950,7 +996,7 @@ pub const Inst = struct { /// here is runtime-known, which is usually not allowed for vectors. `Legalize` may emit /// this instruction when scalarizing vector operations. /// - /// Uses the `bin_op` field. `lhs` is the vector pointer. `rhs` is the element index. Result + /// Uses the `bin_op` field. `lhs` is the vector value. `rhs` is the element index. Result /// type is the vector element type. legalize_vec_elem_val, @@ -1662,12 +1708,19 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) => return datas[@intFromEnum(inst)].ty_pl.ty.toType(), .not, - .bitcast, + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, .load, .fpext, .fptrunc, - .intcast, - .intcast_safe, + .int_cast, + .int_cast_safe, .trunc, .optional_payload, .optional_payload_ptr, @@ -1793,6 +1846,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) .work_item_id, .work_group_size, .work_group_id, + .spirv_runtime_array_len, => return .u32, .legalize_compiler_rt_call => return datas[@intFromEnum(inst)].legalize_compiler_rt_call.func.returnType(), @@ -1907,7 +1961,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .add_safe, .sub_safe, .mul_safe, - .intcast_safe, + .int_cast_safe, .int_from_float_safe, .int_from_float_optimized_safe, .legalize_vec_store_elem, @@ -1959,7 +2013,14 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .shl_sat, .xor, .not, - .bitcast, + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, .ret_addr, .frame_addr, .clz, @@ -2003,7 +2064,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .is_non_err, .fptrunc, .fpext, - .intcast, + .int_cast, .trunc, .optional_payload, .optional_payload_ptr, @@ -2056,6 +2117,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { .work_group_size, .work_group_id, .legalize_vec_elem_val, + .spirv_runtime_array_len, => false, .is_non_null_ptr, .is_null_ptr, .is_non_err_ptr, .is_err_ptr => air.typeOf(data.un_op, ip).isVolatilePtrIp(ip), diff --git a/src/Air/Legalize.zig b/src/Air/Legalize.zig index 5b9c4031a93abe2bd4258a641faf5cea633f8b9c..370666280c21b0d8306888c17fd7a87acd4f8b85 100644 --- a/src/Air/Legalize.zig +++ b/src/Air/Legalize.zig @@ -75,13 +75,9 @@ pub const Feature = enum { scalarize_shl_sat, scalarize_xor, scalarize_not, - /// Scalarize `bitcast` from or to an array or vector type to `bitcast`s of the elements. - /// This does not apply if `@bitSizeOf(Elem) == 8 * @sizeOf(Elem)`. - /// When this feature is enabled, all remaining `bitcast`s can be lowered using the old bitcast - /// semantics (reinterpret memory) instead of the new bitcast semantics (copy logical bits) and - /// the behavior will be equivalent. However, the behavior of `@bitSize` on arrays must be - /// changed in `Type.zig` before enabling this feature to conform to the new bitcast semantics. - scalarize_bitcast, + scalarize_ptr_cast, + scalarize_ptr_from_int, + scalarize_int_from_ptr, scalarize_clz, scalarize_ctz, scalarize_popcount, @@ -107,8 +103,8 @@ pub const Feature = enum { scalarize_cmp_vector_optimized, scalarize_fptrunc, scalarize_fpext, - scalarize_intcast, - scalarize_intcast_safe, + scalarize_int_cast, + scalarize_int_cast_safe, scalarize_trunc, scalarize_int_from_float, scalarize_int_from_float_optimized, @@ -122,16 +118,45 @@ pub const Feature = enum { scalarize_select, scalarize_mul_add, + // Below are several different features for scalarizing `bit_cast` in different scenarios. It is + // valid to enable any combination of these features. + + /// Scalarize `bit_cast` where the operand or result type is an array. + scalarize_bit_cast_array, + /// Scalarize `bit_cast` where either: + /// + /// * operand type is `@Vector(n, A), but result type is not `@Vector(n, B)`; or + /// * result type is `@Vector(n, A), but operand type is not `@Vector(n, B)` + /// + /// This effectively scalarizes any `bit_cast` to/from a vector, *unless* the operation can be + /// performed by bitcasting each vector element and returning a vector of the results. + /// + /// If this feature is enabled, the following AIR instruction tags may be emitted: + /// * `.legalize_vec_elem_val` + /// * `.legalize_vec_store_elem` + scalarize_bit_cast_vector_non_elementwise, + /// Scalarize `bit_cast` where the operand or result type is an array or vector whose element + /// type `E` has `@bitSizeOf(E) != 8 * @sizeOf(E)`. These are the cases where the backend may + /// need to sign- or zero-extend multiple elements to populate "padding" bits. + /// + /// Enabling this feature requires changing the behavior of `@bitSize` on arrays in `Type.zig` + /// to conform to the new bitcast semantics. + /// + /// If this feature is enabled, the following AIR instruction tags may be emitted: + /// * `.legalize_vec_elem_val` + /// * `.legalize_vec_store_elem` + scalarize_bit_cast_padded_elems, + /// Legalize (shift lhs, (splat rhs)) -> (shift lhs, rhs) unsplat_shift_rhs, /// Legalize reduce of a one element vector to a bitcast. - reduce_one_elem_to_bitcast, + reduce_one_elem_to_bit_cast, /// Legalize splat to a one element vector to a bitcast. - splat_one_elem_to_bitcast, + splat_one_elem_to_bit_cast, - /// Replace `intcast_safe` with an explicit safety check which `call`s the panic function on failure. - /// Not compatible with `scalarize_intcast_safe`. - expand_intcast_safe, + /// Replace `int_cast_safe` with an explicit safety check which `call`s the panic function on failure. + /// Not compatible with `scalarize_int_cast_safe`. + expand_int_cast_safe, /// Replace `int_from_float_safe` with an explicit safety check which `call`s the panic function on failure. /// Not compatible with `scalarize_int_from_float_safe`. expand_int_from_float_safe, @@ -156,9 +181,9 @@ pub const Feature = enum { /// Currently assumes little endian and a specific integer layout where the lsb of every integer is the lsb of the /// first byte of memory until bit pointers know their backing type. expand_packed_store, - /// Replace `struct_field_val` of a packed field with a `bitcast` to integer, `shr`, `trunc`, and `bitcast` to field type. + /// Replace `struct_field_val` of a packed field with a `bit_cast` to integer, `shr`, `trunc`, and `bit_cast` to field type. expand_packed_struct_field_val, - /// Replace `aggregate_init` of a packed struct with a sequence of `shl_exact`, `bitcast`, `intcast`, and `bit_or`. + /// Replace `aggregate_init` of a packed struct with a sequence of `shl_exact`, `bit_cast`, `int_cast`, and `bit_or`. expand_packed_aggregate_init, /// Replace all arithmetic operations on 16-bit floating-point types with calls to soft-float @@ -227,7 +252,6 @@ pub const Feature = enum { .shl_sat => .scalarize_shl_sat, .xor => .scalarize_xor, .not => .scalarize_not, - .bitcast => .scalarize_bitcast, .clz => .scalarize_clz, .ctz => .scalarize_ctz, .popcount => .scalarize_popcount, @@ -253,8 +277,11 @@ pub const Feature = enum { .cmp_vector_optimized => .scalarize_cmp_vector_optimized, .fptrunc => .scalarize_fptrunc, .fpext => .scalarize_fpext, - .intcast => .scalarize_intcast, - .intcast_safe => .scalarize_intcast_safe, + .int_cast => .scalarize_int_cast, + .int_cast_safe => .scalarize_int_cast_safe, + .ptr_cast => .scalarize_ptr_cast, + .ptr_from_int => .scalarize_ptr_from_int, + .int_from_ptr => .scalarize_int_from_ptr, .trunc => .scalarize_trunc, .int_from_float => .scalarize_int_from_float, .int_from_float_optimized => .scalarize_int_from_float_optimized, @@ -474,7 +501,10 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { .popcount, .byte_swap, .bit_reverse, - .intcast, + .int_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, .trunc, => |air_tag| if (l.features.has(comptime .scalarize(air_tag))) { const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op; @@ -548,15 +578,19 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { }, } }, - .bitcast => if (l.features.has(.scalarize_bitcast)) { + .bit_cast => if (l.features.hasAny(&.{ + .scalarize_bit_cast_array, + .scalarize_bit_cast_vector_non_elementwise, + .scalarize_bit_cast_padded_elems, + })) { if (try l.scalarizeBitcastBlockPayload(inst)) |payload| { continue :inst l.replaceInst(inst, .block, payload); } }, - .intcast_safe => if (l.features.has(.expand_intcast_safe)) { - assert(!l.features.has(.scalarize_intcast_safe)); // it doesn't make sense to do both + .int_cast_safe => if (l.features.has(.expand_int_cast_safe)) { + assert(!l.features.has(.scalarize_int_cast_safe)); // it doesn't make sense to do both continue :inst l.replaceInst(inst, .block, try l.safeIntcastBlockPayload(inst)); - } else if (l.features.has(.scalarize_intcast_safe)) { + } else if (l.features.has(.scalarize_int_cast_safe)) { const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op; if (ty_op.ty.toType().isVector(zcu)) { continue :inst l.replaceInst(inst, .block, try l.scalarizeBlockPayload(inst, .ty_op)); @@ -772,10 +806,10 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { inline .reduce, .reduce_optimized => |air_tag| { const reduce = l.air_instructions.items(.data)[@intFromEnum(inst)].reduce; const vector_ty = l.typeOf(reduce.operand); - if (l.features.has(.reduce_one_elem_to_bitcast)) { + if (l.features.has(.reduce_one_elem_to_bit_cast)) { switch (vector_ty.vectorLen(zcu)) { 0 => unreachable, - 1 => continue :inst l.replaceInst(inst, .bitcast, .{ .ty_op = .{ + 1 => continue :inst l.replaceInst(inst, .bit_cast, .{ .ty_op = .{ .ty = .fromType(vector_ty.childType(zcu)), .operand = reduce.operand, } }), @@ -792,11 +826,11 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { .soft_float => unreachable, // the operand is not a scalar } }, - .splat => if (l.features.has(.splat_one_elem_to_bitcast)) { + .splat => if (l.features.has(.splat_one_elem_to_bit_cast)) { const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op; switch (ty_op.ty.toType().vectorLen(zcu)) { 0 => unreachable, - 1 => continue :inst l.replaceInst(inst, .bitcast, .{ .ty_op = .{ + 1 => continue :inst l.replaceInst(inst, .bit_cast, .{ .ty_op = .{ .ty = ty_op.ty, .operand = ty_op.operand, } }), @@ -862,7 +896,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { const field_bits = agg_ty.fieldType(field_index, zcu).bitSize(zcu); if (field_bits == struct_bits) { // Just bitcast this field. - continue :inst l.replaceInst(inst, .bitcast, .{ .ty_op = .{ + continue :inst l.replaceInst(inst, .bit_cast, .{ .ty_op = .{ .ty = .fromType(agg_ty), .operand = @enumFromInt(l.air_extra.items[ty_pl.payload + field_index]), } }); @@ -908,6 +942,11 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { .legalize_vec_elem_val, .legalize_vec_store_elem, .legalize_compiler_rt_call, + .spirv_runtime_array_len, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, => {}, } } @@ -930,7 +969,7 @@ fn scalarizeBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, form: Scalariz if (result_is_array) { // This is only allowed when legalizing an elementwise bitcast. - assert(orig.tag == .bitcast); + assert(orig.tag == .bit_cast); assert(form == .ty_op); } @@ -1422,35 +1461,94 @@ fn scalarizeBitcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!? const ty_op = l.air_instructions.items(.data)[@intFromEnum(orig_inst)].ty_op; const dest_ty = ty_op.ty.toType(); - const dest_legal = switch (dest_ty.zigTypeTag(zcu)) { - else => true, - .array, .vector => legal: { - if (dest_ty.arrayLen(zcu) == 1) break :legal true; - const dest_elem_ty = dest_ty.childType(zcu); - break :legal dest_elem_ty.bitSize(zcu) == 8 * dest_elem_ty.abiSize(zcu); - }, - }; - const operand_ty = l.typeOf(ty_op.operand); - const operand_legal = switch (operand_ty.zigTypeTag(zcu)) { - else => true, - .array, .vector => legal: { - if (operand_ty.arrayLen(zcu) == 1) break :legal true; - const operand_elem_ty = operand_ty.childType(zcu); - break :legal operand_elem_ty.bitSize(zcu) == 8 * operand_elem_ty.abiSize(zcu); - }, + + // We exit this block only if the scalarization is actually necessary. Otherwise we will return + // `null` from within the block. + const operand_to_int_ok: bool, const int_to_dest_ok: bool = int_ok: { + const operand_tag = operand_ty.zigTypeTag(zcu); + const dest_tag = dest_ty.zigTypeTag(zcu); + + if (operand_tag != .array and + operand_tag != .vector and + dest_tag != .array and + dest_tag != .vector) + { + return null; + } + + // We track the validity of 3 different bitcast operations: + // * operand -> dest + // * operand -> uint + // * uint -> dest + // If operand->dest turns out to be valid, we don't need to scalarize. Otherwise, knowing + // the validity of the other operations helps us lower the scalarization efficiently. + var operand_to_dest: bool = true; + var operand_to_int: bool = true; + var int_to_dest: bool = true; + + if (l.features.has(.scalarize_bit_cast_array)) { + if (operand_tag == .array) { + operand_to_dest = false; + operand_to_int = false; + } + if (dest_tag == .array) { + operand_to_dest = false; + int_to_dest = false; + } + } + + if (l.features.has(.scalarize_bit_cast_vector_non_elementwise)) { + if (operand_tag == .vector) operand_to_int = false; + if (dest_tag == .vector) int_to_dest = false; + + if (operand_tag == .vector or dest_tag == .vector) { + if (operand_tag != .vector or + dest_tag != .vector or + operand_ty.vectorLen(zcu) != dest_ty.vectorLen(zcu)) + { + operand_to_dest = false; + } + } + } + + if (l.features.has(.scalarize_bit_cast_padded_elems)) { + if (operand_tag == .array or operand_tag == .vector) { + const elem_ty = operand_ty.childType(zcu); + if (elem_ty.bitSize(zcu) != 8 * elem_ty.abiSize(zcu)) { + operand_to_int = false; + operand_to_dest = false; + } + } + if (dest_tag == .array or dest_tag == .vector) { + const elem_ty = dest_ty.childType(zcu); + if (elem_ty.bitSize(zcu) != 8 * elem_ty.abiSize(zcu)) { + int_to_dest = false; + operand_to_dest = false; + } + } + } + + if (operand_to_dest) { + return null; // no scalarization needed! + } + + // We need a scalarization, but before breaking from the block, check if we can do it + // elementwise---if we can, that's preferable to the generic lowering. + if ((operand_tag == .array or operand_tag == .vector) and + (dest_tag == .array or dest_tag == .vector) and + operand_ty.arrayLenIncludingSentinel(zcu) == dest_ty.arrayLenIncludingSentinel(zcu)) + { + // Operand and result types are both arrays/vectors whose element types have the same + // bit size, so we can do an elementwise bitcast. + return try l.scalarizeBlockPayload(orig_inst, .ty_op); + } + + break :int_ok .{ operand_to_int, int_to_dest }; }; - if (dest_legal and operand_legal) return null; - - if (!operand_legal and !dest_legal and operand_ty.arrayLen(zcu) == dest_ty.arrayLen(zcu)) { - // from_ty and to_ty are both arrays or vectors of types with the same bit size, - // so we can do an elementwise bitcast. - return try l.scalarizeBlockPayload(orig_inst, .ty_op); - } - - // Fallback path. Our strategy is to use an unsigned integer type as an intermediate - // "bag of bits" representation which can be manipulated by bitwise operations. + // Generic scalarization implementation. Our strategy is to use an unsigned integer type as an + // intermediate "bag of bits" representation which can be manipulated by bitwise operations. const num_bits: u16 = @intCast(dest_ty.bitSize(zcu)); assert(operand_ty.bitSize(zcu) == num_bits); @@ -1464,11 +1562,17 @@ fn scalarizeBitcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!? // First, convert `operand_ty` to `uint_ty` (`uN`). const uint_val: Air.Inst.Ref = uint_val: { - if (operand_legal) { + if (operand_to_int_ok) { _ = main_block.stealCapacity(19); break :uint_val main_block.addBitCast(l, uint_ty, ty_op.operand); } + if (operand_ty.arrayLenIncludingSentinel(zcu) == 1) { + _ = main_block.stealCapacity(18); + const elem = main_block.addBinOp(l, .array_elem_val, ty_op.operand, .zero_usize).toRef(); + break :uint_val main_block.addBitCast(l, uint_ty, elem); + } + // %1 = block({ // %2 = alloc(*usize) // %3 = alloc(*uN) @@ -1477,8 +1581,8 @@ fn scalarizeBitcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!? // %6 = loop({ // %7 = load(%2) // %8 = array_elem_val(orig_operand, %7) - // %9 = bitcast(uE, %8) - // %10 = intcast(uN, %9) + // %9 = bit_cast(uE, %8) + // %10 = int_cast(uN, %9) // %11 = load(%3) // %12 = shl_exact(%11, ) // %13 = bit_or(%12, %10) @@ -1528,7 +1632,7 @@ fn scalarizeBitcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!? index_val, ).toRef(); const elem_uint = loop.block.addBitCast(l, elem_uint_ty, raw_elem); - const elem_extended = loop.block.addTyOp(l, .intcast, uint_ty, elem_uint).toRef(); + const elem_extended = loop.block.addTyOp(l, .int_cast, uint_ty, elem_uint).toRef(); const old_result = loop.block.addTyOp(l, .load, uint_ty, result_ptr).toRef(); const shifted_result = loop.block.addBinOp(l, .shl_exact, old_result, .fromValue(elem_bits_val)).toRef(); const new_result = loop.block.addBinOp(l, .bit_or, shifted_result, elem_extended).toRef(); @@ -1559,10 +1663,23 @@ fn scalarizeBitcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!? // Now convert `uint_ty` (`uN`) to `dest_ty`. - if (dest_legal) { + if (int_to_dest_ok) { _ = main_block.stealCapacity(17); const result = main_block.addBitCast(l, dest_ty, uint_val); main_block.addBr(l, orig_inst, result); + } else if (dest_ty.arrayLenIncludingSentinel(zcu) == 1) { + _ = main_block.stealCapacity(16); + const elem = main_block.addBitCast(l, dest_ty.childType(zcu), uint_val); + const aggregate_init_payload_start = l.air_extra.items.len; + try l.air_extra.append(zcu.gpa, @intFromEnum(elem)); + const result = main_block.add(l, .{ + .tag = .aggregate_init, + .data = .{ .ty_pl = .{ + .ty = .fromType(dest_ty), + .payload = @intCast(aggregate_init_payload_start), + } }, + }).toRef(); + main_block.addBr(l, orig_inst, result); } else { // %1 = alloc(*usize) // %2 = alloc(*@Vector(N, Result)) @@ -1570,10 +1687,10 @@ fn scalarizeBitcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!? // %4 = loop({ // %5 = load(%1) // %6 = mul(%5, ) - // %7 = intcast(uS, %6) + // %7 = int_cast(uS, %6) // %8 = shr(uint_val, %7) // %9 = trunc(uE, %8) - // %10 = bitcast(Result, %9) + // %10 = bit_cast(Result, %9) // %11 = legalize_vec_store_elem(%2, %5, %10) // %12 = cmp_eq(%5, ) // %13 = cond_br(%12, { @@ -1602,7 +1719,7 @@ fn scalarizeBitcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!? const index_val = loop.block.addTyOp(l, .load, .usize, index_ptr).toRef(); const bit_offset = loop.block.addBinOp(l, .mul, index_val, .fromValue(try pt.intValue(.usize, elem_bits))).toRef(); - const casted_bit_offset = loop.block.addTyOp(l, .intcast, shift_ty, bit_offset).toRef(); + const casted_bit_offset = loop.block.addTyOp(l, .int_cast, shift_ty, bit_offset).toRef(); const shifted_uint = loop.block.addBinOp(l, .shr, uint_val, casted_bit_offset).toRef(); const elem_uint = loop.block.addTyOp(l, .trunc, elem_uint_ty, shifted_uint).toRef(); const elem_val = loop.block.addBitCast(l, elem_ty, elem_uint); @@ -1980,7 +2097,7 @@ fn safeIntcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.In // %5 = call(@panic.invalidEnumValue, []) // %6 = unreach() // }, { - // %7 = intcast(@res_ty, %y) + // %7 = int_cast(@res_ty, %y) // %8 = is_named_enum_value(%7) // %9 = cond_br(%8, { // %10 = br(%x, %7) @@ -2002,7 +2119,7 @@ fn safeIntcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.In // %6 = call(@panic.invalidEnumValue, []) // %7 = unreach() // }, { - // %8 = intcast(@res_ty, %y) + // %8 = int_cast(@res_ty, %y) // %9 = br(%x, %8) // }) // }) @@ -2055,9 +2172,9 @@ fn safeIntcastBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.In cur_block = &condbr.else_block; } - // Now we know we're in-range, we can intcast: + // Now we know we're in-range, we can int_cast: const cast_inst = cur_block.add(l, .{ - .tag = .intcast, + .tag = .int_cast, .data = .{ .ty_op = .{ .ty = Air.internedToRef(dest_ty.toIntern()), .operand = operand_ref, @@ -2228,7 +2345,7 @@ fn safeArithmeticBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, overflow_ // %1 = add_with_overflow(%x, %y) // %2 = struct_field_val(%1, .@"1") // %3 = reduce(%2, .@"or") - // %4 = bitcast(%3, @bool_type) + // %4 = bit_cast(%3, @bool_type) // %5 = cond_br(%4, { // %6 = call(@panic.integerOverflow, []) // %7 = unreach() @@ -2334,7 +2451,7 @@ fn packedLoadBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.Ins .tag = .load, .data = .{ .ty_op = .{ .ty = Air.internedToRef(load_ty.toIntern()), - .operand = res_block.addBitCast(l, load_ptr_ty: { + .operand = res_block.addPtrCast(l, load_ptr_ty: { var load_ptr_info = ptr_info; load_ptr_info.child = load_ty.toIntern(); load_ptr_info.flags.vector_index = .none; @@ -2377,23 +2494,17 @@ fn packedStoreBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.In var res_block: Block = .init(&inst_buf); { - const backing_ptr_inst = res_block.add(l, .{ - .tag = .bitcast, - .data = .{ .ty_op = .{ - .ty = Air.internedToRef((load_store_ptr_ty: { - var load_ptr_info = ptr_info; - load_ptr_info.child = load_store_ty.toIntern(); - load_ptr_info.flags.vector_index = .none; - load_ptr_info.packed_offset = .{ .host_size = 0, .bit_offset = 0 }; - break :load_store_ptr_ty try pt.ptrType(load_ptr_info); - }).toIntern()), - .operand = orig_bin_op.lhs, - } }, - }); + const backing_ptr = res_block.addPtrCast(l, load_store_ptr_ty: { + var load_ptr_info = ptr_info; + load_ptr_info.child = load_store_ty.toIntern(); + load_ptr_info.flags.vector_index = .none; + load_ptr_info.packed_offset = .{ .host_size = 0, .bit_offset = 0 }; + break :load_store_ptr_ty try pt.ptrType(load_ptr_info); + }, orig_bin_op.lhs); _ = res_block.add(l, .{ .tag = .store, .data = .{ .bin_op = .{ - .lhs = backing_ptr_inst.toRef(), + .lhs = backing_ptr, .rhs = res_block.add(l, .{ .tag = .bit_or, .data = .{ .bin_op = .{ @@ -2404,7 +2515,7 @@ fn packedStoreBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.In .tag = .load, .data = .{ .ty_op = .{ .ty = Air.internedToRef(load_store_ty.toIntern()), - .operand = backing_ptr_inst.toRef(), + .operand = backing_ptr, } }, }).toRef(), .rhs = Air.internedToRef((keep_mask: { @@ -2433,7 +2544,7 @@ fn packedStoreBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.In .tag = .shl_exact, .data = .{ .bin_op = .{ .lhs = res_block.add(l, .{ - .tag = .intcast, + .tag = .int_cast, .data = .{ .ty_op = .{ .ty = Air.internedToRef(load_store_ty.toIntern()), .operand = res_block.addBitCast(l, operand_int_ty, orig_bin_op.rhs), @@ -2531,7 +2642,7 @@ fn packedAggregateInitBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Erro const shifted = main_block.addBinOp(l, .shl_exact, cur_uint, field_bit_size_ref).toRef(); const field_as_uint = main_block.addBitCast(l, field_uint_ty, field_val); - const field_extended = main_block.addTyOp(l, .intcast, uint_ty, field_as_uint).toRef(); + const field_extended = main_block.addTyOp(l, .int_cast, uint_ty, field_as_uint).toRef(); cur_uint = main_block.addBinOp(l, .bit_or, shifted, field_extended).toRef(); } @@ -2720,18 +2831,51 @@ const Block = struct { }); } - /// Adds a `bitcast` instruction to `b`. This is a thin wrapper that omits the instruction for + /// Adds a `bit_cast` instruction to `b`. This is a thin wrapper that omits the instruction for /// no-op casts. fn addBitCast( b: *Block, l: *Legalize, - ty: Type, + result_ty: Type, operand: Air.Inst.Ref, ) Air.Inst.Ref { - if (ty.toIntern() != l.typeOf(operand).toIntern()) return b.add(l, .{ - .tag = .bitcast, + const zcu = l.pt.zcu; + const operand_ty = l.typeOf(operand); + assert(!operand_ty.isPtrAtRuntime(zcu)); + assert(!operand_ty.isSliceAtRuntime(zcu)); + assert(!result_ty.isPtrAtRuntime(zcu)); + assert(!result_ty.isSliceAtRuntime(zcu)); + if (result_ty.toIntern() != operand_ty.toIntern()) return b.add(l, .{ + .tag = .bit_cast, .data = .{ .ty_op = .{ - .ty = Air.internedToRef(ty.toIntern()), + .ty = .fromType(result_ty), + .operand = operand, + } }, + }).toRef(); + _ = b.stealCapacity(1); + return operand; + } + + /// Adds a `ptr_cast` instruction to `b`. This is a thin wrapper that omits the instruction for + /// no-op casts. + fn addPtrCast( + b: *Block, + l: *Legalize, + result_ty: Type, + operand: Air.Inst.Ref, + ) Air.Inst.Ref { + const zcu = l.pt.zcu; + const operand_ty = l.typeOf(operand); + if (operand_ty.isSliceAtRuntime(zcu)) { + assert(result_ty.isSliceAtRuntime(zcu)); + } else { + assert(operand_ty.isPtrAtRuntime(zcu)); + assert(result_ty.isPtrAtRuntime(zcu)); + } + if (result_ty.toIntern() != operand_ty.toIntern()) return b.add(l, .{ + .tag = .ptr_cast, + .data = .{ .ty_op = .{ + .ty = .fromType(result_ty), .operand = operand, } }, }).toRef(); @@ -3072,7 +3216,7 @@ fn softFloatFromInt(l: *Legalize, orig_inst: Air.Inst.Index) Error!union(enum) { var main_block: Block = .init(&inst_buf); try l.air_instructions.ensureUnusedCapacity(zcu.gpa, inst_buf.len); - const extended_val = main_block.addTyOp(l, .intcast, extended_ty, ty_op.operand).toRef(); + const extended_val = main_block.addTyOp(l, .int_cast, extended_ty, ty_op.operand).toRef(); const call_inst = try main_block.addCompilerRtCall(l, func, &.{extended_val}); const casted_result = main_block.addBitCast(l, dest_ty, call_inst.toRef()); main_block.addBr(l, orig_inst, casted_result); @@ -3099,7 +3243,7 @@ fn softFloatFromInt(l: *Legalize, orig_inst: Air.Inst.Index) Error!union(enum) { try l.air_instructions.ensureUnusedCapacity(zcu.gpa, inst_buf.len); const extended_val: Air.Inst.Ref = if (extended_ty.toIntern() != src_ty.toIntern()) ext: { - break :ext main_block.addTyOp(l, .intcast, extended_ty, ty_op.operand).toRef(); + break :ext main_block.addTyOp(l, .int_cast, extended_ty, ty_op.operand).toRef(); } else ext: { _ = main_block.stealCapacity(1); break :ext ty_op.operand; @@ -3164,7 +3308,7 @@ fn softIntFromFloat(l: *Legalize, orig_inst: Air.Inst.Index) Error!union(enum) { try l.air_instructions.ensureUnusedCapacity(zcu.gpa, inst_buf.len); const call_inst = try main_block.addCompilerRtCall(l, func, &.{ty_op.operand}); - const casted_val = main_block.addTyOp(l, .intcast, dest_ty, call_inst.toRef()).toRef(); + const casted_val = main_block.addTyOp(l, .int_cast, dest_ty, call_inst.toRef()).toRef(); main_block.addBr(l, orig_inst, casted_val); return .{ .block_payload = .{ .ty_pl = .{ @@ -3188,7 +3332,7 @@ fn softIntFromFloat(l: *Legalize, orig_inst: Air.Inst.Index) Error!union(enum) { const bits_val = try pt.intValue(.usize, dest_info.bits); _ = try main_block.addCompilerRtCall(l, func, &.{ extended_ptr, .fromValue(bits_val), ty_op.operand }); const extended_val = main_block.addTyOp(l, .load, extended_ty, extended_ptr).toRef(); - const result_val = main_block.addTyOp(l, .intcast, dest_ty, extended_val).toRef(); + const result_val = main_block.addTyOp(l, .int_cast, dest_ty, extended_val).toRef(); main_block.addBr(l, orig_inst, result_val); return .{ .block_payload = .{ .ty_pl = .{ diff --git a/src/Air/Liveness.zig b/src/Air/Liveness.zig index 773074a1ce9de7cf019a167d36483db6e3316ec8..ee1c1a2e819fba98a1af5484a2e60a85ed98586b 100644 --- a/src/Air/Liveness.zig +++ b/src/Air/Liveness.zig @@ -488,12 +488,19 @@ fn analyzeInst( => return analyzeFuncEnd(a, pass, data, inst, .{ .none, .none, .none }), .not, - .bitcast, + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, .load, .fpext, .fptrunc, - .intcast, - .intcast_safe, + .int_cast, + .int_cast_safe, .trunc, .optional_payload, .optional_payload_ptr, @@ -673,7 +680,7 @@ fn analyzeInst( const extra = a.air.extraData(Air.UnionInit, inst_datas[@intFromEnum(inst)].ty_pl.payload).data; return analyzeOperands(a, pass, data, inst, .{ extra.init, .none, .none }); }, - .struct_field_ptr, .struct_field_val => { + .struct_field_ptr, .struct_field_val, .spirv_runtime_array_len => { const extra = a.air.extraData(Air.StructField, inst_datas[@intFromEnum(inst)].ty_pl.payload).data; return analyzeOperands(a, pass, data, inst, .{ extra.struct_operand, .none, .none }); }, diff --git a/src/Air/Liveness/Verify.zig b/src/Air/Liveness/Verify.zig index 294a68fc4640072ce924a986e3a6ae0125bf04d4..dbd664db52b56951a8d4de99686ab55cb896d769 100644 --- a/src/Air/Liveness/Verify.zig +++ b/src/Air/Liveness/Verify.zig @@ -78,12 +78,19 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { // unary .not, - .bitcast, + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, .load, .fpext, .fptrunc, - .intcast, - .intcast_safe, + .int_cast, + .int_cast_safe, .trunc, .optional_payload, .optional_payload_ptr, @@ -191,7 +198,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; try self.verifyInstOperands(inst, .{ extra.init, .none, .none }); }, - .struct_field_ptr, .struct_field_val => { + .struct_field_ptr, .struct_field_val, .spirv_runtime_array_len => { const ty_pl = data[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; try self.verifyInstOperands(inst, .{ extra.struct_operand, .none, .none }); diff --git a/src/Air/Verify.zig b/src/Air/Verify.zig new file mode 100644 index 0000000000000000000000000000000000000000..1216ff2f2ee14ffde2ca3e830376a674d95f0cfb --- /dev/null +++ b/src/Air/Verify.zig @@ -0,0 +1,465 @@ +/// Verifies that AIR is valid, in that every instruction has valid operands and types. In compiler +/// builds with debug extensions, this is run on all AIR, both before `Air.Legalize` is run and (if +/// it is run) after it. +/// +/// This verification pass is currently highly incomplete---expand it as needed. +const Verify = @This(); + +zcu: *Zcu, +func_index: InternPool.Index, +ret_ty: Type, +air: *const Air, +cur_inst: Air.Inst.Index, + +pub fn run(pt: Zcu.PerThread, func_index: InternPool.Index, air: *const Air) void { + if (!@import("build_options").enable_debug_extensions) { + // `Air.Verify` is a debugging feature---it should not be used in release builds because it + // has little benefit and negatively affects compiler performance. + return; + } + + const zcu = pt.zcu; + + const func_ty: Type = Value.fromInterned(func_index).typeOf(zcu); + const ret_ty = func_ty.fnReturnType(zcu); + + var verify: Verify = .{ + .zcu = zcu, + .func_index = func_index, + .ret_ty = ret_ty, + .air = air, + .cur_inst = undefined, // populated by `body(...)` + }; + verify.body(air.getMainBody()) catch |verify_err| switch (verify_err) { + error.VerifyFail => { + const ip = &zcu.intern_pool; + const func_nav = ip.indexToKey(func_index).func.owner_nav; + const func_fqn = ip.getNav(func_nav).fqn.toSlice(ip); + log.info("AIR for '{s}':", .{func_fqn}); + const io = zcu.comp.io; + const stderr = io.lockStderr(&.{}, null) catch |err| switch (err) { + error.Canceled => return io.recancel(), + }; + defer io.unlockStderr(); + air.write(&stderr.file_writer.interface, pt, null) catch |err| switch (err) { + error.WriteFailed => switch (stderr.file_writer.err.?) { + error.Canceled => return io.recancel(), + else => {}, + }, + }; + }, + }; +} + +const Error = error{VerifyFail}; + +fn fail(verify: *Verify, msg: []const u8) Error { + const ip = &verify.zcu.intern_pool; + const func_nav = ip.indexToKey(verify.func_index).func.owner_nav; + const func_fqn = ip.getNav(func_nav).fqn.toSlice(ip); + log.err("'{s}', %{d}: {s}", .{ func_fqn, verify.cur_inst, msg }); + return error.VerifyFail; +} + +fn body(verify: *Verify, body_insts: []const Air.Inst.Index) Error!void { + const zcu = verify.zcu; + const ip = &zcu.intern_pool; + const air = verify.air; + const tags = air.instructions.items(.tag); + const data = air.instructions.items(.data); + for (body_insts, 0..) |inst, body_index| { + verify.cur_inst = inst; + switch (tags[@intFromEnum(inst)]) { + .block => { + const block = air.unwrapBlock(inst); + try verify.body(block.body); + }, + .dbg_inline_block => { + const block = air.unwrapDbgBlock(inst); + try verify.body(block.body); + }, + .@"try", .try_cold => { + const @"try" = air.unwrapTry(inst); + try verify.body(@"try".else_body); + }, + .try_ptr, .try_ptr_cold => { + const try_ptr = air.unwrapTryPtr(inst); + try verify.body(try_ptr.else_body); + }, + .loop => { + const block = air.unwrapBlock(inst); + try verify.body(block.body); + }, + .cond_br => { + const cond_br = air.unwrapCondBr(inst); + try verify.body(cond_br.then_body); + try verify.body(cond_br.else_body); + }, + .switch_br, .loop_switch_br => { + const switch_br = air.unwrapSwitch(inst); + var it = switch_br.iterateCases(); + while (it.next()) |case| { + try verify.body(case.body); + } + const else_body = it.elseBody(); + if (else_body.len > 0) { + try verify.body(else_body); + } + }, + .ret, .ret_safe => { + const operand = data[@intFromEnum(inst)].un_op; + if (air.typeOf(operand, ip).toIntern() != verify.ret_ty.toIntern()) return verify.fail("bad return type"); + }, + .ret_load => { + const operand = data[@intFromEnum(inst)].un_op; + const ptr_ty = air.typeOf(operand, ip); + if (ptr_ty.zigTypeTag(zcu) != .pointer) return verify.fail("operand is not a pointer"); + if (ptr_ty.ptrSize(zcu) != .one) return verify.fail("pointer size is not '.one'"); + if (ptr_ty.childType(zcu).toIntern() != verify.ret_ty.toIntern()) return verify.fail("bad return type"); + }, + + .bit_cast => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + // Enums are allowed here even if their backing type is implicit. + if (!operand_ty.hasBitRepresentation(zcu) and operand_ty.zigTypeTag(zcu) != .@"enum") { + return verify.fail("bad operand type"); + } + if (!result_ty.hasBitRepresentation(zcu) and result_ty.zigTypeTag(zcu) != .@"enum") { + return verify.fail("bad result type"); + } + if (operand_ty.isPtrAtRuntime(zcu)) return verify.fail("bad operand type (pointer)"); + if (result_ty.isPtrAtRuntime(zcu)) return verify.fail("bad result type (pointer)"); + if (operand_ty.bitSize(zcu) != result_ty.bitSize(zcu)) return verify.fail("bit size mismatch"); + }, + .ptr_cast => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + const operand_scalar_ty = operand_ty.scalarType(zcu); + const result_scalar_ty = result_ty.scalarType(zcu); + if (operand_ty.isSliceAtRuntime(zcu)) { + if (!result_ty.isSliceAtRuntime(zcu)) return verify.fail("operand is slice, but result is not"); + } else { + if (!operand_scalar_ty.isPtrAtRuntime(zcu)) return verify.fail("bad operand type"); + if (!result_scalar_ty.isPtrAtRuntime(zcu)) return verify.fail("operand is pointer, but result is not"); + if (operand_ty.isVector(zcu) and !result_ty.isVector(zcu)) return verify.fail("operand is vector, but result is not"); + if (!operand_ty.isVector(zcu) and result_ty.isVector(zcu)) return verify.fail("result is vector, but operand is not"); + } + if (operand_scalar_ty.ptrAddressSpace(zcu) != result_scalar_ty.ptrAddressSpace(zcu)) { + return verify.fail("illegal change to address space"); + } + }, + .ptr_from_int => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + const operand_scalar_ty = operand_ty.scalarType(zcu); + const result_scalar_ty = result_ty.scalarType(zcu); + if (operand_scalar_ty.toIntern() != .usize_type) return verify.fail("bad operand type"); + if (!result_scalar_ty.isPtrAtRuntime(zcu)) return verify.fail("bad result type"); + if (operand_ty.isVector(zcu) and !result_ty.isVector(zcu)) return verify.fail("operand is vector, but result is not"); + if (!operand_ty.isVector(zcu) and result_ty.isVector(zcu)) return verify.fail("result is vector, but operand is not"); + }, + .int_from_ptr => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + const operand_scalar_ty = operand_ty.scalarType(zcu); + const result_scalar_ty = result_ty.scalarType(zcu); + if (!operand_scalar_ty.isPtrAtRuntime(zcu)) return verify.fail("bad operand type"); + if (result_scalar_ty.toIntern() != .usize_type) return verify.fail("bad result type"); + if (operand_ty.isVector(zcu) and !result_ty.isVector(zcu)) return verify.fail("operand is vector, but result is not"); + if (!operand_ty.isVector(zcu) and result_ty.isVector(zcu)) return verify.fail("result is vector, but operand is not"); + }, + .error_cast => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + switch (operand_ty.zigTypeTag(zcu)) { + else => return verify.fail("bad operand type"), + .error_union => { + if (result_ty.zigTypeTag(zcu) != .error_union) { + return verify.fail("operand is error union, but result is not"); + } + if (operand_ty.errorUnionPayload(zcu).toIntern() != result_ty.errorUnionPayload(zcu).toIntern()) { + return verify.fail("error union payload type differs"); + } + }, + .error_set => if (result_ty.zigTypeTag(zcu) != .error_set) { + return verify.fail("operand is error set, but result is not"); + }, + } + }, + .error_from_int => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + if (!operand_ty.isUnsignedInt(zcu)) return verify.fail("bad operand type"); + if (operand_ty.bitSize(zcu) != zcu.errorSetBits()) return verify.fail("bad operand bit size"); + if (result_ty.zigTypeTag(zcu) != .error_set) return verify.fail("bad result type"); + }, + .int_from_error => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + if (operand_ty.zigTypeTag(zcu) != .error_set) return verify.fail("bad operand type"); + if (!result_ty.isUnsignedInt(zcu)) return verify.fail("bad result type"); + if (result_ty.bitSize(zcu) != zcu.errorSetBits()) return verify.fail("bad result bit size"); + }, + .union_from_enum => { + const ty_op = data[@intFromEnum(inst)].ty_op; + const operand_ty = air.typeOf(ty_op.operand, ip); + const result_ty = ty_op.ty.toType(); + if (operand_ty.zigTypeTag(zcu) != .@"enum") return verify.fail("bad operand type"); + if (result_ty.zigTypeTag(zcu) != .@"union") return verify.fail("bad result type"); + const union_tag_ty = result_ty.unionTagType(zcu) orelse return verify.fail("union type is not tagged"); + if (union_tag_ty.toIntern() != operand_ty.toIntern()) return verify.fail("union tag type does not match operand type"); + }, + + .ptr_elem_ptr => { + const ty_pl = data[@intFromEnum(inst)].ty_pl; + const bin_op = air.extraData(Air.Bin, ty_pl.payload).data; + const ptr_ty = air.typeOf(bin_op.lhs, ip); + const result_ty = ty_pl.ty.toType(); + if (ptr_ty.zigTypeTag(zcu) != .pointer) return verify.fail("bad pointer type"); + if (result_ty.zigTypeTag(zcu) != .pointer) return verify.fail("bad result type"); + const ptr_info = ptr_ty.ptrInfo(zcu); + const result_ptr_info = result_ty.ptrInfo(zcu); + if (ptr_info.packed_offset.host_size != 0) return verify.fail("pointer type is bitpacked pointer"); + if (result_ptr_info.packed_offset.host_size != 0) return verify.fail("result type is bitpacked pointer"); + }, + + .arg, + .add, + .add_safe, + .add_optimized, + .add_wrap, + .add_sat, + .sub, + .sub_safe, + .sub_optimized, + .sub_wrap, + .sub_sat, + .mul, + .mul_safe, + .mul_optimized, + .mul_wrap, + .mul_sat, + .div_float, + .div_float_optimized, + .div_trunc, + .div_trunc_optimized, + .div_floor, + .div_floor_optimized, + .div_exact, + .div_exact_optimized, + .rem, + .rem_optimized, + .mod, + .mod_optimized, + .ptr_add, + .ptr_sub, + .max, + .min, + .add_with_overflow, + .sub_with_overflow, + .mul_with_overflow, + .shl_with_overflow, + .alloc, + .inferred_alloc, + .inferred_alloc_comptime, + .ret_ptr, + .assembly, + .bit_and, + .bit_or, + .shr, + .shr_exact, + .shl, + .shl_exact, + .shl_sat, + .xor, + .not, + .repeat, + .br, + .trap, + .breakpoint, + .ret_addr, + .frame_addr, + .call, + .call_always_tail, + .call_never_tail, + .call_never_inline, + .clz, + .ctz, + .popcount, + .byte_swap, + .bit_reverse, + .sqrt, + .sin, + .cos, + .tan, + .exp, + .exp2, + .log, + .log2, + .log10, + .abs, + .floor, + .ceil, + .round, + .trunc_float, + .neg, + .neg_optimized, + .cmp_lt, + .cmp_lt_optimized, + .cmp_lte, + .cmp_lte_optimized, + .cmp_eq, + .cmp_eq_optimized, + .cmp_gte, + .cmp_gte_optimized, + .cmp_gt, + .cmp_gt_optimized, + .cmp_neq, + .cmp_neq_optimized, + .cmp_vector, + .cmp_vector_optimized, + .switch_dispatch, + .dbg_stmt, + .dbg_empty_stmt, + .dbg_var_ptr, + .dbg_var_val, + .dbg_arg_inline, + .is_null, + .is_non_null, + .is_null_ptr, + .is_non_null_ptr, + .is_err, + .is_non_err, + .is_err_ptr, + .is_non_err_ptr, + .load, + .store, + .store_safe, + .unreach, + .fptrunc, + .fpext, + .int_cast, + .int_cast_safe, + .trunc, + .optional_payload, + .optional_payload_ptr, + .optional_payload_ptr_set, + .wrap_optional, + .unwrap_errunion_payload, + .unwrap_errunion_err, + .unwrap_errunion_payload_ptr, + .unwrap_errunion_err_ptr, + .errunion_payload_ptr_set, + .wrap_errunion_payload, + .wrap_errunion_err, + .struct_field_ptr, + .struct_field_ptr_index_0, + .struct_field_ptr_index_1, + .struct_field_ptr_index_2, + .struct_field_ptr_index_3, + .struct_field_val, + .set_union_tag, + .get_union_tag, + .slice, + .slice_len, + .slice_ptr, + .ptr_slice_len_ptr, + .ptr_slice_ptr_ptr, + .array_elem_val, + .slice_elem_val, + .slice_elem_ptr, + .ptr_elem_val, + .array_to_slice, + .int_from_float, + .int_from_float_optimized, + .int_from_float_safe, + .int_from_float_optimized_safe, + .float_from_int, + .reduce, + .reduce_optimized, + .splat, + .shuffle_one, + .shuffle_two, + .select, + .memset, + .memset_safe, + .memcpy, + .memmove, + .cmpxchg_weak, + .cmpxchg_strong, + .atomic_load, + .atomic_store_unordered, + .atomic_store_monotonic, + .atomic_store_release, + .atomic_store_seq_cst, + .atomic_rmw, + .is_named_enum_value, + .tag_name, + .error_name, + .error_set_has_value, + .aggregate_init, + .union_init, + .prefetch, + .mul_add, + .field_parent_ptr, + .wasm_memory_size, + .wasm_memory_grow, + .cmp_lte_errors_len, + .err_return_trace, + .set_err_return_trace, + .addrspace_cast, + .save_err_return_trace_index, + .runtime_nav_ptr, + .c_va_arg, + .c_va_copy, + .c_va_end, + .c_va_start, + .spirv_runtime_array_len, + .work_item_id, + .work_group_size, + .work_group_id, + .legalize_vec_store_elem, + .legalize_vec_elem_val, + .legalize_compiler_rt_call, + => {}, + } + if (air.typeOfIndex(inst, ip).isNoReturn(zcu)) { + if (body_index == body_insts.len - 1) return; + + // HACK: right now, we emit the safety check for noreturn functions returning in a weird + // way, where the `call` instruction is `noreturn` but there are still instructions + // following it. We need to figure out a better way to represent that! That safety check + // probably just needs to live exclusively in backends; putting AIR instructions after a + // call implies that we have e.g. a valid stack at that point, which we can't actually + // assume when the user has gotten a function's ABI wrong. + switch (tags[@intFromEnum(inst)]) { + .call, + .call_always_tail, + .call_never_tail, + .call_never_inline, + => continue, + else => {}, + } + + return verify.fail("body contains instructions after noreturn"); + } + } + return verify.fail("body does not terminate noreturn"); +} + +const std = @import("std"); +const log = std.log.scoped(.air_verify); + +const Zcu = @import("../Zcu.zig"); +const InternPool = @import("../InternPool.zig"); +const Air = @import("../Air.zig"); +const Type = @import("../Type.zig"); +const Value = @import("../Value.zig"); diff --git a/src/Air/print.zig b/src/Air/print.zig index b3739ece3334ede99c3d66164b9fdbd3b7dfec54..39fe184ee492e51ab8b81a227d4dc7fbcc91572c 100644 --- a/src/Air/print.zig +++ b/src/Air/print.zig @@ -73,23 +73,19 @@ pub fn writeInst( } pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { - const comp = pt.zcu.comp; - const io = comp.io; - var buffer: [512]u8 = undefined; - const stderr = try io.lockStderr(&buffer, null); - defer io.unlockStderr(); + var buffer: [4096]u8 = undefined; + const stderr = std.debug.lockStderr(&buffer); + defer std.debug.unlockStderr(); const w = &stderr.file_writer.interface; - air.write(w, pt, liveness); + air.write(w, pt, liveness) catch return; } pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void { - const comp = pt.zcu.comp; - const io = comp.io; - var buffer: [512]u8 = undefined; - const stderr = try io.lockStderr(&buffer, null); - defer io.unlockStderr(); + var buffer: [4096]u8 = undefined; + const stderr = std.debug.lockStderr(&buffer); + defer std.debug.unlockStderr(); const w = &stderr.file_writer.interface; - air.writeInst(w, inst, pt, liveness); + air.writeInst(w, inst, pt, liveness) catch return; } const Writer = struct { @@ -232,12 +228,19 @@ const Writer = struct { .arg => try w.writeArg(s, inst), .not, - .bitcast, + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, .load, .fptrunc, .fpext, - .intcast, - .intcast_safe, + .int_cast, + .int_cast_safe, .trunc, .optional_payload, .optional_payload_ptr, @@ -306,6 +309,7 @@ const Writer = struct { .struct_field_ptr => try w.writeStructField(s, inst), .struct_field_val => try w.writeStructField(s, inst), + .spirv_runtime_array_len => try w.writeStructField(s, inst), .inferred_alloc => @panic("TODO"), .inferred_alloc_comptime => @panic("TODO"), .assembly => try w.writeAssembly(s, inst), diff --git a/src/Compilation.zig b/src/Compilation.zig index d50586581e3a530b39309573da3dffb933f988ec..2660f74e18f4a4a2efc962c0381141cd159e4a9c 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -87,7 +87,7 @@ link_inputs: []const link.Input, framework_dirs: []const []const u8, /// These are only for DLLs dependencies fulfilled by the `.def` files shipped /// with Zig. Static libraries are provided as `link.Input` values. -windows_libs: std.StringArrayHashMapUnmanaged(void), +windows_libs: std.array_hash_map.String(void), /// The number of items in `windows_libs` which we have already built. All items at or after this /// index will be built in `performAllTheWork`. windows_libs_num_done: u32, @@ -101,18 +101,14 @@ native_system_include_paths: []const []const u8, /// List of symbols forced as undefined in the symbol table /// thus forcing their resolution by the linker. /// Corresponds to `-u ` for ELF/MachO and `/include:` for COFF/PE. -force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), +force_undefined_symbols: std.array_hash_map.String(void), -c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .empty, -win32_resource_table: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMapUnmanaged(*Win32Resource, void) else struct { - pub fn keys(_: @This()) [0]void { - return .{}; - } - pub fn count(_: @This()) u0 { - return 0; - } +c_objects: std.ArrayList(*CObject) = .empty, +win32_resources: if (dev.env.supports(.win32_resource)) std.ArrayList(*Win32Resource) else struct { + items: [0]*struct {}, + pub const empty: @This() = .{ .items = .{} }; pub fn deinit(_: @This(), _: Allocator) void {} -} = .{}, +} = .empty, link_diags: link.Diags, link_queue: link.Queue = .empty, @@ -145,11 +141,11 @@ win32_resource_work_queue: if (dev.env.supports(.win32_resource)) std.Deque(*Win /// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator. /// This data is accessed by multiple threads and is protected by `mutex`. -failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.Diag.Bundle) = .empty, +failed_c_objects: std.array_hash_map.Auto(*CObject, *CObject.Diag.Bundle) = .empty, /// The ErrorBundle memory is owned by the `Win32Resource`, using Compilation's general purpose allocator. /// This data is accessed by multiple threads and is protected by `mutex`. -failed_win32_resources: if (dev.env.supports(.win32_resource)) std.AutoArrayHashMapUnmanaged(*Win32Resource, ErrorBundle) else struct { +failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_map.Auto(*Win32Resource, ErrorBundle) else struct { pub fn values(_: @This()) [0]void { return .{}; } @@ -157,7 +153,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.AutoArrayHash } = .{}, /// Miscellaneous things that can fail. -misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .empty, +misc_failures: std.array_hash_map.Auto(MiscTask, MiscError) = .empty, /// When this is `true` it means invoking clang as a sub-process is expected to inherit /// stdin, stdout, stderr, and if it returns non success, to forward the exit code. @@ -227,8 +223,6 @@ compiler_rt_lib: ?CrtFile = null, /// Populated when we build the compiler_rt_obj object. A Job to build this is indicated /// by setting `queued_jobs.compiler_rt_obj` and resolved before calling linker.flush(). compiler_rt_obj: ?CrtFile = null, -/// hack for stage2_x86_64 + coff -compiler_rt_dyn_lib: ?CrtFile = null, /// Populated when we build the libfuzzer static library. A Job to build this /// is indicated by setting `queued_jobs.fuzzer_lib` and resolved before /// calling linker.flush(). @@ -291,8 +285,6 @@ emit_llvm_bc: ?[]const u8, emit_docs: ?[]const u8, const QueuedJobs = struct { - /// hack for stage2_x86_64 + coff - compiler_rt_dyn_lib: bool = false, compiler_rt_lib: bool = false, compiler_rt_obj: bool = false, ubsan_rt_lib: bool = false, @@ -865,7 +857,7 @@ pub const TimeReport = struct { /// a function) all generic instances of this function. It also includes time spent analyzing /// function bodies if this is a function (generic or otherwise). /// An entry not existing means the declaration has not been analyzed (so far). - decl_sema_info: std.AutoArrayHashMapUnmanaged(InternPool.TrackedInst.Index, struct { + decl_sema_info: std.array_hash_map.Auto(InternPool.TrackedInst.Index, struct { ns: u64, count: u32, }), @@ -875,14 +867,14 @@ pub const TimeReport = struct { /// instances, both of this function itself and of its parent namespace. /// An entry not existing means the declaration has not been codegenned (so far). /// Every key in `decl_codegen_ns` is also in `decl_sema_ns`. - decl_codegen_ns: std.AutoArrayHashMapUnmanaged(InternPool.TrackedInst.Index, u64), + decl_codegen_ns: std.array_hash_map.Auto(InternPool.TrackedInst.Index, u64), /// Key is a ZIR `declaration` instruction which is anything other than a `comptime` decl; value /// is the number of nanoseconds spent linking it into the binary. As above, this is the total /// across all generic instances. /// An entry not existing means the declaration has not been linked (so far). /// Every key in `decl_link_ns` is also in `decl_sema_ns`. - decl_link_ns: std.AutoArrayHashMapUnmanaged(InternPool.TrackedInst.Index, u64), + decl_link_ns: std.array_hash_map.Auto(InternPool.TrackedInst.Index, u64), pub fn deinit(tr: *TimeReport, gpa: Allocator) void { tr.stats = undefined; @@ -915,21 +907,6 @@ pub const CrtFile = struct { } }; -/// Supported languages for "zig clang -x ". -/// Loosely based on llvm-project/clang/include/clang/Driver/Types.def -pub const LangToExt = std.StaticStringMap(FileExt).initComptime(.{ - .{ "c", .c }, - .{ "c-header", .h }, - .{ "c++", .cpp }, - .{ "c++-header", .hpp }, - .{ "objective-c", .m }, - .{ "objective-c-header", .hm }, - .{ "objective-c++", .mm }, - .{ "objective-c++-header", .hmm }, - .{ "assembler", .assembly }, - .{ "assembler-with-cpp", .assembly_with_cpp }, -}); - /// For passing to a C compiler. pub const CSourceFile = struct { /// Many C compiler flags are determined by settings contained in the owning Module. @@ -1068,8 +1045,8 @@ pub const CObject = struct { } pub const Bundle = struct { - file_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .empty, - category_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .empty, + file_names: std.array_hash_map.Auto(u32, []const u8) = .empty, + category_names: std.array_hash_map.Auto(u32, []const u8) = .empty, diags: []Diag = &.{}, pub fn destroy(bundle: *Bundle, gpa: Allocator) void { @@ -1122,13 +1099,13 @@ pub const CObject = struct { var bc = std.zig.llvm.BitcodeReader.init(gpa, .{ .reader = &file_reader.interface }); defer bc.deinit(); - var file_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .empty; + var file_names: std.array_hash_map.Auto(u32, []const u8) = .empty; errdefer { for (file_names.values()) |file_name| gpa.free(file_name); file_names.deinit(gpa); } - var category_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .empty; + var category_names: std.array_hash_map.Auto(u32, []const u8) = .empty; errdefer { for (category_names.values()) |category_name| gpa.free(category_name); category_names.deinit(gpa); @@ -1604,7 +1581,7 @@ pub const CreateOptions = struct { /// implementations still do. lib_directories: []const Cache.Directory = &.{}, rpath_list: []const []const u8 = &[0][]const u8{}, - symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .empty, + symbol_wrap_set: std.array_hash_map.String(void) = .empty, c_source_files: []const CSourceFile = &.{}, rc_source_files: []const RcSourceFile = &.{}, manifest_file: ?[]const u8 = null, @@ -1683,7 +1660,7 @@ pub const CreateOptions = struct { skip_linker_dependencies: bool = false, hash_style: link.File.Lld.Elf.HashStyle = .both, entry: Entry = .default, - force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .empty, + force_undefined_symbols: std.array_hash_map.String(void) = .empty, stack_size: ?u64 = null, image_base: ?u64 = null, version: ?std.SemanticVersion = null, @@ -1800,7 +1777,7 @@ fn addModuleTableToCacheHash( } } -const RtStrat = enum { none, lib, obj, zcu, dyn_lib }; +const RtStrat = enum { none, lib, obj, zcu }; pub const CreateDiagnostic = union(enum) { export_table_import_table_conflict, @@ -1921,12 +1898,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, }; if (have_zcu and (!need_llvm or use_llvm)) { if (output_mode == .Obj) break :s .zcu; - switch (target_util.zigBackend(target, use_llvm)) { - else => {}, - .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) { - break :s if (is_exe_or_dyn_lib and build_options.have_llvm) .dyn_lib else .zcu; - }, - } } if (need_llvm and !build_options.have_llvm) break :s .none; // impossible to build without llvm if (is_exe_or_dyn_lib) break :s .lib; @@ -2308,9 +2279,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, if (opt_zcu) |zcu| { // Populate `zcu.module_roots`. - const pt: Zcu.PerThread = .activate(zcu, .main); - defer pt.deactivate(); - pt.populateModuleRootTable() catch |err| switch (err) { + const active = zcu.acquire(); + defer active.release(); + active.pt.populateModuleRootTable() catch |err| switch (err) { error.OutOfMemory => |e| return e, error.IllegalZigImport => return diag.fail(.illegal_zig_import), }; @@ -2476,7 +2447,14 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, }, } - if (use_llvm) { + if (use_llvm and + (comp.emit_bin != null or + comp.emit_asm != null or + comp.emit_llvm_ir != null or + comp.emit_llvm_bc != null or + comp.verbose_llvm_ir != null or + comp.verbose_llvm_bc != null)) + { if (opt_zcu) |zcu| { zcu.llvm_object = try LlvmObject.create(arena, zcu); } @@ -2486,8 +2464,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, }; errdefer comp.destroy(); + if (target.ofmt == .c) return comp; + // Add a `CObject` for each `c_source_files`. - try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len); + try comp.c_objects.ensureTotalCapacity(gpa, options.c_source_files.len); for (options.c_source_files) |c_source_file| { const c_object = try gpa.create(CObject); errdefer gpa.destroy(c_object); @@ -2496,7 +2476,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .status = .{ .new = {} }, .src = c_source_file, }; - comp.c_object_table.putAssumeCapacityNoClobber(c_object, {}); + comp.c_objects.appendAssumeCapacity(c_object); } // Add a `Win32Resource` for each `rc_source_files` and one for `manifest_file`. @@ -2504,7 +2484,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, options.rc_source_files.len + @intFromBool(options.manifest_file != null); if (win32_resource_count > 0) { dev.check(.win32_resource); - try comp.win32_resource_table.ensureTotalCapacity(gpa, win32_resource_count); + try comp.win32_resources.ensureTotalCapacity(gpa, win32_resource_count); for (options.rc_source_files) |rc_source_file| { const win32_resource = try gpa.create(Win32Resource); errdefer gpa.destroy(win32_resource); @@ -2513,7 +2493,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .status = .{ .new = {} }, .src = .{ .rc = rc_source_file }, }; - comp.win32_resource_table.putAssumeCapacityNoClobber(win32_resource, {}); + comp.win32_resources.appendAssumeCapacity(win32_resource); } if (options.manifest_file) |manifest_path| { @@ -2524,11 +2504,11 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .status = .{ .new = {} }, .src = .{ .manifest = manifest_path }, }; - comp.win32_resource_table.putAssumeCapacityNoClobber(win32_resource, {}); + comp.win32_resources.appendAssumeCapacity(win32_resource); } } - if (comp.emit_bin != null and target.ofmt != .c) { + if (comp.emit_bin != null) { if (!comp.skip_linker_dependencies) { // If we need to build libc for the target, add work items for it. // We go through the work queue so that building can be done in parallel. @@ -2645,11 +2625,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, log.debug("queuing a job to build compiler_rt_obj", .{}); comp.queued_jobs.compiler_rt_obj = true; }, - .dyn_lib => { - // hack for stage2_x86_64 + coff - log.debug("queuing a job to build compiler_rt_dyn_lib", .{}); - comp.queued_jobs.compiler_rt_dyn_lib = true; - }, } switch (comp.ubsan_rt_strat) { @@ -2662,7 +2637,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, log.debug("queuing a job to build ubsan_rt_obj", .{}); comp.queued_jobs.ubsan_rt_obj = true; }, - .dyn_lib => unreachable, // hack for compiler_rt only } switch (comp.zigc_strat) { @@ -2671,7 +2645,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, log.debug("queuing a job to build libzigc", .{}); comp.queued_jobs.zigc_lib = true; }, - .obj, .dyn_lib => unreachable, // only available as a static library or inside an existing ZCU + .obj => unreachable, // only available as a static library or inside an existing ZCU } if (is_exe_or_dyn_lib and comp.config.any_fuzz) { @@ -2730,7 +2704,6 @@ pub fn destroy(comp: *Compilation) void { if (comp.zigc_static_lib) |*crt_file| crt_file.deinit(gpa, io); if (comp.compiler_rt_lib) |*crt_file| crt_file.deinit(gpa, io); if (comp.compiler_rt_obj) |*crt_file| crt_file.deinit(gpa, io); - if (comp.compiler_rt_dyn_lib) |*crt_file| crt_file.deinit(gpa, io); if (comp.fuzzer_lib) |*crt_file| crt_file.deinit(gpa, io); if (comp.glibc_so_files) |*glibc_file| { @@ -2749,20 +2722,20 @@ pub fn destroy(comp: *Compilation) void { openbsd_file.deinit(gpa, io); } - for (comp.c_object_table.keys()) |key| { - key.destroy(gpa, io); + for (comp.c_objects.items) |c_object| { + c_object.destroy(gpa, io); } - comp.c_object_table.deinit(gpa); + comp.c_objects.deinit(gpa); for (comp.failed_c_objects.values()) |bundle| { bundle.destroy(gpa); } comp.failed_c_objects.deinit(gpa); - for (comp.win32_resource_table.keys()) |key| { - key.destroy(gpa, io); + for (comp.win32_resources.items) |win32_resource| { + win32_resource.destroy(gpa, io); } - comp.win32_resource_table.deinit(gpa); + comp.win32_resources.deinit(gpa); for (comp.failed_win32_resources.values()) |*value| { value.deinit(gpa); @@ -3016,8 +2989,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // changes. For now, to avoid crashing the linker in this case, don't kick off C object // updates if we've done prelink already. https://codeberg.org/ziglang/zig/issues/32081 } else { - try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_object_table.count()); - for (comp.c_object_table.keys()) |c_object| { + try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_objects.items.len); + for (comp.c_objects.items) |c_object| { comp.c_object_work_queue.pushBackAssumeCapacity(c_object); try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); } @@ -3032,8 +3005,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work. // Add a Job for each Win32 resource file. - try comp.win32_resource_work_queue.ensureUnusedCapacity(gpa, comp.win32_resource_table.count()); - for (comp.win32_resource_table.keys()) |win32_resource| { + try comp.win32_resource_work_queue.ensureUnusedCapacity(gpa, comp.win32_resources.items.len); + for (comp.win32_resources.items) |win32_resource| { comp.win32_resource_work_queue.pushBackAssumeCapacity(win32_resource); switch (win32_resource.src) { .rc => |f| { @@ -3044,9 +3017,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE } if (comp.zcu) |zcu| { - const pt: Zcu.PerThread = .activate(zcu, .main); - defer pt.deactivate(); - assert(zcu.cur_analysis_timer == null); zcu.skip_analysis_this_update = false; @@ -3099,8 +3069,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE try comp.performAllTheWork(main_progress_node, arena); if (comp.zcu) |zcu| { - const pt: Zcu.PerThread = .activate(zcu, .main); - defer pt.deactivate(); + const active = zcu.acquire(); + defer active.release(); + const pt = active.pt; assert(zcu.cur_analysis_timer == null); @@ -3142,18 +3113,16 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE return; } - if (comp.zcu == null and comp.config.output_mode == .Obj and comp.c_object_table.count() == 1) { + if (comp.zcu == null and comp.config.output_mode == .Obj and comp.c_objects.items.len == 1) { // This is `zig build-obj foo.c`. We can emit asm and LLVM IR/bitcode. - const c_obj_path = comp.c_object_table.keys()[0].status.success.object_path; + const c_obj_path = comp.c_objects.items[0].status.success.object_path; if (comp.emit_asm) |path| try comp.emitFromCObject(arena, c_obj_path, ".s", path); if (comp.emit_llvm_ir) |path| try comp.emitFromCObject(arena, c_obj_path, ".ll", path); if (comp.emit_llvm_bc) |path| try comp.emitFromCObject(arena, c_obj_path, ".bc", path); } switch (comp.cache_use) { - .none, .incremental => { - try flush(comp, arena, .main); - }, + .none, .incremental => try flush(comp, arena), .whole => |whole| { if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); if (comp.parent_whole_cache) |pwc| { @@ -3234,7 +3203,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE }; } - try flush(comp, arena, .main); + try flush(comp, arena); // Calling `flush` may have produced errors, in which case the // cache manifest must not be written. @@ -3325,12 +3294,12 @@ pub fn resolveEmitPathFlush( } } -fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id) (Io.Cancelable || Allocator.Error)!void { +fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error)!void { const io = comp.io; + const tid: Zcu.PerThread.Id = .acquire(io); + defer tid.release(io); if (comp.zcu) |zcu| { if (zcu.llvm_object) |llvm_object| { - const pt: Zcu.PerThread = .activate(zcu, tid); - defer pt.deactivate(); // Emit the ZCU object from LLVM now; it's required to flush the output file. // If there's an output file, it wants to decide where the LLVM object goes! @@ -3348,7 +3317,9 @@ fn flush(comp: *Compilation, arena: Allocator, tid: Zcu.PerThread.Id) (Io.Cancel break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename); } else null; - llvm_object.emit(pt, .{ + const active = zcu.activate(tid); + defer active.deactivate(); + llvm_object.emit(active.pt, .{ .pre_ir_path = comp.verbose_llvm_ir, .pre_bc_path = comp.verbose_llvm_bc, @@ -3484,14 +3455,14 @@ fn addNonIncrementalStuffToCacheManifest( try link.hashInputs(man, comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - _ = try man.addFile(key.src.src_path, null); - man.hash.addOptional(key.src.ext); - man.hash.addListOfBytes(key.src.extra_flags); + for (comp.c_objects.items) |c_object| { + _ = try man.addFile(c_object.src.src_path, null); + man.hash.addOptional(c_object.src.ext); + man.hash.addListOfBytes(c_object.src.extra_flags); } - for (comp.win32_resource_table.keys()) |key| { - switch (key.src) { + for (comp.win32_resources.items) |win32_resource| { + switch (win32_resource.src) { .rc => |rc_src| { _ = try man.addFile(rc_src.src_path, null); man.hash.addListOfBytes(rc_src.extra_flags); @@ -4066,7 +4037,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { } } if (zcu.skip_analysis_this_update) break :zcu_errors; - var sorted_failed_analysis: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: { + var sorted_failed_analysis: std.array_hash_map.Auto(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: { const SortOrder = struct { zcu: *Zcu, errors: []const *Zcu.ErrorMsg, @@ -4362,7 +4333,7 @@ pub fn addModuleErrorMsg( // De-duplicate error notes. The main use case in mind for this is // too many "note: called from here" notes when eval branch quota is reached. - var notes: std.ArrayHashMapUnmanaged(ErrorBundle.ErrorMessage, void, ErrorNoteHashContext, true) = .empty; + var notes: std.array_hash_map.Custom(ErrorBundle.ErrorMessage, void, ErrorNoteHashContext, true) = .empty; defer notes.deinit(gpa); var last_note_loc: ?std.zig.Loc = null; @@ -4502,33 +4473,25 @@ fn performAllTheWork( defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu); if (comp.zcu) |zcu| { - const pt: Zcu.PerThread = .activate(zcu, .main); - defer { - pt.deactivate(); - // Regardless of errors, `comp.zcu` needs to update its generation number. - zcu.generation += 1; - } - try pt.update(main_progress_node, &decl_work_timer); + // Regardless of errors, `comp.zcu` needs to update its generation number. + defer zcu.generation += 1; + const active = zcu.acquire(); + defer active.release(); + try active.pt.update(main_progress_node, &decl_work_timer); } comp.link_queue.finishZcuQueue(comp); - // This has to happen after the main semantic analysis loop because it is possible for Sema to + // Main thread work is all done, now just wait for all async work. + try misc_group.await(io); + + // This has to happen again after the main semantic analysis loop because it is possible for Sema to // call `addLinkLib` and hence add more items to `comp.windows_libs`. - for (comp.windows_libs.keys()[comp.windows_libs_num_done..]) |link_lib| { - mingw.buildImportLib(comp, link_lib) catch |err| { - // TODO Surface more error details. - comp.lockAndSetMiscFailure( - .windows_import_lib, - "unable to generate DLL import .lib file for {s}: {t}", - .{ link_lib, err }, - ); - }; - } + for (comp.windows_libs.keys()[comp.windows_libs_num_done..]) |lib_name| + misc_group.async(io, buildMingwImportLib, .{ comp, lib_name, false, main_progress_node }); comp.windows_libs_num_done = @intCast(comp.windows_libs.count()); - - // Main thread work is all done, now just wait for all async work. try misc_group.await(io); + comp.link_queue.wait(io); } @@ -4587,24 +4550,6 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node }); } - // hack for stage2_x86_64 + coff - if (comp.queued_jobs.compiler_rt_dyn_lib and comp.compiler_rt_dyn_lib == null) { - prelink_group.async(io, buildRt, .{ - comp, - "compiler_rt.zig", - "compiler_rt", - .Lib, - .dynamic, - .compiler_rt, - main_progress_node, - RtOptions{ - .checks_valgrind = true, - .allow_lto = false, - }, - &comp.compiler_rt_dyn_lib, - }); - } - if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) { prelink_group.async(io, buildRt, .{ comp, @@ -4748,6 +4693,16 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node }); } + while (comp.windows_libs_num_done < comp.windows_libs.count()) { + prelink_group.async(io, buildMingwImportLib, .{ + comp, + comp.windows_libs.keys()[comp.windows_libs_num_done], + true, + main_progress_node, + }); + comp.windows_libs_num_done += 1; + } + prelink_group.await(io) catch |err| switch (err) { error.Canceled => unreachable, // see swapCancelProtection above }; @@ -4835,7 +4790,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { var buffer: [1024]u8 = undefined; var tar_file_writer = tar_file.writer(io, &buffer); - var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .empty; + var seen_table: std.array_hash_map.Auto(*Package.Module, []const u8) = .empty; defer seen_table.deinit(comp.gpa); try seen_table.put(comp.gpa, zcu.main_mod, comp.root_name); @@ -5433,6 +5388,39 @@ fn buildMingwCrtFile(comp: *Compilation, crt_file: mingw.CrtFile, prog_node: std } } +fn buildMingwImportLib(comp: *Compilation, lib_name: []const u8, is_prelink: bool, prog_node: std.Progress.Node) void { + const crt_file_path = mingw.buildImportLib(comp, lib_name, prog_node) catch |err| switch (err) { + // TODO: This isn't actually true for self-hosted + // In the non-prelink case we will end up putting foo.lib onto the linker line and letting the linker + // use its library paths to look for libraries and report any problems. + error.DefNotFound => return if (is_prelink) { + comp.lockAndSetMiscFailure( + .windows_import_lib, + "definition not found for required mingw DLL import .lib {s}", + .{lib_name}, + ); + }, + // TODO Surface more error details. + else => |e| return comp.lockAndSetMiscFailure( + .windows_import_lib, + "unable to generate mingw DLL import .lib file for {s}: {t}", + .{ lib_name, e }, + ), + }; + + if (is_prelink) + comp.queuePrelinkTasks(&.{.{ + .load_archive = .{ + .path = crt_file_path, + .must_link = false, + }, + }}) catch |err| comp.lockAndSetMiscFailure( + .windows_import_lib, + "unable to queue prelink task for mingw import lib {f}: {t}", + .{ crt_file_path, err }, + ); +} + fn buildWasiLibcCrtFile(comp: *Compilation, crt_file: wasi_libc.CrtFile, prog_node: std.Progress.Node) void { if (wasi_libc.buildCrtFile(comp, crt_file, prog_node)) |_| { comp.queued_jobs.wasi_libc_crt_file[@intFromEnum(crt_file)] = false; @@ -5596,9 +5584,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr c_source_basename[0 .. c_source_basename.len - fs.path.extension(c_source_basename).len]; const target = comp.getTarget(); + assert(target.ofmt != .c); const o_ext = target.ofmt.fileExt(target.cpu.arch); const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { - var argv = std.array_list.Managed([]const u8).init(gpa); + var argv: std.array_list.Managed([]const u8) = .init(gpa); defer argv.deinit(); // In case we are doing passthrough mode, we need to detect -S and -emit-llvm. @@ -6357,6 +6346,8 @@ fn addCommonCCArgs( .serenity => try argv.append("__serenity__"), // Homebrew targets without LLVM support; use communities's preferred macros. .@"3ds" => try argv.append("-D__3DS__"), + .wiiu => try argv.append("-D__WIIU__"), + .psx => try argv.append("-D__psx__"), .psp => try argv.append("-D__PSP__"), .vita => try argv.append("-D__vita__"), else => {}, @@ -7059,13 +7050,41 @@ pub const FileExt = enum { .unknown => "", }; } + + /// The value accepted by "zig clang -x " and passed to "clang -x ". + pub fn toLang(ext: FileExt) ?[]const u8 { + return switch (ext) { + else => null, + .c => "c", + .h => "c-header", + .cpp => "c++", + .hpp => "c++-header", + .m => "objective-c", + .hm => "objective-c-header", + .mm => "objective-c++", + .hmm => "objective-c++-header", + .assembly => "assembler", + .assembly_with_cpp => "assembler-with-cpp", + }; + } + + /// Supported languages for "zig clang -x ". + /// Loosely based on llvm-project/clang/include/clang/Driver/Types.def + pub const from_lang = std.StaticStringMap(FileExt).initComptime(init: { + var init: []const struct { []const u8, FileExt } = &.{}; + for (std.enums.values(FileExt)) |file_ext| if (file_ext.toLang()) |lang| { + init = init ++ .{.{ lang, file_ext }}; + }; + break :init init; + }); }; pub fn hasObjectExt(filename: []const u8) bool { return mem.endsWith(u8, filename, ".o") or mem.endsWith(u8, filename, ".lo") or mem.endsWith(u8, filename, ".obj") or - mem.endsWith(u8, filename, ".rmeta"); + mem.endsWith(u8, filename, ".rmeta") or + mem.endsWith(u8, filename, ".spv"); } pub fn hasStaticLibraryExt(filename: []const u8) bool { diff --git a/src/InternPool.zig b/src/InternPool.zig index b32dee237ddd36f81abc2277fe23992cc1380c09..be6e45441e55ec373e533643786528d0abeb310c 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -41,22 +41,22 @@ tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32), /// * For a `func`, this is the source of the full function signature. /// These are also invalidated if tracking fails for this instruction. /// Value is index into `dep_entries` of the first dependency on this hash. -src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index), +src_hash_deps: std.array_hash_map.Auto(TrackedInst.Index, DepEntry.Index), /// Dependencies on the value of a Nav. /// Value is index into `dep_entries` of the first dependency on this Nav value. -nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index), +nav_val_deps: std.array_hash_map.Auto(Nav.Index, DepEntry.Index), /// Dependencies on the type of a Nav. /// Value is index into `dep_entries` of the first dependency on this Nav value. -nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index), +nav_ty_deps: std.array_hash_map.Auto(Nav.Index, DepEntry.Index), /// Dependencies on a function's inferred error set. Key is the function body, not the IES. /// Value is index into `dep_entries` of the first dependency on this function's IES. -func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), +func_ies_deps: std.array_hash_map.Auto(Index, DepEntry.Index), /// Dependencies on the resolved layout of a `struct`, `union`, or `enum` type. /// Value is index into `dep_entries` of the first dependency on this type's layout. -type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), +type_layout_deps: std.array_hash_map.Auto(Index, DepEntry.Index), /// Dependencies on the resolved default field values of a `struct` type. /// Value is index into `dep_entries` of the first dependency on this type's inits. -struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), +struct_defaults_deps: std.array_hash_map.Auto(Index, DepEntry.Index), /// Dependencies on a Zig or ZON source file. Triggered by `@import`. /// * For ZON source files, the dependency is invalidated if the file changes at all. The `@import` /// must be re-analyzed to return the new data structure. @@ -64,18 +64,18 @@ struct_defaults_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), /// (which can only happen because the `.main_struct_inst` got lost). The `@import` must be /// re-analyzed to return the new type. /// Value is index into `dep_entries` of the first dependency on this Zig/ZON file. -source_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), +source_file_deps: std.array_hash_map.Auto(FileIndex, DepEntry.Index), /// Dependencies on an embedded file. /// Introduced by `@embedFile`; invalidated when the file changes. /// Value is index into `dep_entries` of the first dependency on this `Zcu.EmbedFile`. -embed_file_deps: std.AutoArrayHashMapUnmanaged(Zcu.EmbedFile.Index, DepEntry.Index), +embed_file_deps: std.array_hash_map.Auto(Zcu.EmbedFile.Index, DepEntry.Index), /// Dependencies on the full set of names in a ZIR namespace. /// Key refers to a `struct_decl`, `union_decl`, etc. /// Value is index into `dep_entries` of the first dependency on this namespace. -namespace_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index), +namespace_deps: std.array_hash_map.Auto(TrackedInst.Index, DepEntry.Index), /// Dependencies on the (non-)existence of some name in a namespace. /// Value is index into `dep_entries` of the first dependency on this name. -namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.Index), +namespace_name_deps: std.array_hash_map.Auto(NamespaceNameKey, DepEntry.Index), // Dependencies on the value of fields memoized on `Zcu` (`panic_messages` etc). // If set, these are indices into `dep_entries` of the first dependency on this state. memoized_state_main_deps: DepEntry.Index.Optional, @@ -86,7 +86,7 @@ memoized_state_assembly_deps: DepEntry.Index.Optional, /// Given a `Depender`, points to an entry in `dep_entries` whose `depender` /// matches. The `next_dependee` field can be used to iterate all such entries /// and remove them from the corresponding lists. -first_dependency: std.AutoArrayHashMapUnmanaged(AnalUnit, DepEntry.Index), +first_dependency: std.array_hash_map.Auto(AnalUnit, DepEntry.Index), /// Stores dependency information. The hashmaps declared above are used to look /// up entries in this list as required. This is not stored in `extra` so that @@ -108,9 +108,9 @@ pub const empty: InternPool = .{ .shards = &.{}, .global_error_set = .empty, .tid_width = 0, - .tid_shift_30 = if (single_threaded) 0 else 31, - .tid_shift_31 = if (single_threaded) 0 else 31, - .tid_shift_32 = if (single_threaded) 0 else 31, + .tid_shift_30 = 0, + .tid_shift_31 = 0, + .tid_shift_32 = 0, .src_hash_deps = .empty, .nav_val_deps = .empty, .nav_ty_deps = .empty, @@ -648,15 +648,15 @@ pub const Nav = struct { fn wrap(unwrapped: Unwrapped, ip: *const InternPool) Nav.Index { assert(@intFromEnum(unwrapped.tid) <= ip.getTidMask()); - assert(unwrapped.index <= ip.getIndexMask(u32)); - return @enumFromInt(@shlExact(@as(u32, @intFromEnum(unwrapped.tid)), ip.tid_shift_32) | + assert(unwrapped.index <= ip.getIndexMask(u30)); + return @enumFromInt(@shlExact(@as(u32, @intFromEnum(unwrapped.tid)), ip.tid_shift_30) | unwrapped.index); } }; fn unwrap(nav_index: Nav.Index, ip: *const InternPool) Unwrapped { return .{ - .tid = @enumFromInt(@intFromEnum(nav_index) >> ip.tid_shift_32 & ip.getTidMask()), - .index = @intFromEnum(nav_index) & ip.getIndexMask(u32), + .tid = @enumFromInt(@intFromEnum(nav_index) >> ip.tid_shift_30 & ip.getTidMask()), + .index = @intFromEnum(nav_index) & ip.getIndexMask(u30), }; } @@ -1587,7 +1587,7 @@ fn getIndexMask(ip: *const InternPool, comptime BackingInt: type) u32 { return @as(u32, std.math.maxInt(BackingInt)) >> ip.tid_width; } -const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false); +const FieldMap = std.array_hash_map.Custom(void, void, std.array_hash_map.AutoContext(void), false); /// An index into `maps` which might be `none`. pub const OptionalMapIndex = enum(u32) { @@ -1983,6 +1983,7 @@ pub const Key = union(enum) { union_type: ContainerType, opaque_type: ContainerType, enum_type: ContainerType, + spirv_type: SpirvType, func_type: FuncType, error_set_type: ErrorSetType, /// The payload is the function body, either a `func_decl` or `func_instance`. @@ -2146,6 +2147,15 @@ pub const Key = union(enum) { }; }; + pub const SpirvType = extern struct { + /// A `spirv_reify` instruction. + zir_index: TrackedInst.Index, + /// Always 0. + padding: u32 = 0, + /// A hash of this type's attributes generated by Sema. + type_hash: u64, + }; + pub const FuncType = struct { param_types: Index.Slice, return_type: Index, @@ -2583,13 +2593,13 @@ pub const Key = union(enum) { const KeyTag = @typeInfo(Key).@"union".tag_type.?; const seed = @intFromEnum(@as(KeyTag, key)); return switch (key) { - // TODO: assert no padding in these types inline .ptr_type, .array_type, .vector_type, .opt_type, .anyframe_type, .error_union_type, + .spirv_type, .simple_type, .simple_value, .opt, @@ -2599,7 +2609,11 @@ pub const Key = union(enum) { .enum_tag, .inferred_error_set_type, .un, - => |x| Hash.hash(seed, asBytes(&x)), + => |x| { + _ = extern struct { is_extern: @TypeOf(x) }; + comptime assert(std.meta.hasUniqueRepresentation(@TypeOf(x))); + return Hash.hash(seed, asBytes(&x)); + }, .int_type => |x| Hash.hash(seed + @intFromEnum(x.signedness), asBytes(&x.bits)), @@ -2841,6 +2855,10 @@ pub const Key = union(enum) { const b_info = b.error_union_type; return std.meta.eql(a_info, b_info); }, + .spirv_type => |a_info| { + const b_info = b.spirv_type; + return std.meta.eql(a_info, b_info); + }, .simple_type => |a_info| { const b_info = b.simple_type; return a_info == b_info; @@ -3130,6 +3148,7 @@ pub const Key = union(enum) { .simple_type, .struct_type, .union_type, + .spirv_type, .opaque_type, .enum_type, .tuple_type, @@ -3877,6 +3896,14 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType { }; } +pub fn loadSpirvType(ip: *const InternPool, index: Index) Tag.TypeSpirv { + const unwrapped_index = index.unwrap(ip); + const item = unwrapped_index.getItem(ip); + assert(item.tag == .type_spirv); + const extra = extraData(unwrapped_index.getExtra(ip), Tag.TypeSpirv, item.data); + return extra; +} + pub const Item = struct { tag: Tag, /// The doc comments on the respective Tag explain how to interpret this. @@ -4146,10 +4173,7 @@ pub const Index = enum(u32) { const debug_state = InternPool.debug_state; }; pub fn unwrap(index: Index, ip: *const InternPool) Unwrapped { - return if (single_threaded) .{ - .tid = .main, - .index = @intFromEnum(index), - } else .{ + return .{ .tid = @enumFromInt(@intFromEnum(index) >> ip.tid_shift_30 & ip.getTidMask()), .index = @intFromEnum(index) & ip.getIndexMask(u30), }; @@ -4183,12 +4207,14 @@ pub const Index = enum(u32) { 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, param_types: []Index }, + trailing: struct { comptime_bits: []u32, noalias_bits: []u32, cc_bits: []u32, param_types: []Index }, }, type_tuple: struct { const @"data.fields_len" = opaque {}; @@ -4214,6 +4240,8 @@ pub const Index = enum(u32) { type_enum_nonexhaustive: struct { data: *Tag.TypeEnum }, type_opaque: struct { data: *Tag.TypeOpaque }, + type_spirv: struct { data: *Tag.TypeSpirv }, + undef: DataIsIndex, simple_value: void, ptr_nav: struct { data: *PtrNav }, @@ -4841,6 +4869,10 @@ pub const Tag = enum(u8) { /// data is extra index of `TypeEnum`. type_enum_nonexhaustive, + /// An spirv type. + /// data is index of `TypeSpirv` in extra. + type_spirv, + /// An opaque type. /// data is extra index of `TypeOpaque`. type_opaque, @@ -5033,9 +5065,9 @@ pub const Tag = enum(u8) { field_types: []Index, }, .config = .{ - .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", - .@"trailing.captures.?" = .@"payload.captures_len != .reified", - .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", + .@"trailing.type_hash.?" = .@"payload.bits.captures_len == .reified", + .@"trailing.captures.?" = .@"payload.bits.captures_len != .reified", + .@"trailing.captures.?.len" = .@"@intFromEnum(payload.bits.captures_len)", .@"trailing.field_names.len" = .@"payload.fields_len", .@"trailing.field_types.len" = .@"payload.fields_len", }, @@ -5051,9 +5083,9 @@ pub const Tag = enum(u8) { field_defaults: []Index, }, .config = .{ - .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", - .@"trailing.captures.?" = .@"payload.captures_len != .reified", - .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", + .@"trailing.type_hash.?" = .@"payload.bits.captures_len == .reified", + .@"trailing.captures.?" = .@"payload.bits.captures_len != .reified", + .@"trailing.captures.?.len" = .@"@intFromEnum(payload.bits.captures_len)", .@"trailing.field_names.len" = .@"payload.fields_len", .@"trailing.field_types.len" = .@"payload.fields_len", .@"trailing.field_defaults.len" = .@"payload.fields_len", @@ -5068,9 +5100,9 @@ pub const Tag = enum(u8) { field_types: []Index, }, .config = .{ - .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", - .@"trailing.captures.?" = .@"payload.captures_len != .reified", - .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", + .@"trailing.type_hash.?" = .@"payload.bits.captures_len == .reified", + .@"trailing.captures.?" = .@"payload.bits.captures_len != .reified", + .@"trailing.captures.?.len" = .@"@intFromEnum(payload.bits.captures_len)", .@"trailing.field_types.len" = .@"payload.fields_len", }, }; @@ -5087,11 +5119,11 @@ pub const Tag = enum(u8) { field_values: []Index, }, .config = .{ - .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag", - .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag", - .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", - .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag", - .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", + .@"trailing.owner_union.?" = .@"payload.bits.captures_len == .generated_union_tag", + .@"trailing.zir_index.?" = .@"payload.bits.captures_len != .generated_union_tag", + .@"trailing.type_hash.?" = .@"payload.bits.captures_len == .reified", + .@"trailing.captures.?" = .@"payload.bits.captures_len != .reified and payload.bits.captures_len != .generated_union_tag", + .@"trailing.captures.?.len" = .@"@intFromEnum(payload.bits.captures_len)", .@"trailing.field_names.len" = .@"payload.fields_len", .@"trailing.field_values.len" = .@"payload.fields_len", }, @@ -5140,6 +5172,7 @@ pub const Tag = enum(u8) { .trailing = struct { param_comptime_bits: ?[]u32, param_noalias_bits: ?[]u32, + param_cc_bits: ?[]u32, param_type: []Index, }, .config = .{ @@ -5147,6 +5180,8 @@ pub const Tag = enum(u8) { .@"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", }, }, @@ -5221,16 +5256,17 @@ pub const Tag = enum(u8) { field_names: []NullTerminatedString, }, .config = .{ - .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag", - .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag", - .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", - .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag", - .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", + .@"trailing.owner_union.?" = .@"payload.bits.captures_len == .generated_union_tag", + .@"trailing.zir_index.?" = .@"payload.bits.captures_len != .generated_union_tag", + .@"trailing.type_hash.?" = .@"payload.bits.captures_len == .reified", + .@"trailing.captures.?" = .@"payload.bits.captures_len != .reified and payload.bits.captures_len != .generated_union_tag", + .@"trailing.captures.?.len" = .@"@intFromEnum(payload.bits.captures_len)", .@"trailing.field_names.len" = .@"payload.fields_len", }, }, .type_enum_explicit = enum_explicit_encoding, .type_enum_nonexhaustive = enum_explicit_encoding, + .type_spirv = .{ .summary = .@"{.payload.name%summary#\"}", .payload = Tag.TypeSpirv }, .type_opaque = .{ .summary = .@"{.payload.name%summary#\"}", .payload = TypeOpaque, @@ -5375,16 +5411,15 @@ pub const Tag = enum(u8) { _: u23 = 0, pub const Source = enum(u1) { builtin, syntax }; - pub const DecorationType = enum(u2) { none, location, descriptor }; + pub const DecorationType = enum(u2) { none, location, descriptor, flat }; }; pub fn decoration(self: Extern) ?std.lang.ExternOptions.Decoration { return switch (self.flags.decoration_type) { .none => null, - .location => std.lang.ExternOptions.Decoration{ - .location = self.location_or_descriptor_set, - }, + .location => std.lang.ExternOptions.Decoration{ .location = self.location_or_descriptor_set }, .descriptor => std.lang.ExternOptions.Decoration{ .descriptor = .{ .set = self.location_or_descriptor_set, .binding = self.descriptor_binding } }, + .flat => std.lang.ExternOptions.Decoration{ .flat = self.location_or_descriptor_set }, }; } }; @@ -5688,6 +5723,34 @@ pub const Tag = enum(u8) { name_nav: Nav.Index.Optional, namespace: NamespaceIndex, }; + + /// Trailing: + /// 0. type_hash: PackedU64 + pub const TypeSpirv = struct { + name: NullTerminatedString, + /// The index of the `reify_spirv_type` instruction. + zir_index: TrackedInst.Index, + /// If tag is `.image`, this is the sampled type or `.none` if `usage` is `.storage`. + /// If tag is `.sampled_image`, this is the image type. + /// If tag is `.runtime_array`, this is the element type. + /// Otherwise this is `.none`. + ty: Index, + flags: Flags, + + pub const Flags = packed struct(u32) { + tag: @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?, + // Image type flags + usage: @typeInfo(std.lang.Type.Spirv.Image.Usage).@"union".tag_type.?, + format: std.lang.Type.Spirv.Image.Format, + dim: std.lang.Type.Spirv.Image.Dimensionality, + depth: std.lang.Type.Spirv.Image.Depth, + access: std.lang.Type.Spirv.Image.Access, + is_arrayed: bool, + is_multisampled: bool, + + _: u16 = 0, + }; + }; }; /// Differentiates between user-provided and compiler-generated backing types for packed and tagged types. @@ -5949,13 +6012,7 @@ pub const Alignment = enum(u6) { return r; } - const LlvmBuilderAlignment = std.zig.llvm.Builder.Alignment; - - pub fn toLlvm(a: Alignment) LlvmBuilderAlignment { - return @enumFromInt(@intFromEnum(a)); - } - - pub fn fromLlvm(a: LlvmBuilderAlignment) Alignment { + pub fn toLlvm(a: Alignment) std.zig.llvm.Builder.Alignment { return @enumFromInt(@intFromEnum(a)); } }; @@ -6322,7 +6379,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, io: Io, available_threads: usize) ! } pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { - if (debug_state.enable_checks) std.debug.assert(debug_state.intern_pool == null); + std.debug.assert(debug_state.intern_pool == null); ip.src_hash_deps.deinit(gpa); ip.nav_val_deps.deinit(gpa); @@ -6367,8 +6424,15 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { ip.* = undefined; } -pub fn activate(ip: *const InternPool) void { - if (!debug_state.enable) return; +pub const Active = struct { + prev_ip: if (debug_state.enable) ?*const InternPool else void, + pub fn deactivate(active: Active) void { + if (!debug_state.enable) return; + debug_state.intern_pool = active.prev_ip; + } +}; +pub fn activate(ip: *const InternPool) Active { + if (!debug_state.enable) return .{ .prev_ip = {} }; _ = Index.Unwrapped.debug_state; _ = String.debug_state; _ = OptionalString.debug_state; @@ -6378,20 +6442,16 @@ pub fn activate(ip: *const InternPool) void { _ = TrackedInst.Index.Optional.debug_state; _ = Nav.Index.debug_state; _ = Nav.Index.Optional.debug_state; - if (debug_state.enable_checks) std.debug.assert(debug_state.intern_pool == null); - debug_state.intern_pool = ip; -} - -pub fn deactivate(ip: *const InternPool) void { - if (!debug_state.enable) return; - std.debug.assert(debug_state.intern_pool == ip); - if (debug_state.enable_checks) debug_state.intern_pool = null; + defer debug_state.intern_pool = ip; + return .{ .prev_ip = debug_state.intern_pool }; } /// For debugger access only. const debug_state = struct { - const enable = false; - const enable_checks = enable and !builtin.single_threaded; + const enable = switch (builtin.zig_backend) { + else => false, + .stage2_x86_64 => !builtin.strip_debug_info and build_options.io_mode == .threaded, + }; threadlocal var intern_pool: ?*const InternPool = null; }; @@ -6573,6 +6633,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { } }, }; } }, + .type_spirv => .{ .spirv_type = ns: { + const extra_list = unwrapped_index.getExtra(ip); + const extra = extraDataTrail(extra_list, Tag.TypeSpirv, data); + break :ns .{ + .zir_index = extra.data.zir_index, + .type_hash = extraData(extra_list, PackedU64, extra.end).get(), + }; + } }, .type_opaque => .{ .opaque_type = ns: { const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); break :ns .{ .declared = .{ @@ -6918,6 +6986,9 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke trail_index += 1; break :b x; }; + const cc_extra_len = type_function.data.flags.cc.extraLen(); + const cc = type_function.data.flags.cc.unpack(extra.view().items(.@"0")[trail_index..][0..cc_extra_len]); + trail_index += cc_extra_len; return .{ .param_types = .{ .tid = tid, @@ -6927,7 +6998,7 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke .return_type = type_function.data.return_type, .comptime_bits = comptime_bits, .noalias_bits = noalias_bits, - .cc = type_function.data.flags.cc.unpack(), + .cc = cc, .is_var_args = type_function.data.flags.is_var_args, .is_noinline = type_function.data.flags.is_noinline, }; @@ -7345,6 +7416,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType .opaque_type => unreachable, // instead use: getDeclaredOpaqueType + .spirv_type => unreachable, // instead use: getSpirvType .tuple_type => unreachable, // use getTupleType() instead .func_type => unreachable, // use getFuncType() instead @@ -8717,6 +8789,39 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT } }; } +pub fn getReifiedSpirvType( + ip: *InternPool, + gpa: Allocator, + io: Io, + tid: Zcu.PerThread.Id, + ini: struct { + zir_index: TrackedInst.Index, + type_hash: u64, + type_spirv: Tag.TypeSpirv, + }, +) Allocator.Error!Index { + var gop = try ip.getOrPutKey(gpa, io, tid, .{ .spirv_type = .{ + .zir_index = ini.zir_index, + .type_hash = ini.type_hash, + } }); + defer gop.deinit(); + if (gop == .existing) return gop.existing; + + const local = ip.getLocal(tid); + const items = local.getMutableItems(gpa, io); + const extra = local.getMutableExtra(gpa, io); + try items.ensureUnusedCapacity(1); + + try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeSpirv).@"struct".field_names.len + + 2 // type_hash: PackedU64 + ); + const extra_index = addExtraAssumeCapacity(extra, ini.type_spirv); + _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); + + items.appendAssumeCapacity(.{ .tag = .type_spirv, .data = extra_index }); + return gop.put(); +} + pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { /// The union type for which this enum is a generated tag. union_type: Index, @@ -8992,18 +9097,21 @@ pub fn getFuncType( // ask if it already exists, and if so, revert the lengths of the mutated // arrays. This is similar to what `getOrPutTrailingString` does. const prev_extra_len = extra.mutate.len; + const packed_cc: PackedCallingConvention = .pack(key.cc orelse .auto); + const cc_extra_len = packed_cc.extraLen(); const params_len: u32 = @intCast(key.param_types.len); try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeFunction).@"struct".field_names.len + @intFromBool(key.comptime_bits != 0) + @intFromBool(key.noalias_bits != 0) + + cc_extra_len + params_len); const func_type_extra_index = addExtraAssumeCapacity(extra, Tag.TypeFunction{ .params_len = params_len, .return_type = key.return_type, .flags = .{ - .cc = .pack(key.cc orelse .auto), + .cc = packed_cc, .is_var_args = key.is_var_args, .has_comptime_bits = key.comptime_bits != 0, .has_noalias_bits = key.noalias_bits != 0, @@ -9013,6 +9121,18 @@ pub fn getFuncType( if (key.comptime_bits != 0) extra.appendAssumeCapacity(.{key.comptime_bits}); if (key.noalias_bits != 0) extra.appendAssumeCapacity(.{key.noalias_bits}); + if (key.cc) |cc| switch (cc) { + .spirv_kernel, .spirv_task => |kernel| extra.appendSliceAssumeCapacity(.{&.{ + kernel.x, + kernel.y, + kernel.z, + }}), + .spirv_mesh => |mesh| extra.appendSliceAssumeCapacity(.{&.{ + mesh.max_primitives, + mesh.max_vertices, + }}), + else => {}, + }; extra.appendSliceAssumeCapacity(.{@ptrCast(key.param_types)}); errdefer extra.mutate.len = prev_extra_len; @@ -9077,7 +9197,8 @@ pub fn getExtern( }) catch unreachable; // capacity asserted above const decoration_type, const location_or_descriptor_set, const descriptor_binding = if (key.decoration) |decoration| switch (decoration) { .location => |location| .{ Tag.Extern.Flags.DecorationType.location, location, undefined }, - .descriptor => |descriptor| .{ Tag.Extern.Flags.DecorationType.descriptor, descriptor.binding, descriptor.set }, + .flat => |location| .{ Tag.Extern.Flags.DecorationType.flat, location, undefined }, + .descriptor => |descriptor| .{ Tag.Extern.Flags.DecorationType.descriptor, descriptor.set, descriptor.binding }, } else .{ Tag.Extern.Flags.DecorationType.none, undefined, undefined }; const extra_index = addExtraAssumeCapacity(extra, Tag.Extern{ .ty = key.ty, @@ -9810,6 +9931,7 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { Tag.TypeStructPacked.Bits, Tag.TypeUnionPacked.Bits, Tag.TypeEnum.Bits, + Tag.TypeSpirv.Flags, => @bitCast(@field(item, field_name)), else => @compileError("bad field type: " ++ @typeName(field_type)), @@ -9877,6 +9999,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat Tag.TypeStructPacked.Bits, Tag.TypeUnionPacked.Bits, Tag.TypeEnum.Bits, + Tag.TypeSpirv.Flags, => @bitCast(extra_item), else => @compileError("bad field type: " ++ @typeName(field_type)), @@ -9930,6 +10053,11 @@ pub fn childType(ip: *const InternPool, i: Index) Index { .vector_type => |vector_type| vector_type.child, .array_type => |array_type| array_type.child, .opt_type, .anyframe_type => |child| child, + .spirv_type => blk: { + const info = ip.loadSpirvType(i); + assert(info.flags.tag == .runtime_array); + break :blk info.ty; + }, else => unreachable, }; } @@ -10583,6 +10711,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo .type_optional => 0, .type_anyframe => 0, .type_error_union => @sizeOf(Key.ErrorUnionType), + .type_spirv => @sizeOf(Tag.TypeSpirv) + @sizeOf(PackedU64), .type_anyerror_union => 0, .type_error_set => b: { const info = extraData(extra_list, Tag.ErrorSet, data); @@ -10597,6 +10726,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo const info = extraData(extra_list, Tag.TypeFunction, data); break :b @sizeOf(Tag.TypeFunction) + (@sizeOf(Index) * info.params_len) + + (@as(u32, 4) * info.flags.cc.extraLen()) + (@as(u32, 4) * @intFromBool(info.flags.has_comptime_bits)) + (@as(u32, 4) * @intFromBool(info.flags.has_noalias_bits)); }, @@ -10860,6 +10990,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { .type_enum_explicit, .type_enum_nonexhaustive, .type_opaque, + .type_spirv, .undef, .ptr_nav, .ptr_comptime_alloc, @@ -10931,7 +11062,7 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator, defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - var instances: std.AutoArrayHashMapUnmanaged(Index, std.ArrayList(Index)) = .empty; + var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty; for (ip.locals, 0..) |*local, tid| { const items = local.shared.items.view().slice(); const extra_list = local.shared.extra; @@ -11598,6 +11729,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { .type_enum_explicit, .type_enum_nonexhaustive, .type_opaque, + .type_spirv, => .type_type, .undef, @@ -11955,6 +12087,8 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.lang.TypeId { .type_opaque, => .@"opaque", + .type_spirv => .spirv, + .type_function => .@"fn", // values, not types @@ -12462,12 +12596,35 @@ const PackedCallingConvention = packed struct(u18) { .incoming_stack_alignment = .fromByteUnits(pl.incoming_stack_alignment orelse 0), .extra = @intFromEnum(pl.save), }, + std.lang.CallingConvention.SpirvKernelOptions => .{ + .tag = tag, + .incoming_stack_alignment = .none, + .extra = 0, + }, + std.lang.CallingConvention.SpirvFragmentOptions => .{ + .tag = tag, + .incoming_stack_alignment = .none, + .extra = @as(u4, @intFromEnum(pl.depth_assumption)) << 1 | @intFromBool(pl.pixel_centered_integer), + }, + std.lang.CallingConvention.SpirvMeshOptions => .{ + .tag = tag, + .incoming_stack_alignment = .none, + .extra = @intFromEnum(pl.stage_output), + }, else => comptime unreachable, }, }; } - fn unpack(cc: PackedCallingConvention) std.lang.CallingConvention { + fn extraLen(cc: PackedCallingConvention) u2 { + return switch (cc.tag) { + .spirv_kernel, .spirv_task => 3, + .spirv_mesh => 2, + else => 0, + }; + } + + fn unpack(cc: PackedCallingConvention, trailing: []const u32) std.lang.CallingConvention { return switch (cc.tag) { inline else => |tag| @unionInit( std.lang.CallingConvention, @@ -12505,6 +12662,20 @@ const PackedCallingConvention = packed struct(u18) { .incoming_stack_alignment = cc.incoming_stack_alignment.toByteUnits(), .save = @enumFromInt(cc.extra), }, + std.lang.CallingConvention.SpirvKernelOptions => .{ + .x = trailing[0], + .y = trailing[1], + .z = trailing[2], + }, + std.lang.CallingConvention.SpirvFragmentOptions => .{ + .pixel_centered_integer = @bitCast(@as(u1, @truncate(cc.extra))), + .depth_assumption = @enumFromInt(@as(u2, @truncate(cc.extra >> 1))), + }, + std.lang.CallingConvention.SpirvMeshOptions => .{ + .stage_output = @enumFromInt(cc.extra), + .max_primitives = trailing[0], + .max_vertices = trailing[1], + }, else => comptime unreachable, }, ), diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig index d5e0c3e615c687b775852f65a9d1df9393ec852e..20e19cdaa7ad2e55b9ddb07f490df1ffdaa26eea 100644 --- a/src/Package/Fetch.zig +++ b/src/Package/Fetch.zig @@ -162,9 +162,9 @@ pub const JobQueue = struct { /// Both non-lazy and lazy dependencies are always fetched. all, }; - pub const Table = std.AutoArrayHashMapUnmanaged(Package.Hash, *Fetch); - pub const UnlazySet = std.AutoArrayHashMapUnmanaged(Package.Hash, void); - pub const ForkSet = std.ArrayHashMapUnmanaged(Fork, void, Fork.Context, false); + pub const Table = std.array_hash_map.Auto(Package.Hash, *Fetch); + pub const UnlazySet = std.array_hash_map.Auto(Package.Hash, void); + pub const ForkSet = std.array_hash_map.Custom(Fork, void, Fork.Context, false); pub const Fork = struct { path: Cache.Path, @@ -1725,7 +1725,7 @@ fn computeHash(f: *Fetch, pkg_path: Cache.Path, filter: Filter) RunError!Compute // Track directories which had any files deleted from them so that empty directories // can be deleted. - var sus_dirs: std.StringArrayHashMapUnmanaged(void) = .empty; + var sus_dirs: std.array_hash_map.String(void) = .empty; defer sus_dirs.deinit(gpa); var walker = try root_dir.walk(gpa); @@ -2002,7 +2002,7 @@ fn normalizePath(bytes: []u8) void { } const Filter = struct { - include_paths: std.StringArrayHashMapUnmanaged(void) = .empty, + include_paths: std.array_hash_map.String(void) = .empty, /// sub_path is relative to the package root. pub fn includePath(self: *const Filter, sub_path: []const u8) bool { diff --git a/src/Package/Manifest.zig b/src/Package/Manifest.zig index 05ca2a31c25d6939bc190f19b79cc9d53bea2647..849fc742ec5c7b5be02a2895f54f99fece02b2ff 100644 --- a/src/Package/Manifest.zig +++ b/src/Package/Manifest.zig @@ -42,9 +42,9 @@ name: []const u8, id: u32, version: std.SemanticVersion, version_node: Ast.Node.Index, -dependencies: std.StringArrayHashMapUnmanaged(Dependency), +dependencies: std.array_hash_map.String(Dependency), dependencies_node: Ast.Node.OptionalIndex, -paths: std.StringArrayHashMapUnmanaged(void), +paths: std.array_hash_map.String(void), minimum_zig_version: ?std.SemanticVersion, errors: []ErrorMessage, @@ -144,9 +144,9 @@ const Parse = struct { id: u32, version: std.SemanticVersion, version_node: Ast.Node.Index, - dependencies: std.StringArrayHashMapUnmanaged(Dependency), + dependencies: std.array_hash_map.String(Dependency), dependencies_node: Ast.Node.OptionalIndex, - paths: std.StringArrayHashMapUnmanaged(void), + paths: std.array_hash_map.String(void), allow_missing_paths_field: bool, minimum_zig_version: ?std.SemanticVersion, diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 9241293d1dd480b1d9046c26e2d419a6874d2556..0c7e4166adf7d6c290cbb330bb12857c1cf21d90 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -35,11 +35,11 @@ cc_argv: []const []const u8, structured_cfg: bool, no_builtin: bool, -pub const Deps = std.StringArrayHashMapUnmanaged(*Module); +pub const Deps = std.array_hash_map.String(*Module); pub const Tree = struct { /// Each `Package` exposes a `Module` with build.zig as its root source file. - build_module_table: std.AutoArrayHashMapUnmanaged(MultiHashHexDigest, *Module), + build_module_table: std.array_hash_map.Auto(MultiHashHexDigest, *Module), }; pub const CreateOptions = struct { diff --git a/src/RangeSet.zig b/src/RangeSet.zig index 34597062027bf7c04667575ed43c719ac48eeeb5..3033e8510394cbef68b815601f4eea545fb4feae 100644 --- a/src/RangeSet.zig +++ b/src/RangeSet.zig @@ -1,6 +1,6 @@ const RangeSet = @This(); -ranges: std.ArrayList(Range), +ranges: std.MultiArrayList(Range), pub const Range = struct { first: Value, @@ -20,17 +20,21 @@ pub fn ensureUnusedCapacity(self: *RangeSet, allocator: Allocator, additional_co } pub fn addAssumeCapacity(set: *RangeSet, new: Range, ty: Type, zcu: *Zcu) ?LazySrcLoc { - assert(new.first.typeOf(zcu).eql(ty, zcu)); - assert(new.last.typeOf(zcu).eql(ty, zcu)); + assert(new.first.typeOf(zcu).eql(ty)); + assert(new.last.typeOf(zcu).eql(ty)); + assert(new.first.compareScalar(.lte, new.last, ty, zcu)); - for (set.ranges.items) |range| { - if (new.last.compareScalar(.gte, range.first, ty, zcu) and - new.first.compareScalar(.lte, range.last, ty, zcu)) - { - return range.src; // They overlap. - } + const idx = std.sort.lowerBound(Value, set.ranges.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)) + { + return set.ranges.items(.src)[idx]; // `new` overlaps with existing range. } - set.ranges.appendAssumeCapacity(new); + set.ranges.insertAssumeCapacity(idx, new); return null; } @@ -39,15 +43,6 @@ pub fn add(set: *RangeSet, allocator: Allocator, new: Range, ty: Type, zcu: *Zcu return set.addAssumeCapacity(new, ty, zcu); } -const SortCtx = struct { - ty: Type, - zcu: *Zcu, -}; -/// Assumes a and b do not overlap -fn lessThan(ctx: SortCtx, a: Range, b: Range) bool { - return a.first.compareScalar(.lt, b.first, ctx.ty, ctx.zcu); -} - pub fn spans( set: *RangeSet, allocator: Allocator, @@ -56,37 +51,38 @@ pub fn spans( ty: Type, zcu: *Zcu, ) Allocator.Error!bool { - assert(first.typeOf(zcu).eql(ty, zcu)); - assert(last.typeOf(zcu).eql(ty, zcu)); - if (set.ranges.items.len == 0) return false; + assert(first.typeOf(zcu).eql(ty)); + assert(last.typeOf(zcu).eql(ty)); + if (set.ranges.len == 0) return false; - std.mem.sort(Range, set.ranges.items, SortCtx{ .ty = ty, .zcu = zcu }, lessThan); + 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)); - if (!set.ranges.items[0].first.eql(first, ty, zcu) or - !set.ranges.items[set.ranges.items.len - 1].last.eql(last, ty, zcu)) + if (!set.ranges.items(.first)[0].eql(first, ty, zcu) or + !set.ranges.items(.last)[set.ranges.len - 1].eql(last, ty, zcu)) { return false; } const limbs = try allocator.alloc( - std.math.big.Limb, - std.math.big.int.calcTwosCompLimbCount(ty.intInfo(zcu).bits), + math.big.Limb, + math.big.int.calcTwosCompLimbCount(ty.intInfo(zcu).bits), ); defer allocator.free(limbs); - var counter: std.math.big.int.Mutable = .init(limbs, 0); + var counter: math.big.int.Mutable = .init(limbs, 0); var space: InternPool.Key.Int.Storage.BigIntSpace = undefined; // look for gaps - for (set.ranges.items[1..], 0..) |cur, i| { - // i starts counting from the second item. - const prev = set.ranges.items[i]; - - // prev.last + 1 == cur.first - counter.copy(prev.last.toBigInt(&space, zcu)); + for ( + set.ranges.items(.first)[1..], + set.ranges.items(.last)[0 .. set.ranges.len - 1], + ) |cur_first, prev_last| { + // prev_last + 1 == cur_first + counter.copy(prev_last.toBigInt(&space, zcu)); counter.addScalar(counter.toConst(), 1); - const cur_start_int = cur.first.toBigInt(&space, zcu); + const cur_start_int = cur_first.toBigInt(&space, zcu); if (!cur_start_int.eql(counter.toConst())) { return false; } @@ -95,7 +91,24 @@ pub fn spans( return true; } +const SearchCtx = struct { + val: Value, + zcu: *const Zcu, +}; +fn compare(ctx: SearchCtx, other: Value) math.Order { + return ctx.val.order(other, ctx.zcu); +} + +const SortCtx = struct { + ty: Type, + zcu: *Zcu, +}; +fn lessThan(ctx: SortCtx, a: Value, b: Value) bool { + return a.compareScalar(.lt, b, ctx.ty, ctx.zcu); +} + const std = @import("std"); +const math = std.math; const assert = std.debug.assert; const Allocator = std.mem.Allocator; diff --git a/src/Sema.zig b/src/Sema.zig index 0d8a40ae9d808c4b6e60e4015bc73c002a0eba5e..08510f58975ced08aeb2416f5d1530c0fa724c6c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -88,7 +88,7 @@ err: ?*Zcu.ErrorMsg = null, /// The temporary arena is used for the memory of the `InferredAlloc` values /// here so the values can be dropped without any cleanup. -unresolved_inferred_allocs: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .empty, +unresolved_inferred_allocs: std.array_hash_map.Auto(Air.Inst.Index, InferredAlloc) = .empty, /// Links every pointer derived from a base `alloc` back to that `alloc`. Used /// to detect comptime-known `const`s. @@ -119,13 +119,13 @@ exports: std.ArrayList(Zcu.Export) = .empty, /// All references registered so far by this `Sema`. This is a temporary duplicate /// of data stored in `Zcu.all_references`. It exists to avoid adding references to /// a given `AnalUnit` multiple times. -references: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty, -type_references: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty, +references: std.array_hash_map.Auto(AnalUnit, void) = .empty, +type_references: std.array_hash_map.Auto(InternPool.Index, void) = .empty, /// All dependencies registered so far by this `Sema`. This is a temporary duplicate /// of the main dependency data. It exists to avoid adding dependencies to a given /// `AnalUnit` multiple times. -dependencies: std.AutoArrayHashMapUnmanaged(InternPool.Dependee, void) = .empty, +dependencies: std.array_hash_map.Auto(InternPool.Dependee, void) = .empty, /// Whether memoization of this call is permitted. Operations with side effects global /// to the `Sema`, such as `@setEvalBranchQuota`, set this to `false`. It is observed @@ -212,11 +212,11 @@ pub const InferredErrorSet = struct { /// are returned from any dependent functions. errors: NameMap = .{}, /// Other inferred error sets which this inferred error set should include. - inferred_error_sets: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty, + inferred_error_sets: std.array_hash_map.Auto(InternPool.Index, void) = .empty, /// The regular error set created by resolving this inferred error set. resolved: InternPool.Index = .none, - pub const NameMap = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); + pub const NameMap = std.array_hash_map.Auto(InternPool.NullTerminatedString, void); pub fn addErrorSet( self: *InferredErrorSet, @@ -583,16 +583,6 @@ pub const Block = struct { }); } - fn addBitCast(block: *Block, ty: Type, operand: Air.Inst.Ref) Allocator.Error!Air.Inst.Ref { - return block.addInst(.{ - .tag = .bitcast, - .data = .{ .ty_op = .{ - .ty = Air.internedToRef(ty.toIntern()), - .operand = operand, - } }, - }); - } - fn addNoOp(block: *Block, tag: Air.Inst.Tag) error{OutOfMemory}!Air.Inst.Ref { return block.addInst(.{ .tag = tag, @@ -1241,6 +1231,8 @@ fn analyzeBodyInner( .optional_type => try sema.zirOptionalType(block, inst), .ptr_type => try sema.zirPtrType(block, inst), .ref => try sema.zirRef(block, inst), + .deref => try sema.zirDeref(block, inst), + .ref_deref => try sema.zirRefDeref(block, inst), .shr => try sema.zirShr(block, inst, .shr), .shr_exact => try sema.zirShr(block, inst, .shr_exact), .slice_end => try sema.zirSliceEnd(block, inst), @@ -1434,6 +1426,7 @@ fn analyzeBodyInner( .reify_struct => try sema.zirReifyStruct( block, extended, inst), .reify_union => try sema.zirReifyUnion( block, extended, inst), .reify_enum => try sema.zirReifyEnum( block, extended, inst), + .reify_spirv_type => try sema.zirReifySpirvType( block, extended, inst), // zig fmt: on .set_float_mode => { @@ -1442,9 +1435,7 @@ fn analyzeBodyInner( continue; }, .breakpoint => { - if (!block.isComptime()) { - _ = try block.addNoOp(.breakpoint); - } + try sema.zirBreakpoint(block, extended); i += 1; continue; }, @@ -1567,11 +1558,6 @@ fn analyzeBodyInner( i += 1; continue; }, - .validate_deref => { - try sema.zirValidateDeref(block, inst); - i += 1; - continue; - }, .validate_destructure => { try sema.zirValidateDestructure(block, inst); i += 1; @@ -3083,6 +3069,79 @@ fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins return sema.analyzeRef(block, block.tokenOffset(inst_data.src_tok), operand, .none); } +fn zirDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; + const src = block.nodeOffset(inst_data.src_node); + const ptr_src = block.src(.{ .node_offset_deref_ptr = inst_data.src_node }); + const operand = sema.resolveInst(inst_data.operand); + + try sema.validateDeref(block, src, operand, sema.typeOf(operand)); + + return sema.analyzeLoad(block, src, operand, ptr_src); +} + +fn zirRefDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const pt = sema.pt; + const zcu = pt.zcu; + const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; + const src = block.nodeOffset(inst_data.src_node); + const operand = sema.resolveInst(inst_data.operand); + const operand_ty = sema.typeOf(operand); + + 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: { + const single_ptr_ty = try pt.ptrType(p: { + var p = ptr_info; + p.flags.size = .one; + p.flags.is_allowzero = false; + break :p p; + }); + // https://github.com/ziglang/zig/issues/6597 + if (sema.resolveValue(operand)) |operand_val| { + if (!operand_val.isNull(zcu)) { + break :single_ptr .fromValue(try pt.getCoerced(operand_val, single_ptr_ty)); + } + } + if (block.wantSafety()) { + const is_non_null = try block.addUnOp(.is_non_null, operand); + try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null); + } + const single_ptr = try block.addTyOp(.ptr_cast, single_ptr_ty, operand); + try sema.checkKnownAllocPtr(block, operand, single_ptr); + break :single_ptr single_ptr; + }, + .one => operand, + }; +} + +fn validateDeref( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + ref: Air.Inst.Ref, + ty: Type, +) CompileError!void { + const pt = sema.pt; + const zcu = pt.zcu; + 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 => {}, + .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)}), + } + 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", .{}); + } + } +} + fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand = sema.resolveInst(inst_data.operand); @@ -3517,7 +3576,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, .{ .elem = idx_val.toUnsignedInt(zcu) }, }; }, - .bitcast => .{ + .ptr_cast => .{ tmp_air.instructions.items(.data)[@intFromEnum(air_ptr)].ty_op.operand, .same_addr, }, @@ -3660,7 +3719,7 @@ fn finishResolveComptimeKnownAllocPtr( // This instruction has type `alloc_ty`, meaning we can rewrite the `alloc` AIR instruction to // this one to drop the side effect. We also need to rewrite the stores; we'll turn them to this // too because it doesn't really matter what they become. - const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ + const nop_inst: Air.Inst = .{ .tag = .ptr_from_int, .data = .{ .ty_op = .{ .ty = .fromIntern(alloc_ty.toIntern()), .operand = .zero_usize, } } }; @@ -3710,7 +3769,7 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai return Air.internedToRef((try sema.pt.getCoerced(val, const_ptr_ty)).toIntern()); } - return block.addBitCast(const_ptr_ty, alloc); + return block.addTyOp(.ptr_cast, const_ptr_ty, alloc); } fn zirAllocInferredComptime( @@ -4607,30 +4666,6 @@ fn zirValidatePtrArrayInit( } } -fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { - const pt = sema.pt; - const zcu = pt.zcu; - const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; - const src = block.nodeOffset(inst_data.src_node); - const operand = sema.resolveInst(inst_data.operand); - const operand_ty = sema.typeOf(operand); - - if (operand_ty.zigTypeTag(zcu) != .pointer) { - return sema.fail(block, src, "cannot dereference non-pointer type '{f}'", .{operand_ty.fmt(pt)}); - } else switch (operand_ty.ptrSize(zcu)) { - .one, .c => {}, - .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{f}'", .{operand_ty.fmt(pt)}), - .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}), - } - - if (sema.resolveValue(operand)) |val| { - // Error for deref of undef pointer, unless the pointee is OPV in which case it's legal. - if (val.isUndef(zcu) and operand_ty.childType(zcu).classify(zcu) != .one_possible_value) { - return sema.fail(block, src, "cannot dereference undefined value", .{}); - } - } -} - fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const pt = sema.pt; const zcu = pt.zcu; @@ -5081,6 +5116,14 @@ fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { _ = try block.addNoOp(.trap); } +fn zirBreakpoint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { + const src_node: std.zig.Ast.Node.Offset = @enumFromInt(@as(i32, @bitCast(extended.operand))); + const src = block.nodeOffset(src_node); + if (block.isComptime()) + return sema.fail(block, src, "encountered @breakpoint at comptime", .{}); + _ = try block.addNoOp(.breakpoint); +} + fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; @@ -5244,33 +5287,51 @@ fn resolveBlockBody( return sema.resolveAnalyzedBlock(parent_block, src, child_block, merges, need_debug_scope); } else |err| switch (err) { error.ComptimeBreak => { + const break_inst = sema.comptime_break_inst; + const break_data = sema.code.instructions.items(.data)[@intFromEnum(break_inst)].@"break"; + const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; + const breaks_to_body = extra.block_inst == body_inst; + // Comptime control flow is happening, however child_block may still contain // runtime instructions which need to be copied to the parent block. if (need_debug_scope and child_block.instructions.items.len > 0) { - // We need a runtime block for scoping reasons. - _ = try child_block.addBr(merges.block_inst, .void_value); + // We need a runtime block for scoping reasons. The break + // operand may have been produced by a runtime instruction + // inside `child_blocks`. + const operand = sema.resolveInst(break_data.operand); + const operand_ty = sema.typeOf(operand); + _ = try child_block.addBr(merges.block_inst, operand); try parent_block.instructions.append(sema.gpa, merges.block_inst); try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).@"struct".field_names.len + child_block.instructions.items.len); sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{ - .ty = .void_type, + .ty = Air.internedToRef(operand_ty.toIntern()), .payload = sema.addExtraAssumeCapacity(Air.Block{ .body_len = @intCast(child_block.instructions.items.len), }), } }; sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items)); + + // The block result now holds the operand value, so we remap + // the operand such that an enclosing scope which resolves + // it picks up the block result rather than the internal + // block instruction. + if (break_data.operand.toIndex()) |operand_zir| { + sema.inst_map.putAssumeCapacity(operand_zir, merges.block_inst.toRef()); + } + if (breaks_to_body) { + return merges.block_inst.toRef(); + } else { + return error.ComptimeBreak; + } } else { // We can copy instructions directly to the parent block. try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items); - } - - const break_inst = sema.comptime_break_inst; - const break_data = sema.code.instructions.items(.data)[@intFromEnum(break_inst)].@"break"; - const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; - if (extra.block_inst == body_inst) { - return sema.resolveInst(break_data.operand); - } else { - return error.ComptimeBreak; + if (breaks_to_body) { + return sema.resolveInst(break_data.operand); + } else { + return error.ComptimeBreak; + } } }, else => |e| return e, @@ -5455,7 +5516,7 @@ fn resolveAnalyzedBlock( const br_operand = sema.air_instructions.items(.data)[@intFromEnum(br)].br.operand; const br_operand_src = src; const br_operand_ty = sema.typeOf(br_operand); - if (br_operand_ty.eql(resolved_ty, zcu)) { + if (br_operand_ty.eql(resolved_ty)) { // No type coercion needed. continue; } @@ -6415,22 +6476,6 @@ const CallArgsInfo = union(enum) { const uncoerced_arg: Air.Inst.Ref = switch (cai) { inline .resolved, .call_builtin => |resolved| resolved.args[arg_index], .zir_call => |zir_call| arg_val: { - const has_bound_arg = zir_call.bound_arg != .none; - if (arg_index == 0 and has_bound_arg) { - break :arg_val zir_call.bound_arg; - } - const real_arg_idx = arg_index - @intFromBool(has_bound_arg); - - const arg_body = if (real_arg_idx == 0) blk: { - const start = zir_call.num_args; - const end = @intFromEnum(zir_call.args_body[0]); - break :blk zir_call.args_body[start..end]; - } else blk: { - const start = @intFromEnum(zir_call.args_body[real_arg_idx - 1]); - const end = @intFromEnum(zir_call.args_body[real_arg_idx]); - break :blk zir_call.args_body[start..end]; - }; - // Generate args to comptime params in comptime block const parent_comptime = block.comptime_reason; defer block.comptime_reason = parent_comptime; @@ -6452,11 +6497,27 @@ const CallArgsInfo = union(enum) { }; } } - // Give the arg its result type - const provide_param_ty: Type = maybe_param_ty orelse .generic_poison; - sema.inst_map.putAssumeCapacity(zir_call.call_inst, Air.internedToRef(provide_param_ty.toIntern())); - // Resolve the arg! - const uncoerced_arg = try sema.resolveInlineBody(block, arg_body, zir_call.call_inst); + + const has_bound_arg = zir_call.bound_arg != .none; + const uncoerced_arg = if (arg_index == 0 and has_bound_arg) zir_call.bound_arg else arg: { + const real_arg_idx = arg_index - @intFromBool(has_bound_arg); + + const arg_body = if (real_arg_idx == 0) blk: { + const start = zir_call.num_args; + const end = @intFromEnum(zir_call.args_body[0]); + break :blk zir_call.args_body[start..end]; + } else blk: { + const start = @intFromEnum(zir_call.args_body[real_arg_idx - 1]); + const end = @intFromEnum(zir_call.args_body[real_arg_idx]); + break :blk zir_call.args_body[start..end]; + }; + + // Give the arg its result type + const provide_param_ty: Type = maybe_param_ty orelse .generic_poison; + sema.inst_map.putAssumeCapacity(zir_call.call_inst, Air.internedToRef(provide_param_ty.toIntern())); + // Resolve the arg! + break :arg try sema.resolveInlineBody(block, arg_body, zir_call.call_inst); + }; if (block.isComptime() and !try sema.isComptimeKnown(uncoerced_arg)) { return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null); @@ -7277,7 +7338,7 @@ fn analyzeCall( if (resolved_ty == .none) break :r result_raw; // TODO: mutate in place the previous instruction if possible // rather than adding a bitcast instruction. - break :r try block.addBitCast(.fromInterned(resolved_ty), result_raw); + break :r try block.addTyOp(.error_cast, .fromInterned(resolved_ty), result_raw); }; if (block.isComptime()) { @@ -7583,7 +7644,7 @@ fn zirIntFromError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD } try sema.requireRuntimeBlock(block, src, operand_src); - return block.addBitCast(err_int_ty, operand); + return block.addTyOp(.int_from_error, err_int_ty, operand); } fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { @@ -7621,13 +7682,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD const ok = try block.addBinOp(.bit_and, is_lte_len, is_non_zero); try sema.addSafetyCheck(block, src, ok, .invalid_error_code); } - return block.addInst(.{ - .tag = .bitcast, - .data = .{ .ty_op = .{ - .ty = .anyerror_type, - .operand = operand, - } }, - }); + return block.addTyOp(.error_from_int, .anyerror, operand); } fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -7810,7 +7865,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } try sema.requireRuntimeBlock(block, src, operand_src); - return block.addBitCast(int_tag_ty, enum_tag); + return block.addTyOp(.bit_cast, int_tag_ty, enum_tag); } fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -7869,9 +7924,9 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError try sema.requireRuntimeBlock(block, src, operand_src); if (block.wantSafety()) { try sema.preparePanicId(src, .invalid_enum_value); - return block.addTyOp(.intcast_safe, dest_ty, operand); + return block.addTyOp(.int_cast_safe, dest_ty, operand); } - return block.addTyOp(.intcast, dest_ty, operand); + return block.addTyOp(.int_cast, dest_ty, operand); } /// Pointer in, pointer out. @@ -7913,12 +7968,10 @@ fn analyzeOptionalPayloadPtr( } const child_type = opt_type.optionalChild(zcu); - const child_pointer = try pt.ptrType(.{ - .child = child_type.toIntern(), - .flags = .{ - .is_const = optional_ptr_ty.isConstPtr(zcu), - .address_space = optional_ptr_ty.ptrAddressSpace(zcu), - }, + const child_pointer = try pt.ptrType(info: { + var new = optional_ptr_ty.ptrInfo(zcu); + new.child = child_type.toIntern(); + break :info new; }); if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { @@ -8592,6 +8645,7 @@ fn checkReturnTypeAndCallConv( ) CompileError!void { const pt = sema.pt; const zcu = pt.zcu; + const target = zcu.getTarget(); if (opt_varargs_src) |varargs_src| { try sema.checkCallConvSupportsVarArgs(block, varargs_src, @"callconv"); } @@ -8653,6 +8707,32 @@ fn checkReturnTypeAndCallConv( .@"inline" => if (is_noinline) { return sema.fail(block, callconv_src, "'noinline' function cannot have calling convention 'inline'", .{}); }, + .spirv_fragment => |fragment| { + if (fragment.pixel_centered_integer and target.os.tag != .opengl) { + return sema.fail(block, callconv_src, "'pixel_centered_integer' is not supported on this target", .{}); + } + }, + .spirv_kernel => |kernel| { + if (kernel.x == 0 or kernel.y == 0 or kernel.z == 0) { + return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{}); + } + }, + .spirv_task => |task| { + if (task.x == 0 or task.y == 0 or task.z == 0) { + return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{}); + } + if (!target.cpu.has(.spirv, .mesh_shading_ext)) { + return sema.fail(block, callconv_src, "calling convention '{t}' requires the 'mesh_shading_ext' feature", .{@"callconv"}); + } + }, + .spirv_mesh => |mesh| { + if (mesh.max_vertices == 0 or mesh.max_primitives == 0) { + return sema.fail(block, callconv_src, "mesh shader 'max_vertices' and 'max_primitives' must be at least 1", .{}); + } + if (!target.cpu.has(.spirv, .mesh_shading_ext)) { + return sema.fail(block, callconv_src, "calling convention '{t}' requires the 'mesh_shading_ext' feature", .{@"callconv"}); + } + }, else => {}, } switch (zcu.callconvSupported(@"callconv")) { @@ -8763,6 +8843,8 @@ fn callConvIsCallable(cc: std.lang.CallingConvention.Tag) bool { .spirv_kernel, .spirv_fragment, .spirv_vertex, + .spirv_task, + .spirv_mesh, => false, else => true, @@ -8791,7 +8873,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type) try sema.errNote(runtime_src, msg, "runtime control flow here", .{}); const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm); - try sema.errNote(src, msg, "pointers with address space '{s}' cannot be returned from a branch on target {s}-{s} by compiler backend {s}", .{ + try sema.errNote(src, msg, "pointers with address space '{s}' cannot be returned from a branch on target '{s}-{s}' by compiler backend '{s}'", .{ @tagName(as), @tagName(target.cpu.arch.family()), @tagName(target.os.tag), @@ -9083,7 +9165,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), ptr_src); try sema.validateRuntimeValue(block, ptr_src, operand); try sema.checkLogicalPtrOperation(block, ptr_src, ptr_ty); - return block.addBitCast(dest_ty, operand); + return block.addTyOp(.int_from_ptr, dest_ty, operand); } fn zirFieldPtrLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9232,7 +9314,7 @@ fn intCast( break :ok all_in_range; } else ok: { const zero_inst = Air.internedToRef((try pt.intValue(operand_ty, 0)).toIntern()); - const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst); + const is_in_range = try block.addBinOp(.cmp_eq, operand, zero_inst); break :ok is_in_range; }; try sema.addSafetyCheck(block, src, ok, .integer_out_of_bounds); @@ -9245,9 +9327,9 @@ fn intCast( try sema.requireRuntimeBlock(block, src, operand_src); if (block.wantSafety()) { try sema.preparePanicId(src, .integer_out_of_bounds); - return block.addTyOp(.intcast_safe, dest_ty, operand); + return block.addTyOp(.int_cast_safe, dest_ty, operand); } - return block.addTyOp(.intcast, dest_ty, operand); + return block.addTyOp(.int_cast, dest_ty, operand); } fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9261,156 +9343,53 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@bitCast"); const operand = sema.resolveInst(extra.rhs); const operand_ty = sema.typeOf(operand); - switch (dest_ty.zigTypeTag(zcu)) { - .@"anyframe", - .comptime_float, - .comptime_int, - .enum_literal, - .error_set, - .error_union, - .@"fn", - .frame, - .noreturn, - .null, - .@"opaque", - .optional, - .type, - .undefined, - .void, - => return sema.fail(block, src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}), - .@"enum" => { - const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - switch (operand_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(src, msg, "use @enumFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}), - else => {}, - } - - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); - }, - - .pointer => { - const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - switch (operand_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}), - .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{f}'", .{operand_ty.fmt(pt)}), - else => {}, - } - - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); - }, - .@"struct", .@"union" => if (dest_ty.containerLayout(zcu) == .auto) { - const container = switch (dest_ty.zigTypeTag(zcu)) { - .@"struct" => "struct", - .@"union" => "union", - else => unreachable, - }; - return sema.fail(block, src, "cannot @bitCast to '{f}'; {s} does not have a guaranteed in-memory layout", .{ - dest_ty.fmt(pt), container, - }); - }, - .array => { - const elem_ty = dest_ty.childType(zcu); - if (!elem_ty.hasWellDefinedLayout(zcu)) { - const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - try sema.errNote(src, msg, "array element type '{f}' does not have a guaranteed in-memory layout", .{elem_ty.fmt(pt)}); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + // Check for pointers before checking `hasBitRepresentation` so we can emit a better message for slices. + switch (dest_ty.scalarType(zcu).zigTypeTag(zcu)) { + .pointer, .optional => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); + errdefer msg.destroy(sema.gpa); + switch (operand_ty.zigTypeTag(zcu)) { + .int, .comptime_int => try sema.errNote(src, msg, "use @ptrFromInt to cast from '{f}'", .{operand_ty.fmt(pt)}), + .pointer => try sema.errNote(src, msg, "use @ptrCast to cast from '{f}'", .{operand_ty.fmt(pt)}), + else => {}, } - }, - - .bool, - .float, - .int, - .vector, - => {}, - } - switch (operand_ty.zigTypeTag(zcu)) { - .@"anyframe", - .comptime_float, - .comptime_int, - .enum_literal, - .error_set, - .error_union, - .@"fn", - .frame, - .noreturn, - .null, - .@"opaque", - .optional, - .type, - .undefined, - .void, - => return sema.fail(block, operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}), - .@"enum" => { - const msg = msg: { - const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - switch (dest_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromEnum to cast to '{f}'", .{dest_ty.fmt(pt)}), - else => {}, - } - - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + break :msg msg; + }), + .array => switch (dest_ty.arrayBase(zcu)[0].zigTypeTag(zcu)) { + .pointer, .optional => return sema.fail(block, src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}), + else => {}, }, - .pointer => { - const msg = msg: { - const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - switch (dest_ty.zigTypeTag(zcu)) { - .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{f}'", .{dest_ty.fmt(pt)}), - .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{f}'", .{dest_ty.fmt(pt)}), - else => {}, - } + else => {}, + } + if (!dest_ty.hasBitRepresentation(zcu)) { + return sema.fail(block, src, "cannot @bitCast to '{f}'", .{dest_ty.fmt(pt)}); + } - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); - }, - .@"struct", .@"union" => if (operand_ty.containerLayout(zcu) == .auto) { - const container = switch (operand_ty.zigTypeTag(zcu)) { - .@"struct" => "struct", - .@"union" => "union", - else => unreachable, - }; - return sema.fail(block, operand_src, "cannot @bitCast from '{f}'; {s} does not have a guaranteed in-memory layout", .{ - operand_ty.fmt(pt), container, - }); - }, - .array => { - const elem_ty = operand_ty.childType(zcu); - if (!elem_ty.hasWellDefinedLayout(zcu)) { - const msg = msg: { - const msg = try sema.errMsg(src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - try sema.errNote(src, msg, "array element type '{f}' does not have a guaranteed in-memory layout", .{elem_ty.fmt(pt)}); - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + // Check for pointers before checking `hasBitRepresentation` so we can emit a better message for slices. + switch (operand_ty.scalarType(zcu).zigTypeTag(zcu)) { + .pointer, .optional => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); + errdefer msg.destroy(sema.gpa); + switch (dest_ty.zigTypeTag(zcu)) { + .int, .comptime_int => try sema.errNote(operand_src, msg, "use @intFromPtr to cast to '{f}'", .{dest_ty.fmt(pt)}), + .pointer => try sema.errNote(operand_src, msg, "use @ptrCast to cast to '{f}'", .{dest_ty.fmt(pt)}), + else => {}, } + break :msg msg; + }), + .array => switch (operand_ty.arrayBase(zcu)[0].zigTypeTag(zcu)) { + .pointer, .optional => return sema.fail(block, operand_src, "cannot @bitCast from '{f}'", .{dest_ty.fmt(pt)}), + else => {}, }, - - .bool, - .float, - .int, - .vector, - => {}, + else => {}, } - return sema.bitCast(block, dest_ty, operand, block.nodeOffset(inst_data.src_node), operand_src); + if (!operand_ty.hasBitRepresentation(zcu)) { + return sema.fail(block, operand_src, "cannot @bitCast from '{f}'", .{operand_ty.fmt(pt)}); + } + + return sema.bitCast(block, dest_ty, operand, block.nodeOffset(inst_data.src_node)); } fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -9780,7 +9759,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp const maybe_switch_ref: ?Air.Inst.Ref = ref: { // make err capture (i.e. switch operand) available to switch prong bodies - sema.inst_map.putAssumeCapacityNoClobber(inst, raw_switch_operand); + sema.inst_map.putAssumeCapacity(inst, raw_switch_operand); defer assert(sema.inst_map.remove(inst)); break :ref try sema.analyzeSwitchBlock(block, &switch_block, raw_switch_operand, false, merges, inst, &zir_switch, &validated_switch); }; @@ -10839,7 +10818,7 @@ fn finishSwitchBr( const ValidatedSwitchBlock = struct { seen_enum_fields: []const ?LazySrcLoc, seen_errors: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), - seen_ranges: []const RangeSet.Range, + seen_ranges: std.MultiArrayList(RangeSet.Range).Slice, true_src: ?LazySrcLoc, false_src: ?LazySrcLoc, void_src: ?LazySrcLoc, @@ -10874,7 +10853,7 @@ const ValidatedSwitchBlock = struct { error_names: InternPool.NullTerminatedString.Slice, seen_enum_fields: []const ?LazySrcLoc, seen_errors: *const std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, LazySrcLoc), - seen_ranges: []const RangeSet.Range, + seen_ranges: std.MultiArrayList(RangeSet.Range).Slice, seen_true: bool, seen_false: bool, seen_void: bool, @@ -10911,13 +10890,13 @@ const ValidatedSwitchBlock = struct { else => unreachable, }; while (it.next_idx < it.seen_ranges.len and - cur_val.eql(it.seen_ranges[it.next_idx].first, int_ty, zcu)) + cur_val.eql(it.seen_ranges.items(.first)[it.next_idx], int_ty, zcu)) { defer it.next_idx += 1; const incr = try arith.incrementDefinedInt( sema, int_ty, - it.seen_ranges[it.next_idx].last, + it.seen_ranges.items(.last)[it.next_idx], ); if (incr.overflow) { it.next_val = null; @@ -11405,7 +11384,7 @@ fn validateSwitchBlock( return .{ .seen_enum_fields = seen_enum_fields, .seen_errors = seen_errors, - .seen_ranges = range_set.ranges.items, + .seen_ranges = range_set.ranges.slice(), .true_src = true_src, .false_src = false_src, .void_src = void_src, @@ -11955,11 +11934,17 @@ fn analyzeSwitchCaptures( .@"inline" => unreachable, // handled above .has_ranges => unreachable, // not possible for error set .special => { - if (else_err_ty) |err_ty| { - break :payload_ref try sema.bitCast(case_block, err_ty, loaded_operand, operand_src, null); - } else { + const capture_err_ty = else_err_ty orelse { try sema.analyzeUnreachable(case_block, operand_src, false); break :payload_ref .unreachable_value; + }; + if (sema.resolveValue(loaded_operand)) |err_val| { + break :payload_ref .fromIntern(try pt.intern(.{ .err = .{ + .ty = capture_err_ty.toIntern(), + .name = zcu.intern_pool.indexToKey(err_val.toIntern()).err.name, + } })); + } else { + break :payload_ref try case_block.addTyOp(.error_cast, capture_err_ty, loaded_operand); } }, .item_refs => |item_refs| { @@ -11969,8 +11954,15 @@ fn analyzeSwitchCaptures( const item_val = sema.resolveValue(item_ref).?; names.putAssumeCapacityNoClobber(item_val.getErrorName(zcu).unwrap().?, {}); } - const narrowed_ty = try pt.errorSetFromUnsortedNames(names.keys()); - break :payload_ref try sema.bitCast(case_block, narrowed_ty, loaded_operand, operand_src, null); + const capture_err_ty = try pt.errorSetFromUnsortedNames(names.keys()); + if (sema.resolveValue(loaded_operand)) |err_val| { + break :payload_ref .fromIntern(try pt.intern(.{ .err = .{ + .ty = capture_err_ty.toIntern(), + .name = zcu.intern_pool.indexToKey(err_val.toIntern()).err.name, + } })); + } else { + break :payload_ref try case_block.addTyOp(.error_cast, capture_err_ty, loaded_operand); + } }, } } @@ -12020,15 +12012,12 @@ fn resolveSwitchPayloadCaptureTaggedUnion( const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); const payload_ref: Air.Inst.Ref = payload_ref: { if (capture_by_ref) { - const operand_ptr_info = sema.typeOf(loaded_operand).ptrInfo(zcu); - const ptr_field_ty = try pt.ptrType(.{ - .child = field_ty.toIntern(), - .flags = .{ - .is_const = operand_ptr_info.flags.is_const, - .is_volatile = operand_ptr_info.flags.is_volatile, - .address_space = operand_ptr_info.flags.address_space, - }, - }); + const ptr_field_ty = try sema.typeOf(loaded_operand).fieldPtrType(field_index, pt); + if (try sema.resolveDefinedValue(case_block, operand_src, loaded_operand)) |op_ptr_val| { + if (op_ptr_val.isUndef(zcu)) break :payload_ref try pt.undefRef(ptr_field_ty); + const field_ptr_val = try op_ptr_val.ptrField(field_index, pt); + break :payload_ref .fromValue(try pt.getCoerced(field_ptr_val, ptr_field_ty)); + } break :payload_ref try case_block.addStructFieldPtr(loaded_operand, field_index, ptr_field_ty); } if (try sema.resolveDefinedValue(case_block, operand_src, loaded_operand)) |union_val| { @@ -12083,7 +12072,7 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( // PTR! This will also allow us to emit simpler code. const same_types = for (field_indices[1..]) |field_idx| { const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); - if (!field_ty.eql(first_field_ty, zcu)) break false; + if (!field_ty.eql(first_field_ty)) break false; } else true; const capture_ty: Type = capture_ty: { @@ -12188,40 +12177,9 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( return case_block.addStructFieldVal(loaded_operand, first_field_index, capture_ty); } - // We may have to emit a switch block which coerces the operand to the capture type. - // If we can, try to avoid that using in-memory coercions. - const first_non_imc = in_mem: { - for (field_indices, 0..) |field_idx, i| { - const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); - if (.ok != try sema.coerceInMemoryAllowed(case_block, capture_ty, field_ty, false, zcu.getTarget(), .unneeded, .unneeded, null)) { - break :in_mem i; - } - } - // All fields are in-memory coercible to the resolved type! - // Just take the first field and bitcast the result. - const uncoerced = try case_block.addStructFieldVal(loaded_operand, first_field_index, first_field_ty); - return case_block.addBitCast(capture_ty, uncoerced); - }; - // By-val capture with heterogeneous types which are not all in-memory coercible to // the resolved capture type. We finally have to fall back to the ugly method. - // However, let's first track which operands are in-memory coercible. There may well - // be several, and we can squash all of these cases into the same switch prong using - // a simple bitcast. We'll make this the 'else' prong. - - var in_mem_coercible: std.bit_set.Dynamic = try .initFull(sema.arena, field_indices.len); - in_mem_coercible.unset(first_non_imc); - { - const next = first_non_imc + 1; - for (field_indices[next..], next..) |field_idx, i| { - const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); - if (.ok != try sema.coerceInMemoryAllowed(case_block, capture_ty, field_ty, false, zcu.getTarget(), .unneeded, .unneeded, null)) { - in_mem_coercible.unset(i); - } - } - } - const capture_block_inst = try case_block.addInstAsIndex(.{ .tag = .block, .data = .{ @@ -12232,23 +12190,19 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( }, }); - const prong_count = field_indices.len - in_mem_coercible.count(); - - const estimated_extra = prong_count * 6 + (prong_count / 10); // 2 for Case, 1 item, probably 3 insts; plus hints + const estimated_extra = field_indices.len * 6 + (field_indices.len / 10); // 2 for Case, 1 item, probably 3 insts; plus hints var cases_extra = try std.ArrayList(u32).initCapacity(gpa, estimated_extra); defer cases_extra.deinit(gpa); { // All branch hints are `.none`, so just add zero elems. comptime assert(@intFromEnum(std.lang.BranchHint.none) == 0); - const need_elems = std.math.divCeil(usize, prong_count + 1, 10) catch unreachable; + const need_elems = std.math.divCeil(usize, field_indices.len + 1, 10) catch unreachable; try cases_extra.appendNTimes(gpa, 0, need_elems); } { - // Non-bitcast cases - var it = in_mem_coercible.iterator(.{ .kind = .unset }); - while (it.next()) |idx| { + for (field_indices, item_refs, 0..) |field_index, item, item_index| { var coerce_block = case_block.makeSubBlock(); defer coerce_block.instructions.deinit(sema.gpa); @@ -12257,13 +12211,12 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( .offset = .{ .switch_case_item = .{ .switch_node_offset = switch_node_offset, .case_idx = capture_src.offset.switch_capture.case_idx, - .item_idx = .{ .kind = .single, .value = @intCast(idx) }, + .item_idx = .{ .kind = .single, .value = @intCast(item_index) }, } }, }; - const field_idx = field_indices[idx]; - const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); - const uncoerced = try coerce_block.addStructFieldVal(loaded_operand, field_idx, field_ty); + const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); + const uncoerced = try coerce_block.addStructFieldVal(loaded_operand, field_index, field_ty); const coerced = try sema.coerce(&coerce_block, capture_ty, uncoerced, case_src); _ = try coerce_block.addBr(capture_block_inst, coerced); @@ -12275,24 +12228,16 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( .ranges_len = 0, .body_len = @intCast(coerce_block.instructions.items.len), })); - cases_extra.appendAssumeCapacity(@intFromEnum(item_refs[idx])); // item + cases_extra.appendAssumeCapacity(@intFromEnum(item)); // item cases_extra.appendSliceAssumeCapacity(@ptrCast(coerce_block.instructions.items)); // body } } const else_body_len = len: { - // 'else' prong uses a bitcast - var coerce_block = case_block.makeSubBlock(); - defer coerce_block.instructions.deinit(sema.gpa); - - const first_imc_item_idx = in_mem_coercible.findFirstSet().?; - const first_imc_field_idx = field_indices[first_imc_item_idx]; - const first_imc_field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[first_imc_field_idx]); - const uncoerced = try coerce_block.addStructFieldVal(loaded_operand, first_imc_field_idx, first_imc_field_ty); - const coerced = try coerce_block.addBitCast(capture_ty, uncoerced); - _ = try coerce_block.addBr(capture_block_inst, coerced); - - try cases_extra.appendSlice(gpa, @ptrCast(coerce_block.instructions.items)); - break :len coerce_block.instructions.items.len; + // 'else' prong is unreachable + const result_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); + try sema.air_instructions.append(gpa, .{ .tag = .unreach, .data = .{ .no_op = {} } }); + try cases_extra.append(gpa, @intFromEnum(result_index)); + break :len 1; }; try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.SwitchBr).@"struct".field_names.len + @@ -12307,7 +12252,7 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( .pl_op = .{ .operand = undefined, // set by switch below .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{ - .cases_len = @intCast(prong_count), + .cases_len = @intCast(field_indices.len), .else_body_len = @intCast(else_body_len), }), }, @@ -12417,7 +12362,7 @@ fn resolveSwitchItem( // being switched on if their prong body is `=> comptime unreachable,`. switch (try sema.coerceInMemoryAllowedErrorSets(block, item_ty, uncoerced_ty, item_src, item_src)) { .ok => if (sema.resolveValue(uncoerced)) |uncoerced_val| { - break :item_ref try sema.coerceInMemory(uncoerced_val, item_ty); + break :item_ref .fromValue(try pt.getCoerced(uncoerced_val, item_ty)); }, .missing_error => if (prong_is_comptime_unreach) { break :item_ref uncoerced; @@ -13323,8 +13268,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai defer trash_block.instructions.deinit(sema.gpa); const instructions = [_]Air.Inst.Ref{ - try trash_block.addBitCast(lhs_info.elem_type, .void_value), - try trash_block.addBitCast(rhs_info.elem_type, .void_value), + try trash_block.addTyOp(.bit_cast, lhs_info.elem_type, .void_value), + try trash_block.addTyOp(.bit_cast, rhs_info.elem_type, .void_value), }; break :t try sema.resolvePeerTypes(block, src, &instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, @@ -13416,7 +13361,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai while (elem_i < lhs_len) : (elem_i += 1) { const lhs_elem_i = elem_i; const elem_default_val: ?Value = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else null; - const elem_val = elem_default_val orelse try lhs_sub_val.elemValue(pt, lhs_elem_i); + const elem_val = elem_default_val orelse + if (lhs_sub_val.isUndef(zcu)) try pt.undefValue(resolved_elem_ty) else try lhs_sub_val.elemValue(pt, lhs_elem_i); const operand_src = block.src(.{ .array_cat_lhs = .{ .array_cat_offset = inst_data.src_node, .elem_index = elem_i, @@ -13428,7 +13374,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai while (elem_i < result_len) : (elem_i += 1) { const rhs_elem_i = elem_i - lhs_len; const elem_default_val: ?Value = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else null; - const elem_val = elem_default_val orelse try rhs_sub_val.elemValue(pt, rhs_elem_i); + const elem_val = elem_default_val orelse + if (rhs_sub_val.isUndef(zcu)) try pt.undefValue(resolved_elem_ty) else try rhs_sub_val.elemValue(pt, rhs_elem_i); const operand_src = block.src(.{ .array_cat_rhs = .{ .array_cat_offset = inst_data.src_node, .elem_index = @intCast(rhs_elem_i), @@ -13479,7 +13426,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }); const many_ty = slice_ty.slicePtrFieldType(zcu); - const many_alloc = try block.addBitCast(many_ty, mutable_alloc); + const many_alloc = try block.addTyOp(.ptr_cast, many_ty, mutable_alloc); // lhs_dest_slice = dest[0..lhs.len] if (lhs_len > 0) { @@ -13528,7 +13475,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); } - return block.addBitCast(constant_alloc_ty, mutable_alloc); + return block.addTyOp(.ptr_cast, constant_alloc_ty, mutable_alloc); } var elem_i: u32 = 0; @@ -13561,7 +13508,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); } - return block.addBitCast(constant_alloc_ty, mutable_alloc); + return block.addTyOp(.ptr_cast, constant_alloc_ty, mutable_alloc); } const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len); @@ -14844,8 +14791,8 @@ fn analyzeArithmetic( try sema.requireRuntimeBlock(block, src, runtime_src); try sema.checkLogicalPtrOperation(block, src, lhs_ty); try sema.checkLogicalPtrOperation(block, src, rhs_ty); - const lhs_int = try block.addBitCast(.usize, lhs); - const rhs_int = try block.addBitCast(.usize, rhs); + const lhs_int = try block.addTyOp(.int_from_ptr, .usize, lhs); + const rhs_int = try block.addTyOp(.int_from_ptr, .usize, rhs); const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int); return try block.addBinOp(.div_exact, address, try pt.intRef(.usize, elem_size)); } @@ -15113,15 +15060,76 @@ fn zirAsm( break :out_ty sema.typeOf(inst).childType(zcu); } }; - if (!out_ty.hasWellDefinedLayout(zcu)) { - return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(output_src, "invalid inline assembly output type; '{f}' does not have a guaranteed in-memory layout", .{ - out_ty.fmt(pt), - }); + switch (out_ty.zigTypeTag(zcu)) { + .int, .float, .bool, .vector => {}, + + .pointer => if (out_ty.isSlice(zcu)) return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(output_src, "invalid inline assembly output type '{f}'", .{out_ty.fmt(pt)}); errdefer msg.destroy(gpa); - try sema.addDeclaredHereNote(msg, out_ty); + try sema.errNote(output_src, msg, "consider separate outputs for 'ptr' and 'len'", .{}); break :msg msg; - }); + }), + + .optional => if (!out_ty.isPtrLikeOptional(zcu)) { + return sema.fail(block, output_src, "invalid inline assembly output type '{f}'", .{out_ty.fmt(pt)}); + }, + + .@"enum" => switch (ip.loadEnumType(out_ty.toIntern()).int_tag_mode) { + .explicit => {}, + .auto => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(output_src, "invalid inline assembly output type '{f}'", .{out_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.errNote(out_ty.srcLoc(zcu), msg, "integer tag type of enum is inferred", .{}); + try sema.errNote(out_ty.srcLoc(zcu), msg, "consider explicitly specifying the integer tag type", .{}); + break :msg msg; + }), + }, + + .@"struct" => switch (out_ty.containerLayout(zcu)) { + .@"packed" => {}, + .auto, .@"extern" => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(output_src, "invalid inline assembly output type '{f}'", .{out_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.errNote(output_src, msg, "struct types cannot be passed to inline assembly", .{}); + try sema.addDeclaredHereNote(msg, out_ty); + break :msg msg; + }), + }, + + .@"union" => switch (out_ty.containerLayout(zcu)) { + .@"packed" => {}, + .auto, .@"extern" => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(output_src, "invalid inline assembly output type '{f}'", .{out_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.errNote(output_src, msg, "union types cannot be passed to inline assembly", .{}); + try sema.addDeclaredHereNote(msg, out_ty); + break :msg msg; + }), + }, + + .array => return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(output_src, "invalid inline assembly output type '{f}'", .{out_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.errNote(output_src, msg, "array types cannot be passed to inline assembly", .{}); + break :msg msg; + }), + + .void, + .type, + .noreturn, + .comptime_float, + .comptime_int, + .undefined, + .null, + .error_union, + .error_set, + .@"fn", + .@"opaque", + .frame, + .@"anyframe", + .enum_literal, + .spirv, + => return sema.fail(block, output_src, "invalid inline assembly output type '{f}'", .{out_ty.fmt(pt)}), } const constraint = sema.code.nullTerminatedString(output.data.constraint); @@ -15292,7 +15300,7 @@ fn zirCmpEq( if (lhs_ty_tag == .type and rhs_ty_tag == .type) { const lhs_as_type = try sema.analyzeAsType(block, lhs_src, .type, lhs); const rhs_as_type = try sema.analyzeAsType(block, rhs_src, .type, rhs); - return if (lhs_as_type.eql(rhs_as_type, zcu) == (op == .eq)) .bool_true else .bool_false; + return if (lhs_as_type.eql(rhs_as_type) == (op == .eq)) .bool_true else .bool_false; } return sema.analyzeCmp(block, src, lhs, rhs, op, lhs_src, rhs_src, true); } @@ -15525,36 +15533,13 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); - switch (operand_ty.zigTypeTag(zcu)) { - .@"fn", - .noreturn, - .undefined, - .null, - .@"opaque", - .type, - .enum_literal, - .comptime_float, - .comptime_int, - => return sema.fail(block, operand_src, "no size available for type '{f}'", .{operand_ty.fmt(pt)}), - - .void, - => return .zero, - - .bool, - .int, - .float, - .pointer, - .array, - .@"struct", - .optional, - .error_union, - .error_set, - .@"enum", - .@"union", - .vector, - .frame, - .@"anyframe", - => {}, + if (!operand_ty.hasBitRepresentation(zcu) and + // TODO: allow these types too for now because this is used in some places. We need to + // figure out whether we think errors and auto-enums have bit representations! + operand_ty.zigTypeTag(zcu) != .error_set and + operand_ty.zigTypeTag(zcu) != .@"enum") + { + return sema.fail(block, operand_src, "no bit size available for type '{f}'", .{operand_ty.fmt(pt)}); } try sema.ensureLayoutResolved(operand_ty, operand_src, .size_of); return .fromValue(try pt.intValue(.comptime_int, operand_ty.bitSize(zcu))); @@ -16834,6 +16819,43 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .val = (try pt.aggregateValue(type_opaque_ty, &field_values)).toIntern(), }))); }, + .spirv => { + const spirv_info = ip.loadSpirvType(ty.toIntern()); + const spirv_union_ty = try sema.getStdLangType(src, .@"Type.Spirv"); + const spirv_tag_ty = spirv_union_ty.unionTagType(zcu).?; + const spirv_tag_val = try pt.enumValueFieldIndex(spirv_tag_ty, @intFromEnum(spirv_info.flags.tag)); + const spirv_payload_val: Value = switch (spirv_info.flags.tag) { + .sampler => .void, + .sampled_image, .runtime_array => .fromInterned(spirv_info.ty), + .image => image: { + const image_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image"); + const usage_union_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Usage"); + const format_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Format"); + const dim_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Dimensionality"); + const depth_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Depth"); + const access_ty = try sema.getStdLangType(src, .@"Type.Spirv.Image.Access"); + const usage_tag_ty = usage_union_ty.unionTagType(zcu).?; + const usage_tag_val = try pt.enumValueFieldIndex(usage_tag_ty, @intFromEnum(spirv_info.flags.usage)); + const usage_val = try pt.unionValue(usage_union_ty, usage_tag_val, .fromInterned(spirv_info.ty)); + const image_field_vals = [_]InternPool.Index{ + usage_val.toIntern(), + (try pt.enumValueFieldIndex(format_ty, @intFromEnum(spirv_info.flags.format))).toIntern(), + (try pt.enumValueFieldIndex(dim_ty, @intFromEnum(spirv_info.flags.dim))).toIntern(), + (try pt.enumValueFieldIndex(depth_ty, @intFromEnum(spirv_info.flags.depth))).toIntern(), + (try pt.enumValueFieldIndex(access_ty, @intFromEnum(spirv_info.flags.access))).toIntern(), + Value.makeBool(spirv_info.flags.is_arrayed).toIntern(), + Value.makeBool(spirv_info.flags.is_multisampled).toIntern(), + }; + break :image try pt.aggregateValue(image_ty, &image_field_vals); + }, + }; + const spirv_val = try pt.unionValue(spirv_union_ty, spirv_tag_val, spirv_payload_val); + return Air.internedToRef((try pt.internUnion(.{ + .ty = type_info_ty.toIntern(), + .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.lang.TypeId.spirv))).toIntern(), + .val = spirv_val.toIntern(), + }))); + }, .frame => return sema.failWithUseOfAsync(block, src), .@"anyframe" => return sema.failWithUseOfAsync(block, src), } @@ -17523,15 +17545,10 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr const is_cold = sema.branch_hint == .cold; const operand_ty = sema.typeOf(operand); - const ptr_info = operand_ty.ptrInfo(zcu); - const res_ty = try pt.ptrType(.{ - .child = err_union_ty.errorUnionPayload(zcu).toIntern(), - .flags = .{ - .is_const = ptr_info.flags.is_const, - .is_volatile = ptr_info.flags.is_volatile, - .is_allowzero = ptr_info.flags.is_allowzero, - .address_space = ptr_info.flags.address_space, - }, + const res_ty = try pt.ptrType(info: { + var new = operand_ty.ptrInfo(zcu); + new.child = err_union_ty.errorUnionPayload(zcu).toIntern(); + break :info new; }); const res_ty_ref = Air.internedToRef(res_ty.toIntern()); try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.TryPtr).@"struct".field_names.len + @@ -18004,6 +18021,12 @@ fn analyzeRet( try inlining.merges.results.append(sema.gpa, operand); try inlining.merges.br_list.append(sema.gpa, br_inst.toIndex().?); try inlining.merges.src_locs.append(sema.gpa, operand_src); + var body_block = block; + while (body_block.parent) |parent| body_block = parent; + if (body_block.runtime_cond == null and body_block.runtime_loop == null) { + body_block.runtime_cond = block.runtime_cond orelse block.runtime_loop; + body_block.runtime_loop = block.runtime_loop; + } } else { try sema.validateRuntimeValue(block, operand_src, operand); const ret_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret; @@ -18098,13 +18121,19 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air } else 0; if (host_size != 0) { + try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .bit_ptr_child); + if (elem_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { + const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); + errdefer msg.destroy(sema.gpa); + try sema.explainWhyTypeIsUnpackable(msg, elem_ty_src, reason); + break :msg msg; + }); + const elem_bit_size = elem_ty.bitSize(zcu); if (bit_offset >= host_size * 8) { return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} starts {d} bits after the end of a {d} byte host integer", .{ elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size, }); } - try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .bit_ptr_child); - const elem_bit_size = elem_ty.bitSize(zcu); if (elem_bit_size > host_size * 8 - bit_offset) { return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{ elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size, @@ -18120,15 +18149,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.fail(block, elem_ty_src, "indexable pointer to opaque type '{f}' not allowed", .{elem_ty.fmt(pt)}); } - if (host_size != 0) { - if (elem_ty.unpackable(zcu)) |reason| return sema.failWithOwnedErrorMsg(block, msg: { - const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); - errdefer msg.destroy(sema.gpa); - try sema.explainWhyTypeIsUnpackable(msg, elem_ty_src, reason); - break :msg msg; - }); - } - const ty = try pt.ptrType(.{ .child = elem_ty.toIntern(), .sentinel = sentinel, @@ -18298,7 +18318,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const payload = try sema.coerce(block, field_ty, sema.resolveInst(extra.init), payload_src); if (union_ty.containerLayout(zcu) == .@"packed") { - return sema.bitCast(block, union_ty, payload, block.nodeOffset(inst_data.src_node), payload_src); + return sema.bitCast(block, union_ty, payload, block.nodeOffset(inst_data.src_node)); } if (sema.resolveValue(payload)) |payload_val| { @@ -18435,7 +18455,7 @@ fn zirStructInit( const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src); if (resolved_ty.containerLayout(zcu) == .@"packed") { - const union_val = try sema.bitCast(block, resolved_ty, init_inst, src, field_src); + const union_val = try sema.bitCast(block, resolved_ty, init_inst, src); const result_val = try sema.coerce(block, result_ty, union_val, src); if (is_ref) { return sema.analyzeRef(block, src, result_val, .none); @@ -18599,20 +18619,15 @@ fn finishStructInit( }, .@"packed" => { const buf = try sema.arena.alloc(u8, @intCast((struct_ty.bitSize(zcu) + 7) / 8)); + @memset(buf, 0); var bit_offset: u16 = 0; for (field_inits) |field_init| { const field_val = sema.resolveValue(field_init).?; - field_val.writeToPackedMemory(zcu, buf, bit_offset) catch |err| switch (err) { - error.ReinterpretDeclRef => unreachable, // bitpack fields cannot be pointers - error.OutOfMemory => |e| return e, - }; + field_val.writeToPackedMemory(zcu, buf, bit_offset); bit_offset += @intCast(field_val.typeOf(zcu).bitSize(zcu)); } assert(bit_offset == struct_ty.bitSize(zcu)); - const struct_val = Value.readFromPackedMemory(struct_ty, pt, buf, 0, sema.arena) catch |err| switch (err) { - error.IllDefinedMemoryLayout => unreachable, // bitpacks have well-defined layout - error.OutOfMemory => |e| return e, - }; + const struct_val: Value = try .readFromPackedMemory(struct_ty, pt, buf, 0); const final_val_ref = try sema.coerce(block, result_ty, .fromValue(struct_val), init_src); return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref); }, @@ -18748,6 +18763,18 @@ fn structInitAnon( break :rs runtime_index; }; + // A field can't be `comptime` if it references a `comptime var` but the aggregate can still be comptime-known. + // Replace these fields with `.none` only for generating the type. + const values_no_comptime = if (!any_values) values else blk: { + const new_values = try sema.arena.alloc(InternPool.Index, types.len); + for (values, new_values) |val, *new_val| { + if (val != .none and Value.fromInterned(val).canMutateComptimeVarState(zcu)) { + new_val.* = .none; + } else new_val.* = val; + } + break :blk new_values; + }; + // We treat anonymous struct types as reified types, because there are similarities: they have // no captures, and instead use a form of structural equivalence which we can easy represent by // hashing the field names/types/values. They also perform layout resolution immediately. These @@ -18756,7 +18783,7 @@ fn structInitAnon( const type_hash: u64 = hash: { var hasher = std.hash.Wyhash.init(0); hasher.update(std.mem.sliceAsBytes(types)); - hasher.update(std.mem.sliceAsBytes(values)); + hasher.update(std.mem.sliceAsBytes(values_no_comptime)); hasher.update(std.mem.sliceAsBytes(names)); break :hash hasher.final(); }; @@ -18780,9 +18807,9 @@ fn structInitAnon( @memcpy(wip.field_names.get(ip), names); @memcpy(wip.field_types.get(ip), types); if (any_values) { - @memcpy(wip.field_values.get(ip), values); + @memcpy(wip.field_values.get(ip), values_no_comptime); @memset(wip.field_is_comptime_bits.getAll(ip), 0); - for (values, 0..) |val, field_index| { + for (values_no_comptime, 0..) |val, field_index| { if (val == .none) continue; const bit_bag_index = field_index / 32; const mask = @as(u32, 1) << @intCast(field_index % 32); @@ -18810,6 +18837,15 @@ fn structInitAnon( return sema.addConstantMaybeRef(struct_val, is_ref); }; + for (values, 0..) |field_val, i| { + if (field_val == .none) continue; // runtime-known + const field_src = block.src(.{ .init_elem = .{ + .init_node_offset = src.offset.node_offset.x, + .elem_index = @intCast(i), + } }); + try sema.validateRuntimeValue(block, field_src, .fromIntern(field_val)); + } + if (is_ref) { const target = zcu.getTarget(); const alloc_ty = try pt.ptrType(.{ @@ -19066,13 +19102,11 @@ fn arrayInitAnon( .values = values_no_comptime, })); - const runtime_src = opt_runtime_src orelse { + _ = opt_runtime_src orelse { const tuple_val = try pt.aggregateValue(tuple_ty, values); return sema.addConstantMaybeRef(tuple_val, is_ref); }; - try sema.requireRuntimeBlock(block, src, runtime_src); - for (operands, 0..) |operand, i| { const operand_src = block.src(.{ .init_elem = .{ .init_node_offset = src.offset.node_offset.x, @@ -19287,7 +19321,7 @@ fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError } return Air.internedToRef((try pt.aggregateValue(dest_ty, new_elems)).toIntern()); } - return block.addBitCast(dest_ty, operand); + return block.addTyOp(.bit_cast, dest_ty, operand); } fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -20449,6 +20483,303 @@ fn zirReifyEnum( } } +fn zirReifySpirvType( + sema: *Sema, + block: *Block, + extended: Zir.Inst.Extended.InstData, + inst: Zir.Inst.Index, +) CompileError!Air.Inst.Ref { + const pt = sema.pt; + const zcu = pt.zcu; + const comp = zcu.comp; + const gpa = comp.gpa; + const io = comp.io; + const ip = &zcu.intern_pool; + const target = zcu.getTarget(); + + const extra = sema.code.extraData(Zir.Inst.ReifySpirvType, extended.operand).data; + const tracked_inst = try block.trackZir(inst); + const src: LazySrcLoc = .{ + .base_node_inst = tracked_inst, + .offset = .nodeOffset(.zero), + }; + const operand_src: LazySrcLoc = .{ + .base_node_inst = tracked_inst, + .offset = .{ .node_offset_builtin_call_arg = .{ + .builtin_call_node = .zero, + .arg_index = 0, + } }, + }; + + if (!target.cpu.arch.isSpirV()) { + return sema.fail( + block, + src, + "builtin @SpirvType is only available when targeting SPIR-V; targeted CPU architecture is {t}", + .{target.cpu.arch}, + ); + } + + const spirv_type_options_ty = try sema.getStdLangType(operand_src, .@"Type.Spirv"); + const operand_uncoerced = sema.resolveInst(extra.operand); + const operand_coerced = try sema.coerce(block, spirv_type_options_ty, operand_uncoerced, operand_src); + const operand_val = try sema.resolveConstDefinedValue(block, operand_src, operand_coerced, .{ .simple = .type }); + const union_val = ip.indexToKey(operand_val.toIntern()).un; + + if (try sema.anyUndef(block, operand_src, .fromInterned(union_val.val))) { + return sema.failWithUseOfUndef(block, operand_src, null); + } + + // TODO: use a longer hash! + var hasher = std.hash.Wyhash.init(0); + std.hash.autoHash(&hasher, union_val.tag); + + const name = try ip.getOrPutStringFmt( + gpa, + io, + pt.tid, + "{f}__SpirvType_{d}", + .{ block.type_name_ctx.fmt(ip), @intFromEnum(inst) }, + .no_embedded_nulls, + ); + const tag = try sema.interpretStdLangType(block, src, .fromInterned(union_val.tag), @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?); + const ip_data: InternPool.Tag.TypeSpirv = switch (tag) { + .sampler => .{ + .name = name, + .zir_index = tracked_inst, + .ty = .none, + .flags = .{ + .tag = .sampler, + .usage = .unknown, + .format = .unknown, + .dim = .@"1d", + .depth = .unknown, + .access = .unknown, + .is_arrayed = false, + .is_multisampled = false, + }, + }, + .image => ip_data: { + const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); + const usage_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( + ip, + try ip.getOrPutString(gpa, io, pt.tid, "usage", .no_embedded_nulls), + ).?); + const format_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( + ip, + try ip.getOrPutString(gpa, io, pt.tid, "format", .no_embedded_nulls), + ).?); + const dim_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( + ip, + try ip.getOrPutString(gpa, io, pt.tid, "dim", .no_embedded_nulls), + ).?); + const depth_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( + ip, + try ip.getOrPutString(gpa, io, pt.tid, "depth", .no_embedded_nulls), + ).?); + const access_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( + ip, + try ip.getOrPutString(gpa, io, pt.tid, "access", .no_embedded_nulls), + ).?); + const arrayed_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( + ip, + try ip.getOrPutString(gpa, io, pt.tid, "arrayed", .no_embedded_nulls), + ).?); + const multisampled_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( + ip, + try ip.getOrPutString(gpa, io, pt.tid, "multisampled", .no_embedded_nulls), + ).?); + const format = try sema.interpretStdLangType(block, operand_src, format_val, std.lang.Type.Spirv.Image.Format); + const dim = try sema.interpretStdLangType(block, operand_src, dim_val, std.lang.Type.Spirv.Image.Dimensionality); + const depth = try sema.interpretStdLangType(block, operand_src, depth_val, std.lang.Type.Spirv.Image.Depth); + const access = try sema.interpretStdLangType(block, operand_src, access_val, std.lang.Type.Spirv.Image.Access); + + switch (target.os.tag) { + .opencl => if (access == .unknown) { + return sema.fail(block, operand_src, "'access' field must be specified under the 'opencl' os", .{}); + }, + else => if (access != .unknown) { + return sema.fail(block, operand_src, "access qualifier '.{t}' is only valid under the 'opencl' os", .{access}); + }, + } + + const arrayed = try sema.interpretStdLangType(block, operand_src, arrayed_val, bool); + const multisampled = try sema.interpretStdLangType(block, operand_src, multisampled_val, bool); + + const usage_tag_val = usage_val.unionTag(zcu).?; + const usage_tag = try sema.interpretStdLangType(block, operand_src, usage_tag_val, @typeInfo(std.lang.Type.Spirv.Image.Usage).@"union".tag_type.?); + + switch (target.os.tag) { + .vulkan => { + if (usage_tag == .unknown) { + return sema.fail( + block, + operand_src, + "'usage' must be '.sampled' or '.storage' under the 'vulkan' os (Sampled == 0 is forbidden)", + .{}, + ); + } + }, + .opencl => { + if (usage_tag != .unknown) { + return sema.fail(block, operand_src, "'usage' must be '.unknown' under the 'opencl' os", .{}); + } + if (multisampled) { + return sema.fail(block, operand_src, "'multisampled' must be 'false' under the 'opencl' os", .{}); + } + if (format != .unknown) { + return sema.fail(block, operand_src, "'format' must be '.unknown' under the 'opencl' os", .{}); + } + if (dim == .cube) { + return sema.fail(block, operand_src, "'dim' '.cube' is not allowed under the 'opencl' os", .{}); + } + if (arrayed and dim != .@"1d" and dim != .@"2d") { + return sema.fail(block, operand_src, "'arrayed' may only be 'true' when 'dim' is '.1d' or '.2d' under the 'opencl' os", .{}); + } + }, + else => {}, + } + + std.hash.autoHash(&hasher, usage_tag); + std.hash.autoHash(&hasher, format); + std.hash.autoHash(&hasher, dim); + std.hash.autoHash(&hasher, depth); + std.hash.autoHash(&hasher, access); + std.hash.autoHash(&hasher, arrayed); + std.hash.autoHash(&hasher, multisampled); + + break :ip_data .{ + .name = name, + .zir_index = tracked_inst, + .ty = blk: { + const sampled_type = usage_val.unionPayload(zcu).toType(); + std.hash.autoHash(&hasher, sampled_type.toIntern()); + + if (target.os.tag != .opencl and sampled_type.toIntern() == .void_type) { + return sema.fail(block, operand_src, "'void' type for '{t}' field is only valid under the 'opencl' os", .{usage_tag}); + } + if (target.os.tag == .opencl and sampled_type.toIntern() != .void_type) { + return sema.fail(block, operand_src, "'{t}' field type must be 'void' under the 'opencl' os", .{usage_tag}); + } + + if (sampled_type.toIntern() != .void_type and + (!sampled_type.hasRuntimeBits(zcu) or (!sampled_type.isRuntimeFloat() and !sampled_type.isInt(zcu)))) + { + return sema.fail(block, operand_src, "invalid '{t}' field value '{f}'", .{ usage_tag, sampled_type.fmt(pt) }); + } + + if (target.os.tag == .vulkan) { + const ok = (sampled_type.isRuntimeFloat() and sampled_type.bitSize(zcu) == 32) or + (sampled_type.isInt(zcu) and (sampled_type.bitSize(zcu) == 32 or sampled_type.bitSize(zcu) == 64)); + if (!ok) { + return sema.fail( + block, + operand_src, + "'{t}' field value must be a 32-bit int, 64-bit int or 32-bit float under the 'vulkan' os", + .{usage_tag}, + ); + } + + if (format != .unknown) { + const format_kind: enum { float, sint, uint } = switch (format) { + .rgba32f, .rgba16f, .rgba8unorm, .rgba8snorm, .r32f => .float, + .rgba32i, .rgba16i, .rgba8i, .r32i => .sint, + .rgba32u, .rgba16u, .rgba8u, .r32u => .uint, + .unknown => unreachable, + }; + const matches = switch (format_kind) { + .float => sampled_type.isRuntimeFloat(), + .sint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .signed, + .uint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .unsigned, + }; + if (!matches) { + return sema.fail( + block, + operand_src, + "image 'format' '.{t}' does not match '{t}' type '{f}' under the 'vulkan' os", + .{ format, usage_tag, sampled_type.fmt(pt) }, + ); + } + } + } + + break :blk sampled_type.toIntern(); + }, + .flags = .{ + .tag = .image, + .usage = usage_tag, + .format = format, + .dim = dim, + .depth = depth, + .access = access, + .is_arrayed = arrayed, + .is_multisampled = multisampled, + }, + }; + }, + .sampled_image => blk: { + const image_ty = Value.fromInterned(union_val.val).toType(); + if (image_ty.zigTypeTag(zcu) != .spirv or ip.loadSpirvType(image_ty.toIntern()).flags.tag != .image) { + return sema.fail(block, operand_src, "'sampled_image' element must be an @SpirvType image, found '{f}'", .{image_ty.fmt(pt)}); + } + const image_info = ip.loadSpirvType(image_ty.toIntern()).flags; + if (image_info.usage != .sampled) { + return sema.fail(block, operand_src, "'sampled_image' element must be an image with 'usage = .sampled'", .{}); + } + std.hash.autoHash(&hasher, union_val.val); + break :blk .{ + .name = name, + .zir_index = tracked_inst, + .ty = union_val.val, + .flags = .{ + .tag = tag, + .usage = .unknown, + .format = .unknown, + .dim = .@"1d", + .depth = .unknown, + .access = .unknown, + .is_arrayed = false, + .is_multisampled = false, + }, + }; + }, + .runtime_array => blk: { + const elem_ty = Value.fromInterned(union_val.val).toType(); + if (elem_ty.toIntern() == .void_type) { + return sema.fail(block, operand_src, "'runtime_array' element type must not be 'void'", .{}); + } + if (target.os.tag == .vulkan and + elem_ty.zigTypeTag(zcu) == .spirv and + ip.loadSpirvType(elem_ty.toIntern()).flags.tag == .runtime_array) + { + return sema.fail(block, operand_src, "'runtime_array' of 'runtime_array' is not allowed under the 'vulkan' os", .{}); + } + std.hash.autoHash(&hasher, union_val.val); + break :blk .{ + .name = name, + .zir_index = tracked_inst, + .ty = union_val.val, + .flags = .{ + .tag = tag, + .usage = .unknown, + .format = .unknown, + .dim = .@"1d", + .depth = .unknown, + .access = .unknown, + .is_arrayed = false, + .is_multisampled = false, + }, + }; + }, + }; + + return .fromIntern(try ip.getReifiedSpirvType(gpa, io, pt.tid, .{ + .zir_index = tracked_inst, + .type_hash = hasher.final(), + .type_spirv = ip_data, + })); +} + fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { const pt = sema.pt; const va_list_ty = try sema.getStdLangType(src, .VaList); @@ -20845,7 +21176,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment); } } - return block.addBitCast(dest_ty, operand_coerced); + return block.addTyOp(.ptr_from_int, dest_ty, operand_coerced); } fn ptrFromIntVal( @@ -21044,7 +21375,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData .error_union => try block.addTyOp(.unwrap_errunion_err, operand_err_ty, operand), else => unreachable, }; - const err_int_inst = try block.addBitCast(err_int_ty, err_code_inst); + const err_int_inst = try block.addTyOp(.int_from_error, err_int_ty, err_code_inst); if (dest_tag == .error_union) { const zero_err = try pt.intRef(err_int_ty, 0); const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err); @@ -21064,10 +21395,10 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData } if (operand_tag == .error_set and dest_tag == .error_union) { - const err_val = try block.addBitCast(dest_err_ty, operand); + const err_val = try block.addTyOp(.error_cast, dest_err_ty, operand); return block.addTyOp(.wrap_errunion_err, dest_ty, err_val); } else { - return block.addBitCast(dest_ty, operand); + return block.addTyOp(.error_cast, dest_ty, operand); } } @@ -21615,7 +21946,7 @@ fn ptrCastFull( // `operand_ptr` converted to an integer, for safety checks. const operand_ptr_int: Air.Inst.Ref = if (need_null_check or need_align_check) i: { assert(need_operand_ptr); - break :i try block.addBitCast(.usize, operand_ptr); + break :i try block.addTyOp(.int_from_ptr, .usize, operand_ptr); } else .none; if (need_null_check) { @@ -21642,8 +21973,8 @@ fn ptrCastFull( if (dest_info.flags.size == .slice) { if (src_info.flags.size == .slice and !flags.addrspace_cast and !slice_needs_len_change) { - // Fast path: just bitcast! - return block.addBitCast(dest_ty, operand); + // Fast path: just pointer cast! + return block.addTyOp(.ptr_cast, dest_ty, operand); } // We need to deconstruct the slice (if applicable) and reconstruct it. @@ -21701,7 +22032,7 @@ fn ptrCastFull( else => unreachable, }; const coerced_ptr = if (operand_ptr_ty.toIntern() != want_ptr_ty.toIntern()) ptr: { - break :ptr try block.addBitCast(want_ptr_ty, operand_ptr); + break :ptr try block.addTyOp(.ptr_cast, want_ptr_ty, operand_ptr); } else operand_ptr; return block.addInst(.{ @@ -21716,12 +22047,11 @@ fn ptrCastFull( }); } else { assert(need_operand_ptr); - // We just need to bitcast the pointer, if necessary. - // It might not be necessary, since we might have just needed the `addrspace_cast`. + // We just need a ptr_cast, if even that (we might only have needed the `addrspace_cast`). const result = if (sema.typeOf(operand_ptr).toIntern() == dest_ty.toIntern()) operand_ptr else - try block.addBitCast(dest_ty, operand_ptr); + try block.addTyOp(.ptr_cast, dest_ty, operand_ptr); try sema.checkKnownAllocPtr(block, operand, result); return result; @@ -21757,7 +22087,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst } try sema.requireRuntimeBlock(block, src, null); - const new_ptr = try block.addBitCast(dest_ty, operand); + const new_ptr = try block.addTyOp(.ptr_cast, dest_ty, operand); try sema.checkKnownAllocPtr(block, operand, new_ptr); return new_ptr; } @@ -23859,7 +24189,7 @@ fn analyzeMinMax( // where we have refined the range, so we should be doing an intcast. assert(intermediate_scalar_ty.zigTypeTag(zcu) == .int); assert(result_scalar_ty.zigTypeTag(zcu) == .int); - return block.addTyOp(.intcast, result_ty, cur_result); + return block.addTyOp(.int_cast, result_ty, cur_result); } fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref { @@ -23889,7 +24219,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A try block.addTyOp(.slice_ptr, ptr_ty.slicePtrFieldType(zcu), ptr) else ptr; - return block.addBitCast(new_ty, non_slice_ptr); + return block.addTyOp(.ptr_cast, new_ty, non_slice_ptr); } fn zirMemcpy( @@ -24635,6 +24965,13 @@ fn zirBuiltinExtern( .pcrel => if (options.visibility == .default) return sema.fail(block, options_src, "cannot require a pc-relative relocation to a symbol with default visibility", .{}), } + if (options.decoration) |decoration| switch (decoration) { + .flat => if (ptr_info.flags.address_space != .input) { + return sema.fail(block, options_src, "'flat' decoration requires 'input' address space", .{}); + }, + .location, .descriptor => {}, + }; + // TODO: error for threadlocal functions, non-const functions, etc const extern_val = try pt.getExtern(.{ @@ -24680,7 +25017,7 @@ fn zirBuiltinExtern( const casted_ptr_val = try pt.getCoerced(uncasted_ptr_val, result_ptr_ty); return Air.internedToRef(casted_ptr_val.toIntern()); } else { - return block.addBitCast(result_ptr_ty, uncasted_ptr); + return block.addTyOp(.ptr_cast, result_ptr_ty, uncasted_ptr); } } @@ -24760,6 +25097,7 @@ fn zirStdLangValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD .fn_attributes, => .@"Type.Fn.Attributes", .container_layout => .@"Type.ContainerLayout", .enum_mode => .@"Type.Enum.Mode", + .spirv_type_options => .@"Type.Spirv", // zig fmt: on // Values are handled here. @@ -24957,6 +25295,7 @@ fn explainWhyTypeIsComptime( .void, .@"enum", .@"opaque", + .spirv, .pointer, => unreachable, // not comptime-only @@ -25043,6 +25382,7 @@ pub fn explainWhyTypeIsNotExtern( .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), .@"opaque", + .spirv, .bool, .float, .@"anyframe", @@ -25123,7 +25463,7 @@ pub fn explainWhyTypeIsNotExtern( .param_ty => try sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{}), else => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element), }, - .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element), + .vector => try sema.errNote(src_loc, msg, "vectors have no guaranteed in-memory representation", .{}), .optional => try sema.errNote(src_loc, msg, "non-pointer optionals have no guaranteed in-memory representation", .{}), } } @@ -25391,7 +25731,7 @@ fn addSafetyCheckSentinelMismatch( .address_space = ptr_info.flags.address_space, }, }); - const many_ptr = try parent_block.addBitCast(many_ptr_ty, ptr); + const many_ptr = try parent_block.addTyOp(.ptr_cast, many_ptr_ty, ptr); break :s try parent_block.addBinOp(.ptr_elem_val, many_ptr, sentinel_index); }, .many => unreachable, @@ -25458,17 +25798,21 @@ fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.Simple fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { sema.branch_count += 1; if (sema.branch_count > sema.branch_quota) { - const msg = try sema.errMsg( - src, - "evaluation exceeded {d} backwards branches", - .{sema.branch_quota}, - ); - try sema.errNote( - src, - msg, - "use @setEvalBranchQuota() to raise the branch limit from {d}", - .{sema.branch_quota}, - ); + const msg = msg: { + const msg = try sema.errMsg( + src, + "evaluation exceeded {d} backwards branches", + .{sema.branch_quota}, + ); + errdefer msg.destroy(sema.gpa); + try sema.errNote( + src, + msg, + "use @setEvalBranchQuota() to raise the branch limit from {d}", + .{sema.branch_quota}, + ); + break :msg msg; + }; return sema.failWithOwnedErrorMsg(block, msg); } } @@ -25483,9 +25827,13 @@ fn fieldPtrLoad( ) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; + const ip = &zcu.intern_pool; const object_ptr_ty = sema.typeOf(object_ptr); assert(object_ptr_ty.zigTypeTag(zcu) == .pointer); const pointee_ty = object_ptr_ty.childType(zcu); + if (pointee_ty.isSpirvRuntimeArray(zcu) and field_name.eqlSlice("len", ip)) { + return sema.analyzeSpirvRuntimeArrayLen(block, src, object_ptr, field_name_src); + } try sema.ensureLayoutResolved(pointee_ty, src, .ptr_access); if (try pointee_ty.onePossibleValue(pt)) |opv| { const object: Air.Inst.Ref = .fromValue(opv); @@ -25675,11 +26023,123 @@ fn fieldVal( } else { return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); }, + .spirv => if (inner_ty.isSpirvRuntimeArray(zcu) and field_name.eqlSlice("len", ip)) { + if (!is_pointer_to) { + return sema.fail( + block, + src, + "accessing 'len' field on a SPIR-V runtime_array requires a pointer to the array field", + .{}, + ); + } + return sema.analyzeSpirvRuntimeArrayLen(block, src, object, field_name_src); + }, else => {}, } return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); } +fn analyzeSpirvRuntimeArrayLen( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + runtime_array_ptr: Air.Inst.Ref, + src_for_err: LazySrcLoc, +) CompileError!Air.Inst.Ref { + const pt = sema.pt; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + + const struct_operand: Air.Inst.Ref, const field_index: u32 = sf: { + if (runtime_array_ptr.toIndex()) |inst| { + const tag = sema.air_instructions.items(.tag)[@intFromEnum(inst)]; + const data = sema.air_instructions.items(.data)[@intFromEnum(inst)]; + switch (tag) { + .struct_field_ptr => { + const extra = sema.getTmpAir().extraData(Air.StructField, data.ty_pl.payload).data; + break :sf .{ extra.struct_operand, extra.field_index }; + }, + .struct_field_ptr_index_0 => break :sf .{ data.ty_op.operand, 0 }, + .struct_field_ptr_index_1 => break :sf .{ data.ty_op.operand, 1 }, + .struct_field_ptr_index_2 => break :sf .{ data.ty_op.operand, 2 }, + .struct_field_ptr_index_3 => break :sf .{ data.ty_op.operand, 3 }, + else => {}, + } + } + + const ptr_val = sema.resolveValue(runtime_array_ptr) orelse return sema.fail( + block, + src_for_err, + "'len' field on a SPIR-V runtime_array requires direct struct field access", + .{}, + ); + const ptr_key = ip.indexToKey(ptr_val.toIntern()).ptr; + if (ptr_key.base_addr == .field and ptr_key.byte_offset == 0) { + const field = ptr_key.base_addr.field; + break :sf .{ .fromIntern(field.base), @intCast(field.index) }; + } + + const parent_ty: Type = switch (ptr_key.base_addr) { + .nav => |nav| .fromInterned(ip.getNav(nav).resolved.?.type), + .uav => |uav| .fromInterned(ip.typeOf(uav.val)), + .comptime_alloc, + .comptime_field, + .eu_payload, + .opt_payload, + .arr_elem, + .field, + .int, + => return sema.fail( + block, + src_for_err, + "'len' field on a SPIR-V runtime_array requires direct struct field access", + .{}, + ), + }; + if (parent_ty.zigTypeTag(zcu) != .@"struct") return sema.fail( + block, + src_for_err, + "'len' field on a SPIR-V runtime_array requires the array to be a struct field", + .{}, + ); + + const field_ptr_info = ip.indexToKey(ptr_key.ty).ptr_type; + const rtarr_ty_ip = field_ptr_info.child; + const struct_obj = ip.loadStructType(parent_ty.toIntern()); + const field_idx: u32 = for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, i| { + if (field_ty_ip == rtarr_ty_ip and + struct_obj.field_offsets.get(ip)[i] == ptr_key.byte_offset) + { + break @intCast(i); + } + } else unreachable; + const struct_ptr_ty = try pt.ptrType(.{ + .child = parent_ty.toIntern(), + .flags = field_ptr_info.flags, + }); + const struct_ptr_val = try sema.ptrSubtract( + block, + src_for_err, + ptr_val, + ptr_key.byte_offset, + struct_ptr_ty, + ); + break :sf .{ .fromIntern(struct_ptr_val.toIntern()), field_idx }; + }; + + try sema.requireRuntimeBlock(block, src, null); + return block.addInst(.{ + .tag = .spirv_runtime_array_len, + .data = .{ .ty_pl = .{ + .ty = .u32_type, + .payload = try sema.addExtra(Air.StructField{ + .struct_operand = struct_operand, + .field_index = field_index, + }), + } }, + }); +} + fn fieldPtr( sema: *Sema, block: *Block, @@ -25748,7 +26208,7 @@ fn fieldPtr( }, .packed_offset = ptr_ptr_info.packed_offset, }); - return sema.bitCast(block, result_ty, object_ptr, src, null); + return block.addTyOp(.ptr_cast, result_ty, object_ptr); } else { return sema.fail( block, @@ -25767,17 +26227,7 @@ fn fieldPtr( const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty; if (field_name.eqlSlice("ptr", ip)) { - const slice_ptr_ty = inner_ty.slicePtrFieldType(zcu); - - const result_ty = try pt.ptrType(.{ - .child = slice_ptr_ty.toIntern(), - .flags = .{ - .is_const = !attr_ptr_ty.ptrIsMutable(zcu), - .is_volatile = attr_ptr_ty.isVolatilePtr(zcu), - .address_space = attr_ptr_ty.ptrAddressSpace(zcu), - }, - }); - + const result_ty = try attr_ptr_ty.fieldPtrType(Value.slice_ptr_index, pt); if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { return Air.internedToRef((try val.ptrField(Value.slice_ptr_index, pt)).toIntern()); } @@ -25787,15 +26237,7 @@ fn fieldPtr( try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); return field_ptr; } else if (field_name.eqlSlice("len", ip)) { - const result_ty = try pt.ptrType(.{ - .child = .usize_type, - .flags = .{ - .is_const = !attr_ptr_ty.ptrIsMutable(zcu), - .is_volatile = attr_ptr_ty.isVolatilePtr(zcu), - .address_space = attr_ptr_ty.ptrAddressSpace(zcu), - }, - }); - + const result_ty = try attr_ptr_ty.fieldPtrType(Value.slice_len_index, pt); if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { return Air.internedToRef((try val.ptrField(Value.slice_len_index, pt)).toIntern()); } @@ -25954,23 +26396,21 @@ fn fieldCallBind( .@"struct" => { if (zcu.typeToStruct(concrete_ty)) |struct_type| { const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field; - const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); - - return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr); + return sema.finishFieldCallBind(block, src, ptr_ty, field_index, object_ptr); } else if (concrete_ty.isTuple(zcu)) { if (field_name.eqlSlice("len", ip)) { return .{ .direct = try pt.intRef(.usize, concrete_ty.structFieldCount(zcu)) }; } if (field_name.toUnsigned(ip)) |field_index| { if (field_index >= concrete_ty.structFieldCount(zcu)) break :find_field; - return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.fieldType(field_index, zcu), field_index, object_ptr); + return sema.finishFieldCallBind(block, src, ptr_ty, field_index, object_ptr); } } else { const max = concrete_ty.structFieldCount(zcu); for (0..max) |i_usize| { const i: u32 = @intCast(i_usize); if (field_name == concrete_ty.structFieldName(i, zcu).unwrap().?) { - return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.fieldType(i, zcu), i, object_ptr); + return sema.finishFieldCallBind(block, src, ptr_ty, i, object_ptr); } } } @@ -26007,7 +26447,7 @@ fn fieldCallBind( (first_param_type.zigTypeTag(zcu) == .pointer and (first_param_type.ptrSize(zcu) == .one or first_param_type.ptrSize(zcu) == .c) and - first_param_type.childType(zcu).eql(concrete_ty, zcu))) + first_param_type.childType(zcu).eql(concrete_ty))) { // Note that if the param type is generic poison, we know that it must // specifically be `anytype` since it's the first parameter, meaning we @@ -26018,7 +26458,7 @@ fn fieldCallBind( .func_inst = decl_val, .arg0_inst = object_ptr, } }; - } else if (first_param_type.eql(concrete_ty, zcu)) { + } else if (first_param_type.eql(concrete_ty)) { const deref = try sema.analyzeLoad(block, src, object_ptr, src); return .{ .method = .{ .func_inst = decl_val, @@ -26026,7 +26466,7 @@ fn fieldCallBind( } }; } else if (first_param_type.zigTypeTag(zcu) == .optional) { const child = first_param_type.optionalChild(zcu); - if (child.eql(concrete_ty, zcu)) { + if (child.eql(concrete_ty)) { const deref = try sema.analyzeLoad(block, src, object_ptr, src); return .{ .method = .{ .func_inst = decl_val, @@ -26034,7 +26474,7 @@ fn fieldCallBind( } }; } else if (child.zigTypeTag(zcu) == .pointer and child.ptrSize(zcu) == .one and - child.childType(zcu).eql(concrete_ty, zcu)) + child.childType(zcu).eql(concrete_ty)) { return .{ .method = .{ .func_inst = decl_val, @@ -26042,7 +26482,7 @@ fn fieldCallBind( } }; } } else if (first_param_type.zigTypeTag(zcu) == .error_union and - first_param_type.errorUnionPayload(zcu).eql(concrete_ty, zcu)) + first_param_type.errorUnionPayload(zcu).eql(concrete_ty)) { const deref = try sema.analyzeLoad(block, src, object_ptr, src); return .{ .method = .{ @@ -26086,19 +26526,12 @@ fn finishFieldCallBind( block: *Block, src: LazySrcLoc, ptr_ty: Type, - field_ty: Type, field_index: u32, object_ptr: Air.Inst.Ref, ) CompileError!ResolvedFieldCallee { const pt = sema.pt; const zcu = pt.zcu; - const ptr_field_ty = try pt.ptrType(.{ - .child = field_ty.toIntern(), - .flags = .{ - .is_const = !ptr_ty.ptrIsMutable(zcu), - .address_space = ptr_ty.ptrAddressSpace(zcu), - }, - }); + const ptr_field_ty = try ptr_ty.fieldPtrType(field_index, pt); const container_ty = ptr_ty.childType(zcu); if (container_ty.zigTypeTag(zcu) == .@"struct") { @@ -26484,16 +26917,13 @@ fn unionFieldVal( break :msg msg; }); }, - .@"extern" => if (try sema.bitCastVal(union_val, field_ty, 0, 0, 0)) |field_val| { + .@"extern" => if (try sema.castMemory(union_val, field_ty, 0)) |field_val| { return .fromValue(field_val); } else { // Runtime-known due to a pointer-to-integer conversion. }, .@"packed" => { - const field_val = try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0) orelse { - unreachable; // `null` is only possible if the input value contains a pointer, which a packed union cannot. - }; - return .fromValue(field_val); + return .fromValue(try sema.bitCastVal(union_val, field_ty)); }, } } @@ -26540,6 +26970,7 @@ fn elemPtr( .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), .array => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src), + .spirv => try sema.elemPtrSpirvRuntimeArray(block, indexable_ptr, elem_index), else => { const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src, .ptr_access); @@ -26584,16 +27015,14 @@ fn elemPtrOneLayerOnly( return .fromValue(try ptr_val.ptrElem(index, pt)); } - try sema.checkLogicalPtrOperation(block, src, indexable_ty); - const result_ty = try indexable_ty.elemPtrType(maybe_index, pt); - try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src); + try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_src); try sema.validateRuntimeValue(block, indexable_src, indexable); if (child_ty.abiSize(zcu) == 0) { // zero-bit child type; just bitcast the pointer - return block.addBitCast(result_ty, indexable); + return block.addTyOp(.ptr_cast, result_ty, indexable); } return block.addPtrElemPtr(indexable, elem_index, result_ty); @@ -26651,7 +27080,7 @@ fn elemVal( return sema.analyzeLoad(block, src, .fromValue(elem_ptr_val), indexable_src); } - try sema.validateRuntimeElemAccess(block, elem_index_src, child_ty, indexable_ty, src); + try sema.validateRuntimeElemAccess(block, elem_index_src, child_ty, src); switch (child_ty.classify(zcu)) { .runtime => {}, .one_possible_value => return .fromValue((try child_ty.onePossibleValue(pt)).?), @@ -26700,11 +27129,9 @@ fn validateRuntimeElemAccess( block: *Block, elem_index_src: LazySrcLoc, elem_ty: Type, - parent_ty: Type, parent_src: LazySrcLoc, ) CompileError!void { - const pt = sema.pt; - const zcu = pt.zcu; + const zcu = sema.pt.zcu; if (elem_ty.comptimeOnly(zcu)) { const msg = msg: { @@ -26721,14 +27148,6 @@ fn validateRuntimeElemAccess( }; return sema.failWithOwnedErrorMsg(block, msg); } - - if (zcu.intern_pool.indexToKey(parent_ty.toIntern()) == .ptr_type) { - const target = zcu.getTarget(); - const as = parent_ty.ptrAddressSpace(zcu); - if (target_util.shouldBlockPointerOps(target, as)) { - return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{f}'", .{parent_ty.fmt(pt)}); - } - } } /// Validates `elem_index`, and returns a pointer to that field using `structFieldPtrByIndex`. @@ -26799,7 +27218,7 @@ fn tupleField( return Air.internedToRef((try tuple_val.fieldValue(pt, field_index)).toIntern()); } - try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); + try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_src); return block.addStructFieldVal(tuple, field_index, field_ty); } @@ -26854,7 +27273,7 @@ fn elemValArray( if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); } - try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); + try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_src); try sema.validateRuntimeValue(block, array_src, array); if (oob_safety and block.wantSafety()) { @@ -26900,68 +27319,52 @@ fn elemPtrVector( } const elem_ty = vector_ty.childType(zcu); - const elem_bits = elem_ty.bitSize(zcu); - // Exiting this block means the operation is a runtime one. - const elem_ptr_ty: Type = if (elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits)) elem_ptr_ty: { - // Use a packed pointer (i.e. vector_index != 0) - const vector_ptr_info = vector_ptr_ty.ptrInfo(zcu); - const elem_ptr_ty = try pt.ptrType(.{ - .child = elem_ty.toIntern(), - .flags = .{ - .size = .one, - .alignment = vector_ptr_info.flags.alignment, - .is_const = vector_ptr_info.flags.is_const, - .is_volatile = vector_ptr_info.flags.is_volatile, - .is_allowzero = vector_ptr_info.flags.is_allowzero, - .address_space = vector_ptr_info.flags.address_space, - .vector_index = @enumFromInt(index), - }, - .packed_offset = .{ - .host_size = @intCast(vector_len), - .bit_offset = 0, - }, - }); - if (maybe_vector_ptr_val) |ptr_val| { - if (ptr_val.isUndef(zcu)) return pt.undefRef(elem_ptr_ty); - return .fromValue(try pt.getCoerced(ptr_val, elem_ptr_ty)); - } - break :elem_ptr_ty elem_ptr_ty; - } else elem_ptr_ty: { - // Use a normal pointer (i.e. vector_index == 0) - const vector_ptr_info = vector_ptr_ty.ptrInfo(zcu); - const elem_ptr_ty = try pt.ptrType(.{ - .child = elem_ty.toIntern(), - .flags = .{ - .size = .one, - // TODO: this logic was ported from old code, but it's bogus. This entire block will - // go away when https://github.com/ziglang/zig/issues/24061 is implemented anyway. - .alignment = switch (vector_ptr_info.flags.alignment) { - .none => .none, - else => |vec_align| switch (index * elem_ty.abiSize(zcu)) { - 0 => vec_align, - else => |byte_offset| .minStrict(vec_align, .fromLog2Units(@ctz(byte_offset))), - }, - }, - .is_const = vector_ptr_info.flags.is_const, - .is_volatile = vector_ptr_info.flags.is_volatile, - .is_allowzero = vector_ptr_info.flags.is_allowzero, - .address_space = vector_ptr_info.flags.address_space, - }, - }); - if (maybe_vector_ptr_val) |ptr_val| { - if (ptr_val.isUndef(zcu)) return pt.undefRef(elem_ptr_ty); - const bit_offset = index * @divExact(elem_ty.bitSize(zcu), 8); - return .fromValue(try ptr_val.getOffsetPtr(bit_offset, elem_ptr_ty, pt)); - } - break :elem_ptr_ty elem_ptr_ty; - }; + + const vector_ptr_info = vector_ptr_ty.ptrInfo(zcu); + const elem_ptr_ty = try pt.ptrType(.{ + .child = elem_ty.toIntern(), + .flags = .{ + .size = .one, + .alignment = vector_ptr_info.flags.alignment, + .is_const = vector_ptr_info.flags.is_const, + .is_volatile = vector_ptr_info.flags.is_volatile, + .is_allowzero = vector_ptr_info.flags.is_allowzero, + .address_space = vector_ptr_info.flags.address_space, + .vector_index = @enumFromInt(index), + }, + .packed_offset = .{ + .host_size = @intCast(vector_len), + .bit_offset = 0, + }, + }); + + if (maybe_vector_ptr_val) |ptr_val| { + if (ptr_val.isUndef(zcu)) return pt.undefRef(elem_ptr_ty); + return .fromValue(try pt.getCoerced(ptr_val, elem_ptr_ty)); + } if (!init) { - try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, vector_ty, vector_ptr_src); + try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, vector_ptr_src); try sema.validateRuntimeValue(block, vector_ptr_src, vector_ptr); } - return block.addPtrElemPtr(vector_ptr, elem_index, elem_ptr_ty); + return block.addTyOp(.ptr_cast, elem_ptr_ty, vector_ptr); +} + +fn elemPtrSpirvRuntimeArray( + sema: *Sema, + block: *Block, + array_ptr: Air.Inst.Ref, + elem_index: Air.Inst.Ref, +) CompileError!Air.Inst.Ref { + const pt = sema.pt; + const zcu = pt.zcu; + const array_ptr_ty = sema.typeOf(array_ptr); + assert(array_ptr_ty.ptrSize(zcu) == .one); + const array_ty = array_ptr_ty.childType(zcu); + assert(array_ty.isSpirvRuntimeArray(zcu)); + const elem_ptr_ty = try array_ptr_ty.elemPtrType(null, pt); + return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); } /// Asserts that the layout of the array is already resolved. @@ -27014,7 +27417,7 @@ fn elemPtrArray( } if (!init) { - try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.childType(zcu), array_ty, array_ptr_src); + try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.childType(zcu), array_ptr_src); try sema.validateRuntimeValue(block, array_ptr_src, array_ptr); } @@ -27027,7 +27430,7 @@ fn elemPtrArray( if (array_ty.childType(zcu).abiSize(zcu) == 0) { // zero-bit child type; just bitcast the pointer - return block.addBitCast(elem_ptr_ty, array_ptr); + return block.addTyOp(.ptr_cast, elem_ptr_ty, array_ptr); } return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); @@ -27077,7 +27480,7 @@ fn elemValSlice( if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); - try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); + try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_src); try sema.validateRuntimeValue(block, slice_src, slice); if (oob_safety and block.wantSafety()) { @@ -27137,7 +27540,7 @@ fn elemPtrSlice( } } - try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src); + try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_src); try sema.validateRuntimeValue(block, slice_src, slice); if (oob_safety and block.wantSafety()) { @@ -27153,7 +27556,7 @@ fn elemPtrSlice( if (elem_ty.abiSize(zcu) == 0) { // zero-bit child type; just extract the pointer and bitcast it const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice); - return block.addBitCast(elem_ptr_ty, slice_ptr); + return block.addTyOp(.ptr_cast, elem_ptr_ty, slice_ptr); } return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); } @@ -27228,7 +27631,7 @@ fn coerceExtra( try sema.ensureLayoutResolved(dest_ty, inst_src, .coerce); // If the types are the same, we can return the operand. - if (dest_ty.eql(inst_ty, zcu)) + if (dest_ty.eql(inst_ty)) return inst; const maybe_inst_val = sema.resolveValue(inst); @@ -27236,12 +27639,31 @@ fn coerceExtra( var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src, maybe_inst_val); if (in_memory_result == .ok) { if (maybe_inst_val) |val| { - return sema.coerceInMemory(val, dest_ty); + return .fromValue(try pt.getCoerced(val, dest_ty)); } - try sema.requireRuntimeBlock(block, inst_src, null); - const new_val = try block.addBitCast(dest_ty, inst); - try sema.checkKnownAllocPtr(block, inst, new_val); - return new_val; + const coerced: Air.Inst.Ref = switch (in_memory_result.ok) { + .none => coerced: { + const @"addrspace" = target_util.defaultAddressSpace(zcu.getTarget(), .local); + const src_ptr_ty = try pt.ptrType(.{ + .child = inst_ty.toIntern(), + .flags = .{ .size = .one, .address_space = @"addrspace" }, + }); + const dest_ptr_ty = try pt.ptrType(.{ + .child = dest_ty.toIntern(), + .flags = .{ .size = .one, .address_space = @"addrspace" }, + }); + const ptr = try block.addTy(.alloc, src_ptr_ty); + _ = try block.addBinOp(.store_safe, ptr, inst); + const casted_ptr = try block.addTyOp(.ptr_cast, dest_ptr_ty, ptr); + break :coerced try block.addTyOp(.load, dest_ty, casted_ptr); + }, + .same_type => unreachable, // we checked for equal types just above + .bit_cast => try block.addTyOp(.bit_cast, dest_ty, inst), + .ptr_cast => try block.addTyOp(.ptr_cast, dest_ty, inst), + .error_cast => try block.addTyOp(.error_cast, dest_ty, inst), + }; + try sema.checkKnownAllocPtr(block, inst, coerced); + return coerced; } switch (dest_ty.zigTypeTag(zcu)) { @@ -27355,8 +27777,8 @@ fn coerceExtra( if (dest_info.sentinel != .none) { if (array_ty.sentinel(zcu)) |inst_sent| { - if (Air.internedToRef(dest_info.sentinel) != - try sema.coerceInMemory(inst_sent, dst_elem_type)) + if (dest_info.sentinel != + (try pt.getCoerced(inst_sent, dst_elem_type)).toIntern()) { in_memory_result = .{ .ptr_sentinel = .{ .actual = inst_sent, @@ -27550,8 +27972,8 @@ fn coerceExtra( } if (dest_info.sentinel == .none or inst_info.sentinel == .none or - Air.internedToRef(dest_info.sentinel) != - try sema.coerceInMemory(Value.fromInterned(inst_info.sentinel), .fromInterned(dest_info.child))) + dest_info.sentinel != + (try pt.getCoerced(.fromInterned(inst_info.sentinel), .fromInterned(dest_info.child))).toIntern()) break :p; const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); @@ -27600,7 +28022,7 @@ fn coerceExtra( (dst_info.signedness == .signed and dst_info.bits > src_info.bits)) { try sema.requireRuntimeBlock(block, inst_src, null); - return block.addTyOp(.intcast, dest_ty, inst); + return block.addTyOp(.int_cast, dest_ty, inst); } }, else => {}, @@ -27862,16 +28284,8 @@ fn coerceExtra( return sema.failWithOwnedErrorMsg(block, msg); } -fn coerceInMemory( - sema: *Sema, - val: Value, - dst_ty: Type, -) CompileError!Air.Inst.Ref { - return Air.internedToRef((try sema.pt.getCoerced(val, dst_ty)).toIntern()); -} - const InMemoryCoercionResult = union(enum) { - ok, + ok: Strategy, no_match: Pair, int_not_coercible: Int, comptime_int_not_coercible: TypeValuePair, @@ -27907,6 +28321,21 @@ const InMemoryCoercionResult = union(enum) { double_ptr_to_anyopaque: Pair, slice_to_anyopaque: Pair, + const Strategy = enum { + /// There isn't a special strategy for this particular coercion---we'll just need to + /// reinterpret the bytes in memory. + none, + + /// The source and destination types are equal, so no explicit cast operation is necessary. + same_type, + /// The coercion can be lowered to `Air.Inst.Tag.bit_cast`. + bit_cast, + /// The coercion can be lowered to `Air.Inst.Tag.ptr_cast`. + ptr_cast, + /// The coercion can be lowered to `Air.Inst.Tag.error_cast`. + error_cast, + }; + const Pair = struct { actual: Type, wanted: Type, @@ -28279,8 +28708,8 @@ pub fn coerceInMemoryAllowed( assert(val.typeOf(zcu).toIntern() == src_ty.toIntern()); } - if (dest_ty.eql(src_ty, zcu)) - return .ok; + if (dest_ty.eql(src_ty)) + return .{ .ok = .same_type }; const dest_tag = dest_ty.zigTypeTag(zcu); const src_tag = src_ty.zigTypeTag(zcu); @@ -28293,7 +28722,7 @@ pub fn coerceInMemoryAllowed( if (dest_info.signedness == src_info.signedness and dest_info.bits == src_info.bits) { - return .ok; + return .{ .ok = .bit_cast }; } if ((src_info.signedness == dest_info.signedness and dest_info.bits < src_info.bits) or @@ -28301,7 +28730,7 @@ pub fn coerceInMemoryAllowed( (dest_info.signedness == .signed and src_info.signedness == .unsigned and dest_info.bits <= src_info.bits) or (dest_info.signedness == .unsigned and src_info.signedness == .signed)) { - return InMemoryCoercionResult{ .int_not_coercible = .{ + return .{ .int_not_coercible = .{ .actual_signedness = src_info.signedness, .wanted_signedness = dest_info.signedness, .actual_bits = src_info.bits, @@ -28324,7 +28753,7 @@ pub fn coerceInMemoryAllowed( const dest_bits = dest_ty.floatBits(target); const src_bits = src_ty.floatBits(target); if (dest_bits == src_bits) { - return .ok; + return .{ .ok = .bit_cast }; } } @@ -28347,24 +28776,38 @@ pub fn coerceInMemoryAllowed( if (dest_tag == .error_union and src_tag == .error_union) { const dest_payload = dest_ty.errorUnionPayload(zcu); const src_payload = src_ty.errorUnionPayload(zcu); - const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src, null); - if (child != .ok) { - return .{ .error_union_payload = .{ - .child = try child.dupe(sema.arena), + const payload_strat = switch (try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src, null)) { + .ok => |strat| strat, + else => |payload_result| return .{ .error_union_payload = .{ + .child = try payload_result.dupe(sema.arena), .actual = src_payload, .wanted = dest_payload, - } }; + } }, + }; + switch (try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(zcu), src_ty.errorUnionSet(zcu), dest_is_mut, target, dest_src, src_src, null)) { + .ok => {}, + else => |err_set_result| return err_set_result, } - return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(zcu), src_ty.errorUnionSet(zcu), dest_is_mut, target, dest_src, src_src, null); + return switch (payload_strat) { + .same_type => .{ .ok = .error_cast }, + else => .{ .ok = .none }, + }; } // Error Sets if (dest_tag == .error_set and src_tag == .error_set) { - const res1 = try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src); - if (!dest_is_mut or res1 != .ok) return res1; - // src -> dest is okay, but `dest_is_mut`, so it needs to be allowed in the other direction. - const res2 = try sema.coerceInMemoryAllowedErrorSets(block, src_ty, dest_ty, src_src, dest_src); - return res2; + switch (try sema.coerceInMemoryAllowedErrorSets(block, dest_ty, src_ty, dest_src, src_src)) { + .ok => |strat| assert(strat == .error_cast), + else => |result| return result, + } + if (dest_is_mut) { + // src -> dest is okay, but `dest_is_mut`, so it needs to be allowed in the other direction. + switch (try sema.coerceInMemoryAllowedErrorSets(block, src_ty, dest_ty, src_src, dest_src)) { + .ok => |strat| assert(strat == .error_cast), + else => |result| return result, + } + } + return .{ .ok = .error_cast }; } // Arrays @@ -28379,9 +28822,9 @@ pub fn coerceInMemoryAllowed( } const child = try sema.coerceInMemoryAllowed(block, dest_info.elem_type, src_info.elem_type, dest_is_mut, target, dest_src, src_src, null); - switch (child) { - .ok => {}, - .no_match => return child, + const child_strat = switch (child) { + .ok => |strat| strat, + .no_match => |no_match| return .{ .no_match = no_match }, else => { return .{ .array_elem = .{ .child = try child.dupe(sema.arena), @@ -28389,7 +28832,7 @@ pub fn coerceInMemoryAllowed( .wanted = dest_info.elem_type, } }; }, - } + }; const ok_sent = (dest_info.sentinel == null and src_info.sentinel == null) or (src_info.sentinel != null and dest_info.sentinel != null and @@ -28405,7 +28848,10 @@ pub fn coerceInMemoryAllowed( .ty = dest_info.elem_type, } }; } - return .ok; + return .{ .ok = switch (child_strat) { + .bit_cast => .bit_cast, + else => .none, + } }; } // Vectors @@ -28421,16 +28867,18 @@ pub fn coerceInMemoryAllowed( const dest_elem_ty = dest_ty.scalarType(zcu); const src_elem_ty = src_ty.scalarType(zcu); - const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); - if (child != .ok) { - return .{ .vector_elem = .{ - .child = try child.dupe(sema.arena), + switch (try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null)) { + .ok => |child_strat| return .{ .ok = switch (child_strat) { + .bit_cast => .bit_cast, + .ptr_cast => .ptr_cast, + else => .none, + } }, + else => |child_result| return .{ .vector_elem = .{ + .child = try child_result.dupe(sema.arena), .actual = src_elem_ty, .wanted = dest_elem_ty, - } }; + } }, } - - return .ok; } // Optionals @@ -28454,7 +28902,7 @@ pub fn coerceInMemoryAllowed( } }; } - return .ok; + return .{ .ok = .none }; } // Tuples (with in-memory-coercible fields) @@ -28468,7 +28916,7 @@ pub fn coerceInMemoryAllowed( const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src, null); if (field != .ok) break :tuple; } - return .ok; + return .{ .ok = .none }; } return .{ .no_match = .{ @@ -28491,13 +28939,13 @@ fn coerceInMemoryAllowedErrorSets( const ip = &zcu.intern_pool; const dest_set: InternPool.Key.ErrorSetType = err_set: switch (dest_ty.toIntern()) { - .anyerror_type => return .ok, + .anyerror_type => return .{ .ok = .error_cast }, .adhoc_inferred_error_set_type => { // We are trying to coerce an error set to the current function's // inferred error set. const dst_ies = sema.fn_ret_ty_ies.?; try dst_ies.addErrorSet(src_ty, ip, sema.arena); - return .ok; + return .{ .ok = .error_cast }; }, else => |err_set_ty| switch (ip.indexToKey(err_set_ty)) { .inferred_error_set_type => |func_index| { @@ -28506,7 +28954,7 @@ fn coerceInMemoryAllowedErrorSets( // We are trying to coerce an error set to the current function's // inferred error set. try dst_ies.addErrorSet(src_ty, ip, sema.arena); - return .ok; + return .{ .ok = .error_cast }; } } try sema.ensureFuncIesResolved(block, dest_src, func_index); @@ -28545,7 +28993,7 @@ fn coerceInMemoryAllowedErrorSets( ) }; } - return .ok; + return .{ .ok = .error_cast }; } fn coerceInMemoryAllowedFns( @@ -28662,7 +29110,7 @@ fn coerceInMemoryAllowedFns( } } - return .ok; + return .{ .ok = .none }; } fn callconvCoerceAllowed( @@ -28676,10 +29124,10 @@ fn callconvCoerceAllowed( switch (src_cc) { inline else => |src_data, tag| { const dest_data = @field(dest_cc, @tagName(tag)); - if (@TypeOf(src_data) != void) { + if (@TypeOf(src_data) != void and @hasField(@TypeOf(src_data), "incoming_stack_alignment")) { const default_stack_align = target.stackAlignment(); const src_stack_align = src_data.incoming_stack_alignment orelse default_stack_align; - const dest_stack_align = src_data.incoming_stack_alignment orelse default_stack_align; + const dest_stack_align = dest_data.incoming_stack_alignment orelse default_stack_align; if (dest_stack_align < src_stack_align) return false; } switch (@TypeOf(src_data)) { @@ -28705,6 +29153,10 @@ fn callconvCoerceAllowed( std.lang.CallingConvention.ShInterruptOptions => { if (src_data.save != dest_data.save) return false; }, + std.lang.CallingConvention.SpirvKernelOptions, + std.lang.CallingConvention.SpirvFragmentOptions, + std.lang.CallingConvention.SpirvMeshOptions, + => {}, else => comptime unreachable, } }, @@ -28735,7 +29187,7 @@ fn coerceInMemoryAllowedPtrs( const ok_ptr_size = src_info.flags.size == dest_info.flags.size or src_info.flags.size == .c or dest_info.flags.size == .c; if (!ok_ptr_size) { - return InMemoryCoercionResult{ .ptr_size = .{ + return .{ .ptr_size = .{ .actual = src_info.flags.size, .wanted = dest_info.flags.size, } }; @@ -28871,14 +29323,14 @@ fn coerceInMemoryAllowedPtrs( break :a dest_child.abiAlignment(zcu); } else dest_info.flags.alignment; if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) { - return InMemoryCoercionResult{ .ptr_alignment = .{ + return .{ .ptr_alignment = .{ .actual = src_align, .wanted = dest_align, } }; } } - return .ok; + return .{ .ok = .ptr_cast }; } fn coerceVarArgParam( @@ -29182,7 +29634,6 @@ fn bitCast( dest_ty: Type, inst: Air.Inst.Ref, inst_src: LazySrcLoc, - operand_src: ?LazySrcLoc, ) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; @@ -29191,6 +29642,11 @@ fn bitCast( old_ty.assertHasLayout(zcu); try sema.ensureLayoutResolved(dest_ty, inst_src, .init); + assert(old_ty.hasBitRepresentation(zcu)); + assert(dest_ty.hasBitRepresentation(zcu)); + assert(old_ty.scalarType(zcu).zigTypeTag(zcu) != .pointer); + assert(dest_ty.scalarType(zcu).zigTypeTag(zcu) != .pointer); + const dest_bits = dest_ty.bitSize(zcu); const old_bits = old_ty.bitSize(zcu); @@ -29204,20 +29660,30 @@ fn bitCast( } if (sema.resolveValue(inst)) |val| { - if (val.isUndef(zcu)) - return pt.undefRef(dest_ty); - if (old_ty.zigTypeTag(zcu) == .error_set and dest_ty.zigTypeTag(zcu) == .error_set) { - // Special case: we sometimes call `bitCast` on error set values, but they - // don't have a well-defined layout, so we can't use `bitCastVal` on them. - return Air.internedToRef((try pt.getCoerced(val, dest_ty)).toIntern()); - } - if (try sema.bitCastVal(val, dest_ty, 0, 0, 0)) |result_val| { - return Air.internedToRef(result_val.toIntern()); - } + return .fromValue(try sema.bitCastVal(val, dest_ty)); } - try sema.requireRuntimeBlock(block, inst_src, operand_src); try sema.validateRuntimeValue(block, inst_src, inst); - return block.addBitCast(dest_ty, inst); + return block.addTyOp(.bit_cast, dest_ty, inst); +} + +/// Supports only types which `@bitCast` supports, so pointers are *not* supported. +pub fn bitCastVal( + sema: *Sema, + val: Value, + dest_ty: Type, +) Allocator.Error!Value { + const pt = sema.pt; + const zcu = pt.zcu; + const bit_size = dest_ty.bitSize(zcu); + assert(val.typeOf(zcu).bitSize(zcu) == bit_size); + if (val.isUndef(zcu)) { + return pt.undefValue(dest_ty); + } else { + const buf = try sema.arena.alloc(u8, @intCast((bit_size + 7) / 8)); + @memset(buf, 0); + val.writeToPackedMemory(zcu, buf, 0); + return .readFromPackedMemory(dest_ty, pt, buf, 0); + } } fn coerceArrayPtrToSlice( @@ -29334,14 +29800,17 @@ fn coerceCompatiblePtrs( ); } try sema.requireRuntimeBlock(block, inst_src, null); - const inst_allows_zero = inst_ty.zigTypeTag(zcu) != .pointer or inst_ty.ptrAllowsZero(zcu); - if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu)) { + const maybe_zero: bool = switch (inst_ty.toIntern()) { + .usize_type, .isize_type => true, + else => inst_ty.ptrAllowsZero(zcu), + }; + if (block.wantSafety() and maybe_zero and !dest_ty.ptrAllowsZero(zcu)) { try sema.checkLogicalPtrOperation(block, inst_src, inst_ty); const actual_ptr = if (inst_ty.isSlice(zcu)) try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) else inst; - const ptr_int = try block.addBitCast(.usize, actual_ptr); + const ptr_int = try block.addTyOp(.int_from_ptr, .usize, actual_ptr); const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); const ok = if (inst_ty.isSlice(zcu)) ok: { const len = try sema.analyzeSliceLen(block, inst_src, inst); @@ -29350,7 +29819,14 @@ fn coerceCompatiblePtrs( } else is_non_zero; try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null); } - const new_ptr = try sema.bitCast(block, dest_ty, inst, inst_src, null); + const new_ptr: Air.Inst.Ref = switch (inst_ty.toIntern()) { + .usize_type => try block.addTyOp(.ptr_from_int, dest_ty, inst), + .isize_type => new_ptr: { + const usize_inst = try block.addTyOp(.bit_cast, .usize, inst); + break :new_ptr try block.addTyOp(.ptr_from_int, dest_ty, usize_inst); + }, + else => try block.addTyOp(.ptr_cast, dest_ty, inst), + }; try sema.checkKnownAllocPtr(block, inst, new_ptr); return new_ptr; } @@ -29447,7 +29923,7 @@ fn coerceEnumToUnion( return .fromValue(opv); } else { // The union layout is just the tag, so we can bitcast the enum straight to the union. - return block.addBitCast(union_ty, enum_tag); + return block.addTyOp(.union_from_enum, union_ty, enum_tag); } } @@ -29496,18 +29972,6 @@ fn coerceArrayLike( const inst_ty = sema.typeOf(inst); const target = zcu.getTarget(); - // try coercion of the whole array - const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src, null); - if (in_memory_result == .ok) { - if (sema.resolveValue(inst)) |inst_val| { - // These types share the same comptime value representation. - return sema.coerceInMemory(inst_val, dest_ty); - } - try sema.requireRuntimeBlock(block, inst_src, null); - return block.addBitCast(dest_ty, inst); - } - - // otherwise, try element by element const inst_len = inst_ty.arrayLen(zcu); const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(zcu)); if (dest_len != inst_len) { @@ -29534,7 +29998,7 @@ fn coerceArrayLike( (dst_info.signedness == .signed and dst_info.bits > src_info.bits)) { try sema.requireRuntimeBlock(block, inst_src, null); - return block.addTyOp(.intcast, dest_ty, inst); + return block.addTyOp(.int_cast, dest_ty, inst); } }, .float => if (inst_elem_ty.isRuntimeFloat()) { @@ -30061,7 +30525,7 @@ fn analyzeRef( // Cast to the constant pointer type. We do this directly rather than going via `coerce` to // avoid errors in the `block.isComptime()` case. - return block.addBitCast(ptr_type, alloc); + return block.addTyOp(.ptr_cast, ptr_type, alloc); } fn analyzeLoad( @@ -30104,6 +30568,11 @@ fn analyzeLoad( break :msg msg; }); + // https://github.com/ziglang/zig/issues/6597 + if (block.wantSafety() and ptr_ty.isCPtr(zcu)) { + const is_non_null = try block.addUnOp(.is_non_null, ptr); + try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null); + } return block.addTyOp(.load, elem_ty, ptr); } @@ -30808,7 +31277,7 @@ fn analyzeSlice( const opt_new_ptr_val = sema.resolveValue(new_ptr); const new_ptr_val = opt_new_ptr_val orelse { - const result = try block.addBitCast(return_ty, new_ptr); + const result = try block.addTyOp(.ptr_cast, return_ty, new_ptr); if (block.wantSafety()) { // requirement: slicing C ptr is non-null if (ptr_ptr_child_ty.isCPtr(zcu)) { @@ -31496,7 +31965,7 @@ const PeerResolveStrategy = enum { fn select(ty: Type, zcu: *Zcu) PeerResolveStrategy { return switch (ty.zigTypeTag(zcu)) { - .type, .void, .bool, .@"opaque", .frame, .@"anyframe" => .exact, + .type, .void, .bool, .@"opaque", .spirv, .frame, .@"anyframe" => .exact, .noreturn, .undefined => .unknown, .null => .nullable, .comptime_int => .comptime_int, @@ -31793,7 +32262,7 @@ fn resolvePeerTypesInner( .nullable => { for (peer_tys, 0..) |opt_ty, i| { const ty = opt_ty orelse continue; - if (!ty.eql(.null, zcu)) return .{ .conflict = .{ + if (!ty.eql(.null)) return .{ .conflict = .{ .peer_idx_a = strat_reason, .peer_idx_b = i, } }; @@ -31881,7 +32350,7 @@ fn resolvePeerTypesInner( } }; const peer_elem_ty = ty.childType(zcu); - if (!peer_elem_ty.eql(elem_ty, zcu)) coerce: { + if (!peer_elem_ty.eql(elem_ty)) coerce: { const peer_elem_coerces_to_elem = try sema.coerceInMemoryAllowed(block, elem_ty, peer_elem_ty, false, zcu.getTarget(), src, src, null); if (peer_elem_coerces_to_elem == .ok) { @@ -32462,11 +32931,11 @@ fn resolvePeerTypesInner( .@"enum" => switch (ty.zigTypeTag(zcu)) { .enum_literal => {}, .@"enum" => { - if (!ty.eql(cur_ty, zcu)) return generic_err; + if (!ty.eql(cur_ty)) return generic_err; }, .@"union" => { const tag_ty = ty.unionTagTypeHypothetical(zcu); - if (!tag_ty.eql(cur_ty, zcu)) return generic_err; + if (!tag_ty.eql(cur_ty)) return generic_err; opt_cur_ty = ty; cur_ty_idx = i; }, @@ -32476,10 +32945,10 @@ fn resolvePeerTypesInner( .enum_literal => {}, .@"enum" => { const cur_tag_ty = cur_ty.unionTagTypeHypothetical(zcu); - if (!ty.eql(cur_tag_ty, zcu)) return generic_err; + if (!ty.eql(cur_tag_ty)) return generic_err; }, .@"union" => { - if (!ty.eql(cur_ty, zcu)) return generic_err; + if (!ty.eql(cur_ty)) return generic_err; }, else => unreachable, }, @@ -32612,7 +33081,7 @@ fn resolvePeerTypesInner( .comptime_float, .comptime_int, .int => {}, .float => { if (opt_cur_ty) |cur_ty| { - if (cur_ty.eql(ty, zcu)) continue; + if (cur_ty.eql(ty)) continue; // Recreate the type so we eliminate any c_longdouble const bits = @max(cur_ty.floatBits(target), ty.floatBits(target)); opt_cur_ty = switch (bits) { @@ -32787,7 +33256,7 @@ fn resolvePeerTypesInner( for (peer_tys, 0..) |opt_ty, i| { const ty = opt_ty orelse continue; if (expect_ty) |expect| { - if (!ty.eql(expect, zcu)) return .{ .conflict = .{ + if (!ty.eql(expect)) return .{ .conflict = .{ .peer_idx_a = first_idx, .peer_idx_b = i, } }; @@ -32853,7 +33322,7 @@ fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike { }; const elem_ty = ty.fieldType(0, zcu); for (1..field_count) |i| { - if (!ty.fieldType(i, zcu).eql(elem_ty, zcu)) { + if (!ty.fieldType(i, zcu).eql(elem_ty)) { return null; } } @@ -32873,6 +33342,7 @@ fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { const msg = try sema.errMsg(src, "type '{f}' does not support indexing", .{ty.fmt(pt)}); errdefer msg.destroy(sema.gpa); try sema.errNote(src, msg, "operand must be an array, slice, tuple, or vector", .{}); + try sema.addDeclaredHereNote(msg, ty); break :msg msg; }; return sema.failWithOwnedErrorMsg(block, msg); @@ -33839,8 +34309,8 @@ pub fn flushExports(sema: *Sema) !void { } } -pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; -pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; +pub const castMemory = @import("Sema/reinterpret.zig").castMemory; +pub const spliceMemory = @import("Sema/reinterpret.zig").spliceMemory; const loadComptimePtr = @import("Sema/comptime_ptr_access.zig").loadComptimePtr; const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadResult; diff --git a/src/Sema/LowerZon.zig b/src/Sema/LowerZon.zig index 0ba12a8813477ce26016c34443c2ea3825630740..f807043d8ecd7bbf6c628feb877d25c92212d08c 100644 --- a/src/Sema/LowerZon.zig +++ b/src/Sema/LowerZon.zig @@ -244,6 +244,7 @@ fn checkTypeInner( .frame, .@"anyframe", .@"opaque", + .spirv, => return self.failUnsupportedResultType(ty, null), .pointer => { @@ -408,6 +409,7 @@ fn lowerExprKnownResTyInner( .error_set, .@"fn", .@"opaque", + .spirv, .frame, .@"anyframe", .void, @@ -813,20 +815,15 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool .@"packed" => result: { const arena = self.sema.arena; const buf = try arena.alloc(u8, @intCast((res_ty.bitSize(zcu) + 7) / 8)); + @memset(buf, 0); var bit_offset: u16 = 0; for (field_values) |field_ip| { const field_val: Value = .fromInterned(field_ip); - field_val.writeToPackedMemory(zcu, buf, bit_offset) catch |err| switch (err) { - error.ReinterpretDeclRef => unreachable, // bitpack fields cannot be pointers - error.OutOfMemory => |e| return e, - }; + field_val.writeToPackedMemory(zcu, buf, bit_offset); bit_offset += @intCast(field_val.typeOf(zcu).bitSize(zcu)); } assert(bit_offset == res_ty.bitSize(zcu)); - break :result Value.readFromPackedMemory(res_ty, pt, buf, 0, arena) catch |err| switch (err) { - error.IllDefinedMemoryLayout => unreachable, // bitpacks have well-defined layout - error.OutOfMemory => |e| return e, - }; + break :result try .readFromPackedMemory(res_ty, pt, buf, 0); }, }; return result.toIntern(); @@ -979,9 +976,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. }; const result: Value = switch (union_info.layout) { .auto, .@"extern" => try pt.unionValue(res_ty, tag, val), - .@"packed" => try self.sema.bitCastVal(val, res_ty, 0, 0, 0) orelse { - unreachable; // `null` is only possible if the input value contains a pointer, which a packed union cannot. - }, + .@"packed" => try self.sema.bitCastVal(val, res_ty), }; return result.toIntern(); } diff --git a/src/Sema/bitcast.zig b/src/Sema/bitcast.zig deleted file mode 100644 index 40a29e183bd4324aedc297ab1cba278c987e63fa..0000000000000000000000000000000000000000 --- a/src/Sema/bitcast.zig +++ /dev/null @@ -1,773 +0,0 @@ -//! This file contains logic for bit-casting arbitrary values at comptime, including splicing -//! bits together for comptime stores of bit-pointers. The strategy is to "flatten" values to -//! a sequence of values in *packed* memory, and then unflatten through a combination of special -//! cases (particularly for pointers and `undefined` values) and in-memory buffer reinterprets. -//! -//! This is a little awkward on big-endian targets, as non-packed datastructures (e.g. `extern struct`) -//! have their fields reversed when represented as packed memory on such targets. - -/// If `host_bits` is `0`, attempts to convert the memory at offset -/// `byte_offset` into `val` to a non-packed value of type `dest_ty`, -/// ignoring `bit_offset`. -/// -/// Otherwise, `byte_offset` is an offset in bytes into `val` to a -/// non-packed value consisting of `host_bits` bits. A value of type -/// `dest_ty` will be interpreted at a packed offset of `bit_offset` -/// into this value. -/// -/// Returns `null` if the operation must be performed at runtime. -pub fn bitCast( - sema: *Sema, - val: Value, - dest_ty: Type, - byte_offset: u64, - host_bits: u64, - bit_offset: u64, -) CompileError!?Value { - return bitCastInner(sema, val, dest_ty, byte_offset, host_bits, bit_offset) catch |err| switch (err) { - error.ReinterpretDeclRef => return null, - error.IllDefinedMemoryLayout => unreachable, - error.Unimplemented => @panic("unimplemented bitcast"), - else => |e| return e, - }; -} - -/// Uses bitcasting to splice the value `splice_val` into `val`, -/// replacing overlapping bits and returning the modified value. -/// -/// If `host_bits` is `0`, splices `splice_val` at an offset -/// `byte_offset` bytes into the virtual memory of `val`, ignoring -/// `bit_offset`. -/// -/// Otherwise, `byte_offset` is an offset into bytes into `val` to -/// a non-packed value consisting of `host_bits` bits. The value -/// `splice_val` will be placed at a packed offset of `bit_offset` -/// into this value. -pub fn bitCastSplice( - sema: *Sema, - val: Value, - splice_val: Value, - byte_offset: u64, - host_bits: u64, - bit_offset: u64, -) CompileError!?Value { - return bitCastSpliceInner(sema, val, splice_val, byte_offset, host_bits, bit_offset) catch |err| switch (err) { - error.ReinterpretDeclRef => return null, - error.IllDefinedMemoryLayout => unreachable, - error.Unimplemented => @panic("unimplemented bitcast"), - else => |e| return e, - }; -} - -const BitCastError = CompileError || error{ ReinterpretDeclRef, IllDefinedMemoryLayout, Unimplemented }; - -fn bitCastInner( - sema: *Sema, - val: Value, - dest_ty: Type, - byte_offset: u64, - host_bits: u64, - bit_offset: u64, -) BitCastError!Value { - const pt = sema.pt; - const zcu = pt.zcu; - const endian = zcu.getTarget().cpu.arch.endian(); - - if (dest_ty.toIntern() == val.typeOf(zcu).toIntern() and bit_offset == 0) { - return val; - } - - const val_ty = val.typeOf(zcu); - - val_ty.assertHasLayout(zcu); - dest_ty.assertHasLayout(zcu); - - assert(val_ty.hasWellDefinedLayout(zcu)); - - const abi_pad_bits, const host_pad_bits = if (host_bits > 0) - .{ val_ty.abiSize(zcu) * 8 - host_bits, host_bits - val_ty.bitSize(zcu) } - else - .{ val_ty.abiSize(zcu) * 8 - val_ty.bitSize(zcu), 0 }; - - const skip_bits = switch (endian) { - .little => bit_offset + byte_offset * 8, - .big => if (host_bits > 0) - val_ty.abiSize(zcu) * 8 - byte_offset * 8 - host_bits + bit_offset - else - val_ty.abiSize(zcu) * 8 - byte_offset * 8 - dest_ty.bitSize(zcu), - }; - - var unpack: UnpackValueBits = .{ - .pt = sema.pt, - .arena = sema.arena, - .skip_bits = skip_bits, - .remaining_bits = dest_ty.bitSize(zcu), - .unpacked = std.array_list.Managed(InternPool.Index).init(sema.arena), - }; - switch (endian) { - .little => { - try unpack.add(val); - try unpack.padding(abi_pad_bits); - }, - .big => { - try unpack.padding(abi_pad_bits); - try unpack.add(val); - }, - } - try unpack.padding(host_pad_bits); - - var pack: PackValueBits = .{ - .pt = sema.pt, - .arena = sema.arena, - .unpacked = unpack.unpacked.items, - }; - return pack.get(dest_ty); -} - -fn bitCastSpliceInner( - sema: *Sema, - val: Value, - splice_val: Value, - byte_offset: u64, - host_bits: u64, - bit_offset: u64, -) BitCastError!Value { - const pt = sema.pt; - const zcu = pt.zcu; - const endian = zcu.getTarget().cpu.arch.endian(); - const val_ty = val.typeOf(zcu); - const splice_val_ty = splice_val.typeOf(zcu); - - val_ty.assertHasLayout(zcu); - splice_val_ty.assertHasLayout(zcu); - - const splice_bits = splice_val_ty.bitSize(zcu); - - const splice_offset = switch (endian) { - .little => bit_offset + byte_offset * 8, - .big => if (host_bits > 0) - val_ty.abiSize(zcu) * 8 - byte_offset * 8 - host_bits + bit_offset - else - val_ty.abiSize(zcu) * 8 - byte_offset * 8 - splice_bits, - }; - - assert(splice_offset + splice_bits <= val_ty.abiSize(zcu) * 8); - - const abi_pad_bits, const host_pad_bits = if (host_bits > 0) - .{ val_ty.abiSize(zcu) * 8 - host_bits, host_bits - val_ty.bitSize(zcu) } - else - .{ val_ty.abiSize(zcu) * 8 - val_ty.bitSize(zcu), 0 }; - - var unpack: UnpackValueBits = .{ - .pt = pt, - .arena = sema.arena, - .skip_bits = 0, - .remaining_bits = splice_offset, - .unpacked = std.array_list.Managed(InternPool.Index).init(sema.arena), - }; - switch (endian) { - .little => { - try unpack.add(val); - try unpack.padding(abi_pad_bits); - }, - .big => { - try unpack.padding(abi_pad_bits); - try unpack.add(val); - }, - } - try unpack.padding(host_pad_bits); - - unpack.remaining_bits = splice_bits; - try unpack.add(splice_val); - - unpack.skip_bits = splice_offset + splice_bits; - unpack.remaining_bits = val_ty.abiSize(zcu) * 8 - splice_offset - splice_bits; - switch (endian) { - .little => { - try unpack.add(val); - try unpack.padding(abi_pad_bits); - }, - .big => { - try unpack.padding(abi_pad_bits); - try unpack.add(val); - }, - } - try unpack.padding(host_pad_bits); - - var pack: PackValueBits = .{ - .pt = pt, - .arena = sema.arena, - .unpacked = unpack.unpacked.items, - }; - switch (endian) { - .little => {}, - .big => try pack.padding(abi_pad_bits), - } - return pack.get(val_ty); -} - -/// Recurses through struct fields, array elements, etc, to get a sequence of "primitive" values -/// which are bit-packed in memory to represent a single value. `unpacked` represents a series -/// of values in *packed* memory - therefore, on big-endian targets, the first element of this -/// list contains bits from the *final* byte of the value. -const UnpackValueBits = struct { - pt: Zcu.PerThread, - arena: Allocator, - skip_bits: u64, - remaining_bits: u64, - extra_bits: u64 = undefined, - unpacked: std.array_list.Managed(InternPool.Index), - - fn add(unpack: *UnpackValueBits, val: Value) BitCastError!void { - const pt = unpack.pt; - const zcu = pt.zcu; - const endian = zcu.getTarget().cpu.arch.endian(); - const ip = &zcu.intern_pool; - - if (unpack.remaining_bits == 0) { - return; - } - - const ty = val.typeOf(zcu); - const bit_size = ty.bitSize(zcu); - - if (unpack.skip_bits >= bit_size) { - unpack.skip_bits -= bit_size; - return; - } - - switch (ip.indexToKey(val.toIntern())) { - .int_type, - .ptr_type, - .array_type, - .vector_type, - .opt_type, - .anyframe_type, - .error_union_type, - .simple_type, - .struct_type, - .tuple_type, - .union_type, - .opaque_type, - .enum_type, - .func_type, - .error_set_type, - .inferred_error_set_type, - .@"extern", - .func, - .err, - .error_union, - .enum_literal, - .slice, - .memoized_call, - => unreachable, // ill-defined layout or not real values - - .undef, - .int, - .enum_tag, - .simple_value, - .float, - .ptr, - .opt, - => try unpack.primitive(val), - - .bitpack => |bitpack| try unpack.primitive(.fromInterned(bitpack.backing_int_val)), - - .aggregate => switch (ty.zigTypeTag(zcu)) { - .vector => { - const len: usize = @intCast(ty.arrayLen(zcu)); - for (0..len) |i| { - // We reverse vector elements in packed memory on BE targets. - const real_idx = switch (endian) { - .little => i, - .big => len - i - 1, - }; - const elem_val = try val.elemValue(pt, real_idx); - try unpack.add(elem_val); - } - }, - .array => { - // Each element is padded up to its ABI size. Padding bits are undefined. - // The final element does not have trailing padding. - // Elements are reversed in packed memory on BE targets. - const elem_ty = ty.childType(zcu); - const pad_bits = elem_ty.abiSize(zcu) * 8 - elem_ty.bitSize(zcu); - const len = ty.arrayLen(zcu); - const maybe_sent = ty.sentinel(zcu); - - if (endian == .big) if (maybe_sent) |s| { - try unpack.add(s); - if (len != 0) try unpack.padding(pad_bits); - }; - - for (0..@intCast(len)) |i| { - // We reverse array elements in packed memory on BE targets. - const real_idx = switch (endian) { - .little => i, - .big => len - i - 1, - }; - const elem_val = try val.elemValue(pt, @intCast(real_idx)); - try unpack.add(elem_val); - if (i != len - 1) try unpack.padding(pad_bits); - } - - if (endian == .little) if (maybe_sent) |s| { - if (len != 0) try unpack.padding(pad_bits); - try unpack.add(s); - }; - }, - .@"struct" => switch (ty.containerLayout(zcu)) { - .auto => unreachable, // ill-defined layout - .@"extern" => switch (endian) { - .little => { - var cur_bit_off: u64 = 0; - var it = zcu.typeToStruct(ty).?.iterateRuntimeOrder(ip); - while (it.next()) |field_idx| { - const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8; - const pad_bits = want_bit_off - cur_bit_off; - const field_val = try val.fieldValue(pt, field_idx); - try unpack.padding(pad_bits); - try unpack.add(field_val); - cur_bit_off = want_bit_off + field_val.typeOf(zcu).bitSize(zcu); - } - // Add trailing padding bits. - try unpack.padding(bit_size - cur_bit_off); - }, - .big => { - var cur_bit_off: u64 = bit_size; - var it = zcu.typeToStruct(ty).?.iterateRuntimeOrderReverse(ip); - while (it.next()) |field_idx| { - const field_val = try val.fieldValue(pt, field_idx); - const field_ty = field_val.typeOf(zcu); - const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8 + field_ty.bitSize(zcu); - const pad_bits = cur_bit_off - want_bit_off; - try unpack.padding(pad_bits); - try unpack.add(field_val); - cur_bit_off = want_bit_off - field_ty.bitSize(zcu); - } - assert(cur_bit_off == 0); - }, - }, - .@"packed" => { - // Just add all fields in order. There are no padding bits. - // This is identical between LE and BE targets. - for (0..ty.structFieldCount(zcu)) |i| { - const field_val = try val.fieldValue(pt, i); - try unpack.add(field_val); - } - }, - }, - else => unreachable, - }, - - .un => |un| { - // We actually don't care about the tag here! - // Instead, we just need to write the payload value, plus any necessary padding. - // This correctly handles the case where `tag == .none`, since the payload is then - // either an integer or a byte array, both of which we can unpack. - const payload_val = Value.fromInterned(un.val); - const pad_bits = bit_size - payload_val.typeOf(zcu).bitSize(zcu); - if (endian == .little or ty.containerLayout(zcu) == .@"packed") { - try unpack.add(payload_val); - try unpack.padding(pad_bits); - } else { - try unpack.padding(pad_bits); - try unpack.add(payload_val); - } - }, - } - } - - fn padding(unpack: *UnpackValueBits, pad_bits: u64) BitCastError!void { - if (pad_bits == 0) return; - const pt = unpack.pt; - // Figure out how many full bytes and leftover bits there are. - const bytes = pad_bits / 8; - const bits = pad_bits % 8; - // Add undef u8 values for the bytes... - const undef_u8 = try pt.undefValue(Type.u8); - for (0..@intCast(bytes)) |_| { - try unpack.primitive(undef_u8); - } - // ...and an undef int for the leftover bits. - if (bits == 0) return; - const bits_ty = try pt.intType(.unsigned, @intCast(bits)); - const bits_val = try pt.undefValue(bits_ty); - try unpack.primitive(bits_val); - } - - fn primitive(unpack: *UnpackValueBits, val: Value) BitCastError!void { - const pt = unpack.pt; - const zcu = pt.zcu; - - if (unpack.remaining_bits == 0) { - return; - } - - const ty = val.typeOf(pt.zcu); - const bit_size = ty.bitSize(zcu); - - // Note that this skips all zero-bit types. - if (unpack.skip_bits >= bit_size) { - unpack.skip_bits -= bit_size; - return; - } - - if (unpack.skip_bits > 0) { - const skip = unpack.skip_bits; - unpack.skip_bits = 0; - return unpack.splitPrimitive(val, skip, bit_size - skip); - } - - if (unpack.remaining_bits < bit_size) { - return unpack.splitPrimitive(val, 0, unpack.remaining_bits); - } - - unpack.remaining_bits -|= bit_size; - - try unpack.unpacked.append(val.toIntern()); - } - - fn splitPrimitive(unpack: *UnpackValueBits, val: Value, bit_offset: u64, bit_count: u64) BitCastError!void { - const pt = unpack.pt; - const zcu = pt.zcu; - const ty = val.typeOf(pt.zcu); - - const val_bits = ty.bitSize(zcu); - assert(bit_offset + bit_count <= val_bits); - - switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) { - // In the `ptr` case, this will return `error.ReinterpretDeclRef` - // if we're trying to split a non-integer pointer value. - .int, .float, .enum_tag, .ptr, .opt => { - // This @intCast is okay because no primitive can exceed the size of a u16. - const int_ty = try unpack.pt.intType(.unsigned, @intCast(bit_count)); - const buf = try unpack.arena.alloc(u8, @intCast((val_bits + 7) / 8)); - try val.writeToPackedMemory(zcu, buf, 0); - const sub_val = try Value.readFromPackedMemory(int_ty, unpack.pt, buf, @intCast(bit_offset), unpack.arena); - try unpack.primitive(sub_val); - }, - .undef => try unpack.padding(bit_count), - // The only values here with runtime bits are `true` and `false. - // These are both 1 bit, so will never need truncating. - .simple_value => unreachable, - else => unreachable, // zero-bit or not primitives - } - } -}; - -/// Given a sequence of bit-packed values in packed memory (see `UnpackValueBits`), -/// reconstructs a value of an arbitrary type, with correct handling of `undefined` -/// values and of pointers which align in virtual memory. -const PackValueBits = struct { - pt: Zcu.PerThread, - arena: Allocator, - bit_offset: u64 = 0, - unpacked: []const InternPool.Index, - - fn get(pack: *PackValueBits, ty: Type) BitCastError!Value { - const pt = pack.pt; - const zcu = pt.zcu; - const endian = zcu.getTarget().cpu.arch.endian(); - const ip = &zcu.intern_pool; - const arena = pack.arena; - switch (ty.zigTypeTag(zcu)) { - .vector => { - // Elements are bit-packed. - const len = ty.arrayLen(zcu); - const elem_ty = ty.childType(zcu); - const elems = try arena.alloc(InternPool.Index, @intCast(len)); - // We reverse vector elements in packed memory on BE targets. - switch (endian) { - .little => for (elems) |*elem| { - elem.* = (try pack.get(elem_ty)).toIntern(); - }, - .big => { - var i = elems.len; - while (i > 0) { - i -= 1; - elems[i] = (try pack.get(elem_ty)).toIntern(); - } - }, - } - return pt.aggregateValue(ty, elems); - }, - .array => { - // Each element is padded up to its ABI size. The final element does not have trailing padding. - const len = ty.arrayLen(zcu); - const elem_ty = ty.childType(zcu); - const maybe_sent = ty.sentinel(zcu); - const pad_bits = elem_ty.abiSize(zcu) * 8 - elem_ty.bitSize(zcu); - const elems = try arena.alloc(InternPool.Index, @intCast(len)); - - if (endian == .big and maybe_sent != null) { - // TODO: validate sentinel was preserved! - try pack.padding(elem_ty.bitSize(zcu)); - if (len != 0) try pack.padding(pad_bits); - } - - for (0..elems.len) |i| { - const real_idx = switch (endian) { - .little => i, - .big => len - i - 1, - }; - elems[@intCast(real_idx)] = (try pack.get(elem_ty)).toIntern(); - if (i != len - 1) try pack.padding(pad_bits); - } - - if (endian == .little and maybe_sent != null) { - // TODO: validate sentinel was preserved! - if (len != 0) try pack.padding(pad_bits); - try pack.padding(elem_ty.bitSize(zcu)); - } - - return pt.aggregateValue(ty, elems); - }, - .@"struct" => switch (ty.containerLayout(zcu)) { - .auto => unreachable, // ill-defined layout - .@"extern" => { - const elems = try arena.alloc(InternPool.Index, ty.structFieldCount(zcu)); - @memset(elems, .none); - switch (endian) { - .little => { - var cur_bit_off: u64 = 0; - var it = zcu.typeToStruct(ty).?.iterateRuntimeOrder(ip); - while (it.next()) |field_idx| { - const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8; - try pack.padding(want_bit_off - cur_bit_off); - const field_ty = ty.fieldType(field_idx, zcu); - elems[field_idx] = (try pack.get(field_ty)).toIntern(); - cur_bit_off = want_bit_off + field_ty.bitSize(zcu); - } - try pack.padding(ty.bitSize(zcu) - cur_bit_off); - }, - .big => { - var cur_bit_off: u64 = ty.bitSize(zcu); - var it = zcu.typeToStruct(ty).?.iterateRuntimeOrderReverse(ip); - while (it.next()) |field_idx| { - const field_ty = ty.fieldType(field_idx, zcu); - const want_bit_off = ty.structFieldOffset(field_idx, zcu) * 8 + field_ty.bitSize(zcu); - try pack.padding(cur_bit_off - want_bit_off); - elems[field_idx] = (try pack.get(field_ty)).toIntern(); - cur_bit_off = want_bit_off - field_ty.bitSize(zcu); - } - assert(cur_bit_off == 0); - }, - } - // Any fields which do not have runtime bits should be OPV or comptime fields. - // Fill those values now. - for (elems, 0..) |*elem, field_idx| { - if (elem.* != .none) continue; - const val = (try ty.structFieldValueComptime(pt, field_idx)).?; - elem.* = val.toIntern(); - } - return pt.aggregateValue(ty, elems); - }, - .@"packed" => { - const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu)); - if (backing_int_val.isUndef(zcu)) return pt.undefValue(ty); - return pt.bitpackValue(ty, backing_int_val); - }, - }, - .@"union" => switch (ty.containerLayout(zcu)) { - .auto => unreachable, // ill-defined layout - .@"extern" => { - // We will attempt to read as the backing representation. If this emits - // `error.ReinterpretDeclRef`, we will try each union field, preferring larger ones. - // We will also attempt smaller fields when we get `undefined`, as if some bits are - // defined we want to include them. - // TODO: this is very very bad. We need a more sophisticated union representation. - - const prev_unpacked = pack.unpacked; - const prev_bit_offset = pack.bit_offset; - - const backing_ty = try ty.externUnionBackingType(pt); - - backing: { - const backing_val = pack.get(backing_ty) catch |err| switch (err) { - error.ReinterpretDeclRef => { - pack.unpacked = prev_unpacked; - pack.bit_offset = prev_bit_offset; - break :backing; - }, - else => |e| return e, - }; - if (backing_val.isUndef(zcu)) { - pack.unpacked = prev_unpacked; - pack.bit_offset = prev_bit_offset; - break :backing; - } - return Value.fromInterned(try pt.internUnion(.{ - .ty = ty.toIntern(), - .tag = .none, - .val = backing_val.toIntern(), - })); - } - - const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu)); - for (field_order, 0..) |*f, i| f.* = @intCast(i); - // Sort `field_order` to put the fields with the largest bit sizes first. - const SizeSortCtx = struct { - zcu: *Zcu, - field_types: []const InternPool.Index, - fn lessThan(ctx: @This(), a_idx: u32, b_idx: u32) bool { - const a_ty = Type.fromInterned(ctx.field_types[a_idx]); - const b_ty = Type.fromInterned(ctx.field_types[b_idx]); - return a_ty.bitSize(ctx.zcu) > b_ty.bitSize(ctx.zcu); - } - }; - std.mem.sortUnstable(u32, field_order, SizeSortCtx{ - .zcu = zcu, - .field_types = zcu.typeToUnion(ty).?.field_types.get(ip), - }, SizeSortCtx.lessThan); - - const padding_after = endian == .little or ty.containerLayout(zcu) == .@"packed"; - - for (field_order) |field_idx| { - const field_ty = Type.fromInterned(zcu.typeToUnion(ty).?.field_types.get(ip)[field_idx]); - const pad_bits = ty.bitSize(zcu) - field_ty.bitSize(zcu); - if (!padding_after) try pack.padding(pad_bits); - const field_val = pack.get(field_ty) catch |err| switch (err) { - error.ReinterpretDeclRef => { - pack.unpacked = prev_unpacked; - pack.bit_offset = prev_bit_offset; - continue; - }, - else => |e| return e, - }; - if (padding_after) try pack.padding(pad_bits); - if (field_val.isUndef(zcu)) { - pack.unpacked = prev_unpacked; - pack.bit_offset = prev_bit_offset; - continue; - } - const tag_val = try pt.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_idx); - return Value.fromInterned(try pt.internUnion(.{ - .ty = ty.toIntern(), - .tag = tag_val.toIntern(), - .val = field_val.toIntern(), - })); - } - - // No field could represent the value. Just do whatever happens when we try to read - // the backing type - either `undefined` or `error.ReinterpretDeclRef`. - const backing_val = try pack.get(backing_ty); - return Value.fromInterned(try pt.internUnion(.{ - .ty = ty.toIntern(), - .tag = .none, - .val = backing_val.toIntern(), - })); - }, - .@"packed" => { - const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu)); - if (backing_int_val.isUndef(zcu)) return pt.undefValue(ty); - return pt.bitpackValue(ty, backing_int_val); - }, - }, - else => return pack.primitive(ty), - } - } - - fn padding(pack: *PackValueBits, pad_bits: u64) BitCastError!void { - _ = pack.prepareBits(pad_bits); - } - - fn primitive(pack: *PackValueBits, want_ty: Type) BitCastError!Value { - const pt = pack.pt; - const zcu = pt.zcu; - - if (try want_ty.onePossibleValue(pt)) |opv| return opv; - - const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu)); - - for (vals) |val| { - if (!Value.fromInterned(val).isUndef(zcu)) break; - } else { - // All bits of the value are `undefined`. - return pt.undefValue(want_ty); - } - - // TODO: we need to decide how to handle partially-undef values here. - // Currently, a value with some undefined bits becomes `0xAA` so that we - // preserve the well-defined bits, because we can't currently represent - // a partially-undefined primitive (e.g. an int with some undef bits). - // In future, we probably want to take one of these two routes: - // * Define that if any bits are `undefined`, the entire value is `undefined`. - // This is a major breaking change, and probably a footgun. - // * Introduce tracking for partially-undef values at comptime. - // This would complicate a lot of operations in Sema, such as basic - // arithmetic. - // This design complexity is tracked by #19634. - - ptr_cast: { - if (vals.len != 1) break :ptr_cast; - const val = Value.fromInterned(vals[0]); - if (!val.typeOf(zcu).isPtrAtRuntime(zcu)) break :ptr_cast; - if (!want_ty.isPtrAtRuntime(zcu)) break :ptr_cast; - return pt.getCoerced(val, want_ty); - } - - // Reinterpret via an in-memory buffer. - - var buf_bits: u64 = 0; - for (vals) |ip_val| { - const val = Value.fromInterned(ip_val); - const ty = val.typeOf(pt.zcu); - buf_bits += ty.bitSize(zcu); - } - - const buf = try pack.arena.alloc(u8, @intCast((buf_bits + 7) / 8)); - // We will skip writing undefined values, so mark the buffer as `0xAA` so we get "undefined" bits. - @memset(buf, 0xAA); - var cur_bit_off: usize = 0; - for (vals) |ip_val| { - const val = Value.fromInterned(ip_val); - const ty = val.typeOf(zcu); - if (!val.isUndef(zcu)) { - try val.writeToPackedMemory(zcu, buf, cur_bit_off); - } - cur_bit_off += @intCast(ty.bitSize(zcu)); - } - - return Value.readFromPackedMemory(want_ty, pt, buf, @intCast(bit_offset), pack.arena); - } - - fn prepareBits(pack: *PackValueBits, need_bits: u64) struct { []const InternPool.Index, u64 } { - if (need_bits == 0) return .{ &.{}, 0 }; - - const pt = pack.pt; - const zcu = pt.zcu; - - var bits: u64 = 0; - var len: usize = 0; - while (bits < pack.bit_offset + need_bits) { - bits += Value.fromInterned(pack.unpacked[len]).typeOf(pt.zcu).bitSize(zcu); - len += 1; - } - - const result_vals = pack.unpacked[0..len]; - const result_offset = pack.bit_offset; - - const extra_bits = bits - pack.bit_offset - need_bits; - if (extra_bits == 0) { - pack.unpacked = pack.unpacked[len..]; - pack.bit_offset = 0; - } else { - pack.unpacked = pack.unpacked[len - 1 ..]; - pack.bit_offset = Value.fromInterned(pack.unpacked[0]).typeOf(pt.zcu).bitSize(zcu) - extra_bits; - } - - return .{ result_vals, result_offset }; - } -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; - -const Sema = @import("../Sema.zig"); -const Zcu = @import("../Zcu.zig"); -const InternPool = @import("../InternPool.zig"); -const Type = @import("../Type.zig"); -const Value = @import("../Value.zig"); -const CompileError = Zcu.CompileError; diff --git a/src/Sema/comptime_ptr_access.zig b/src/Sema/comptime_ptr_access.zig index 396cbc0d5ae96fa8731550410217bd1da25070db..4df8dafbe03bddd71ca212af1cf1ebebfdfe1e04 100644 --- a/src/Sema/comptime_ptr_access.zig +++ b/src/Sema/comptime_ptr_access.zig @@ -14,27 +14,46 @@ pub const ComptimeLoadResult = union(enum) { pub fn loadComptimePtr(sema: *Sema, block: *Block, src: LazySrcLoc, ptr: Value) !ComptimeLoadResult { const pt = sema.pt; const zcu = pt.zcu; + const ptr_info = ptr.typeOf(pt.zcu).ptrInfo(pt.zcu); - // TODO: host size for vectors is terrible - const host_bits = switch (ptr_info.flags.vector_index) { - .none => ptr_info.packed_offset.host_size * 8, - else => ptr_info.packed_offset.host_size * Type.fromInterned(ptr_info.child).bitSize(zcu), - }; - const bit_offset = if (host_bits != 0) bit_offset: { - const child_bits = Type.fromInterned(ptr_info.child).bitSize(zcu); - const bit_offset = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) { - .none => 0, - else => |idx| switch (pt.zcu.getTarget().cpu.arch.endian()) { - .little => child_bits * @intFromEnum(idx), - .big => host_bits - child_bits * (@intFromEnum(idx) + 1), // element order reversed on big endian - }, - }; - if (child_bits + bit_offset > host_bits) { + const elem_ty: Type = .fromInterned(ptr_info.child); + const host_size = ptr_info.packed_offset.host_size; + + if (host_size == 0) { + return loadComptimePtrInner(sema, block, src, ptr, elem_ty, 0); + } + + assert(elem_ty.hasBitRepresentation(zcu)); + if (ptr_info.flags.vector_index == .none) { + if (ptr_info.packed_offset.bit_offset + elem_ty.bitSize(zcu) > host_size * 8) { return .exceeds_host_size; } - break :bit_offset bit_offset; - } else 0; - return loadComptimePtrInner(sema, block, src, ptr, bit_offset, host_bits, Type.fromInterned(ptr_info.child), 0); + const load_ty: Type = try pt.intType(.unsigned, host_size * 8); + const backing_int_mv = switch (try loadComptimePtrInner(sema, block, src, ptr, load_ty, 0)) { + else => |result| return result, + .success => |mv| mv, + }; + const backing_int_val = try backing_int_mv.intern(pt, sema.arena); + const buf = try sema.arena.alloc(u8, host_size); + @memset(buf, 0); + backing_int_val.writeToPackedMemory(zcu, buf, 0); + const result_val: Value = try .readFromPackedMemory(elem_ty, pt, buf, ptr_info.packed_offset.bit_offset); + return .{ .success = .{ .interned = result_val.toIntern() } }; + } + if (@intFromEnum(ptr_info.flags.vector_index) >= host_size) { + return .exceeds_host_size; + } + const load_ty: Type = try pt.vectorType(.{ + .len = host_size, + .child = elem_ty.toIntern(), + }); + const vector_mv = switch (try loadComptimePtrInner(sema, block, src, ptr, load_ty, 0)) { + else => |result| return result, + .success => |mv| mv, + }; + const vector_val = try vector_mv.intern(pt, sema.arena); + const result_val = try vector_val.elemValue(pt, @intFromEnum(ptr_info.flags.vector_index)); + return .{ .success = .{ .interned = result_val.toIntern() } }; } pub const ComptimeStoreResult = union(enum) { @@ -52,7 +71,8 @@ pub const ComptimeStoreResult = union(enum) { }; /// Perform a comptime load of value `store_val` to a pointer. -/// The pointer's type is ignored. +/// +/// Asserts that the type of `store_val` equals the element type of the pointer type. pub fn storeComptimePtr( sema: *Sema, block: *Block, @@ -62,42 +82,84 @@ pub fn storeComptimePtr( ) !ComptimeStoreResult { const pt = sema.pt; const zcu = pt.zcu; - const ptr_info = ptr.typeOf(zcu).ptrInfo(zcu); - assert(store_val.typeOf(zcu).toIntern() == ptr_info.child); - { - const store_ty: Type = .fromInterned(ptr_info.child); - if (!store_ty.comptimeOnly(zcu) and !store_ty.hasRuntimeBits(zcu)) { - // zero-bit store; nothing to do - return .success; - } + const ptr_info = ptr.typeOf(pt.zcu).ptrInfo(pt.zcu); + const elem_ty: Type = .fromInterned(ptr_info.child); + const host_size = ptr_info.packed_offset.host_size; + assert(store_val.typeOf(zcu).toIntern() == elem_ty.toIntern()); + + if (host_size == 0) { + return storeComptimePtrInner(sema, block, src, ptr, store_val); } - // TODO: host size for vectors is terrible - const host_bits = switch (ptr_info.flags.vector_index) { - .none => ptr_info.packed_offset.host_size * 8, - else => ptr_info.packed_offset.host_size * Type.fromInterned(ptr_info.child).bitSize(zcu), - }; - const bit_offset = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) { - .none => 0, - else => |idx| switch (zcu.getTarget().cpu.arch.endian()) { - .little => Type.fromInterned(ptr_info.child).bitSize(zcu) * @intFromEnum(idx), - .big => host_bits - Type.fromInterned(ptr_info.child).bitSize(zcu) * (@intFromEnum(idx) + 1), // element order reversed on big endian - }, - }; - const pseudo_store_ty = if (host_bits > 0) t: { - const need_bits = Type.fromInterned(ptr_info.child).bitSize(zcu); - if (need_bits + bit_offset > host_bits) { + assert(elem_ty.hasBitRepresentation(zcu)); + if (ptr_info.flags.vector_index == .none) { + if (ptr_info.packed_offset.bit_offset + elem_ty.bitSize(zcu) > host_size * 8) { return .exceeds_host_size; } - break :t try sema.pt.intType(.unsigned, @intCast(host_bits)); - } else Type.fromInterned(ptr_info.child); + const backing_ty: Type = try pt.intType(.unsigned, host_size * 8); + const backing_int_mv = switch (try loadComptimePtrInner(sema, block, src, ptr, backing_ty, 0)) { + .success => |mv| mv, + .runtime_load => return .runtime_store, + inline else => |payload, tag| return @unionInit(ComptimeStoreResult, @tagName(tag), payload), + }; + const old_backing_int_val = try backing_int_mv.intern(pt, sema.arena); + const buf = try sema.arena.alloc(u8, host_size); + @memset(buf, 0); + old_backing_int_val.writeToPackedMemory(zcu, buf, 0); + // Write the new element... + store_val.writeToPackedMemory(zcu, buf, ptr_info.packed_offset.bit_offset); + // ...then read the resulting backing integer value... + const new_backing_int_val: Value = try .readFromPackedMemory(backing_ty, pt, buf, 0); + // ...and store that back into memory + return storeComptimePtrInner(sema, block, src, ptr, new_backing_int_val); + } - const strat = try prepareComptimePtrStore(sema, block, src, ptr, pseudo_store_ty, 0); + if (@intFromEnum(ptr_info.flags.vector_index) >= host_size) { + return .exceeds_host_size; + } + const vec_ty: Type = try pt.vectorType(.{ + .len = host_size, + .child = elem_ty.toIntern(), + }); + const vector_mv = switch (try loadComptimePtrInner(sema, block, src, ptr, vec_ty, 0)) { + .success => |mv| mv, + .runtime_load => return .runtime_store, + inline else => |payload, tag| return @unionInit(ComptimeStoreResult, @tagName(tag), payload), + }; + const old_vector_val = try vector_mv.intern(pt, sema.arena); + const elems_buf = try sema.arena.alloc(InternPool.Index, host_size); + for (elems_buf, 0..) |*elem, elem_index| { + const elem_val = try old_vector_val.elemValue(pt, elem_index); + elem.* = elem_val.toIntern(); + } + elems_buf[@intFromEnum(ptr_info.flags.vector_index)] = store_val.toIntern(); + const new_vector_val = try pt.aggregateValue(vec_ty, elems_buf); + return storeComptimePtrInner(sema, block, src, ptr, new_vector_val); +} + +/// Like `storeComptimePtr`, except ignores the type of `ptr`, instead treating it as a single-item +/// pointer to `store_val.typeOf(zcu)`. +fn storeComptimePtrInner( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + ptr: Value, + store_val: Value, +) !ComptimeStoreResult { + const pt = sema.pt; + const zcu = pt.zcu; + const store_ty = store_val.typeOf(zcu); + + if (store_ty.classify(zcu) == .one_possible_value) { + // zero-bit store; nothing to do + return .success; + } + + const strat = try prepareComptimePtrStore(sema, block, src, ptr, store_ty, 0); // Propagate errors and handle comptime fields. switch (strat) { - .direct, .index, .flat_index, .reinterpret => {}, .comptime_field => { // To "store" to a comptime field, just perform a load of the field // and see if the store value matches. @@ -125,79 +187,60 @@ pub fn storeComptimePtr( .inactive_union_field => return .inactive_union_field, .needed_well_defined => |ty| return .{ .needed_well_defined = ty }, .out_of_bounds => |ty| return .{ .out_of_bounds = ty }, - } - - // Check the store is not inside a runtime condition - try checkComptimeVarStore(sema, block, src, strat.alloc()); - if (host_bits == 0) { - // We can attempt a direct store depending on the strategy. - switch (strat) { - .direct => |direct| { - const want_ty = direct.val.typeOf(zcu); - const coerced_store_val = try pt.getCoerced(store_val, want_ty); - direct.val.* = .{ .interned = coerced_store_val.toIntern() }; - return .success; - }, - .index => |index| { - const want_ty = index.val.typeOf(zcu).childType(zcu); - const coerced_store_val = try pt.getCoerced(store_val, want_ty); - try index.val.setElem(pt, sema.arena, @intCast(index.elem_index), .{ .interned = coerced_store_val.toIntern() }); - return .success; - }, - .flat_index => |flat| { - const store_elems = store_val.typeOf(zcu).arrayBase(zcu)[1]; - const flat_elems = try sema.arena.alloc(InternPool.Index, @intCast(store_elems)); - { - var next_idx: u64 = 0; - var skip: u64 = 0; - try flattenArray(sema, .{ .interned = store_val.toIntern() }, &skip, &next_idx, flat_elems); - } - for (flat_elems, 0..) |elem, idx| { - // TODO: recursiveIndex in a loop does a lot of redundant work! - // Better would be to gather all the store targets into an array. - var index: u64 = flat.flat_elem_index + idx; - const val_ptr, const final_idx = (try recursiveIndex(sema, flat.val, &index)).?; - try val_ptr.setElem(pt, sema.arena, @intCast(final_idx), .{ .interned = elem }); - } - return .success; - }, - .reinterpret => {}, - else => unreachable, - } - } - - // Either there is a bit offset, or the strategy required reinterpreting. - // Therefore, we must perform a bitcast. + .direct => |direct| { + try checkComptimeVarStore(sema, block, src, direct.alloc); + const want_ty = direct.val.typeOf(zcu); + const coerced_store_val = try pt.getCoerced(store_val, want_ty); + direct.val.* = .{ .interned = coerced_store_val.toIntern() }; + return .success; + }, - const val_ptr: *MutableValue, const byte_offset: u64 = switch (strat) { - .direct => |direct| .{ direct.val, 0 }, - .index => |index| .{ - index.val, - index.elem_index * index.val.typeOf(zcu).childType(zcu).abiSize(zcu), + .index => |index| { + try checkComptimeVarStore(sema, block, src, index.alloc); + const want_ty = index.val.typeOf(zcu).childType(zcu); + const coerced_store_val = try pt.getCoerced(store_val, want_ty); + try index.val.setElem(pt, sema.arena, @intCast(index.elem_index), .{ .interned = coerced_store_val.toIntern() }); + return .success; }, - .flat_index => |flat| .{ flat.val, flat.flat_elem_index * flat.val.typeOf(zcu).arrayBase(zcu)[0].abiSize(zcu) }, - .reinterpret => |reinterpret| .{ reinterpret.val, reinterpret.byte_offset }, - else => unreachable, - }; - if (!val_ptr.typeOf(zcu).hasWellDefinedLayout(zcu)) { - return .{ .needed_well_defined = val_ptr.typeOf(zcu) }; - } + .flat_index => |flat| { + try checkComptimeVarStore(sema, block, src, flat.alloc); + const store_elems = store_val.typeOf(zcu).arrayBase(zcu)[1]; + const flat_elems = try sema.arena.alloc(InternPool.Index, @intCast(store_elems)); + { + var next_idx: u64 = 0; + var skip: u64 = 0; + try flattenArray(sema, .{ .interned = store_val.toIntern() }, &skip, &next_idx, flat_elems); + } + for (flat_elems, 0..) |elem, idx| { + // TODO: recursiveIndex in a loop does a lot of redundant work! + // Better would be to gather all the store targets into an array. + var index: u64 = flat.flat_elem_index + idx; + const val_ptr, const final_idx = (try recursiveIndex(sema, flat.val, &index)).?; + try val_ptr.setElem(pt, sema.arena, @intCast(final_idx), .{ .interned = elem }); + } + return .success; + }, - if (!store_val.typeOf(zcu).hasWellDefinedLayout(zcu)) { - return .{ .needed_well_defined = store_val.typeOf(zcu) }; + .reinterpret => |reinterpret| { + try checkComptimeVarStore(sema, block, src, reinterpret.alloc); + if (!reinterpret.val.typeOf(zcu).hasWellDefinedLayout(zcu)) { + return .{ .needed_well_defined = reinterpret.val.typeOf(zcu) }; + } + if (!store_ty.hasWellDefinedLayout(zcu)) { + return .{ .needed_well_defined = store_ty }; + } + const old_val = try reinterpret.val.intern(pt, sema.arena); + const new_val = try sema.spliceMemory( + old_val, + store_val, + reinterpret.byte_offset, + ) orelse return .runtime_store; + reinterpret.val.* = .{ .interned = new_val.toIntern() }; + return .success; + }, } - - const new_val = try sema.bitCastSpliceVal( - try val_ptr.intern(pt, sema.arena), - store_val, - byte_offset, - host_bits, - bit_offset, - ) orelse return .runtime_store; - val_ptr.* = .{ .interned = new_val.toIntern() }; - return .success; } /// Perform a comptime load of type `load_ty` from a pointer. @@ -207,8 +250,6 @@ fn loadComptimePtrInner( block: *Block, src: LazySrcLoc, ptr_val: Value, - bit_offset: u64, - host_bits: u64, load_ty: Type, /// If `load_ty` is an array, this is the number of array elements to skip /// before `load_ty`. Otherwise, it is ignored and may be `undefined`. @@ -244,7 +285,7 @@ fn loadComptimePtrInner( .eu_payload => |base_ptr_ip| val: { const base_ptr = Value.fromInterned(base_ptr_ip); const base_ty = base_ptr.typeOf(zcu).childType(zcu); - switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, base_ty, undefined)) { + switch (try loadComptimePtrInner(sema, block, src, base_ptr, base_ty, undefined)) { .success => |eu_val| switch (eu_val.unpackErrorUnion(zcu)) { .undef => return .undef, .err => |err| return .{ .err_payload = err }, @@ -256,7 +297,7 @@ fn loadComptimePtrInner( .opt_payload => |base_ptr_ip| val: { const base_ptr = Value.fromInterned(base_ptr_ip); const base_ty = base_ptr.typeOf(zcu).childType(zcu); - switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, base_ty, undefined)) { + switch (try loadComptimePtrInner(sema, block, src, base_ptr, base_ty, undefined)) { .success => |eu_val| switch (eu_val.unpackOptional(zcu)) { .undef => return .undef, .null => return .null_payload, @@ -283,7 +324,7 @@ fn loadComptimePtrInner( .child = base_ty.toIntern(), }); - switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, want_ty, base_index.index)) { + switch (try loadComptimePtrInner(sema, block, src, base_ptr, want_ty, base_index.index)) { .success => |arr_val| break :val arr_val, else => |err| return err, } @@ -293,7 +334,7 @@ fn loadComptimePtrInner( const base_ty = base_ptr.typeOf(zcu).childType(zcu); // Field of a slice, or of an auto-layout struct or union. - const agg_val = switch (try loadComptimePtrInner(sema, block, src, base_ptr, 0, 0, base_ty, undefined)) { + const agg_val = switch (try loadComptimePtrInner(sema, block, src, base_ptr, base_ty, undefined)) { .success => |val| val, else => |err| return err, }; @@ -324,7 +365,7 @@ fn loadComptimePtrInner( }, }; - if (ptr.byte_offset == 0 and host_bits == 0) { + if (ptr.byte_offset == 0) { if (load_ty.zigTypeTag(zcu) != .array or array_offset == 0) { if (.ok == try sema.coerceInMemoryAllowed( block, @@ -343,8 +384,6 @@ fn loadComptimePtrInner( } restructure_array: { - if (host_bits != 0) break :restructure_array; - // We might also be changing the length of an array, or restructuring it. // e.g. [1][2][3]T -> [3][2]T. // This case is important because it's permitted for types with ill-defined layouts. @@ -402,7 +441,7 @@ fn loadComptimePtrInner( cur_offset += load_ty.childType(zcu).abiSize(zcu) * array_offset; } - const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else load_ty.abiSize(zcu); + const need_bytes = load_ty.abiSize(zcu); if (cur_offset + need_bytes > cur_val.typeOf(zcu).abiSize(zcu)) { return .{ .out_of_bounds = cur_val.typeOf(zcu) }; @@ -422,6 +461,7 @@ fn loadComptimePtrInner( .undefined, .enum_literal, .@"opaque", + .spirv, .@"fn", .error_union, => unreachable, // ill-defined layout @@ -452,7 +492,7 @@ fn loadComptimePtrInner( }, .@"struct" => switch (cur_ty.containerLayout(zcu)) { .auto => unreachable, // ill-defined layout - .@"packed" => break, // let the bitcast logic handle this + .@"packed" => break, // let the memory reinterpret logic handle this .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| { const start_off = cur_ty.structFieldOffset(field_idx, zcu); const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu); @@ -465,9 +505,9 @@ fn loadComptimePtrInner( }, .@"union" => switch (cur_ty.containerLayout(zcu)) { .auto => unreachable, // ill-defined layout - .@"packed" => break, // let the bitcast logic handle this + .@"packed" => break, // let the memory reinterpret logic handle this .@"extern" => { - // TODO: we have to let bitcast logic handle this for now. + // TODO: we have to let the memory reinterpret logic handle this for now. // Otherwise, we might traverse into a union field which doesn't allow pointers. // Figure out a solution! if (true) break; @@ -494,27 +534,13 @@ fn loadComptimePtrInner( // Fast path: check again if we're now at the type we want to load. // If so, just return the loaded value. - if (cur_offset == 0 and host_bits == 0 and cur_val.typeOf(zcu).toIntern() == load_ty.toIntern()) { + if (cur_offset == 0 and cur_val.typeOf(zcu).toIntern() == load_ty.toIntern()) { return .{ .success = cur_val }; } - var bitcast_src_val = try cur_val.intern(sema.pt, sema.arena); - - if (host_bits != 0) { - const src_bit_size = bitcast_src_val.typeOf(zcu).bitSize(zcu); - if (src_bit_size > host_bits) { - const truncate_ty = try pt.intType(.unsigned, @intCast(host_bits)); - bitcast_src_val = try pt.getCoerced(bitcast_src_val, truncate_ty); - } - } - - const result_val = try sema.bitCastVal( - bitcast_src_val, - load_ty, - cur_offset, - host_bits, - bit_offset, - ) orelse return .runtime_load; + // Otherwise, use the memory reinterpretation logic to pull out the bytes we need. + const reinterpret_val = try cur_val.intern(pt, sema.arena); + const result_val = try sema.castMemory(reinterpret_val, load_ty, cur_offset) orelse return .runtime_load; return .{ .success = .{ .interned = result_val.toIntern() } }; } @@ -545,7 +571,7 @@ const ComptimeStoreStrategy = union(enum) { val: *MutableValue, flat_elem_index: u64, }, - /// This value should be reinterpreted using bitcast logic to perform the + /// This value should be reinterpreted using `Sema.spliceMemory` to perform /// store. Only returned if `store_ty` and the type of `val` both have /// well-defined layouts. reinterpret: struct { @@ -854,6 +880,7 @@ fn prepareComptimePtrStore( .undefined, .enum_literal, .@"opaque", + .spirv, .@"fn", .error_union, => unreachable, // ill-defined layout @@ -884,7 +911,7 @@ fn prepareComptimePtrStore( }, .@"struct" => switch (cur_ty.containerLayout(zcu)) { .auto => unreachable, // ill-defined layout - .@"packed" => break, // let the bitcast logic handle this + .@"packed" => break, // let the memory reinterp logic handle this .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| { const start_off = cur_ty.structFieldOffset(field_idx, zcu); const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu); @@ -897,9 +924,9 @@ fn prepareComptimePtrStore( }, .@"union" => switch (cur_ty.containerLayout(zcu)) { .auto => unreachable, // ill-defined layout - .@"packed" => break, // let the bitcast logic handle this + .@"packed" => break, // let the memory reinterp logic handle this .@"extern" => { - // TODO: we have to let bitcast logic handle this for now. + // TODO: we have to let the memory reinterp logic handle this for now. // Otherwise, we might traverse into a union field which doesn't allow pointers. // Figure out a solution! if (true) break; diff --git a/src/Sema/reinterpret.zig b/src/Sema/reinterpret.zig new file mode 100644 index 0000000000000000000000000000000000000000..21a5bad1abd72afc1a6c8982e9caadd1825ea824 --- /dev/null +++ b/src/Sema/reinterpret.zig @@ -0,0 +1,576 @@ +//! This file contains logic for bit-casting arbitrary values at comptime, including splicing +//! bits together for comptime stores of bit-pointers. The strategy is to "flatten" values to +//! a sequence of values in *packed* memory, and then unflatten through a combination of special +//! cases (particularly for pointers and `undefined` values) and in-memory buffer reinterprets. +//! +//! This is a little awkward on big-endian targets, as non-packed datastructures (e.g. `extern struct`) +//! have their fields reversed when represented as packed memory on such targets. + +/// If `host_bits` is `0`, attempts to convert the memory at offset +/// `byte_offset` into `val` to a non-packed value of type `dest_ty`, +/// ignoring `bit_offset`. +/// +/// Otherwise, `byte_offset` is an offset in bytes into `val` to a +/// non-packed value consisting of `host_bits` bits. A value of type +/// `dest_ty` will be interpreted at a packed offset of `bit_offset` +/// into this value. +/// +/// Returns `null` if the operation must be performed at runtime. +pub fn castMemory( + sema: *Sema, + val: Value, + dest_ty: Type, + byte_offset: u64, +) CompileError!?Value { + const pt = sema.pt; + const zcu = pt.zcu; + + const val_ty = val.typeOf(zcu); + + if (dest_ty.toIntern() == val_ty.toIntern()) { + assert(byte_offset == 0); + return val; + } + + val_ty.assertHasLayout(zcu); + dest_ty.assertHasLayout(zcu); + + var unpack: UnpackValueBytes = .{ + .pt = pt, + .arena = sema.arena, + .skip_bytes = byte_offset, + .remaining_bytes = dest_ty.abiSize(zcu), + .unpacked = .init(sema.arena), + }; + unpack.add(val) catch |err| switch (err) { + error.ReinterpretDeclRef => return null, + error.OutOfMemory => |e| return e, + }; + + var pack: PackValueBytes = .{ + .pt = pt, + .arena = sema.arena, + .unpacked = unpack.unpacked.items, + }; + return pack.get(dest_ty) catch |err| switch (err) { + error.ReinterpretDeclRef => return null, + error.OutOfMemory => |e| return e, + }; +} + +/// Splice the value `splice_val` into `val` at the given `byte_offset`, replacing overlapping bits +/// and returning the modified value. +pub fn spliceMemory( + sema: *Sema, + val: Value, + splice_val: Value, + byte_offset: u64, +) CompileError!?Value { + const pt = sema.pt; + const zcu = pt.zcu; + const val_ty = val.typeOf(zcu); + const splice_val_ty = splice_val.typeOf(zcu); + + val_ty.assertHasLayout(zcu); + splice_val_ty.assertHasLayout(zcu); + + var unpack: UnpackValueBytes = .{ + .pt = pt, + .arena = sema.arena, + .skip_bytes = 0, + .remaining_bytes = byte_offset, + .unpacked = .init(sema.arena), + }; + unpack.add(val) catch |err| switch (err) { + error.ReinterpretDeclRef => return null, + error.OutOfMemory => |e| return e, + }; + + const splice_len = splice_val_ty.abiSize(zcu); + + unpack.remaining_bytes = splice_len; + unpack.add(splice_val) catch |err| switch (err) { + error.ReinterpretDeclRef => return null, + error.OutOfMemory => |e| return e, + }; + + unpack.skip_bytes = byte_offset + splice_len; + unpack.remaining_bytes = val_ty.abiSize(zcu) * 8 - byte_offset - splice_len; + unpack.add(val) catch |err| switch (err) { + error.ReinterpretDeclRef => return null, + error.OutOfMemory => |e| return e, + }; + + var pack: PackValueBytes = .{ + .pt = pt, + .arena = sema.arena, + .unpacked = unpack.unpacked.items, + }; + return pack.get(val_ty) catch |err| switch (err) { + error.ReinterpretDeclRef => return null, + error.OutOfMemory => |e| return e, + }; +} + +/// Recurses through struct fields, array elements, etc, to get a sequence of "primitive" values +/// which are bit-packed in memory to represent a single value. `unpacked` represents a series +/// of values in *packed* memory - therefore, on big-endian targets, the first element of this +/// list contains bits from the *final* byte of the value. +const UnpackValueBytes = struct { + pt: Zcu.PerThread, + arena: Allocator, + skip_bytes: u64, + remaining_bytes: u64, + unpacked: std.array_list.Managed(InternPool.Index), + + fn add(unpack: *UnpackValueBytes, val: Value) (error{ReinterpretDeclRef} || Allocator.Error)!void { + const pt = unpack.pt; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + + if (unpack.remaining_bytes == 0) { + return; + } + + const ty = val.typeOf(zcu); + const size = ty.abiSize(zcu); + + if (unpack.skip_bytes >= size) { + unpack.skip_bytes -= size; + return; + } + + switch (ip.indexToKey(val.toIntern())) { + .int_type, + .ptr_type, + .array_type, + .vector_type, + .opt_type, + .anyframe_type, + .error_union_type, + .simple_type, + .struct_type, + .tuple_type, + .union_type, + .opaque_type, + .spirv_type, + .enum_type, + .func_type, + .error_set_type, + .inferred_error_set_type, + .@"extern", + .func, + .err, + .error_union, + .enum_literal, + .slice, + .memoized_call, + => unreachable, // ill-defined layout or not real values + + .undef, + .int, + .enum_tag, + .simple_value, + .float, + .ptr, + .opt, + => try unpack.primitive(val), + + .bitpack => |bitpack| try unpack.primitive(.fromInterned(bitpack.backing_int_val)), + + .aggregate => switch (ty.zigTypeTag(zcu)) { + .vector => unreachable, // ill-defined layout + .array => { + for (0..@intCast(ty.arrayLen(zcu))) |elem_index| { + const elem_val = try val.elemValue(pt, @intCast(elem_index)); + try unpack.add(elem_val); + } + if (ty.sentinel(zcu)) |s| { + try unpack.add(s); + } + }, + .@"struct" => switch (ty.containerLayout(zcu)) { + .auto => unreachable, // ill-defined layout + .@"packed" => unreachable, // uses `.bitpack`, not `.aggregate` + .@"extern" => { + var it = ip.loadStructType(ty.toIntern()).iterateRuntimeOrder(ip); + var offset: u64 = 0; + while (it.next()) |field_index| { + const pad_bytes = ty.structFieldOffset(field_index, zcu) - offset; + const field_val = try val.fieldValue(pt, field_index); + try unpack.padding(pad_bytes); + try unpack.add(field_val); + offset += pad_bytes + field_val.typeOf(zcu).abiSize(zcu); + } + try unpack.padding(size - offset); + }, + }, + else => unreachable, + }, + + .un => |un| { + const payload_val = Value.fromInterned(un.val); + const pad_bytes = size - payload_val.typeOf(zcu).abiSize(zcu); + try unpack.add(payload_val); + try unpack.padding(pad_bytes); + }, + } + } + + fn padding(unpack: *UnpackValueBytes, num_bytes: u64) Allocator.Error!void { + if (num_bytes == 0) return; + const undef_u8 = try unpack.pt.undefValue(Type.u8); + for (0..@intCast(num_bytes)) |_| { + unpack.primitive(undef_u8) catch |err| switch (err) { + error.OutOfMemory => |e| return e, + error.ReinterpretDeclRef => unreachable, + }; + } + } + + fn primitive(unpack: *UnpackValueBytes, val: Value) (error{ReinterpretDeclRef} || Allocator.Error)!void { + const pt = unpack.pt; + const zcu = pt.zcu; + + if (unpack.remaining_bytes == 0) { + return; + } + + const ty = val.typeOf(pt.zcu); + const size = ty.abiSize(zcu); + + if (unpack.skip_bytes >= size) { + unpack.skip_bytes -= size; + return; + } + + if (unpack.skip_bytes > 0) { + const offset = unpack.skip_bytes; + unpack.skip_bytes = 0; + return unpack.splitPrimitive(val, offset, @min(size - offset, unpack.remaining_bytes)); + } + + if (unpack.remaining_bytes < size) { + return unpack.splitPrimitive(val, 0, unpack.remaining_bytes); + } + + unpack.remaining_bytes -= size; + try unpack.unpacked.append(val.toIntern()); + } + + fn splitPrimitive(unpack: *UnpackValueBytes, val: Value, offset: u64, len: u64) (error{ReinterpretDeclRef} || Allocator.Error)!void { + const pt = unpack.pt; + const zcu = pt.zcu; + const ty = val.typeOf(pt.zcu); + + assert(offset + len <= ty.abiSize(zcu)); + + try unpack.unpacked.ensureUnusedCapacity(@intCast(len)); + unpack.remaining_bytes -= len; + + switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) { + // In the `ptr` case, this will return `error.ReinterpretDeclRef` + // if we're trying to split a non-integer pointer value. + .int, .float, .enum_tag, .ptr, .opt => { + const buf = try unpack.arena.alloc(u8, @intCast(ty.abiSize(zcu))); + val.writeToMemory(zcu, buf) catch |err| switch (err) { + error.IllDefinedMemoryLayout => unreachable, + else => |e| return e, + }; + for (buf[@intCast(offset)..][0..@intCast(len)]) |byte_raw| { + const byte_val = try pt.intValue(.u8, byte_raw); + unpack.unpacked.appendAssumeCapacity(byte_val.toIntern()); + } + }, + .undef => { + const undef_u8 = try pt.undefValue(.u8); + for (0..@intCast(len)) |_| { + unpack.unpacked.appendAssumeCapacity(undef_u8.toIntern()); + } + }, + // The only values here with runtime bits are `true` and `false`. + // These are both 1 byte, so will never need splitting. + .simple_value => unreachable, + else => unreachable, // zero-bit or not primitives + } + } +}; + +/// Given a sequence of bit-packed values in packed memory (see `UnpackValueBytes`), +/// reconstructs a value of an arbitrary type, with correct handling of `undefined` +/// values and of pointers which align in virtual memory. +const PackValueBytes = struct { + pt: Zcu.PerThread, + arena: Allocator, + byte_offset: u64 = 0, + unpacked: []const InternPool.Index, + + fn get(pack: *PackValueBytes, ty: Type) (Allocator.Error || error{ReinterpretDeclRef})!Value { + const pt = pack.pt; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + const arena = pack.arena; + switch (ty.zigTypeTag(zcu)) { + .vector => unreachable, // ill-defined layout + .array => { + // Each element is padded up to its ABI size. The final element does not have trailing padding. + const elem_ty = ty.childType(zcu); + const elems = try arena.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu))); + + for (elems) |*elem| { + elem.* = (try pack.get(elem_ty)).toIntern(); + } + + if (ty.sentinel(zcu)) |s| { + _ = s; // TODO: validate sentinel was preserved! + pack.padding(elem_ty.abiSize(zcu)); + } + + return pt.aggregateValue(ty, elems); + }, + .@"struct" => switch (ty.containerLayout(zcu)) { + .auto => unreachable, // ill-defined layout + .@"extern" => { + const elems = try arena.alloc(InternPool.Index, ty.structFieldCount(zcu)); + @memset(elems, .none); + var offset: u64 = 0; + var it = ip.loadStructType(ty.toIntern()).iterateRuntimeOrder(ip); + while (it.next()) |field_index| { + const field_ty = ty.fieldType(field_index, zcu); + const pad_bytes = ty.structFieldOffset(field_index, zcu) - offset; + pack.padding(pad_bytes); + elems[field_index] = (try pack.get(field_ty)).toIntern(); + offset += pad_bytes + field_ty.abiSize(zcu); + } + pack.padding(ty.abiSize(zcu) - offset); + // Any fields which do not have runtime bits should be OPV or comptime fields. + // Fill those values now. + for (elems, 0..) |*elem, field_index| { + if (elem.* != .none) continue; + const val = (try ty.structFieldValueComptime(pt, field_index)).?; + elem.* = val.toIntern(); + } + return pt.aggregateValue(ty, elems); + }, + .@"packed" => { + const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu)); + if (backing_int_val.isUndef(zcu)) return pt.undefValue(ty); + return pt.bitpackValue(ty, backing_int_val); + }, + }, + .@"union" => switch (ty.containerLayout(zcu)) { + .auto => unreachable, // ill-defined layout + .@"extern" => { + // We will attempt to read as the backing representation. If this emits + // `error.ReinterpretDeclRef`, we will try each union field, preferring larger ones. + // We will also attempt smaller fields when we get `undefined`, as if some bits are + // defined we want to include them. + // TODO: this is very very bad. We need a more sophisticated union representation. + + const prev_unpacked = pack.unpacked; + const prev_byte_offset = pack.byte_offset; + + const backing_ty = try ty.externUnionBackingType(pt); + + const backing_result: enum { undef, reinterpret_decl_ref } = backing: { + const backing_val = pack.get(backing_ty) catch |err| switch (err) { + error.ReinterpretDeclRef => break :backing .reinterpret_decl_ref, + else => |e| return e, + }; + if (backing_val.isUndef(zcu)) break :backing .undef; + return .fromInterned(try pt.internUnion(.{ + .ty = ty.toIntern(), + .tag = .none, + .val = backing_val.toIntern(), + })); + }; + + const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu)); + for (field_order, 0..) |*f, i| f.* = @intCast(i); + // Sort `field_order` to put the fields with the largest ABI sizes first. + const SizeSortCtx = struct { + zcu: *const Zcu, + field_types: []const InternPool.Index, + fn lessThan(ctx: @This(), a_idx: u32, b_idx: u32) bool { + const a_ty: Type = .fromInterned(ctx.field_types[a_idx]); + const b_ty: Type = .fromInterned(ctx.field_types[b_idx]); + return a_ty.abiSize(ctx.zcu) > b_ty.abiSize(ctx.zcu); + } + }; + std.mem.sortUnstable(u32, field_order, SizeSortCtx{ + .zcu = zcu, + .field_types = zcu.typeToUnion(ty).?.field_types.get(ip), + }, SizeSortCtx.lessThan); + + for (field_order) |field_index| { + pack.unpacked = prev_unpacked; + pack.byte_offset = prev_byte_offset; + const field_ty = ty.fieldType(field_index, zcu); + const field_val = pack.get(field_ty) catch |err| switch (err) { + error.ReinterpretDeclRef => continue, + else => |e| return e, + }; + if (field_val.isUndef(zcu)) continue; + pack.padding(ty.abiSize(zcu) - field_ty.abiSize(zcu)); + const tag_val = try pt.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_index); + return pt.unionValue(ty, tag_val, field_val); + } + + // No field could represent the value. Just do whatever happens when we try to read + // the backing type - either `undefined` or `error.ReinterpretDeclRef`. + switch (backing_result) { + .undef => return pt.undefValue(ty), + .reinterpret_decl_ref => return error.ReinterpretDeclRef, + } + }, + .@"packed" => { + const backing_int_val = try pack.primitive(ty.bitpackBackingInt(zcu)); + if (backing_int_val.isUndef(zcu)) return pt.undefValue(ty); + return pt.bitpackValue(ty, backing_int_val); + }, + }, + .@"enum" => { + const tag_int_val = try pack.primitive(ty.intTagType(zcu)); + if (tag_int_val.isUndef(zcu)) return pt.undefValue(ty); + return pt.enumValue(ty, tag_int_val.toIntern()); + }, + else => return pack.primitive(ty), + } + } + + fn padding(pack: *PackValueBytes, num_bytes: u64) void { + _ = pack.prepareBytes(num_bytes); + } + + fn primitive(pack: *PackValueBytes, want_ty: Type) (Allocator.Error || error{ReinterpretDeclRef})!Value { + const pt = pack.pt; + const zcu = pt.zcu; + + if (try want_ty.onePossibleValue(pt)) |opv| return opv; + + const vals, const byte_offset = pack.prepareBytes(want_ty.abiSize(zcu)); + + for (vals) |val| { + if (!Value.fromInterned(val).isUndef(zcu)) break; + } else { + // All bits of the value are `undefined`. + return pt.undefValue(want_ty); + } + + // TODO: we need to decide how to handle partially-undef values here. + // Currently, a value with some undefined bits becomes `0xAA` so that we + // preserve the well-defined bits, because we can't currently represent + // a partially-undefined primitive (e.g. an int with some undef bits). + // In future, we probably want to take one of these two routes: + // * Define that if any bits are `undefined`, the entire value is `undefined`. + // This is a major breaking change, and probably a footgun. + // * Introduce tracking for partially-undef values at comptime. + // This would complicate a lot of operations in Sema, such as basic + // arithmetic. + // This design complexity is tracked by #19634. + + if (vals.len == 1 and + want_ty.isPtrAtRuntime(zcu) and + Value.fromInterned(vals[0]).typeOf(zcu).isPtrAtRuntime(zcu)) + { + return pt.getCoerced(.fromInterned(vals[0]), want_ty); + } + + // Reinterpret via an in-memory buffer. + + var buf_len: u64 = 0; + for (vals) |ip_val| { + const val: Value = .fromInterned(ip_val); + buf_len += val.typeOf(zcu).abiSize(zcu); + } + + const buf = try pack.arena.alloc(u8, @intCast(buf_len)); + { + var offset: usize = 0; + for (vals) |ip_val| { + const val: Value = .fromInterned(ip_val); + const ty = val.typeOf(zcu); + const size = ty.abiSize(zcu); + if (val.isUndef(zcu)) { + @memset(buf[offset..][0..@intCast(size)], 0xAA); + } else { + val.writeToMemory(zcu, buf[offset..][0..@intCast(size)]) catch |err| switch (err) { + error.IllDefinedMemoryLayout => unreachable, + else => |e| return e, + }; + } + offset += @intCast(size); + } + } + const bytes = buf[@intCast(byte_offset)..]; + + const target = zcu.getTarget(); + const endian = target.cpu.arch.endian(); + switch (want_ty.zigTypeTag(zcu)) { + .bool => return .makeBool(bytes[0] != 0), + .int => return .readIntFromMemory(want_ty, pt, bytes, pack.arena), + .float => switch (want_ty.floatBits(target)) { + 16 => return pt.floatValue(want_ty, @as(f16, @bitCast(std.mem.readInt(u16, bytes[0..2], endian)))), + 32 => return pt.floatValue(want_ty, @as(f32, @bitCast(std.mem.readInt(u32, bytes[0..4], endian)))), + 64 => return pt.floatValue(want_ty, @as(f64, @bitCast(std.mem.readInt(u64, bytes[0..8], endian)))), + 80 => return pt.floatValue(want_ty, @as(f80, @bitCast(std.mem.readInt(u80, bytes[0..10], endian)))), + 128 => return pt.floatValue(want_ty, @as(f128, @bitCast(std.mem.readInt(u128, bytes[0..16], endian)))), + else => unreachable, + }, + .pointer => { + assert(!want_ty.isSlice(zcu)); + const ptr_addr = std.mem.readVarInt(u64, bytes[0..@intCast(want_ty.abiSize(zcu))], endian); + return pt.ptrIntValue(want_ty, ptr_addr); + }, + .optional => { + assert(want_ty.isPtrLikeOptional(zcu)); + const ptr_ty = want_ty.optionalChild(zcu); + const ptr_addr = std.mem.readVarInt(u64, bytes[0..@intCast(want_ty.abiSize(zcu))], endian); + return .fromInterned(try pt.intern(.{ .opt = .{ + .ty = want_ty.toIntern(), + .val = if (ptr_addr == 0) .none else (try pt.ptrIntValue(ptr_ty, ptr_addr)).toIntern(), + } })); + }, + else => unreachable, + } + } + + fn prepareBytes(pack: *PackValueBytes, need_bytes: u64) struct { []const InternPool.Index, u64 } { + if (need_bytes == 0) return .{ &.{}, 0 }; + + const pt = pack.pt; + const zcu = pt.zcu; + + var bytes: u64 = 0; + var len: usize = 0; + while (bytes < pack.byte_offset + need_bytes) { + bytes += Value.fromInterned(pack.unpacked[len]).typeOf(zcu).abiSize(zcu); + len += 1; + } + + const result_vals = pack.unpacked[0..len]; + const result_offset = pack.byte_offset; + + const extra_bytes = bytes - pack.byte_offset - need_bytes; + if (extra_bytes == 0) { + pack.unpacked = pack.unpacked[len..]; + pack.byte_offset = 0; + } else { + pack.unpacked = pack.unpacked[len - 1 ..]; + pack.byte_offset = Value.fromInterned(pack.unpacked[0]).typeOf(zcu).abiSize(zcu) - extra_bytes; + } + + return .{ result_vals, result_offset }; + } +}; + +const std = @import("std"); +const Allocator = std.mem.Allocator; +const assert = std.debug.assert; + +const Sema = @import("../Sema.zig"); +const Zcu = @import("../Zcu.zig"); +const InternPool = @import("../InternPool.zig"); +const Type = @import("../Type.zig"); +const Value = @import("../Value.zig"); +const CompileError = Zcu.CompileError; diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig index 9f260a05795fd5993cb60f5f4bfffb8a1ffe644f..aabb8cfe2e3a48a7ee3830a3bcfbebe124faa950 100644 --- a/src/Sema/type_resolution.zig +++ b/src/Sema/type_resolution.zig @@ -87,6 +87,7 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons .ptr_type, .anyframe_type, .simple_type, + .spirv_type, .opaque_type, .error_set_type, .inferred_error_set_type, @@ -288,10 +289,12 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { } // Resolve the layout of all fields, and check their types are allowed. + const fields_len = struct_obj.field_types.len; for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { const field_ty: Type = .fromInterned(field_ty_ip); assert(!field_ty.isGenericPoison()); const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); + const field_name_src = block.src(.{ .container_field_name = @intCast(field_index) }); try sema.ensureLayoutResolved(field_ty, field_ty_src, .field); if (field_ty.zigTypeTag(zcu) == .@"opaque") { return sema.failWithOwnedErrorMsg(&block, msg: { @@ -302,6 +305,35 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { break :msg msg; }); } + if (field_ty.zigTypeTag(zcu) == .spirv) { + if (field_ty.isSpirvRuntimeArray(zcu)) { + if (struct_obj.layout != .@"extern") { + return sema.failWithOwnedErrorMsg(&block, msg: { + const msg = try sema.errMsg(struct_ty.srcLoc(zcu), "non-extern struct cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.errNote(field_name_src, msg, "while checking this field", .{}); + break :msg msg; + }); + } + if (field_index != fields_len - 1) { + return sema.failWithOwnedErrorMsg(&block, msg: { + const msg = try sema.errMsg(struct_ty.srcLoc(zcu), "struct field of type '{f}' must be the last field", .{field_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.errNote(field_name_src, msg, "while checking this field", .{}); + break :msg msg; + }); + } + } else { + return sema.failWithOwnedErrorMsg(&block, msg: { + const msg = try sema.errMsg(field_ty_src, "cannot directly embed SPIR-V type '{f}' in struct", .{field_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); + try sema.addDeclaredHereNote(msg, field_ty); + break :msg msg; + }); + } + } + if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) { return sema.failWithOwnedErrorMsg(&block, msg: { const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); @@ -413,7 +445,10 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]); const offset = resolved_field_aligns[field_idx].forward(cur_offset); struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below - cur_offset = offset + field_ty.abiSize(zcu); + // A SPIR-V `runtime_array` always trails the struct and + // contributes nothing to the struct's static size. + const field_size = if (field_ty.isSpirvRuntimeArray(zcu)) 0 else field_ty.abiSize(zcu); + cur_offset = offset + field_size; } const struct_size: u32 = switch (class) { .no_possible_value => 0, @@ -858,6 +893,14 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { break :msg msg; }); } + if (field_ty.zigTypeTag(zcu) == .spirv) { + return sema.failWithOwnedErrorMsg(&block, msg: { + const msg = try sema.errMsg(field_ty_src, "SPIR-V type '{f}' have unknown size and therefore cannot be directly embedded in unions", .{field_ty.fmt(pt)}); + errdefer msg.destroy(gpa); + try sema.addDeclaredHereNote(msg, field_ty); + break :msg msg; + }); + } if (union_obj.layout == .@"extern" and !field_ty.validateExtern(.union_field, zcu)) { return sema.failWithOwnedErrorMsg(&block, msg: { const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); diff --git a/src/Type.zig b/src/Type.zig index d2373c36e44a13e92ef64b3524bf9a553bb36fd7..546953b307df5bcb37e99942655801f6b5910676 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -170,6 +170,7 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class { .func_type => .fully_comptime, + .spirv_type => if (cur_ty.isSpirvRuntimeArray(zcu)) .runtime else .no_possible_value, .opaque_type => .no_possible_value, .error_union_type => |eu| { @@ -323,6 +324,7 @@ pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool { .error_set, .@"fn", .@"opaque", + .spirv, .@"anyframe", .@"enum", .enum_literal, @@ -383,8 +385,7 @@ pub fn ptrInfo(ty: Type, zcu: *const Zcu) InternPool.Key.PtrType { }; } -pub fn eql(a: Type, b: Type, zcu: *const Zcu) bool { - _ = zcu; // TODO: remove this parameter +pub fn eql(a: Type, b: Type) bool { // The InternPool data structure hashes based on Key to make interned objects // unique. An Index can be treated simply as u32 value for the // purpose of Type/Value hashing and equality. @@ -617,6 +618,10 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari const name = ip.loadEnumType(ty.toIntern()).name; try writer.print("{f}", .{name.fmt(ip)}); }, + .spirv_type => { + const name = ip.loadSpirvType(ty.toIntern()).name; + try writer.print("{f}", .{name.fmt(ip)}); + }, .func_type => |fn_info| { if (fn_info.is_noinline) { try writer.writeAll("noinline "); @@ -704,6 +709,14 @@ pub fn toIntern(ty: Type) InternPool.Index { return ty.ip_index; } +pub fn isSpirvRuntimeArray(ty: Type, zcu: *const Zcu) bool { + const ip = &zcu.intern_pool; + return switch (ip.indexToKey(ty.toIntern())) { + .spirv_type => ip.loadSpirvType(ty.toIntern()).flags.tag == .runtime_array, + else => false, + }; +} + pub fn toValue(self: Type) Value { return .fromInterned(self.toIntern()); } @@ -744,13 +757,14 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { const ip = &zcu.intern_pool; return switch (ip.indexToKey(ty.toIntern())) { .int_type, - .vector_type, => true, + .vector_type, .error_union_type, .error_set_type, .inferred_error_set_type, .tuple_type, + .spirv_type, .opaque_type, .anyframe_type, // These are function bodies, not function pointers. @@ -1038,6 +1052,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { } }, .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu), + .spirv_type => if (ty.isSpirvRuntimeArray(zcu)) ty.childType(zcu).abiAlignment(zcu) else .@"1", .opaque_type => .@"1", // values, not types @@ -1183,6 +1198,7 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { } }, .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiSize(zcu), + .spirv_type => unreachable, .opaque_type => unreachable, // values, not types @@ -1225,112 +1241,17 @@ pub fn errorAbiSize(zcu: *const Zcu) u64 { } /// Asserts that `ty` is not an opaque or comptime-only type. -/// Once #19755 is implemented, this query will only work on types with a defined bit-level representation. pub fn bitSize(ty: Type, zcu: *const Zcu) u64 { - const target = zcu.getTarget(); - const ip = &zcu.intern_pool; - assertHasLayout(ty, zcu); - return switch (ip.indexToKey(ty.toIntern())) { - .int_type => |int_type| int_type.bits, - .ptr_type => |ptr_type| switch (ptr_type.flags.size) { - .slice => target.ptrBitWidth() * 2, - else => target.ptrBitWidth(), - }, - .anyframe_type => target.ptrBitWidth(), - .array_type => |array_type| { - const elem_ty: Type = .fromInterned(array_type.child); - const len = array_type.lenIncludingSentinel(); - return switch (zcu.comp.getZigBackend()) { - .stage2_x86_64 => len * elem_ty.bitSize(zcu), - // this case will be removed under #19755 - else => switch (len) { - 0 => 0, - else => (len - 1) * 8 * elem_ty.abiSize(zcu) + elem_ty.bitSize(zcu), - }, - }; - }, - .vector_type => |vec| vec.len * Type.fromInterned(vec.child).bitSize(zcu), - .error_set_type, .inferred_error_set_type => zcu.errorSetBits(), - .func_type => unreachable, - - .simple_type => |t| switch (t) { - .void => 0, - .bool => 1, - .anyerror, .adhoc_inferred_error_set => zcu.errorSetBits(), - .usize, .isize => target.ptrBitWidth(), - - .c_char => target.cTypeBitSize(.char), - .c_short => target.cTypeBitSize(.short), - .c_ushort => target.cTypeBitSize(.ushort), - .c_int => target.cTypeBitSize(.int), - .c_uint => target.cTypeBitSize(.uint), - .c_long => target.cTypeBitSize(.long), - .c_ulong => target.cTypeBitSize(.ulong), - .c_longlong => target.cTypeBitSize(.longlong), - .c_ulonglong => target.cTypeBitSize(.ulonglong), - .c_longdouble => target.cTypeBitSize(.longdouble), - - .f16 => 16, - .f32 => 32, - .f64 => 64, - .f80 => 80, - .f128 => 128, - - .anyopaque => unreachable, - .type => unreachable, - .comptime_int => unreachable, - .comptime_float => unreachable, - .noreturn => unreachable, - .null => unreachable, - .undefined => unreachable, - .enum_literal => unreachable, - .generic_poison => unreachable, - }, - - .struct_type => { - const struct_obj = ip.loadStructType(ty.toIntern()); - switch (struct_obj.layout) { - .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).bitSize(zcu), - .auto, .@"extern" => return struct_obj.size * 8, // will be `unreachable` under #19755 - } - }, - .union_type => { - const union_obj = ip.loadUnionType(ty.toIntern()); - switch (union_obj.layout) { - .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).bitSize(zcu), - .auto, .@"extern" => return union_obj.size * 8, // will be `unreachable` under #19755 - } - }, - .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).bitSize(zcu), - - // will be `unreachable` under #19755 - .opt_type, - .error_union_type, - .tuple_type, - => ty.abiSize(zcu) * 8, - - .opaque_type => unreachable, - - // 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, + return switch (ty.zigTypeTag(zcu)) { + .void => 0, + .bool => 1, + .float => ty.floatBits(zcu.getTarget()), + .pointer, .optional => { + assert(ty.isPtrAtRuntime(zcu)); + return zcu.getTarget().ptrBitWidth(); + }, + .array, .vector => ty.arrayLenIncludingSentinel(zcu) * ty.childType(zcu).bitSize(zcu), + else => ty.intInfo(zcu).bits, }; } @@ -1511,14 +1432,18 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type { /// * `[]T` /// * `[*]T` /// * `[*c]T` +/// * `@SpirvType(.{ .runtime_array = T })` +/// * `*@SpirvType(.{ .runtime_array = T })` pub fn indexableElem(ty: Type, zcu: *const Zcu) Type { const ip = &zcu.intern_pool; return switch (ip.indexToKey(ty.toIntern())) { inline .array_type, .vector_type => |arr| .fromInterned(arr.child), + .spirv_type => ty.childType(zcu), .ptr_type => |ptr_type| switch (ptr_type.flags.size) { .many, .slice, .c => .fromInterned(ptr_type.child), .one => switch (ip.indexToKey(ptr_type.child)) { inline .array_type, .vector_type => |arr| .fromInterned(arr.child), + .spirv_type => Type.fromInterned(ptr_type.child).childType(zcu), else => unreachable, }, }, @@ -1864,6 +1789,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { .func_type => unreachable, .simple_type => unreachable, // handled via Index enum tag above + .spirv_type => unreachable, .opaque_type => unreachable, // values, not types @@ -2032,6 +1958,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value { .error_set_type, .inferred_error_set_type, .opaque_type, + .spirv_type, => null, .simple_type => |t| switch (t) { @@ -2219,10 +2146,12 @@ pub fn isIndexable(ty: Type, zcu: *const Zcu) bool { .one => switch (ty.childType(zcu).zigTypeTag(zcu)) { .array, .vector => true, .@"struct" => ty.childType(zcu).isTuple(zcu), + .spirv => ty.childType(zcu).isSpirvRuntimeArray(zcu), else => false, }, }, .@"struct" => ty.isTuple(zcu), + .spirv => ty.isSpirvRuntimeArray(zcu), else => false, }; } @@ -2498,7 +2427,7 @@ pub fn defaultStructFieldAlignment( ((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(.@"16"); + return abi_align.maxStrict(if (zcu.getTarget().cpu.arch == .s390x) .@"8" else .@"16"); } return abi_align; } @@ -2844,6 +2773,7 @@ pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error .slice, .many, .c => .fromInterned(ptr_info.child), .one => switch (ip.indexToKey(ptr_info.child)) { .array_type => |array_type| .fromInterned(array_type.child), + .spirv_type => Type.fromInterned(ptr_info.child).childType(zcu), else => unreachable, }, }; @@ -3095,6 +3025,7 @@ pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { .noreturn, .@"opaque", + .spirv, .error_union, .error_set, .frame, @@ -3156,6 +3087,8 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool .frame, => false, + .vector => position == .param_ty or position == .ret_ty, + .void => switch (position) { .ret_ty, .union_field, @@ -3170,6 +3103,7 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool .noreturn => position == .ret_ty, .@"opaque", + .spirv, .bool, .float, .@"anyframe", @@ -3233,7 +3167,6 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool .other, => ty.childType(zcu).validateExtern(.element, zcu), }, - .vector => ty.childType(zcu).validateExtern(.element, zcu), .optional => ty.isPtrLikeOptional(zcu), }; } @@ -3246,6 +3179,40 @@ fn validateExternCallconv(cc: std.lang.CallingConvention) bool { }; } +/// Returns whether `ty` is considered by Zig to have a bit-level representation, meaning it is +/// allowed as the operand to `@bitSizeOf`. This is a superset of packable types. +pub fn hasBitRepresentation(ty: Type, zcu: *const Zcu) bool { + return switch (ty.zigTypeTag(zcu)) { + .@"fn", + .noreturn, + .undefined, + .null, + .@"opaque", + .spirv, + .type, + .enum_literal, + .comptime_float, + .comptime_int, + .error_set, + .error_union, + .frame, + .@"anyframe", + => false, + + .void, + .bool, + .int, + .float, + => true, + + .@"enum" => zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_mode == .explicit, + .pointer, .optional => ty.isPtrAtRuntime(zcu), + .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", + + .array, .vector => ty.childType(zcu).hasBitRepresentation(zcu), + }; +} + /// Asserts that `ty` has resolved layout. pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { if (!std.debug.runtime_safety) { @@ -3261,6 +3228,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { .simple_type, .opaque_type, .error_set_type, + .spirv_type, .inferred_error_set_type, => {}, .func_type => |func_type| { @@ -3313,7 +3281,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { } /// Recursively walks the type and marks for each subtype how many times it has been seen -fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void { +fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.array_hash_map.Auto(Type, u16)) error{OutOfMemory}!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -3362,6 +3330,7 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn .union_type, .opaque_type, .enum_type, + .spirv_type, .simple_type, .int_type, => {}, @@ -3427,8 +3396,8 @@ fn shouldDedupeType(ty: Type, ctx: *Comparison, pt: Zcu.PerThread) error{OutOfMe /// the subtype length and number of occurences. Placeholders are then found by /// iterating `type_dedupe_cache` which caches the inline/placeholder decisions. pub const Comparison = struct { - type_occurrences: std.AutoArrayHashMapUnmanaged(Type, u16), - type_dedupe_cache: std.AutoArrayHashMapUnmanaged(Type, DedupeEntry), + type_occurrences: std.array_hash_map.Auto(Type, u16), + type_dedupe_cache: std.array_hash_map.Auto(Type, DedupeEntry), placeholder_index: u8, pub const Placeholder = struct { diff --git a/src/Value.zig b/src/Value.zig index 40ccd52792d18e9c0a7b989d433b597740e599d6..7db732c60e38d5a10353a230a1552530f58e7592 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -248,7 +248,6 @@ pub fn toBool(val: Value) bool { pub fn writeToMemory(val: Value, zcu: *const Zcu, buffer: []u8) error{ ReinterpretDeclRef, IllDefinedMemoryLayout, - Unimplemented, OutOfMemory, }!void { const target = zcu.getTarget(); @@ -257,35 +256,50 @@ pub fn writeToMemory(val: Value, zcu: *const Zcu, buffer: []u8) error{ const ty = val.typeOf(zcu); if (val.isUndef(zcu)) { const size: usize = @intCast(ty.abiSize(zcu)); - @memset(buffer[0..size], 0xaa); + @memset(buffer[0..size], 0xAA); return; } - switch (ty.zigTypeTag(zcu)) { + tag: switch (ty.zigTypeTag(zcu)) { + .type => return error.IllDefinedMemoryLayout, + .comptime_float => return error.IllDefinedMemoryLayout, + .comptime_int => return error.IllDefinedMemoryLayout, + .undefined => return error.IllDefinedMemoryLayout, + .null => return error.IllDefinedMemoryLayout, + .error_union => return error.IllDefinedMemoryLayout, + .enum_literal => return error.IllDefinedMemoryLayout, + .@"fn" => return error.IllDefinedMemoryLayout, + .spirv => return error.IllDefinedMemoryLayout, + .@"opaque" => unreachable, + .frame => unreachable, + .@"anyframe" => unreachable, + .noreturn => unreachable, .void => {}, .bool => { buffer[0] = @intFromBool(val.toBool()); }, - .int, .@"enum", .error_set, .pointer => |tag| { - const int_ty = if (tag == .pointer) int_ty: { - if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout; - if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef; - break :int_ty Type.usize; - } else ty; - const int_info = int_ty.intInfo(zcu); - const bits = int_info.bits; - const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8); - + .pointer => { + if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout; + if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef; + continue :tag .int; + }, + .int, .@"enum", .error_set => { var bigint_buffer: BigIntSpace = undefined; const bigint = val.toBigInt(&bigint_buffer, zcu); - bigint.writeTwosComplement(buffer[0..byte_count], endian); + bigint.writeTwosComplement(buffer[0..@intCast(ty.abiSize(zcu))], endian); }, - .float => switch (ty.floatBits(target)) { - 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(val.toFloat(f16, zcu)), endian), - 32 => std.mem.writeInt(u32, buffer[0..4], @bitCast(val.toFloat(f32, zcu)), endian), - 64 => std.mem.writeInt(u64, buffer[0..8], @bitCast(val.toFloat(f64, zcu)), endian), - 80 => std.mem.writeInt(u80, buffer[0..10], @bitCast(val.toFloat(f80, zcu)), endian), - 128 => std.mem.writeInt(u128, buffer[0..16], @bitCast(val.toFloat(f128, zcu)), endian), - else => unreachable, + .float => { + const float_bits = ty.floatBits(target); + switch (float_bits) { + 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(val.toFloat(f16, zcu)), endian), + 32 => std.mem.writeInt(u32, buffer[0..4], @bitCast(val.toFloat(f32, zcu)), endian), + 64 => std.mem.writeInt(u64, buffer[0..8], @bitCast(val.toFloat(f64, zcu)), endian), + 80 => std.mem.writeInt(u80, buffer[0..10], @bitCast(val.toFloat(f80, zcu)), endian), + 128 => std.mem.writeInt(u128, buffer[0..16], @bitCast(val.toFloat(f128, zcu)), endian), + else => unreachable, + } + const float_bytes = @divExact(float_bits, 8); + const total_bytes: usize = @intCast(ty.abiSize(zcu)); + @memset(buffer[float_bytes..total_bytes], 0); // padding }, .array => { const aggregate = ip.indexToKey(val.toIntern()).aggregate; @@ -302,28 +316,33 @@ pub fn writeToMemory(val: Value, zcu: *const Zcu, buffer: []u8) error{ } buf_off += elem_size; } + if (ty.sentinel(zcu)) |sentinel_val| { + try sentinel_val.writeToMemory(zcu, buffer[buf_off..]); + } }, - .vector => { - // We use byte_count instead of abi_size here, so that any padding bytes - // follow the data bytes, on both big- and little-endian systems. - const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8; - return writeToPackedMemory(val, zcu, buffer[0..byte_count], 0); - }, + .vector => return error.IllDefinedMemoryLayout, .@"struct" => { const struct_type = zcu.typeToStruct(ty) orelse return error.IllDefinedMemoryLayout; switch (struct_type.layout) { .auto => return error.IllDefinedMemoryLayout, - .@"extern" => for (0..struct_type.field_types.len) |field_index| { - const off: usize = @intCast(ty.structFieldOffset(field_index, zcu)); - const field_val = Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) { - .bytes => |bytes| { - buffer[off] = bytes.at(field_index, ip); - continue; - }, - .elems => |elems| elems[field_index], - .repeated_elem => |elem| elem, - }); - try writeToMemory(field_val, zcu, buffer[off..]); + .@"extern" => { + var last_off: usize = 0; + for (struct_type.field_types.get(ip), 0..) |field_ty_ip, field_index| { + const off: usize = @intCast(ty.structFieldOffset(field_index, zcu)); + @memset(buffer[last_off..off], 0xAA); + const field_val = Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) { + .bytes => |bytes| { + buffer[off] = bytes.at(field_index, ip); + continue; + }, + .elems => |elems| elems[field_index], + .repeated_elem => |elem| elem, + }); + try writeToMemory(field_val, zcu, buffer[off..]); + last_off = @intCast(off + Type.fromInterned(field_ty_ip).abiSize(zcu)); + } + const struct_size: usize = @intCast(ty.abiSize(zcu)); + @memset(buffer[last_off..struct_size], 0xAA); }, .@"packed" => { const int_index = ip.indexToKey(val.toIntern()).bitpack.backing_int_val; @@ -335,6 +354,9 @@ pub fn writeToMemory(val: Value, zcu: *const Zcu, buffer: []u8) error{ .auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already .@"extern" => { const payload_val = val.unionPayload(zcu); + const payload_size: usize = @intCast(payload_val.typeOf(zcu).abiSize(zcu)); + const union_size: usize = @intCast(ty.abiSize(zcu)); + @memset(buffer[payload_size..union_size], 0xAA); return writeToMemory(payload_val, zcu, buffer); }, .@"packed" => { @@ -352,7 +374,6 @@ pub fn writeToMemory(val: Value, zcu: *const Zcu, buffer: []u8) error{ @memset(buffer[0..@intCast(byte_count)], 0); // null pointer } }, - else => return error.Unimplemented, } } @@ -360,12 +381,15 @@ pub fn writeToMemory(val: Value, zcu: *const Zcu, buffer: []u8) error{ /// /// Both the start and the end of the provided buffer must be tight, since /// big-endian packed memory layouts start at the end of the buffer. +/// +/// Supports arrays and vectors, for which the value is written in logical bit +/// order, i.e. with the first element at bit offset 0. pub fn writeToPackedMemory( val: Value, zcu: *const Zcu, buffer: []u8, bit_offset: usize, -) error{ ReinterpretDeclRef, OutOfMemory }!void { +) void { const ip = &zcu.intern_pool; const target = zcu.getTarget(); const endian = target.cpu.arch.endian(); @@ -392,13 +416,7 @@ pub fn writeToPackedMemory( }, .@"enum" => { const int_val = val.intFromEnum(zcu); - return int_val.writeToPackedMemory(zcu, buffer, bit_offset); - }, - .pointer => { - assert(!ty.isSlice(zcu)); // No well defined layout. - if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef; - const addr = val.toUnsignedInt(zcu); - std.mem.writeVarPackedInt(buffer, bit_offset, zcu.getTarget().ptrBitWidth(), addr, endian); + int_val.writeToPackedMemory(zcu, buffer, bit_offset); }, .int => { const bits = ty.intInfo(zcu).bits; @@ -416,47 +434,46 @@ pub fn writeToPackedMemory( 128 => std.mem.writePackedInt(u128, buffer, bit_offset, @bitCast(val.toFloat(f128, zcu)), endian), else => unreachable, }, - .vector => { - const elem_ty = ty.childType(zcu); - const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu)); - const len: usize = @intCast(ty.arrayLen(zcu)); - - var bits: u16 = 0; - var elem_i: usize = 0; - const aggregate = ip.indexToKey(val.toIntern()).aggregate; - while (elem_i < len) : (elem_i += 1) { - // On big-endian systems, LLVM reverses the element order of vectors by default - const tgt_elem_i = if (endian == .big) len - elem_i - 1 else elem_i; - switch (aggregate.storage) { - .bytes => |bytes| std.mem.writePackedInt(u8, buffer, bit_offset + bits, bytes.at(tgt_elem_i, ip), endian), - .elems => |elems| try Value.fromInterned(elems[tgt_elem_i]).writeToPackedMemory(zcu, buffer, bit_offset + bits), - .repeated_elem => |elem| try Value.fromInterned(elem).writeToPackedMemory(zcu, buffer, bit_offset + bits), - } - bits += elem_bit_size; - } - }, .@"struct", .@"union" => { assert(ty.containerLayout(zcu) == .@"packed"); const int_val: Value = .fromInterned(ip.indexToKey(val.toIntern()).bitpack.backing_int_val); - return int_val.writeToPackedMemory(zcu, buffer, bit_offset); + int_val.writeToPackedMemory(zcu, buffer, bit_offset); }, - .optional => { - assert(ty.isPtrLikeOptional(zcu)); - if (val.optionalValue(zcu)) |ptr_val| { - return ptr_val.writeToPackedMemory(zcu, buffer, bit_offset); - } else { - return Value.zero_usize.writeToPackedMemory(zcu, buffer, bit_offset); + .array, .vector => { + const elem_bits: usize = @intCast(ty.childType(zcu).bitSize(zcu)); + const len: usize = @intCast(ty.arrayLen(zcu)); + var elem_bit_off: usize = bit_offset; + switch (ip.indexToKey(val.toIntern()).aggregate.storage) { + .repeated_elem => |elem_val_ip| { + const elem_val: Value = .fromInterned(elem_val_ip); + for (0..len) |_| { + elem_val.writeToPackedMemory(zcu, buffer, elem_bit_off); + elem_bit_off += elem_bits; + } + }, + .elems => |elems| for (elems[0..len]) |elem_val_ip| { + const elem_val: Value = .fromInterned(elem_val_ip); + elem_val.writeToPackedMemory(zcu, buffer, elem_bit_off); + elem_bit_off += elem_bits; + }, + .bytes => |bytes| for (bytes.toSlice(len, ip)) |raw_byte| { + std.mem.writeVarPackedInt(buffer, elem_bit_off, elem_bits, raw_byte, endian); + elem_bit_off += elem_bits; + }, + } + if (ty.sentinel(zcu)) |sentinel_val| { + sentinel_val.writeToPackedMemory(zcu, buffer, elem_bit_off); } }, - else => @panic("TODO implement writeToPackedMemory for more types"), + else => unreachable, } } -/// Load a Value from the contents of `buffer`, where `ty` is an unsigned integer type. +/// Load a Value from the contents of `buffer`, where `ty` is any integer type. /// /// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past /// the end of the value in memory. -pub fn readUintFromMemory( +pub fn readIntFromMemory( ty: Type, pt: Zcu.PerThread, buffer: []const u8, @@ -465,23 +482,28 @@ pub fn readUintFromMemory( const zcu = pt.zcu; const endian = zcu.getTarget().cpu.arch.endian(); - assert(ty.isUnsignedInt(zcu)); - const bits = ty.intInfo(zcu).bits; - const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8); + const int = ty.intInfo(zcu); + const abi_size: usize = @intCast(ty.abiSize(zcu)); + const exact_buf = buffer[0..abi_size]; - assert(buffer.len >= byte_count); - - if (bits <= 64) { - const val = std.mem.readVarInt(u64, buffer[0..byte_count], endian); - const result = (val << @as(u6, @intCast(64 - bits))) >> @as(u6, @intCast(64 - bits)); - return pt.intValue(ty, result); + if (abi_size <= 8) { + const shift: u6 = @intCast(64 - int.bits); + switch (int.signedness) { + .unsigned => { + const x = std.mem.readVarInt(u64, exact_buf, endian); + return pt.intValue(ty, (x << shift) >> shift); + }, + .signed => { + const x = std.mem.readVarInt(i64, exact_buf, endian); + return pt.intValue(ty, (x << shift) >> shift); + }, + } } else { - const Limb = std.math.big.Limb; - const limb_count = (byte_count + @sizeOf(Limb) - 1) / @sizeOf(Limb); - const limbs_buffer = try arena.alloc(Limb, limb_count); + const limb_count = std.math.big.int.calcTwosCompLimbCount(int.bits); + const limbs_buffer = try arena.alloc(std.math.big.Limb, limb_count); var bigint: BigIntMutable = .init(limbs_buffer, 0); - bigint.readTwosComplement(buffer[0..byte_count], bits, endian, .unsigned); + bigint.readTwosComplement(exact_buf, int.bits, endian, int.signedness); return pt.intValue_big(ty, bigint.toConst()); } } @@ -490,17 +512,17 @@ pub fn readUintFromMemory( /// /// Both the start and the end of the provided buffer must be tight, since /// big-endian packed memory layouts start at the end of the buffer. +/// +/// Supports arrays and vectors, for which the value is read in logical bit +/// order, i.e. with the first element at bit offset 0. pub fn readFromPackedMemory( ty: Type, pt: Zcu.PerThread, buffer: []const u8, bit_offset: usize, - gpa: Allocator, -) error{ - IllDefinedMemoryLayout, - OutOfMemory, -}!Value { +) Allocator.Error!Value { const zcu = pt.zcu; + const gpa = zcu.comp.gpa; const target = zcu.getTarget(); const endian = target.cpu.arch.endian(); switch (ty.zigTypeTag(zcu)) { @@ -543,7 +565,7 @@ pub fn readFromPackedMemory( }, .@"enum" => { const int_ty = ty.intTagType(zcu); - const int_val = try Value.readFromPackedMemory(int_ty, pt, buffer, bit_offset, gpa); + const int_val: Value = try .readFromPackedMemory(int_ty, pt, buffer, bit_offset); return pt.getCoerced(int_val, ty); }, .float => return Value.fromInterned(try pt.intern(.{ .float = .{ @@ -557,40 +579,25 @@ pub fn readFromPackedMemory( else => unreachable, }, } })), - .vector => { - const elem_ty = ty.childType(zcu); - const elems = try gpa.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu))); - defer gpa.free(elems); - - var bits: u16 = 0; - const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu)); - for (elems, 0..) |_, i| { - // On big-endian systems, LLVM reverses the element order of vectors by default - const tgt_elem_i = if (endian == .big) elems.len - i - 1 else i; - elems[tgt_elem_i] = (try readFromPackedMemory(elem_ty, pt, buffer, bit_offset + bits, gpa)).toIntern(); - bits += elem_bit_size; - } - return pt.aggregateValue(ty, elems); - }, .@"struct", .@"union" => { assert(ty.containerLayout(zcu) == .@"packed"); - const int_val: Value = try .readFromPackedMemory(ty.bitpackBackingInt(zcu), pt, buffer, bit_offset, gpa); + const int_val: Value = try .readFromPackedMemory(ty.bitpackBackingInt(zcu), pt, buffer, bit_offset); return pt.bitpackValue(ty, int_val); }, - .pointer => { - assert(!ty.isSlice(zcu)); // No well defined layout. - const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, gpa)).toUnsignedInt(zcu); - return pt.ptrIntValue(ty, addr); + .array, .vector => { + const elem_ty = ty.childType(zcu); + const elem_bits: usize = @intCast(elem_ty.bitSize(zcu)); + const elems_buf = try gpa.alloc(InternPool.Index, @intCast(ty.arrayLen(zcu))); + defer gpa.free(elems_buf); + var elem_bit_off: usize = bit_offset; + for (elems_buf) |*elem| { + const elem_val = try readFromPackedMemory(elem_ty, pt, buffer, elem_bit_off); + elem.* = elem_val.toIntern(); + elem_bit_off += elem_bits; + } + return pt.aggregateValue(ty, elems_buf); }, - .optional => { - assert(ty.isPtrLikeOptional(zcu)); - const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, gpa)).toUnsignedInt(zcu); - return .fromInterned(try pt.intern(.{ .opt = .{ - .ty = ty.toIntern(), - .val = if (addr == 0) .none else (try pt.ptrIntValue(ty.childType(zcu), addr)).toIntern(), - } })); - }, - else => @panic("TODO implement readFromPackedMemory for more types"), + else => unreachable, } } @@ -887,14 +894,9 @@ pub fn fieldValue(val: Value, pt: Zcu.PerThread, index: usize) !Value { const bfa = bfa_state.allocator(); const buf = try bfa.alloc(u8, @intCast((ty.bitSize(zcu) + 7) / 8)); defer bfa.free(buf); - int_val.writeToPackedMemory(zcu, buf, 0) catch |err| switch (err) { - error.ReinterpretDeclRef => unreachable, // it's an integer - error.OutOfMemory => |e| return e, - }; - return Value.readFromPackedMemory(field_ty, pt, buf, field_bit_offset, bfa) catch |err| switch (err) { - error.IllDefinedMemoryLayout => unreachable, // it's a bitpack - error.OutOfMemory => |e| return e, - }; + @memset(buf, 0); + int_val.writeToPackedMemory(zcu, buf, 0); + return .readFromPackedMemory(field_ty, pt, buf, field_bit_offset); }, else => unreachable, }; @@ -1619,7 +1621,6 @@ pub fn hasRepeatedByteRepr(val: Value, zcu: *const Zcu) !?u8 { // code late in compilation. So, this error handling is too aggressive and // causes some false negatives, causing less-than-ideal code generation. error.IllDefinedMemoryLayout => return null, - error.Unimplemented => return null, }; const first_byte = byte_buffer[0]; for (byte_buffer[1..]) |byte| { @@ -2046,7 +2047,10 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu); const need_child: Type = .fromInterned(ptr_ty_info.child); - if (need_child.comptimeOnly(zcu) or need_child.zigTypeTag(zcu) == .@"opaque") { + if (need_child.comptimeOnly(zcu) or + need_child.zigTypeTag(zcu) == .@"opaque" or + need_child.isSpirvRuntimeArray(zcu)) + { // No refinement can happen - this pointer is presumably invalid. // Just offset it. const parent = try arena.create(PointerDeriveStep); @@ -2078,6 +2082,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op .undefined, .enum_literal, .@"opaque", + .spirv, .@"fn", .error_union, .int, @@ -2229,6 +2234,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe .null, .@"fn", .@"opaque", + .spirv, .enum_literal, => comptime unreachable, // comptime-only or otherwise impossible @@ -2332,6 +2338,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory .null, .@"fn", .@"opaque", + .spirv, .enum_literal, => comptime unreachable, // comptime-only or otherwise impossible diff --git a/src/Zcu.zig b/src/Zcu.zig index 98ad151de349ac88d9f137e599fa8f8f6f744cf9..e3a36fe31b987dce03f89d1f4694cf718d72d3dc 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -97,20 +97,20 @@ free_exports: std.ArrayList(Export.Index) = .empty, /// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of /// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit` /// whose analysis triggered the export. -single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, Export.Index) = .empty, +single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index) = .empty, /// Like `single_exports`, but for `AnalUnit`s which perform multiple exports. /// The exports are `all_exports.items[index..][0..len]`. -multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct { +multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct { index: u32, len: u32, }) = .{}, /// Key is the digest returned by `Builtin.hash`; value is the corresponding module. -builtin_modules: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, *Package.Module) = .empty, +builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Package.Module) = .empty, /// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones. /// Modules whose root file is not a Zig or ZON file have the value `.none`. -module_roots: std.AutoArrayHashMapUnmanaged(*Package.Module, File.Index.Optional) = .empty, +module_roots: std.array_hash_map.Auto(*Package.Module, File.Index.Optional) = .empty, /// The set of all the Zig source files in the Zig Compilation Unit. Tracked in /// order to iterate over it and check which source files have been modified on @@ -125,7 +125,7 @@ module_roots: std.AutoArrayHashMapUnmanaged(*Package.Module, File.Index.Optional /// /// Not serialized. This state is reconstructed during the first call to /// `Compilation.update` of the process for a given `Compilation`. -import_table: std.ArrayHashMapUnmanaged( +import_table: std.array_hash_map.Custom( File.Index, void, struct { @@ -141,7 +141,7 @@ import_table: std.ArrayHashMapUnmanaged( /// update removes an import, or if a module specified on the CLI is never imported. /// Reconstructed on every update, after AstGen and before Sema. /// Value is why the file is alive. -alive_files: std.AutoArrayHashMapUnmanaged(File.Index, File.Reference) = .empty, +alive_files: std.array_hash_map.Auto(File.Index, File.Reference) = .empty, /// If this is populated, a "file exists in multiple modules" error should be emitted. /// This causes file errors to not be shown, because we don't really know which files @@ -162,7 +162,7 @@ multi_module_err: ?struct { /// on the `Compilation.Path` of the `EmbedFile`. /// /// This table owns all of the `*EmbedFile` memory, which is allocated into gpa. -embed_table: std.ArrayHashMapUnmanaged( +embed_table: std.array_hash_map.Custom( *EmbedFile, void, struct { @@ -179,27 +179,27 @@ intern_pool: InternPool = .empty, /// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis /// (index 0), and non-`null` for all others. -analysis_in_progress: std.AutoArrayHashMapUnmanaged(AnalUnit, ?*const DependencyReason) = .empty, +analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason) = .empty, /// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. -failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .empty, +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.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty, +transitive_failed_analysis: std.array_hash_map.Auto(AnalUnit, 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. /// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as /// codegen and linking run on a separate thread. -failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty, -failed_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, *ErrorMsg) = .empty, +failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg) = .empty, +failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg) = .empty, /// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one /// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible /// between compilations. So, instead of (for instance) defining where the dependency loop "starts", /// this map simply exists to allow easily iterating all dependency loops exactly once. -dependency_loops: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty, +dependency_loops: std.array_hash_map.Auto(AnalUnit, void) = .empty, /// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so. /// All units in here form loops. To iterate loops, see `dependency_loops`. -dependency_loop_nodes: std.AutoArrayHashMapUnmanaged(AnalUnit, struct { +dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct { unit: AnalUnit, reason: DependencyReason, }) = .empty, @@ -207,7 +207,7 @@ dependency_loop_nodes: std.AutoArrayHashMapUnmanaged(AnalUnit, struct { /// Keep track of `@compileLog`s per `AnalUnit`. /// We track the source location of the first `@compileLog` call, and all logged lines as a linked list. /// The list is singly linked, but we do track its tail for fast appends (optimizing many logs in one unit). -compile_logs: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct { +compile_logs: std.array_hash_map.Auto(AnalUnit, extern struct { base_node_inst: InternPool.TrackedInst.Index, node_offset: Ast.Node.Offset, first_line: CompileLogLine.Index, @@ -228,7 +228,7 @@ free_compile_log_lines: std.ArrayList(CompileLogLine.Index) = .empty, /// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source /// location is always the entire file. The `[]u8` memory is owned by the map /// and allocated into `gpa`. -failed_files: std.AutoArrayHashMapUnmanaged(File.Index, ?[]u8) = .empty, +failed_files: std.array_hash_map.Auto(File.Index, ?[]u8) = .empty, /// AstGen is not aware of modules, and so cannot determine whether an import /// string makes sense. That is the job of a traversal after AstGen. /// @@ -256,10 +256,10 @@ failed_imports: std.ArrayList(struct { import_token: Ast.TokenIndex, kind: enum { file_outside_module_root, illegal_zig_import }, }) = .empty, -failed_exports: std.AutoArrayHashMapUnmanaged(Export.Index, *ErrorMsg) = .empty, +failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg) = .empty, /// If analysis failed due to a cimport error, the corresponding Clang errors /// are stored here. -cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = .empty, +cimport_errors: std.array_hash_map.Auto(AnalUnit, std.zig.ErrorBundle) = .empty, /// Maximum amount of distinct error values, set by --error-limit error_limit: ErrorInt, @@ -271,19 +271,19 @@ outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void = if (std.d /// Value is the number of PO dependencies of this AnalUnit. /// This value will decrease as we perform semantic analysis to learn what is outdated. /// If any of these PO deps is outdated, this value will be moved to `outdated`. -potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .empty, +potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, /// Value is the number of PO dependencies of this AnalUnit. /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. -outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .empty, +outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, /// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0. /// Such `AnalUnit`s are ready for immediate re-analysis. /// See `findOutdatedToAnalyze` for details. outdated_ready: struct { /// These are separate from other units because it allows `findOutdatedToAnalyze` to prioritize /// functions, which is useful because it means they will be sent to codegen more quickly. - funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), + funcs: std.array_hash_map.Auto(InternPool.Index, void), /// Does not contain `.func` units. - other: std.AutoArrayHashMapUnmanaged(AnalUnit, void), + other: std.array_hash_map.Auto(AnalUnit, void), } = .{ .funcs = .empty, .other = .empty }, /// This contains a list of AnalUnit whose analysis or codegen failed, but the /// failure was something like running out of disk space, and trying again may @@ -298,23 +298,23 @@ analysis_roots_len: usize = 0, /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and /// reset to `null` when any semantic analysis occurs (since this invalidates the data). /// Allocated into `gpa`. -resolved_references: ?std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null, +resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = null, /// If `true`, then semantic analysis must not occur on this update due to AstGen errors. /// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped. /// Reset to `false` at the start of each update in `Compilation.update`. skip_analysis_this_update: bool = false, -test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, +test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty, -global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty, +global_assembly: std.array_hash_map.Auto(AnalUnit, []u8) = .empty, /// Key is the `AnalUnit` *performing* the reference. This representation allows /// incremental updates to quickly delete references caused by a specific `AnalUnit`. /// Value is index into `all_references` of the first reference triggered by the unit. /// The `next` field on the `Reference` forms a linked list of all references /// triggered by the key `AnalUnit`. -reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .empty, +reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, all_references: std.ArrayList(Reference) = .empty, /// Freelist of indices in `all_references`. free_references: std.ArrayList(u32) = .empty, @@ -327,7 +327,7 @@ free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index) = .empty /// Value is index into `all_type_reference` of the first reference triggered by the unit. /// The `next` field on the `TypeReference` forms a linked list of all type references /// triggered by the key `AnalUnit`. -type_reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .empty, +type_reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, all_type_references: std.ArrayList(TypeReference) = .empty, /// Freelist of indices in `all_type_references`. free_type_references: std.ArrayList(u32) = .empty, @@ -355,12 +355,12 @@ pub const DependencyReason = struct { pub const IncrementalDebugState = struct { /// All container types in the ZCU, even dead ones. /// Value is the generation the type was created on. - types: std.AutoArrayHashMapUnmanaged(InternPool.Index, u32), + types: std.array_hash_map.Auto(InternPool.Index, u32), /// All `Nav`s in the ZCU, even dead ones. /// Value is the generation the `Nav` was created on. - navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, u32), + navs: std.array_hash_map.Auto(InternPool.Nav.Index, u32), /// All `AnalUnit`s in the ZCU, even dead ones. - units: std.AutoArrayHashMapUnmanaged(AnalUnit, UnitInfo), + units: std.array_hash_map.Auto(AnalUnit, UnitInfo), pub const init: IncrementalDebugState = .{ .types = .empty, @@ -468,6 +468,13 @@ pub const StdLangDecl = enum { @"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, @"panic.call", @@ -548,6 +555,13 @@ pub const StdLangDecl = enum { .@"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", => .type, .panic => .type, @@ -601,7 +615,7 @@ pub const StdLangDecl = enum { .VaList => .va_list, .assembly, .@"assembly.Clobbers" => .assembly, else => { - if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Opaque")) { + if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Spirv.Image.Access")) { return .main; } else { return .panic; @@ -679,7 +693,7 @@ pub const SimplePanicId = enum { } }; -pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); +pub const GlobalErrorSet = std.array_hash_map.Auto(InternPool.NullTerminatedString, void); pub const CImportError = struct { offset: u32, @@ -838,9 +852,9 @@ pub const Namespace = struct { /// Will be a struct, enum, union, or opaque. owner_type: InternPool.Index, /// Members of the namespace which are marked `pub`. - pub_decls: std.ArrayHashMapUnmanaged(InternPool.Nav.Index, void, NavNameContext, true) = .empty, + pub_decls: std.array_hash_map.Custom(InternPool.Nav.Index, void, NavNameContext, true) = .empty, /// Members of the namespace which are *not* marked `pub`. - priv_decls: std.ArrayHashMapUnmanaged(InternPool.Nav.Index, void, NavNameContext, true) = .empty, + priv_decls: std.array_hash_map.Custom(InternPool.Nav.Index, void, NavNameContext, true) = .empty, /// All `comptime` declarations in this namespace. We store these purely so that incremental /// compilation can re-use the existing `ComptimeUnit`s when a namespace changes. comptime_decls: std.ArrayList(InternPool.ComptimeUnit.Id) = .empty, @@ -1529,7 +1543,7 @@ pub const SrcLoc = struct { .node_offset_deref_ptr => |node_off| { const tree = try src_loc.file_scope.getTree(zcu); const node = node_off.toAbsolute(src_loc.base_node); - return tree.nodeToSpan(node); + return tree.nodeToSpan(tree.nodeData(node).node); }, .node_offset_asm_source => |node_off| { const tree = try src_loc.file_scope.getTree(zcu); @@ -2740,6 +2754,7 @@ pub const LazySrcLoc = struct { .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node, .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node, .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node, + .reify_spirv_type => zir.extraData(Zir.Inst.ReifySpirvType, inst.data.extended.operand).data.node, else => unreachable, }, else => unreachable, @@ -2819,15 +2834,12 @@ pub fn deinit(zcu: *Zcu) void { const io = comp.io; const gpa = zcu.gpa; { - const pt: Zcu.PerThread = .activate(zcu, .main); - defer pt.deactivate(); - if (zcu.llvm_object) |llvm_object| llvm_object.deinit(); zcu.builtin_modules.deinit(gpa); zcu.module_roots.deinit(gpa); for (zcu.import_table.keys()) |file_index| { - pt.destroyFile(file_index); + zcu.destroyFile(file_index); } zcu.import_table.deinit(gpa); zcu.alive_files.deinit(gpa); @@ -2910,6 +2922,26 @@ pub fn deinit(zcu: *Zcu) void { zcu.intern_pool.deinit(gpa, io); } +fn deinitFile(zcu: *Zcu, file_index: Zcu.File.Index) void { + const gpa = zcu.gpa; + const file = zcu.fileByIndex(file_index); + log.debug("deinit File {f}", .{file.path.fmt(zcu.comp)}); + file.path.deinit(gpa); + file.unload(gpa); + if (file.prev_zir) |prev_zir| { + prev_zir.deinit(gpa); + gpa.destroy(prev_zir); + } + file.* = undefined; +} + +fn destroyFile(zcu: *Zcu, file_index: Zcu.File.Index) void { + const gpa = zcu.gpa; + const file = zcu.fileByIndex(file_index); + deinitFile(zcu, file_index); + gpa.destroy(file); +} + pub fn namespacePtr(zcu: *Zcu, index: Namespace.Index) *Namespace { return zcu.intern_pool.namespacePtr(index); } @@ -4168,13 +4200,13 @@ pub const ResolvedReference = struct { /// If an `AnalUnit` is not in the returned map, it is unreferenced. /// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller. /// This hashmap is cached, so repeated calls to this function are cheap. -pub fn resolveReferences(zcu: *Zcu) Allocator.Error!*const std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) { +pub fn resolveReferences(zcu: *Zcu) Allocator.Error!*const std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) { if (zcu.resolved_references == null) { zcu.resolved_references = try zcu.resolveReferencesInner(); } return &zcu.resolved_references.?; } -fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) { +fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) { const trace = tracy.trace(@src()); defer trace.end(); @@ -4182,8 +4214,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanag const comp = zcu.comp; const ip = &zcu.intern_pool; - var units: std.AutoArrayHashMapUnmanaged(AnalUnit, ?ResolvedReference) = .empty; - var types: std.AutoArrayHashMapUnmanaged(InternPool.Index, ?ResolvedReference) = .empty; + var units: std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = .empty; + var types: std.array_hash_map.Auto(InternPool.Index, ?ResolvedReference) = .empty; defer { units.deinit(gpa); types.deinit(gpa); @@ -4679,6 +4711,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) .stage2_spirv => switch (cc) { .spirv_device, .spirv_kernel => true, .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan or target.os.tag == .opengl, + .spirv_task, .spirv_mesh => target.os.tag == .vulkan, else => false, }, }; @@ -5373,9 +5406,9 @@ pub const CodegenTaskPool = struct { const io = zcu.comp.io; const tid: Zcu.PerThread.Id = .acquire(io); defer tid.release(io); - const pt: Zcu.PerThread = .activate(zcu, tid); - defer pt.deactivate(); - return pt.runCodegen(func_index, &air); + const active = zcu.activate(tid); + defer active.deactivate(); + return active.pt.runCodegen(func_index, &air); } fn workerCodegenExternalAir( zcu: *Zcu, @@ -5385,9 +5418,9 @@ pub const CodegenTaskPool = struct { const io = zcu.comp.io; const tid: Zcu.PerThread.Id = .acquire(io); defer tid.release(io); - const pt: Zcu.PerThread = .activate(zcu, tid); - defer pt.deactivate(); - return pt.runCodegen(func_index, air); + const active = zcu.activate(tid); + defer active.deactivate(); + return active.pt.runCodegen(func_index, air); } }; @@ -5416,3 +5449,24 @@ fn updateTracyOutdatedPlots(zcu: *const Zcu) void { zcu.updateTracyPlot("potentially_outdated", zcu.potentially_outdated.count()); zcu.updateTracyPlot("outdated_ready", zcu.outdated_ready.funcs.count() + zcu.outdated_ready.other.count()); } + +pub const Active = struct { + pt: Zcu.PerThread, + ip: InternPool.Active, + pub fn deactivate(active: Active) void { + active.ip.deactivate(); + } + pub fn release(active: Active) void { + active.deactivate(); + active.pt.tid.release(active.pt.zcu.comp.io); + } +}; +pub fn activate(zcu: *Zcu, tid: PerThread.Id) Active { + return .{ + .pt = .{ .zcu = zcu, .tid = tid }, + .ip = zcu.intern_pool.activate(), + }; +} +pub fn acquire(zcu: *Zcu) Active { + return zcu.activate(.acquire(zcu.comp.io)); +} diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 260d0eeba84d3cab63e22caf682ab82426d2d922..e1cda016c163cdfde8cb693c5f143f2f86057980 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -125,14 +125,6 @@ pub const Id = if (InternPool.single_threaded) enum { } }; -pub fn activate(zcu: *Zcu, tid: Id) Zcu.PerThread { - zcu.intern_pool.activate(); - return .{ .zcu = zcu, .tid = tid }; -} -pub fn deactivate(pt: Zcu.PerThread) void { - pt.zcu.intern_pool.deactivate(); -} - /// Called from `Compilation.performAllTheWork`. Performs one incremental update of the ZCU: detects /// changes to files, runs AstGen, and then enters the main semantic analysis loop, where we build /// up a graph of declarations, functions, etc, while also sending declarations and functions to @@ -378,10 +370,10 @@ fn workerUpdateFile( const child_prog_node = prog_node.start(std.fs.path.basename(file.path.sub_path), 0); defer child_prog_node.end(); - const pt: Zcu.PerThread = .activate(comp.zcu.?, tid); - defer pt.deactivate(); - pt.updateFile(file_index, file) catch |err| { - pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ std.fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) { + const active = comp.zcu.?.activate(tid); + defer active.deactivate(); + active.pt.updateFile(file_index, file) catch |err| { + active.pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ std.fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) { error.OutOfMemory => { comp.mutex.lockUncancelable(io); defer comp.mutex.unlock(io); @@ -411,7 +403,7 @@ fn workerUpdateFile( const import_path = file.zir.?.nullTerminatedString(item.data.name); - if (pt.discoverImport(file.path, import_path)) |res| switch (res) { + if (active.pt.discoverImport(file.path, import_path)) |res| switch (res) { .module, .existing_file => {}, .new_file => |new| { group.async(io, workerUpdateFile, .{ @@ -443,13 +435,15 @@ fn workerUpdateEmbedFile(comp: *Compilation, ef_index: Zcu.EmbedFile.Index, ef: fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zcu.EmbedFile.Index, ef: *Zcu.EmbedFile) !void { const io = comp.io; const zcu = comp.zcu.?; - const pt: Zcu.PerThread = .activate(zcu, tid); - defer pt.deactivate(); const old_val = ef.val; const old_err = ef.err; - try pt.updateEmbedFile(ef, null); + { + const active = zcu.activate(tid); + defer active.deactivate(); + try active.pt.updateEmbedFile(ef, null); + } if (ef.val != .none and ef.val == old_val) return; // success, value unchanged if (ef.val == .none and old_val == .none and ef.err == old_err) return; // failure, error unchanged @@ -460,27 +454,6 @@ fn detectEmbedFileUpdate(comp: *Compilation, tid: Zcu.PerThread.Id, ef_index: Zc try zcu.markDependeeOutdated(.not_marked_po, .{ .embed_file = ef_index }); } -fn deinitFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void { - const zcu = pt.zcu; - const gpa = zcu.gpa; - const file = zcu.fileByIndex(file_index); - log.debug("deinit File {f}", .{file.path.fmt(zcu.comp)}); - file.path.deinit(gpa); - file.unload(gpa); - if (file.prev_zir) |prev_zir| { - prev_zir.deinit(gpa); - gpa.destroy(prev_zir); - } - file.* = undefined; -} - -pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void { - const gpa = pt.zcu.gpa; - const file = pt.zcu.fileByIndex(file_index); - pt.deinitFile(file_index); - gpa.destroy(file); -} - /// 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. @@ -814,7 +787,7 @@ const UpdatedFile = struct { inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), }; -fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile)) void { +fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.array_hash_map.Auto(Zcu.File.Index, UpdatedFile)) void { for (updated_files.values()) |*elem| elem.inst_map.deinit(gpa); updated_files.deinit(gpa); } @@ -832,7 +805,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { // We need to visit every updated File for every TrackedInst in InternPool. // This only includes Zig files; ZON files are omitted. - var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .empty; + var updated_files: std.array_hash_map.Auto(Zcu.File.Index, UpdatedFile) = .empty; defer cleanupUpdatedFiles(gpa, &updated_files); for (zcu.import_table.keys()) |file_index| { @@ -934,7 +907,7 @@ fn updateZirRefs(pt: Zcu.PerThread) (Io.Cancelable || Allocator.Error)!void { if (!has_namespace) continue; // Value is whether the declaration is `pub`. - var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, bool) = .empty; + var old_names: std.array_hash_map.Auto(InternPool.NullTerminatedString, bool) = .empty; defer old_names.deinit(zcu.gpa); for (old_zir.typeDecls(old_inst)) |decl_inst| { const old_decl = old_zir.getDeclaration(decl_inst); @@ -3595,8 +3568,8 @@ pub fn processExports(pt: Zcu.PerThread) !void { } // First, construct a mapping of every exported value and Nav to the indices of all its different exports. - var nav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, std.ArrayList(Zcu.Export.Index)) = .empty; - var uav_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, std.ArrayList(Zcu.Export.Index)) = .empty; + var nav_exports: std.array_hash_map.Auto(InternPool.Nav.Index, std.ArrayList(Zcu.Export.Index)) = .empty; + var uav_exports: std.array_hash_map.Auto(InternPool.Index, std.ArrayList(Zcu.Export.Index)) = .empty; defer { for (nav_exports.values()) |*exports| { exports.deinit(gpa); @@ -3692,7 +3665,7 @@ pub fn processExports(pt: Zcu.PerThread) !void { } } -const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Zcu.Export.Index); +const SymbolExports = std.array_hash_map.Auto(InternPool.NullTerminatedString, Zcu.Export.Index); fn processExportsInner( pt: Zcu.PerThread, @@ -4540,7 +4513,6 @@ pub fn runCodegen(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) Ru comp.config.use_llvm, )) { else => unreachable, // assertion failure - .stage2_spirv, .stage2_llvm, => {}, }, @@ -4572,8 +4544,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e tracy_trace.addText(fqn.toSlice(ip)); tracy_trace.addTextFmt("func_ip_index={d}", .{func_index}); + Air.Verify.run(pt, func_index, air); + if (codegen.legalizeFeatures(pt, nav)) |features| { try air.legalize(pt, features); + // Verify the AIR again post-legalization. + Air.Verify.run(pt, func_index, air); } var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav)) @@ -4621,18 +4597,6 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e const lf = comp.bin_file orelse return error.NoLinkFile; - // Just like LLVM, the SPIR-V backend can't multi-threaded due to SPIR-V design limitations. - if (lf.cast(.spirv)) |spirv_file| { - assert(zcu.pending_codegen_jobs.load(.monotonic) == 2); // only one codegen at a time (but the value is 2 because 1 is the base) - spirv_file.updateFunc(pt, func_index, air, &liveness) catch |err| { - switch (err) { - error.OutOfMemory => comp.link_diags.setAllocFailure(), - } - return error.AlreadyReported; - }; - return error.BackendDoesNotProduceMir; - } - return codegen.generateFunction(lf, pt, func_index, air, &liveness); } diff --git a/src/codegen.zig b/src/codegen.zig index 4a2be3ea39e3fcdb117cd49c638058134d457d86..55d73b476a7a9a9a89a18fc4c8be9b8e139ac6c3 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -101,6 +101,7 @@ pub const AnyMir = union { x86_64: if (dev.env.supports(.x86_64_backend)) @import("codegen/x86_64/Mir.zig") else noreturn, wasm: if (dev.env.supports(.wasm_backend)) @import("codegen/wasm/Mir.zig") else noreturn, c: if (dev.env.supports(.c_backend)) @import("codegen/c.zig").Mir else noreturn, + spirv: if (dev.env.supports(.spirv_backend)) @import("codegen/spirv/Mir.zig") else noreturn, pub inline fn tag(comptime backend: std.lang.CompilerBackend) []const u8 { return switch (backend) { @@ -110,6 +111,7 @@ pub const AnyMir = union { .stage2_x86_64 => "x86_64", .stage2_wasm => "wasm", .stage2_c => "c", + .stage2_spirv => "spirv", else => unreachable, }; } @@ -125,6 +127,7 @@ pub const AnyMir = union { .stage2_x86_64, .stage2_wasm, .stage2_c, + .stage2_spirv, => |backend_ct| @field(mir, tag(backend_ct)).deinit(gpa), } } @@ -153,6 +156,7 @@ pub fn generateFunction( .stage2_x86_64, .stage2_wasm, .stage2_c, + .stage2_spirv, => |backend| { dev.check(devFeatureForBackend(backend)); const CodeGen = importBackend(backend); @@ -329,6 +333,7 @@ pub fn generateSymbol( .tuple_type, .union_type, .opaque_type, + .spirv_type, .enum_type, .func_type, .error_set_type, diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig index e09ca268b9091dfcf149a9728b0641e303f00cf1..a4b072f448fde6ebb3d0ff7163064892fe88c4b3 100644 --- a/src/codegen/aarch64/Select.zig +++ b/src/codegen/aarch64/Select.zig @@ -4,12 +4,12 @@ air: Air, nav_index: InternPool.Nav.Index, // Blocks -def_order: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, void), -blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Block), -loops: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Loop), +def_order: std.array_hash_map.Auto(Air.Inst.Index, void), +blocks: std.array_hash_map.Auto(Air.Inst.Index, Block), +loops: std.array_hash_map.Auto(Air.Inst.Index, Loop), active_loops: std.ArrayList(Loop.Index), loop_live: struct { - set: std.AutoArrayHashMapUnmanaged(struct { Loop.Index, Air.Inst.Index }, void), + set: std.array_hash_map.Auto(struct { Loop.Index, Air.Inst.Index }, void), list: std.ArrayList(Air.Inst.Index), }, dom_start: u32, @@ -255,6 +255,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { .work_item_id, .work_group_size, .work_group_id, + .spirv_runtime_array_len, => unreachable, .ret_ptr => { const ty = air_data[@intFromEnum(air_inst_index)].ty; @@ -291,8 +292,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { .load, .fptrunc, .fpext, - .intcast, - .intcast_safe, + .int_cast, + .int_cast_safe, .trunc, .optional_payload, .optional_payload_ptr, @@ -333,7 +334,15 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { air_inst_index = air_body[air_body_index]; continue :air_tag air_tags[@intFromEnum(air_inst_index)]; }, - .bitcast => { + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, + => { const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; maybe_noop: { if (ty_op.ty.toInterned().? != isel.air.typeOf(ty_op.operand, ip).toIntern()) break :maybe_noop; @@ -3189,7 +3198,15 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .bitcast => |air_tag| { + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, + => |air_tag| { if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { defer dst_vi.value.deref(isel); const ty_op = air.data(air.inst_index).ty_op; @@ -5220,7 +5237,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .intcast => |air_tag| { + .int_cast => |air_tag| { if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { defer dst_vi.value.deref(isel); @@ -5311,7 +5328,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .intcast_safe => |air_tag| { + .int_cast_safe => |air_tag| { if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { defer dst_vi.value.deref(isel); @@ -7491,7 +7508,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, } if (air.next()) |next_air_tag| continue :air_tag next_air_tag; }, - .work_item_id, .work_group_size, .work_group_id => unreachable, + .work_item_id, .work_group_size, .work_group_id, .spirv_runtime_array_len => unreachable, } assert(air.body_index == 0); } @@ -11224,7 +11241,7 @@ fn dumpValuesInner(isel: *Select, which: WhichValues) !void { defer std.debug.unlockStderr(); const stderr = &locked_stderr.file_writer.interface; - var reverse_live_values: std.AutoArrayHashMapUnmanaged(Value.Index, std.ArrayList(Air.Inst.Index)) = .empty; + var reverse_live_values: std.array_hash_map.Auto(Value.Index, std.ArrayList(Air.Inst.Index)) = .empty; defer { for (reverse_live_values.values()) |*list| list.deinit(gpa); reverse_live_values.deinit(gpa); @@ -11253,7 +11270,7 @@ fn dumpValuesInner(isel: *Select, which: WhichValues) !void { }; } - var roots: std.AutoArrayHashMapUnmanaged(Value.Index, u32) = .empty; + var roots: std.array_hash_map.Auto(Value.Index, u32) = .empty; defer roots.deinit(gpa); { try roots.ensureTotalCapacity(gpa, isel.values.items.len); @@ -11354,7 +11371,7 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem if (try isel.writeKeyToMemory(ip.indexToKey(constant.toIntern()), buffer)) return true; constant.writeToMemory(zcu, buffer) catch |err| switch (err) { error.OutOfMemory => |e| return e, - error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false, + error.ReinterpretDeclRef, error.IllDefinedMemoryLayout => return false, }; return true; } diff --git a/src/codegen/aarch64/abi.zig b/src/codegen/aarch64/abi.zig index 369c0813f76a22d488c24e9165a3ba6362299b3a..dcd192da8395fc6fca07c101aebff596bc4e99cc 100644 --- a/src/codegen/aarch64/abi.zig +++ b/src/codegen/aarch64/abi.zig @@ -21,7 +21,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { if (ty.containerLayout(zcu) == .@"packed") return .byval; if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count }; - const bit_size = ty.bitSize(zcu); + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > 128) return .memory; if (bit_size > 64) return .double_integer; return .integer; @@ -30,7 +30,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { if (ty.containerLayout(zcu) == .@"packed") return .byval; if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count }; - const bit_size = ty.bitSize(zcu); + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > 128) return .memory; if (bit_size > 64) return .double_integer; return .integer; @@ -62,6 +62,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { .null, .@"fn", .@"opaque", + .spirv, .enum_literal, .array, => unreachable, diff --git a/src/codegen/arm/abi.zig b/src/codegen/arm/abi.zig index 22bd34274f49e24d5538302a1a9c285414085c01..14acccbb7963991a3c9c201bcebaeb9218af7ff8 100644 --- a/src/codegen/arm/abi.zig +++ b/src/codegen/arm/abi.zig @@ -30,11 +30,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { const ip = &zcu.intern_pool; switch (ty.zigTypeTag(zcu)) { .@"struct" => { - const bit_size = ty.bitSize(zcu); if (ty.containerLayout(zcu) == .@"packed") { - if (bit_size > 64) return .memory; + if (ty.bitSize(zcu) > 64) return .memory; return .byval; } + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > max_byval_size) return .memory; const float_count = countFloats(ty, zcu, &maybe_float_bits); if (float_count <= byval_float_count) return .byval; @@ -47,17 +47,17 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { var i: u32 = 0; while (i < fields) : (i += 1) { const field_ty = ty.fieldType(i, zcu); - if (field_ty.bitSize(zcu) > 32) return Class.arrSize(bit_size, 64); + if (field_ty.abiSize(zcu) > 4) return Class.arrSize(bit_size, 64); } return Class.arrSize(bit_size, 32); }, .@"union" => { - const bit_size = ty.bitSize(zcu); const union_obj = zcu.typeToUnion(ty).?; if (union_obj.layout == .@"packed") { - if (bit_size > 64) return .memory; + if (ty.bitSize(zcu) > 64) return .memory; return .byval; } + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > max_byval_size) return .memory; const float_count = countFloats(ty, zcu, &maybe_float_bits); if (float_count <= byval_float_count) return .byval; @@ -67,7 +67,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { } for (union_obj.field_types.get(ip)) |field_ty| { - if (Type.fromInterned(field_ty).bitSize(zcu) > 32) { + if (Type.fromInterned(field_ty).abiSize(zcu) > 4) { return Class.arrSize(bit_size, 64); } } @@ -113,6 +113,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { .null, .@"fn", .@"opaque", + .spirv, .enum_literal, .array, => unreachable, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 08e49fa1e13355293532e4bebe108d27a8223193..70be045b9ae3d23ffa3d8a8a45f467bfbbe6f74b 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -27,7 +27,7 @@ pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features { return comptime switch (dev.env.supports(.legalize)) { inline false, true => |supports_legalize| &.init(.{ // we don't currently ask zig1 to use safe optimization modes - .expand_intcast_safe = supports_legalize, + .expand_int_cast_safe = supports_legalize, .expand_int_from_float_safe = supports_legalize, .expand_int_from_float_optimized_safe = supports_legalize, .expand_add_safe = supports_legalize, @@ -38,6 +38,9 @@ pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features { .expand_packed_store = true, .expand_packed_struct_field_val = true, .expand_packed_aggregate_init = true, + + .scalarize_bit_cast_array = true, + .scalarize_bit_cast_vector_non_elementwise = true, }), }; } @@ -59,14 +62,14 @@ pub const Mir = struct { /// Key is the value of the UAV; value is the UAV's alignment, or /// `.none` for natural alignment. The specified alignment is never /// less than the natural alignment. - need_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), + need_uavs: std.array_hash_map.Auto(InternPool.Index, Alignment), ctype_deps: CType.Dependencies, /// Key is an enum type for which we need a generated `@tagName` function. - need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), + need_tag_name_funcs: std.array_hash_map.Auto(InternPool.Index, void), /// Key is a function Nav for which we need a generated `zig_never_tail` wrapper. - need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), + need_never_tail_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void), /// Key is a function Nav for which we need a generated `zig_never_inline` wrapper. - need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), + need_never_inline_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void), pub fn deinit(mir: *Mir, gpa: Allocator) void { gpa.free(mir.fwd_decl); @@ -164,8 +167,8 @@ const LocalType = struct { }; const LocalIndex = u16; -const LocalsList = std.AutoArrayHashMapUnmanaged(LocalIndex, void); -const LocalsMap = std.AutoArrayHashMapUnmanaged(LocalType, LocalsList); +const LocalsList = std.array_hash_map.Auto(LocalIndex, void); +const LocalsMap = std.array_hash_map.Auto(LocalType, LocalsList); const ValueRenderLocation = enum { initializer, @@ -328,6 +331,9 @@ fn isReservedIdent(ident: []const u8) bool { return true; } + // zig.h + if (mem.startsWith(u8, ident, "zig_")) return true; + return reserved_idents.has(ident); } @@ -391,11 +397,11 @@ pub const Function = struct { code: Writer.Allocating, indent_counter: usize, /// Key is an enum type for which we need a generated `@tagName` function. - need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), + need_tag_name_funcs: std.array_hash_map.Auto(InternPool.Index, void), /// Key is a function Nav for which we need a generated `zig_never_tail` wrapper. - need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), + need_never_tail_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void), /// Key is a function Nav for which we need a generated `zig_never_inline` wrapper. - need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), + need_never_inline_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void), func_index: InternPool.Index, /// All the locals, to be emitted at the top of the function. locals: std.ArrayList(LocalType) = .empty, @@ -407,7 +413,7 @@ pub const Function = struct { /// of variable declarations at the top of a function, sorted descending /// by type alignment. /// The value is whether the alloc needs to be emitted in the header. - allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, bool) = .empty, + allocs: std.array_hash_map.Auto(LocalIndex, bool) = .empty, /// Maps from `loop_switch_br` instructions to the allocated local used /// for the switch cond. Dispatches should set this local to the new cond. loop_switch_conds: std.AutoHashMapUnmanaged(Air.Inst.Index, LocalIndex) = .empty, @@ -643,7 +649,7 @@ pub const DeclGen = struct { /// Key is the value of the UAV; value is the UAV's alignment, or /// `.none` for natural alignment. The specified alignment is never /// less than the natural alignment. - uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), + uavs: std.array_hash_map.Auto(InternPool.Index, Alignment), fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) Error { @branchHint(.cold); @@ -902,6 +908,7 @@ pub const DeclGen = struct { .tuple_type, .union_type, .opaque_type, + .spirv_type, .enum_type, .func_type, .error_set_type, @@ -1119,7 +1126,7 @@ pub const DeclGen = struct { } try w.writeByte('{'); const ai = ty.arrayInfo(zcu); - if (ai.elem_type.eql(.u8, zcu)) { + if (ai.elem_type.eql(.u8)) { var literal: StringLiteral = .init(w, @intCast(ty.arrayLenIncludingSentinel(zcu))); try literal.start(); var index: usize = 0; @@ -1538,7 +1545,7 @@ pub const DeclGen = struct { } try w.writeByte('{'); const ai = ty.arrayInfo(zcu); - if (ai.elem_type.eql(.u8, zcu)) { + if (ai.elem_type.eql(.u8)) { var literal: StringLiteral = .init(w, @intCast(ty.arrayLenIncludingSentinel(zcu))); try literal.start(); var index: u64 = 0; @@ -1565,6 +1572,7 @@ pub const DeclGen = struct { }, .anyframe_type, .opaque_type, + .spirv_type, .func_type, => unreachable, @@ -1975,9 +1983,9 @@ pub const DeclGen = struct { } switch (CType.classifyInt(ty, zcu)) { .void => unreachable, // opv - .small => try w.print("{c}{d}", .{ + .small => |s| try w.print("{c}{d}", .{ signAbbrev(ty.intInfo(zcu).signedness), - ty.abiSize(zcu) * 8, + s.bits(zcu.getTarget()), }), .big => try w.writeAll("big"), } @@ -2631,9 +2639,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { // zig fmt: off .inferred_alloc, .inferred_alloc_comptime => unreachable, - // No "scalarize" legalizations are enabled, so these instructions never appear. - .legalize_vec_elem_val => unreachable, - .legalize_vec_store_elem => unreachable, + // Possible because `Air.Legalize.scalarize_bit_cast_vector_non_elementwise` is enabled. + .legalize_vec_elem_val => try airArrayElemVal(f, inst), + .legalize_vec_store_elem => try airLegalizeVecStoreElem(f, inst), // No soft float legalizations are enabled. .legalize_compiler_rt_call => unreachable, @@ -2746,8 +2754,15 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .alloc => try airAlloc(f, inst), .ret_ptr => try airRetPtr(f, inst), .assembly => try airAsm(f, inst), - .bitcast => try airBitcast(f, inst), - .intcast => try airIntCast(f, inst), + .ptr_cast => try airPtrCast(f, inst), + .ptr_from_int => try airSimpleCast(f, inst), + .int_from_ptr => try airSimpleCast(f, inst), + .error_cast => try airNopCast(f, inst), + .error_from_int => try airNopCast(f, inst), + .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), .load => try airLoad(f, inst), .store => try airStore(f, inst, false), @@ -2859,7 +2874,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .add_safe, .sub_safe, .mul_safe, - .intcast_safe, + .int_cast_safe, .int_from_float_safe, .int_from_float_optimized_safe, => return f.fail("TODO implement safety_checked_instructions", .{}), @@ -2877,6 +2892,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { .work_item_id, .work_group_size, .work_group_id, + .spirv_runtime_array_len, => unreachable, // Instructions that are known to always be `noreturn` based on their tag. @@ -3077,6 +3093,28 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { return local; } +fn airLegalizeVecStoreElem(f: *Function, inst: Air.Inst.Index) !CValue { + const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; + const extra = f.air.extraData(Air.Bin, pl_op.payload).data; + + const vec_ptr = try f.resolveInst(pl_op.operand); + const index = try f.resolveInst(extra.lhs); + const elem = try f.resolveInst(extra.rhs); + try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); + + const w = &f.code.writer; + + try f.writeCValueDerefMember(w, vec_ptr, .{ .identifier = "array" }); + try w.writeByte('['); + try f.writeCValue(w, index, .other); + try w.writeAll("] = "); + try f.writeCValue(w, elem, .other); + try w.writeByte(';'); + try f.newline(); + + return .none; +} + fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { const pt = f.dg.pt; const zcu = pt.zcu; @@ -3184,35 +3222,42 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { try reap(f, inst, &.{ty_op.operand}); - const is_aligned = if (ptr_info.flags.alignment != .none) - ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte) - else - true; + const is_aligned = switch (ptr_info.flags.alignment) { + .none => true, + else => |ptr_align| ptr_align.compare(.gte, src_ty.abiAlignment(zcu)), + }; const w = &f.code.writer; const local = try f.allocLocal(inst, src_ty); - const v = try Vectorize.start(f, inst, w, ptr_ty); if (!is_aligned) { try w.writeAll("memcpy(&"); try f.writeCValue(w, local, .other); - try v.elem(f, w); try w.writeAll(", (const char *)"); - try f.writeCValue(w, operand, .other); - try v.elem(f, w); + switch (ptr_info.flags.vector_index) { + .none => try f.writeCValue(w, operand, .other), + else => |index| { + try w.writeByte('&'); + try f.writeCValue(w, operand, .other); + try w.print("[{d}]", .{@intFromEnum(index)}); + }, + } try w.writeAll(", sizeof("); try f.renderType(w, src_ty); try w.writeAll("))"); } else { try f.writeCValue(w, local, .other); - try v.elem(f, w); try w.writeAll(" = "); - try f.writeCValueDeref(w, operand); - try v.elem(f, w); + switch (ptr_info.flags.vector_index) { + .none => try f.writeCValueDeref(w, operand), + else => |index| { + try f.writeCValue(w, operand, .other); + try w.print("[{d}]", .{@intFromEnum(index)}); + }, + } } try w.writeByte(';'); try f.newline(); - try v.end(f, inst, w); return local; } @@ -3425,23 +3470,26 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { if (!is_aligned) { // For this memcpy to safely work we need the rhs to have the same // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). - assert(src_ty.eql(.fromInterned(ptr_info.child), zcu)); + assert(src_ty.eql(.fromInterned(ptr_info.child))); - const v = try Vectorize.start(f, inst, w, ptr_ty); try w.writeAll("memcpy((char *)"); - try f.writeCValue(w, ptr_val, .other); - try v.elem(f, w); + switch (ptr_info.flags.vector_index) { + .none => try f.writeCValue(w, ptr_val, .other), + else => |index| { + try w.writeByte('&'); + try f.writeCValue(w, ptr_val, .other); + try w.print("[{d}]", .{@intFromEnum(index)}); + }, + } try w.writeAll(", &"); switch (src_val) { .constant => |val| try f.dg.renderValueAsLvalue(w, val), else => try f.writeCValue(w, src_val, .other), } - try v.elem(f, w); try w.writeAll(", sizeof("); try f.renderType(w, src_ty); try w.writeAll("));"); try f.newline(); - try v.end(f, inst, w); } else { switch (ptr_val) { .local_ref => |ptr_local_index| switch (src_val) { @@ -3451,15 +3499,18 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { }, else => {}, } - const v = try Vectorize.start(f, inst, w, ptr_ty); - try f.writeCValueDeref(w, ptr_val); - try v.elem(f, w); + + switch (ptr_info.flags.vector_index) { + .none => try f.writeCValueDeref(w, ptr_val), + else => |index| { + try f.writeCValue(w, ptr_val, .other); + try w.print("[{d}]", .{@intFromEnum(index)}); + }, + } try w.writeAll(" = "); try f.writeCValue(w, src_val, .other); - try v.elem(f, w); try w.writeByte(';'); try f.newline(); - try v.end(f, inst, w); } return .none; } @@ -3607,9 +3658,9 @@ fn airCmpOp( const lhs_ty = f.typeOf(data.lhs); const scalar_ty = lhs_ty.scalarType(zcu); - const scalar_bits = scalar_ty.bitSize(zcu); - if (scalar_ty.isInt(zcu) and scalar_bits > 64) - return airCmpBuiltinCall( + if (scalar_ty.isInt(zcu)) { + const scalar_bits = scalar_ty.bitSize(zcu); + if (scalar_bits > 64) return airCmpBuiltinCall( f, inst, data, @@ -3617,6 +3668,7 @@ fn airCmpOp( .cmp, if (scalar_bits > 128) .bits else .none, ); + } if (scalar_ty.isRuntimeFloat()) return airCmpBuiltinCall(f, inst, data, operator, .operator, .none); @@ -3662,9 +3714,9 @@ fn airEquality( const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const operand_ty = f.typeOf(bin_op.lhs); - const operand_bits = operand_ty.bitSize(zcu); - if (operand_ty.isAbiInt(zcu) and operand_bits > 64) - return airCmpBuiltinCall( + if (operand_ty.isAbiInt(zcu)) { + const operand_bits = operand_ty.bitSize(zcu); + if (operand_bits > 64) return airCmpBuiltinCall( f, inst, bin_op, @@ -3672,6 +3724,7 @@ fn airEquality( .cmp, if (operand_bits > 128) .bits else .none, ); + } if (operand_ty.isRuntimeFloat()) return airCmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); @@ -3752,7 +3805,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.print(" < sizeof({f}) / sizeof(*{0f});", .{fmtIdentSolo("zig_errorName")}); + try w.writeAll(" < sizeof(zig_errorName) / sizeof(*zig_errorName);"); try f.newline(); return local; } @@ -4252,125 +4305,240 @@ fn airSwitchDispatch(f: *Function, inst: Air.Inst.Index) !void { try w.print("goto zig_switch_{d}_loop;\n", .{@intFromEnum(br.block_inst)}); } -fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { +fn airPtrCast(f: *Function, inst: Air.Inst.Index) Error!CValue { + const zcu = f.dg.pt.zcu; + + const dest_ty = f.typeOfIndex(inst); + const ptr_ty = switch (dest_ty.zigTypeTag(zcu)) { + .optional => dest_ty.childType(zcu), + .pointer => dest_ty, + else => unreachable, + }; + + if (!ptr_ty.isSlice(zcu)) { + return airSimpleCast(f, inst); + } + + // For slice casts we need to assign both fields. + const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const inst_ty = f.typeOfIndex(inst); + const operand = try f.resolveInst(ty_op.operand); + const w = &f.code.writer; + const dest_local = try f.allocLocal(inst, dest_ty); + + try f.writeCValueMember(w, dest_local, .{ .identifier = "ptr" }); + try w.writeAll(" = ("); + try f.renderType(w, ptr_ty.slicePtrFieldType(zcu)); + try w.writeByte(')'); + try f.writeCValueMember(w, operand, .{ .identifier = "ptr" }); + try w.writeByte(';'); + try f.newline(); + + try f.writeCValueMember(w, dest_local, .{ .identifier = "len" }); + try w.writeAll(" = "); + try f.writeCValueMember(w, operand, .{ .identifier = "len" }); + try w.writeByte(';'); + try f.newline(); + + try reap(f, inst, &.{ty_op.operand}); + return dest_local; +} + +fn airSimpleCast(f: *Function, inst: Air.Inst.Index) Error!CValue { + const zcu = f.dg.pt.zcu; + + const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const dest_ty = f.typeOfIndex(inst); + const operand_ty = f.typeOf(ty_op.operand); const operand = try f.resolveInst(ty_op.operand); + + const w = &f.code.writer; + const dest_local = try f.allocLocal(inst, dest_ty); + const v: Vectorize = try .start(f, inst, w, operand_ty); + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); + try w.writeAll(" = ("); + try f.renderType(w, dest_ty.scalarType(zcu)); + try w.writeByte(')'); + try f.writeCValue(w, operand, .other); + try v.elem(f, w); + try w.writeByte(';'); + try f.newline(); + try v.end(f, inst, w); + + try reap(f, inst, &.{ty_op.operand}); + return dest_local; +} + +fn airNopCast(f: *Function, inst: Air.Inst.Index) Error!CValue { + const zcu = f.dg.pt.zcu; + + const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const dest_ty = f.typeOfIndex(inst); + const operand_ty = f.typeOf(ty_op.operand); + const operand = try f.resolveInst(ty_op.operand); + + assert(operand_ty.abiSize(zcu) == dest_ty.abiSize(zcu)); + assert(operand_ty.isAbiInt(zcu) == dest_ty.isAbiInt(zcu)); + + try reap(f, inst, &.{ty_op.operand}); + return f.moveCValue(inst, dest_ty, operand); +} + +fn airUnionFromEnum(f: *Function, inst: Air.Inst.Index) Error!CValue { + const zcu = f.dg.pt.zcu; + + const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const dest_ty = f.typeOfIndex(inst); const operand_ty = f.typeOf(ty_op.operand); + const operand = try f.resolveInst(ty_op.operand); + + assert(dest_ty.zigTypeTag(zcu) == .@"union"); + assert(operand_ty.zigTypeTag(zcu) == .@"enum"); + + const w = &f.code.writer; + const dest_local = try f.allocLocal(inst, dest_ty); + try f.writeCValueMember(w, dest_local, .{ .identifier = "tag" }); + try w.writeAll(" = "); + try f.writeCValue(w, operand, .other); + try w.writeByte(';'); + try f.newline(); - const bitcasted = try bitcast(f, inst_ty, operand, operand_ty); try reap(f, inst, &.{ty_op.operand}); - return f.moveCValue(inst, inst_ty, bitcasted); + return dest_local; } -fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CValue { +fn airBitCast(f: *Function, inst: Air.Inst.Index) Error!CValue { const pt = f.dg.pt; const zcu = pt.zcu; - const target = &f.dg.mod.resolved_target.result; const w = &f.code.writer; - if (operand_ty.isAbiInt(zcu) and dest_ty.isAbiInt(zcu)) { - const src_info = dest_ty.intInfo(zcu); - const dest_info = operand_ty.intInfo(zcu); - if (src_info.signedness == dest_info.signedness and - src_info.bits == dest_info.bits) return operand; - } - - if (dest_ty.isPtrAtRuntime(zcu) or operand_ty.isPtrAtRuntime(zcu)) { - const local = try f.allocLocal(null, dest_ty); - try f.writeCValue(w, local, .other); + const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const dest_ty = f.typeOfIndex(inst); + + const operand = try f.resolveInst(ty_op.operand); + const operand_ty = f.typeOf(ty_op.operand); + + const dest_local = try f.allocLocal(inst, dest_ty); + + // Because we have `scalarize_bit_cast_array` and `scalarize_bit_cast_vector_non_elementwise` + // enabled, we usually only see scalars here. The only case in which we may see vectors is when + // the operation happens elementwise, which we can handle with `Vectorize`. + var v: Vectorize = try .start(f, inst, w, operand_ty); + 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))) + { + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); try w.writeAll(" = ("); - try f.renderType(w, dest_ty); + try f.renderType(w, dest_scalar_ty); try w.writeByte(')'); try f.writeCValue(w, operand, .other); + try v.elem(f, w); try w.writeByte(';'); try f.newline(); - return local; - } - - const local = try f.allocLocal(null, dest_ty); - // On big-endian targets, copying ABI integers with padding bits is awkward, because the padding bits are at the low bytes of the value. - // We need to offset the source or destination pointer appropriately and copy the right number of bytes. - if (target.cpu.arch.endian() == .big and dest_ty.isAbiInt(zcu) and !operand_ty.isAbiInt(zcu)) { - // e.g. [10]u8 -> u80. We need to offset the destination so that we copy to the least significant bits of the integer. - const offset = dest_ty.abiSize(zcu) - operand_ty.abiSize(zcu); - try w.writeAll("memcpy((char *)&"); - try f.writeCValue(w, local, .other); - try w.print(" + {d}, &", .{offset}); - switch (operand) { - .constant => |val| try f.dg.renderValueAsLvalue(w, val), - else => try f.writeCValue(w, operand, .other), - } - try w.print(", {d});", .{operand_ty.abiSize(zcu)}); - } else if (target.cpu.arch.endian() == .big and operand_ty.isAbiInt(zcu) and !dest_ty.isAbiInt(zcu)) { - // e.g. u80 -> [10]u8. We need to offset the source so that we copy from the least significant bits of the integer. - const offset = operand_ty.abiSize(zcu) - dest_ty.abiSize(zcu); + } else if (dest_scalar_ty.toIntern() == .bool_type) { + // If the result is a boolean type, just check if the operand is non-zero. + assert(operand_scalar_ty.isAbiInt(zcu)); + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); + try w.writeAll(" = "); + try f.writeCValue(w, operand, .other); + 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, local, .other); - try w.writeAll(", (const char *)&"); + 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 w.print(" + {d}, {d});", .{ offset, dest_ty.abiSize(zcu) }); + 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)); + + // memcpy the value... try w.writeAll("memcpy(&"); - try f.writeCValue(w, local, .other); + 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 w.print(", {d});", .{@min(dest_ty.abiSize(zcu), operand_ty.abiSize(zcu))}); - } + try v.elem(f, w); + try w.print(", {d});", .{@min(operand_scalar_ty.abiSize(zcu), dest_scalar_ty.abiSize(zcu))}); + try f.newline(); - try f.newline(); - - // Ensure padding bits have the expected value. - if (dest_ty.isAbiInt(zcu)) { - switch (CType.classifyInt(dest_ty, zcu)) { + // ...and ensure padding bits have the correct value. + switch (CType.classifyInt(dest_scalar_ty, zcu)) { .void => unreachable, // opv .small => { - try f.writeCValue(w, local, .other); + try f.writeCValue(w, dest_local, .other); + try v.elem(f, w); try w.writeAll(" = zig_wrap_"); - try f.dg.renderTypeForBuiltinFnName(w, dest_ty); + try f.dg.renderTypeForBuiltinFnName(w, dest_scalar_ty); try w.writeByte('('); - try f.writeCValue(w, local, .other); - try f.dg.renderBuiltinInfo(w, dest_ty, .bits); + 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_ty.intInfo(zcu); - const padding_index: u16 = switch (target.cpu.arch.endian()) { + 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.writeCValueMember(w, local, .{ .identifier = "limbs" }); - try w.print("[{d}] = zig_wrap_{c}{d}(", .{ + 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.writeCValueMember(w, local, .{ .identifier = "limbs" }); - try w.print("[{d}], {d});", .{ padding_index, wrap_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.writeCValueMember(w, local, .{ .identifier = "limbs" }); - try w.print("[{d}] = zig_bitCast_u128(zig_wrap_i128(zig_bitCast_i128(", .{ + 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.writeCValueMember(w, local, .{ .identifier = "limbs" }); - try w.print("[{d}]), {d}));", .{ padding_index, wrap_bits }); + 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(); } }, } } - return local; + try v.end(f, inst, w); + + try reap(f, inst, &.{ty_op.operand}); + return dest_local; } fn airTrap(f: *Function) !void { @@ -4784,7 +4952,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { while (it.next()) |output| { const constraint = output.constraint; - if (constraint.len < 2 or constraint[0] != '=' or + if (constraint.len < 2 or + (constraint[0] != '=' and constraint[0] != '+') or (constraint[1] == '{' and constraint[constraint.len - 1] != '}')) { return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); @@ -6145,28 +6314,32 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { return .none; } - if (elem_abi_size == 1 and !dest_ty.isVolatilePtr(zcu)) { - const bitcasted = try bitcast(f, .u8, value, elem_ty); + if (elem_abi_size == 1 and elem_ty.isAbiInt(zcu) and !dest_ty.isVolatilePtr(zcu)) { try w.writeAll("memset("); switch (dest_ty.ptrSize(zcu)) { .slice => { try f.writeCValueMember(w, dest_slice, .{ .identifier = "ptr" }); - try w.writeAll(", "); - try f.writeCValue(w, bitcasted, .other); + try w.writeAll(", *(const char *)&"); + switch (value) { + .constant => |v| try f.dg.renderValueAsLvalue(w, v), + else => try f.writeCValue(w, value, .other), + } try w.writeAll(", "); try f.writeCValueMember(w, dest_slice, .{ .identifier = "len" }); }, .one => { try f.writeCValue(w, dest_slice, .other); - try w.writeAll(", "); - try f.writeCValue(w, bitcasted, .other); + try w.writeAll(", *(const char *)&"); + switch (value) { + .constant => |v| try f.dg.renderValueAsLvalue(w, v), + else => try f.writeCValue(w, value, .other), + } try w.print(", {d}", .{dest_ty.childType(zcu).arrayLen(zcu)}); }, .many, .c => unreachable, } try w.writeAll(");"); try f.newline(); - try f.freeCValue(inst, bitcasted); try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); return .none; } diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index c800605168e7481d109a7cd194911e7cbf937ba5..2944d1092e2c119cfd91eeb2e7221b67437cd398 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -249,6 +249,7 @@ pub const CType = union(enum) { .null, .enum_literal, .@"opaque", + .spirv, .noreturn, .void, => return .void, @@ -513,40 +514,39 @@ pub const CType = union(enum) { } } fn classifyBitInt(signedness: std.lang.Signedness, bits: u16, zcu: *const Zcu) IntClass { - const is_ez80 = zcu.getTarget().cpu.arch == .ez80; - return switch (bits) { + const target = zcu.getTarget(); + return switch (std.zig.target.intByteSize(target, bits)) { 0 => .void, - 1...8 => switch (signedness) { + 1 => switch (signedness) { .unsigned => .{ .small = .uint8_t }, .signed => .{ .small = .int8_t }, }, - 9...16 => switch (signedness) { + 2 => switch (signedness) { .unsigned => .{ .small = .uint16_t }, .signed => .{ .small = .int16_t }, }, - 17...24 => switch (signedness) { - .unsigned => .{ .small = if (is_ez80) .uint24_t else .uint32_t }, - .signed => .{ .small = if (is_ez80) .int24_t else .int32_t }, + 3 => switch (signedness) { + .unsigned => .{ .small = .uint24_t }, + .signed => .{ .small = .int24_t }, }, - 25...32 => switch (signedness) { + 4 => switch (signedness) { .unsigned => .{ .small = .uint32_t }, .signed => .{ .small = .int32_t }, }, - 33...48 => switch (signedness) { - .unsigned => .{ .small = if (is_ez80) .uint48_t else .uint64_t }, - .signed => .{ .small = if (is_ez80) .int48_t else .int64_t }, + 6 => switch (signedness) { + .unsigned => .{ .small = .uint48_t }, + .signed => .{ .small = .int48_t }, }, - 49...64 => switch (signedness) { + 8 => switch (signedness) { .unsigned => .{ .small = .uint64_t }, .signed => .{ .small = .int64_t }, }, - 65...128 => switch (signedness) { + 16 => switch (signedness) { .unsigned => .{ .small = .zig_u128 }, .signed => .{ .small = .zig_i128 }, }, - else => { + else => |n| { @branchHint(.unlikely); - const target = zcu.getTarget(); const limb_bytes = std.zig.target.intAlignment(target, bits); return .{ .big = .{ .limb_size = switch (limb_bytes) { @@ -557,10 +557,7 @@ pub const CType = union(enum) { 16 => .@"128", else => unreachable, }, - .limbs_len = @divExact( - std.zig.target.intByteSize(target, bits), - limb_bytes, - ), + .limbs_len = @divExact(n, limb_bytes), } }; }, }; @@ -571,30 +568,30 @@ pub const CType = union(enum) { pub const Dependencies = struct { /// Key is any Zig type which corresponds to a C `struct`, `union`, or `typedef`. That C /// type must be declared and complete. - type: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), + type: std.array_hash_map.Auto(InternPool.Index, void), /// Key is a Zig type which is the *payload* of an error union. The C `struct` type /// corresponding to such an error union must be declared and complete. /// /// These are separate from `type` to avoid redundant types for every different error set /// used with the same payload type---for instance a different C type for every `E!void`. - errunion_type: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), + errunion_type: std.array_hash_map.Auto(InternPool.Index, void), /// Like `type`, but the type does not necessarily need to be completed yet: a forward /// declaration is sufficient. - type_fwd: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), + type_fwd: std.array_hash_map.Auto(InternPool.Index, void), /// Like `errunion_type`, but the type does not necessarily need to be completed yet: a /// forward declaration is sufficient. - errunion_type_fwd: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), + errunion_type_fwd: std.array_hash_map.Auto(InternPool.Index, void), /// Key is a Zig type; value is a bitmask of alignments. For every bit which is set, an /// aligned typedef is required. For instance, if bit 3 is set, the C type 'aligned__8_foo' /// must be declared through `typedef` (but not necessarily completed yet). - aligned_type_fwd: std.AutoArrayHashMapUnmanaged(InternPool.Index, u64), + aligned_type_fwd: std.array_hash_map.Auto(InternPool.Index, u64), /// Key specifies a big-int type whose C `struct` must be declared and complete. - bigint: std.AutoArrayHashMapUnmanaged(BigInt, void), + bigint: std.array_hash_map.Auto(BigInt, void), pub const empty: Dependencies = .{ .type = .empty, @@ -865,6 +862,7 @@ pub const CType = union(enum) { switch (ty.zigTypeTag(zcu)) { .frame => unreachable, .@"anyframe" => unreachable, + .spirv => unreachable, .type => try w.writeAll("type"), .void => try w.writeAll("void"), @@ -988,6 +986,7 @@ pub const CType = union(enum) { .anyframe_type, .simple_type, .opaque_type, + .spirv_type, .error_set_type, .inferred_error_set_type, => true, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3de01b1e6516d05af12c0ec131290d567b279bd9..6361963ab4d898bcf84a08fed641c7390e476e4a 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -20,10 +20,8 @@ const Value = @import("../Value.zig"); const Zcu = @import("../Zcu.zig"); const aarch64_c_abi = @import("aarch64/abi.zig"); const FuncGen = @import("llvm/FuncGen.zig"); -const buildAllocaInner = FuncGen.buildAllocaInner; const isByRef = FuncGen.isByRef; -const firstParamSRet = FuncGen.firstParamSRet; -const lowerFnRetTy = FuncGen.lowerFnRetTy; +const fnReturnStrat = FuncGen.fnReturnStrat; const iterateParamTypes = FuncGen.iterateParamTypes; const ccAbiPromoteInt = FuncGen.ccAbiPromoteInt; @@ -37,6 +35,11 @@ pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features { return comptime &.initMany(&.{ .expand_int_from_float_safe, .expand_int_from_float_optimized_safe, + + .scalarize_bit_cast_array, + // Needed because LLVM's `bitcast` on vectors is endian-specific unless the source and dest + // types are vectors with equal length (hence also with equal bits-per-element). + .scalarize_bit_cast_vector_non_elementwise, }); } @@ -243,9 +246,11 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8 .opengl, .other, .plan9, + .psx, .psp, - .tios, .vita, + .tios, + .wiiu, => "unknown", }; try llvm_triple.appendSlice(llvm_os); @@ -284,6 +289,8 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8 .ilp32 => "unknown", .eabi => "eabi", .eabihf => "eabihf", + .abin32 => "unknown", + .x32 => "muslx32", // https://github.com/ziglang/zig/issues/25649 .android => "android", .androideabi => "androideabi", .musl => switch (target.os.tag) { @@ -369,18 +376,18 @@ pub fn dataLayout(target: *const std.Target) []const u8 { "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-a:8", + .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 => "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + .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 => "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + .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", @@ -395,8 +402,8 @@ pub fn dataLayout(target: *const std.Target) []const u8 { "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-v16:16-v32:32-n16:32:64", - .nvptx64 => "e-p6:32:32-i64:64-i128:128-v16:16-v32:32-n16:32: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" @@ -445,7 +452,7 @@ pub fn dataLayout(target: *const std.Target) []const u8 { .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 => "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", + .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 @@ -724,8 +731,8 @@ pub const Object = struct { // TODO: Address space const slice_ty = Type.slice_const_u8_sentinel_0; - const llvm_usize_ty = try o.lowerType(.usize); - const llvm_slice_ty = try o.lowerType(slice_ty); + const llvm_usize_ty = try o.lowerType(.usize, .in_memory); + const llvm_slice_ty = try o.lowerType(slice_ty, .in_memory); const llvm_table_ty = try o.builder.arrayType(1 + error_name_list.len, llvm_slice_ty); llvm_errors[0] = try o.builder.undefConst(llvm_slice_ty); @@ -791,7 +798,7 @@ pub const Object = struct { { if (o.errors_len_variable != .none) { const errors_len = zcu.intern_pool.global_error_set.getNamesFromMainThread().len; - const init_val = try o.builder.intConst(try o.errorIntType(), errors_len); + const init_val = try o.builder.intConst(try o.errorIntType(.in_memory), errors_len); try o.errors_len_variable.setInitializer(init_val, &o.builder); } try o.genErrorNameTable(); @@ -1183,7 +1190,7 @@ pub const Object = struct { }; { const global = llvm_function.ptrConst(&o.builder).global.ptr(&o.builder); - global.type = try o.lowerType(fn_ty); + global.type = try o.lowerType(fn_ty, .in_memory); global.addr_space = toLlvmAddressSpace(nav.resolved.?.@"addrspace", target); global.linkage = if (o.builder.strip) .private else .internal; global.visibility = .default; @@ -1270,165 +1277,7 @@ pub const Object = struct { } }, &o.builder); } - var deinit_wip = true; - var wip = try Builder.WipFunction.init(&o.builder, .{ - .function = llvm_function, - .strip = owner_mod.strip, - }); - defer if (deinit_wip) wip.deinit(); - wip.cursor = .{ .block = try wip.block(0, "Entry") }; - - // This is the list of args we will use that correspond directly to the AIR arg - // instructions. Depending on the calling convention, this list is not necessarily - // a bijection with the actual LLVM parameters of the function. - var args: std.ArrayList(Builder.Value) = .empty; - defer args.deinit(gpa); - - const ret_ptr: Builder.Value, const err_ret_trace: Builder.Value = implicit_args: { - var it = iterateParamTypes(o, fn_info); - - const ret_ptr: Builder.Value = if (firstParamSRet(fn_info, zcu, target)) param: { - const param = wip.arg(it.llvm_index); - it.llvm_index += 1; - break :param param; - } else .none; - - const err_return_tracing = fn_info.cc == .auto and comp.config.any_error_tracing; - const err_ret_trace: Builder.Value = if (err_return_tracing) param: { - const param = wip.arg(it.llvm_index); - it.llvm_index += 1; - break :param param; - } else .none; - - while (try it.next()) |lowering| { - try args.ensureUnusedCapacity(gpa, 1); - - switch (lowering) { - .no_bits => continue, - .byval => { - assert(!it.byval_attr); - const param_index = it.zig_index - 1; - const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[param_index]); - const param = wip.arg(it.llvm_index - 1); - - if (isByRef(param_ty, zcu)) { - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const param_llvm_ty = param.typeOfWip(&wip); - const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); - _ = try wip.store(.normal, param, arg_ptr, alignment); - args.appendAssumeCapacity(arg_ptr); - } else { - args.appendAssumeCapacity(param); - } - }, - .byref => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const param = wip.arg(it.llvm_index - 1); - - if (isByRef(param_ty, zcu)) { - args.appendAssumeCapacity(param); - } else { - const param_llvm_ty = try o.lowerType(param_ty); - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); - } - }, - .byref_mut => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const param = wip.arg(it.llvm_index - 1); - - if (isByRef(param_ty, zcu)) { - args.appendAssumeCapacity(param); - } else { - const param_llvm_ty = try o.lowerType(param_ty); - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, param, alignment, "")); - } - }, - .abi_sized_int => { - assert(!it.byval_attr); - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const param = wip.arg(it.llvm_index - 1); - - const param_llvm_ty = try o.lowerType(param_ty); - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); - _ = try wip.store(.normal, param, arg_ptr, alignment); - - if (isByRef(param_ty, zcu)) { - args.appendAssumeCapacity(arg_ptr); - } else { - args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); - } - }, - .slice => { - assert(!it.byval_attr); - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - assert(!isByRef(param_ty, zcu)); - const slice_val = try wip.buildAggregate( - try o.lowerType(param_ty), - &.{ wip.arg(it.llvm_index - 2), wip.arg(it.llvm_index - 1) }, - "", - ); - args.appendAssumeCapacity(slice_val); - }, - .multiple_llvm_types => { - assert(!it.byval_attr); - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const param_llvm_ty = try o.lowerType(param_ty); - 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 buildAllocaInner(&wip, llvm_ty, param_alignment.toLlvm(), target); - const llvm_args_start = it.llvm_index - it.types_len; - for (llvm_args_start.., it.offsets_buffer[0..it.types_len]) |llvm_arg_index, offset| { - const param = wip.arg(@intCast(llvm_arg_index)); - const part_ptr = try o.ptraddConst(&wip, arg_ptr, offset); - _ = try wip.store(.normal, param, part_ptr, param_alignment.offset(offset).toLlvm()); - } - - if (isByRef(param_ty, zcu)) { - args.appendAssumeCapacity(arg_ptr); - } else { - args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, param_alignment.toLlvm(), "")); - } - }, - .float_array => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const param_llvm_ty = try o.lowerType(param_ty); - const param = wip.arg(it.llvm_index - 1); - - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target); - _ = try wip.store(.normal, param, arg_ptr, alignment); - - if (isByRef(param_ty, zcu)) { - args.appendAssumeCapacity(arg_ptr); - } else { - args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); - } - }, - .i32_array, .i64_array => { - const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const param_llvm_ty = try o.lowerType(param_ty); - const param = wip.arg(it.llvm_index - 1); - - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const arg_ptr = try buildAllocaInner(&wip, param.typeOfWip(&wip), alignment, target); - _ = try wip.store(.normal, param, arg_ptr, alignment); - - if (isByRef(param_ty, zcu)) { - args.appendAssumeCapacity(arg_ptr); - } else { - args.appendAssumeCapacity(try wip.load(.normal, param_llvm_ty, arg_ptr, alignment, "")); - } - }, - } - } - - break :implicit_args .{ ret_ptr, err_ret_trace }; - }; - - const file, const subprogram = if (!wip.strip) debug_info: { + const file, const subprogram = if (!owner_mod.strip) debug_info: { const file = try o.getDebugFile(file_scope); const line_number = zcu.navSrcLine(func.owner_nav) + 1; @@ -1494,11 +1343,12 @@ pub const Object = struct { .gpa = gpa, .air = air.*, .liveness = liveness.*.?, - .wip = wip, + .wip = try .init(&o.builder, .{ + .function = llvm_function, + .strip = owner_mod.strip, + }), .is_naked = fn_info.cc == .naked, .fuzz = fuzz, - .ret_ptr = ret_ptr, - .args = args.items, .arg_index = 0, .arg_inline_index = 0, .func_inst_table = .empty, @@ -1512,14 +1362,18 @@ pub const Object = struct { .base_line = zcu.navSrcLine(func.owner_nav), .prev_dbg_line = 0, .prev_dbg_column = 0, - .err_ret_trace = err_ret_trace, .disable_intrinsics = disable_intrinsics, .allowzero_access = false, + + .ret_ptr = undefined, // populated by `genMainBody` + .err_ret_trace = undefined, // populated by `genMainBody` + .args = undefined, // populated by `genMainBody` }; defer fg.deinit(); - deinit_wip = false; - try fg.genBody(air.getMainBody(), .poi); + fg.wip.cursor = .{ .block = try fg.wip.block(0, "Entry") }; + + try fg.genMainBody(); // If we saw any loads or stores involving `allowzero` pointers, we need to mark the whole // function as considering null pointers valid so that LLVM's optimizers don't remove these @@ -1585,10 +1439,10 @@ pub const Object = struct { // represent (because it doesn't have runtime bits), we instead lower as the zero-size // type `[0 x i8]`. I don't think the type on an extern declaration actually does much // anyway. - if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) break :ty try o.lowerType(nav_ty); + if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) break :ty try o.lowerType(nav_ty, .in_memory); break :ty try o.builder.arrayType(0, .i8); } else if (nav_ty.hasRuntimeBits(zcu)) ty: { - break :ty try o.lowerType(nav_ty); + break :ty try o.lowerType(nav_ty, .in_memory); } else { // This is a non-extern zero-bit `Nav`---we're not interested in it. // TODO: we might need to rethink this a little under incremental compilation. If a @@ -1681,7 +1535,7 @@ pub const Object = struct { llvm_variable.setAlignment(llvm_align, &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), &o.builder); + try llvm_variable.setInitializer(if (opt_extern != null) .no_init else try o.lowerValue(resolved.value, .in_memory), &o.builder); llvm_variable.setThreadLocal(tl: { if (resolved.@"threadlocal" and !mod.single_threaded) break :tl .generaldynamic; break :tl .default; @@ -1863,6 +1717,7 @@ 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); @@ -2279,7 +2134,7 @@ pub const Object = struct { defer debug_param_types.deinit(gpa); // Return type goes first. - if (firstParamSRet(fn_info, zcu, target)) { + if (try fnReturnStrat(o, fn_info) == .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)); @@ -2662,6 +2517,7 @@ pub const Object = struct { }, .frame => @panic("TODO implement lowerDebugType for Frame types"), .@"anyframe" => @panic("TODO implement lowerDebugType for AnyFrame types"), + .spirv => unreachable, } } @@ -2826,12 +2682,12 @@ pub const Object = struct { if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder); var it = iterateParamTypes(o, fn_info); - if (firstParamSRet(fn_info, zcu, target)) { + 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)); + 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); it.llvm_index += 1; } else if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { @@ -2873,9 +2729,7 @@ pub const Object = struct { }, .byref => { const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); - const param_llvm_ty = try o.lowerType(param_ty); - const alignment = param_ty.abiAlignment(zcu); - try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment.toLlvm(), it.byval_attr, param_llvm_ty); + 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 => { @@ -2985,14 +2839,31 @@ pub const Object = struct { } } - pub fn errorIntType(o: *Object) Allocator.Error!Builder.Type { - return o.builder.intType(o.zcu.errorSetBits()); + 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` + in_memory, + }; + + 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), + }); } - pub fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type { + pub fn lowerType(o: *Object, t: Type, repr: TypeRepr) Allocator.Error!Builder.Type { const zcu = o.zcu; 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 + } + return switch (t.toIntern()) { .u0_type => unreachable, // no runtime bits inline .u1_type, @@ -3008,7 +2879,10 @@ pub const Object = struct { .u80_type, .u128_type, .i128_type, - => |tag| @field(Builder.Type, "i" ++ @tagName(tag)[1 .. @tagName(tag).len - "_type".len]), + => |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, @@ -3043,7 +2917,7 @@ pub const Object = struct { return .i8; }, .bool_type => .i1, - .anyerror_type => try o.errorIntType(), + .anyerror_type => try o.errorIntType(repr), .void_type => unreachable, // no runtime bits .type_type => unreachable, // no runtime bits .comptime_int_type => unreachable, // no runtime bits @@ -3063,10 +2937,10 @@ pub const Object = struct { => .ptr, .slice_const_u8_type, .slice_const_u8_sentinel_0_type, - => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize) }), + => try o.builder.structType(.normal, &.{ .ptr, try o.lowerType(.usize, repr) }), .anyerror_void_error_union_type, .adhoc_inferred_error_set_type, - => try o.errorIntType(), + => try o.errorIntType(repr), .generic_poison_type => unreachable, // values, not types .undef, @@ -3092,7 +2966,10 @@ pub const Object = struct { .none, => unreachable, else => switch (ip.indexToKey(t.toIntern())) { - .int_type => |int_type| try o.builder.intType(int_type.bits), + .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)), + }, .ptr_type => |ptr_type| type: { const ptr_ty = try o.builder.ptrType( toLlvmAddressSpace(ptr_type.flags.address_space, target), @@ -3101,18 +2978,18 @@ pub const Object = struct { .one, .many, .c => ptr_ty, .slice => try o.builder.structType(.normal, &.{ ptr_ty, - try o.lowerType(.usize), + try o.lowerType(.usize, repr), }), }; }, .array_type => |array_type| o.builder.arrayType( array_type.lenIncludingSentinel(), - try o.lowerType(.fromInterned(array_type.child)), + 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)), + try o.lowerType(.fromInterned(vector_type.child), .by_value), ), .opt_type => |child_ty| { // Must stay in sync with `opt_payload` logic in `lowerPtr`. @@ -3122,8 +2999,11 @@ pub const Object = struct { .runtime, .partially_comptime => {}, } - const payload_ty = try o.lowerType(.fromInterned(child_ty)); - if (t.optionalReprIsPayload(zcu)) return payload_ty; + if (t.optionalReprIsPayload(zcu)) { + return o.lowerType(.fromInterned(child_ty), repr); + } + + const payload_ty = try o.lowerType(.fromInterned(child_ty), repr); comptime assert(optional_layout_version == 3); var fields: [3]Builder.Type = .{ payload_ty, .i8, undefined }; @@ -3141,7 +3021,7 @@ pub const Object = struct { .error_union_type => |error_union_type| { // Must stay in sync with `codegen.errUnionPayloadOffset`. // See logic in `lowerPtr`. - const error_type = try o.errorIntType(); + const error_type = try o.errorIntType(repr); switch (Type.fromInterned(error_union_type.payload_type).classify(zcu)) { .fully_comptime => unreachable, @@ -3149,7 +3029,7 @@ pub const Object = struct { .runtime, .partially_comptime => {}, } - const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type)); + const payload_type = try o.lowerType(.fromInterned(error_union_type.payload_type), repr); const payload_align = Type.fromInterned(error_union_type.payload_type).abiAlignment(zcu); const error_align: InternPool.Alignment = .fromByteUnits(std.zig.target.intAlignment(target, zcu.errorSetBits())); @@ -3184,16 +3064,14 @@ pub const Object = struct { }, .simple_type => unreachable, .struct_type => { - if (o.type_map.get(t.toIntern())) |value| return value; - const struct_type = ip.loadStructType(t.toIntern()); if (struct_type.layout == .@"packed") { - const int_ty = try o.lowerType(.fromInterned(struct_type.packed_backing_int_type)); - try o.type_map.put(o.gpa, t.toIntern(), int_ty); - return int_ty; + return o.lowerType(.fromInterned(struct_type.packed_backing_int_type), repr); } + if (o.type_map.get(t.toIntern())) |value| return value; + assert(struct_type.size > 0); var llvm_field_types: std.ArrayList(Builder.Type) = .empty; @@ -3227,7 +3105,7 @@ pub const Object = struct { if (!field_ty.hasRuntimeBits(zcu)) continue; - try llvm_field_types.append(o.gpa, try o.lowerType(field_ty)); + try llvm_field_types.append(o.gpa, try o.lowerType(field_ty, repr)); offset += field_ty.abiSize(zcu); } @@ -3283,7 +3161,7 @@ pub const Object = struct { if (!Type.fromInterned(field_ty).hasRuntimeBits(zcu)) { continue; } - try llvm_field_types.append(o.gpa, try o.lowerType(.fromInterned(field_ty))); + try llvm_field_types.append(o.gpa, try o.lowerType(.fromInterned(field_ty), repr)); offset += Type.fromInterned(field_ty).abiSize(zcu); } @@ -3300,28 +3178,24 @@ pub const Object = struct { return o.builder.structType(.normal, llvm_field_types.items); }, .union_type => { - if (o.type_map.get(t.toIntern())) |value| return value; - const union_obj = ip.loadUnionType(t.toIntern()); if (union_obj.layout == .@"packed") { - const int_ty = try o.lowerType(.fromInterned(union_obj.packed_backing_int_type)); - try o.type_map.put(o.gpa, t.toIntern(), int_ty); - return int_ty; + return o.lowerType(.fromInterned(union_obj.packed_backing_int_type), repr); } - assert(union_obj.size > 0); - const layout = Type.getUnionLayout(union_obj, zcu); if (layout.payload_size == 0) { - const enum_tag_ty = try o.lowerType(.fromInterned(union_obj.enum_tag_type)); - try o.type_map.put(o.gpa, t.toIntern(), enum_tag_ty); - return enum_tag_ty; + return o.lowerType(.fromInterned(union_obj.enum_tag_type), repr); } + if (o.type_map.get(t.toIntern())) |value| return value; + + assert(union_obj.size > 0); + const aligned_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[layout.most_aligned_field]); - const aligned_field_llvm_ty = try o.lowerType(aligned_field_ty); + const aligned_field_llvm_ty = try o.lowerType(aligned_field_ty, repr); const payload_ty = ty: { if (layout.most_aligned_field_size == layout.payload_size) { @@ -3347,7 +3221,7 @@ pub const Object = struct { ); return ty; } - const enum_tag_ty = try o.lowerType(.fromInterned(union_obj.enum_tag_type)); + const enum_tag_ty = try o.lowerType(.fromInterned(union_obj.enum_tag_type), repr); // Put the tag before or after the payload depending on which one's // alignment is greater. @@ -3375,10 +3249,10 @@ pub const Object = struct { ); return ty; }, - .opaque_type => unreachable, // no runtime bits - .enum_type => try o.lowerType(t.intTagType(zcu)), + .opaque_type, .spirv_type => unreachable, // no runtime bits + .enum_type => try o.lowerType(t.intTagType(zcu), repr), .func_type => |func_type| try o.lowerFnType(t, func_type), - .error_set_type, .inferred_error_set_type => try o.errorIntType(), + .error_set_type, .inferred_error_set_type => try o.errorIntType(repr), // values, not types .undef, .simple_value, @@ -3410,12 +3284,12 @@ pub const Object = struct { assert(fn_ty.fnHasRuntimeBits(zcu)); - const ret_ty = try lowerFnRetTy(o, fn_info); + const ret_strat = try fnReturnStrat(o, fn_info); var llvm_params: std.ArrayList(Builder.Type) = .empty; defer llvm_params.deinit(o.gpa); - if (firstParamSRet(fn_info, zcu, target)) { + if (ret_strat == .sret) { try llvm_params.append(o.gpa, .ptr); } @@ -3430,7 +3304,7 @@ pub const Object = struct { .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)); + try llvm_params.append(o.gpa, try o.lowerType(param_ty, if (isByRef(param_ty, zcu)) .in_memory else .by_value)); }, .byref, .byref_mut => { try llvm_params.append(o.gpa, .ptr); @@ -3445,7 +3319,7 @@ pub const Object = struct { const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]); try llvm_params.appendSlice(o.gpa, &.{ try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(zcu), target)), - try o.lowerType(.usize), + try o.lowerType(.usize, .by_value), }); }, .multiple_llvm_types => { @@ -3453,7 +3327,7 @@ pub const Object = struct { }, .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).?); + const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, zcu).?, .in_memory); try llvm_params.append(o.gpa, try o.builder.arrayType(count, float_ty)); }, .i32_array, .i64_array => |arr_len| { @@ -3465,14 +3339,19 @@ pub const Object = struct { }, }; - return o.builder.fnType( - ret_ty, - llvm_params.items, - if (fn_info.is_var_args) .vararg else .normal, - ); + const llvm_ret_ty: Builder.Type = switch (ret_strat) { + .void, .sret => .void, + .by_val => try o.lowerType(.fromInterned(fn_info.return_type), .by_value), + .mem_cast => |llvm_ret_ty| llvm_ret_ty, + }; + const llvm_fn_kind: Builder.Type.Function.Kind = switch (fn_info.is_var_args) { + true => .vararg, + false => .normal, + }; + return o.builder.fnType(llvm_ret_ty, llvm_params.items, llvm_fn_kind); } - pub fn lowerValue(o: *Object, arg_val: InternPool.Index) Allocator.Error!Builder.Constant { + pub fn lowerValue(o: *Object, arg_val: InternPool.Index, repr: TypeRepr) Allocator.Error!Builder.Constant { const zcu = o.zcu; const ip = &zcu.intern_pool; const target = zcu.getTarget(); @@ -3497,13 +3376,14 @@ pub const Object = struct { .tuple_type, .union_type, .opaque_type, + .spirv_type, .enum_type, .func_type, .error_set_type, .inferred_error_set_type, => unreachable, // types, not values - .undef => return o.builder.undefConst(try o.lowerType(ty)), + .undef => return o.builder.undefConst(try o.lowerType(ty, repr)), .simple_value => |simple_value| switch (simple_value) { .void => unreachable, // non-runtime value .null => unreachable, // non-runtime value @@ -3518,15 +3398,15 @@ pub const Object = struct { .int => { var bigint_space: Value.BigIntSpace = undefined; const bigint = val.toBigInt(&bigint_space, zcu); - const llvm_int_ty = try o.builder.intType(ty.intInfo(zcu).bits); + const llvm_int_ty = try o.lowerType(ty, repr); return o.builder.bigIntConst(llvm_int_ty, bigint); }, .err => |err| { const int = zcu.intern_pool.getErrorValueIfExists(err.name).?; - return o.builder.intConst(try o.errorIntType(), int); + return o.builder.intConst(try o.errorIntType(repr), int); }, .error_union => |error_union| { - const llvm_error_ty = try o.errorIntType(); + const llvm_error_ty = try o.errorIntType(repr); const llvm_error_value = switch (error_union.val) { .err_name => |name| try o.builder.intConst( llvm_error_ty, @@ -3544,8 +3424,8 @@ pub const Object = struct { const payload_align = payload_type.abiAlignment(zcu); const error_align = Type.errorAbiAlignment(zcu); const llvm_payload_value = switch (error_union.val) { - .err_name => try o.builder.undefConst(try o.lowerType(payload_type)), - .payload => |payload| try o.lowerValue(payload), + .err_name => try o.builder.undefConst(try o.lowerType(payload_type, repr)), + .payload => |payload| try o.lowerValue(payload, repr), }; var fields: [3]Builder.Type = undefined; @@ -3560,7 +3440,7 @@ pub const Object = struct { fields[0] = vals[0].typeOf(&o.builder); fields[1] = vals[1].typeOf(&o.builder); - const llvm_ty = try o.lowerType(ty); + const llvm_ty = try o.lowerType(ty, repr); const llvm_ty_fields = llvm_ty.structFields(&o.builder); if (llvm_ty_fields.len > 2) { assert(llvm_ty_fields.len == 3); @@ -3572,7 +3452,7 @@ pub const Object = struct { fields[0..llvm_ty_fields.len], ), vals[0..llvm_ty_fields.len]); }, - .enum_tag => |enum_tag| o.lowerValue(enum_tag.int), + .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)) @@ -3588,9 +3468,9 @@ pub const Object = struct { else => unreachable, }, .ptr => try o.lowerPtr(arg_val, 0), - .slice => |slice| return o.builder.structConst(try o.lowerType(ty), &.{ - try o.lowerValue(slice.ptr), - try o.lowerValue(slice.len), + .slice => |slice| return o.builder.structConst(try o.lowerType(ty, repr), &.{ + try o.lowerValue(slice.ptr, repr), + try o.lowerValue(slice.len, repr), }), .opt => |opt| { comptime assert(optional_layout_version == 3); @@ -3600,7 +3480,7 @@ pub const Object = struct { if (!payload_ty.hasRuntimeBits(zcu)) { return non_null_bit; } - const llvm_ty = try o.lowerType(ty); + const llvm_ty = try o.lowerType(ty, repr); if (ty.optionalReprIsPayload(zcu)) return switch (opt.val) { .none => switch (llvm_ty.tag(&o.builder)) { .integer => try o.builder.intConst(llvm_ty, 0), @@ -3608,15 +3488,15 @@ pub const Object = struct { .structure => try o.builder.zeroInitConst(llvm_ty), else => unreachable, }, - else => |payload| try o.lowerValue(payload), + else => |payload| try o.lowerValue(payload, repr), }; assert(payload_ty.zigTypeTag(zcu) != .@"fn"); var fields: [3]Builder.Type = undefined; var vals: [3]Builder.Constant = undefined; vals[0] = switch (opt.val) { - .none => try o.builder.undefConst(try o.lowerType(payload_ty)), - else => |payload| try o.lowerValue(payload), + .none => try o.builder.undefConst(try o.lowerType(payload_ty, repr)), + else => |payload| try o.lowerValue(payload, repr), }; vals[1] = non_null_bit; fields[0] = vals[0].typeOf(&o.builder); @@ -3633,14 +3513,14 @@ pub const Object = struct { fields[0..llvm_ty_fields.len], ), vals[0..llvm_ty_fields.len]); }, - .bitpack => |bitpack| return o.lowerValue(bitpack.backing_int_val), + .bitpack => |bitpack| return o.lowerValue(bitpack.backing_int_val, repr), .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) { .array_type => |array_type| switch (aggregate.storage) { .bytes => |bytes| try o.builder.stringConst(try o.builder.string( bytes.toSlice(array_type.lenIncludingSentinel(), ip), )), .elems => |elems| { - const array_ty = try o.lowerType(ty); + const array_ty = try o.lowerType(ty, repr); const elem_ty = array_ty.childType(&o.builder); assert(elems.len == array_ty.aggregateLen(&o.builder)); @@ -3658,7 +3538,7 @@ pub const Object = struct { var need_unnamed = false; for (vals, fields, elems) |*result_val, *result_field, elem| { - result_val.* = try o.lowerValue(elem); + result_val.* = try o.lowerValue(elem, repr); result_field.* = result_val.typeOf(&o.builder); if (result_field.* != elem_ty) need_unnamed = true; } @@ -3670,7 +3550,7 @@ pub const Object = struct { .repeated_elem => |elem| { const len: usize = @intCast(array_type.len); const len_including_sentinel: usize = @intCast(array_type.lenIncludingSentinel()); - const array_ty = try o.lowerType(ty); + const array_ty = try o.lowerType(ty, repr); const elem_ty = array_ty.childType(&o.builder); const ExpectedContents = extern struct { @@ -3686,12 +3566,12 @@ pub const Object = struct { defer allocator.free(fields); var need_unnamed = false; - @memset(vals[0..len], try o.lowerValue(elem)); + @memset(vals[0..len], try o.lowerValue(elem, repr)); @memset(fields[0..len], vals[0].typeOf(&o.builder)); if (fields[0] != elem_ty) need_unnamed = true; if (array_type.sentinel != .none) { - vals[len] = try o.lowerValue(array_type.sentinel); + vals[len] = try o.lowerValue(array_type.sentinel, repr); fields[len] = vals[len].typeOf(&o.builder); if (fields[len] != elem_ty) need_unnamed = true; } @@ -3703,7 +3583,7 @@ pub const Object = struct { }, }, .vector_type => |vector_type| { - const vector_ty = try o.lowerType(ty); + const vector_ty = try o.lowerType(ty, repr); switch (aggregate.storage) { .bytes, .elems => { const ExpectedContents = [Builder.expected_fields_len]Builder.Constant; @@ -3718,7 +3598,7 @@ 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); + result_val.* = try o.lowerValue(elem, .by_value); }, .repeated_elem => unreachable, } @@ -3726,12 +3606,12 @@ pub const Object = struct { }, .repeated_elem => |elem| return o.builder.splatConst( vector_ty, - try o.lowerValue(elem), + try o.lowerValue(elem, .by_value), ), } }, .tuple_type => |tuple| { - const struct_ty = try o.lowerType(ty); + const struct_ty = try o.lowerType(ty, repr); const llvm_len = struct_ty.aggregateLen(&o.builder); const ExpectedContents = extern struct { @@ -3776,8 +3656,8 @@ pub const Object = struct { vals[llvm_index] = switch (aggregate.storage) { .bytes => |bytes| try o.builder.intConst(.i8, bytes.at(field_index, ip)), - .elems => |elems| try o.lowerValue(elems[field_index]), - .repeated_elem => |elem| try o.lowerValue(elem), + .elems => |elems| try o.lowerValue(elems[field_index], repr), + .repeated_elem => |elem| try o.lowerValue(elem, repr), }; fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) @@ -3806,7 +3686,7 @@ pub const Object = struct { }, .struct_type => { const struct_type = ip.loadStructType(ty.toIntern()); - const struct_ty = try o.lowerType(ty); + const struct_ty = try o.lowerType(ty, repr); assert(struct_type.layout != .@"packed"); const llvm_len = struct_ty.aggregateLen(&o.builder); @@ -3850,8 +3730,8 @@ pub const Object = struct { vals[llvm_index] = switch (aggregate.storage) { .bytes => |bytes| try o.builder.intConst(.i8, bytes.at(field_index, ip)), - .elems => |elems| try o.lowerValue(elems[field_index]), - .repeated_elem => |elem| try o.lowerValue(elem), + .elems => |elems| try o.lowerValue(elems[field_index], repr), + .repeated_elem => |elem| try o.lowerValue(elem, repr), }; fields[llvm_index] = vals[llvm_index].typeOf(&o.builder); if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index]) @@ -3881,9 +3761,9 @@ pub const Object = struct { else => unreachable, }, .un => |un| { - const union_ty = try o.lowerType(ty); + const union_ty = try o.lowerType(ty, repr); const layout = ty.unionGetLayout(zcu); - if (layout.payload_size == 0) return o.lowerValue(un.tag); + if (layout.payload_size == 0) return o.lowerValue(un.tag, repr); const union_obj = zcu.typeToUnion(ty).?; const container_layout = union_obj.layout; @@ -3904,7 +3784,7 @@ pub const Object = struct { const padding_len = layout.payload_size; break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8)); } - const payload = try o.lowerValue(un.val); + const payload = try o.lowerValue(un.val, repr); const payload_ty = payload.typeOf(&o.builder); if (payload_ty != union_ty.structFields(&o.builder)[ @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) @@ -3919,7 +3799,7 @@ pub const Object = struct { ); } else p: { assert(layout.tag_size == 0); - const union_val = try o.lowerValue(un.val); + const union_val = try o.lowerValue(un.val, repr); need_unnamed = true; break :p union_val; }; @@ -3929,7 +3809,7 @@ pub const Object = struct { try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty}) else union_ty, &.{payload}); - const tag = try o.lowerValue(un.tag); + const tag = try o.lowerValue(un.tag, repr); const tag_ty = tag.typeOf(&o.builder); var fields: [3]Builder.Type = undefined; var vals: [3]Builder.Constant = undefined; @@ -3983,8 +3863,8 @@ pub const Object = struct { }, .int => try o.builder.castConst( .inttoptr, - try o.builder.intConst(try o.lowerType(.usize), offset), - try o.lowerType(.fromInterned(ptr.ty)), + try o.builder.intConst(try o.lowerType(.usize, .by_value), offset), + try o.lowerType(.fromInterned(ptr.ty), .by_value), ), .eu_payload => |eu_ptr| try o.lowerPtr( eu_ptr, @@ -4031,7 +3911,7 @@ pub const Object = struct { @"addrspace": std.lang.AddressSpace, ) Allocator.Error!Builder.Constant { const addr: u64 = @"align".toByteUnits().?; - const llvm_usize = try o.lowerType(.usize); + const llvm_usize = try o.lowerType(.usize, .by_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); @@ -4068,17 +3948,18 @@ pub const Object = struct { if (gop.found_existing) { // Keep the greater of the two alignments. const llvm_variable = gop.value_ptr.*; - const old_align: InternPool.Alignment = .fromLlvm(llvm_variable.getAlignment(&o.builder)); - llvm_variable.setAlignment(old_align.maxStrict(@"align").toLlvm(), &o.builder); + const llvm_old_align = llvm_variable.getAlignment(&o.builder); + const llvm_new_align = llvm_old_align.max(@"align".toLlvm()); + 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); + const llvm_ty = try o.lowerType(uav_ty, .in_memory); const llvm_name = try o.builder.strtabStringFmt("__anon_{d}", .{@intFromEnum(uav_val)}); const llvm_variable = try o.builder.addVariable(llvm_name, llvm_ty, llvm_addrspace); gop.value_ptr.* = llvm_variable; - try llvm_variable.setInitializer(try o.lowerValue(uav_val), &o.builder); + 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); const llvm_global = llvm_variable.ptrConst(&o.builder).global; @@ -4150,7 +4031,7 @@ pub const Object = struct { .x86_64_interrupt, .x86_interrupt, => { - const child_type = try lowerType(o, Type.fromInterned(ptr_info.child)); + const child_type = try o.lowerType(.fromInterned(ptr_info.child), .in_memory); try attributes.addParamAttr(llvm_arg_i, .{ .byval = child_type }, &o.builder); }, } @@ -4172,14 +4053,15 @@ pub const Object = struct { o: *Object, attributes: *Builder.FunctionAttributes.Wip, llvm_arg_i: u32, - alignment: Builder.Alignment, byval: bool, - param_llvm_ty: Builder.Type, + 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 = param_llvm_ty }, &o.builder); + if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = llvm_param_ty }, &o.builder); } pub fn getErrorNameTable(o: *Object) Allocator.Error!Builder.Variable.Index { @@ -4204,7 +4086,7 @@ pub const Object = struct { pub fn getErrorsLen(o: *Object) Allocator.Error!Builder.Variable.Index { const builder = &o.builder; if (o.errors_len_variable == .none) { - const llvm_err_int_ty = try o.errorIntType(); + 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); @@ -4244,9 +4126,9 @@ pub const Object = struct { const ip = &zcu.intern_pool; const loaded_enum = ip.loadEnumType(enum_ty.toIntern()); - const llvm_usize_ty = try o.lowerType(.usize); - const llvm_ret_ty = try o.lowerType(.slice_const_u8_sentinel_0); - const llvm_int_ty = try o.lowerType(.fromInterned(loaded_enum.int_tag_type)); + 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); function_index.ptrConst(&o.builder).global.ptr(&o.builder).type = try o.builder.fnType(llvm_ret_ty, &.{llvm_int_ty}, .normal); @@ -4295,7 +4177,7 @@ pub const Object = struct { 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), + else => |tag_val_ip| try o.lowerValue(tag_val_ip, .by_value), }; try wip_switch.addCase(llvm_tag_val, return_block, &wip); @@ -4341,7 +4223,7 @@ pub const Object = struct { 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)); + 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 = try o.builder.fnType(.i1, &.{llvm_int_ty}, .normal); @@ -4368,7 +4250,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); + const llvm_tag_val = try o.lowerValue(tag_val_ip, .by_value); try wip_switch.addCase(llvm_tag_val, named_block, &wip); } } else { @@ -4405,13 +4287,6 @@ pub const Object = struct { toLlvmAddressSpace(.generic, o.zcu.getTarget()), ); } - - pub fn ptraddConst(o: *Object, wip: *Builder.WipFunction, ptr: Builder.Value, offset: u64) Allocator.Error!Builder.Value { - if (offset == 0) return ptr; - const llvm_usize_ty = try o.lowerType(.usize); - const offset_val = try o.builder.intValue(llvm_usize_ty, offset); - return wip.gep(.inbounds, .i8, ptr, &.{offset_val}, ""); - } }; const CallingConventionInfo = struct { @@ -4443,6 +4318,10 @@ pub fn toLlvmCallConv(cc: std.lang.CallingConvention, target: *const std.Target) std.lang.CallingConvention.CommonOptions, => .{ pl.incoming_stack_alignment, 0, 0 }, std.lang.CallingConvention.X86RegparmOptions => .{ pl.incoming_stack_alignment, pl.register_params, 0 }, + std.lang.CallingConvention.SpirvKernelOptions, + std.lang.CallingConvention.SpirvFragmentOptions, + std.lang.CallingConvention.SpirvMeshOptions, + => .{ null, 0, 0 }, else => @compileError("TODO: toLlvmCallConv" ++ @tagName(pl)), }, }; @@ -4586,6 +4465,8 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const .spirv_kernel, .spirv_fragment, .spirv_vertex, + .spirv_task, + .spirv_mesh, => null, }; } @@ -4666,8 +4547,8 @@ fn llvmAddrSpaceInfo(target: *const std.Target) []const AddrSpaceInfo { .wasm32, .wasm64 => &.{ .{ .zig = .generic, .llvm = Builder.AddrSpace.wasm.default, .force_in_data_layout = true }, .{ .zig = null, .llvm = Builder.AddrSpace.wasm.variable, .non_integral = true }, - .{ .zig = null, .llvm = Builder.AddrSpace.wasm.externref, .non_integral = true, .size = 8, .abi = 8 }, - .{ .zig = null, .llvm = Builder.AddrSpace.wasm.funcref, .non_integral = true, .size = 8, .abi = 8 }, + .{ .zig = .externref, .llvm = Builder.AddrSpace.wasm.externref, .non_integral = true, .size = 8, .abi = 8 }, + .{ .zig = .funcref, .llvm = Builder.AddrSpace.wasm.funcref, .non_integral = true, .size = 8, .abi = 8 }, }, .m68k => &.{ .{ .zig = .generic, .llvm = .default, .abi = 16, .pref = 32 }, diff --git a/src/codegen/llvm/FuncGen.zig b/src/codegen/llvm/FuncGen.zig index dd9f28d93e2a085f85f18f105576a8ebd6adfa7e..2c214c0c3259051d26588c207272f2da5b56f1aa 100644 --- a/src/codegen/llvm/FuncGen.zig +++ b/src/codegen/llvm/FuncGen.zig @@ -164,7 +164,7 @@ 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()); + return o.lowerValue(val.toIntern(), .by_value); } else { // We need a pointer to a global constant, i.e. a UAV. return o.lowerUavRef( @@ -175,7 +175,157 @@ fn resolveValue(self: *FuncGen, val: Value) Allocator.Error!Builder.Constant { } } -pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.CoveragePoint) TodoError!void { +/// Populates `fg.ret_ptr`, `fg.err_ret_trace`, and `fg.args` based on the parameters of the +/// function type, then generates the entire function body. +/// +/// The caller may initialize `fg.ret_ptr`, `fg.err_ret_trace`, and `fg.args` to undefined. +pub fn genMainBody(fg: *FuncGen) TodoError!void { + const o = fg.object; + const zcu = o.zcu; + const ip = &zcu.intern_pool; + const comp = zcu.comp; + const gpa = comp.gpa; + + const fn_ty: Type = .fromInterned(ip.getNav(fg.nav_index).resolved.?.type); + const fn_info = zcu.typeToFunc(fn_ty).?; + const param_types = fn_info.param_types.get(ip); + + var it = iterateParamTypes(o, fn_info); + + // Populate `fg.ret_ptr`... + fg.ret_ptr = switch (try fnReturnStrat(o, fn_info)) { + .sret => rp: { + defer it.llvm_index += 1; + break :rp fg.wip.arg(it.llvm_index); + }, + else => .none, + }; + // ...and `fg.err_ret_trace`... + if (fn_info.cc == .auto and comp.config.any_error_tracing) { + fg.err_ret_trace = fg.wip.arg(it.llvm_index); + it.llvm_index += 1; + } else { + fg.err_ret_trace = .none; + } + // ...and as for `fg.args`, we'll put all of the arguments into this ArrayList, and once that's + // done we'll use its buffer as `fg.args`. + var args: std.ArrayList(Builder.Value) = .empty; + defer args.deinit(gpa); + + while (try it.next()) |lowering| { + try args.ensureUnusedCapacity(gpa, 1); + + switch (lowering) { + .no_bits => continue, + .byval => { + assert(!it.byval_attr); + 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); + + if (isByRef(param_ty, zcu)) { + const alignment = param_ty.abiAlignment(zcu).toLlvm(); + const arg_ptr = try fg.buildZigAlloca(param_ty, .none); + // We don't need to handle non-ABI-sized integer types in memory here since they + // are never by-ref. + _ = try fg.wip.store(.normal, param, arg_ptr, alignment); + args.appendAssumeCapacity(arg_ptr); + } else { + args.appendAssumeCapacity(param); + } + }, + .byref, .byref_mut => { + const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); + const param = fg.wip.arg(it.llvm_index - 1); + + if (isByRef(param_ty, zcu)) { + args.appendAssumeCapacity(param); + } else { + args.appendAssumeCapacity(try fg.load(param, .none, param_ty, .normal)); + } + }, + .abi_sized_int => { + assert(!it.byval_attr); + const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); + const param = fg.wip.arg(it.llvm_index - 1); + + const alignment = param_ty.abiAlignment(zcu).toLlvm(); + const arg_ptr = try fg.buildZigAlloca(param_ty, .none); + _ = try fg.wip.store(.normal, param, arg_ptr, alignment); + + if (isByRef(param_ty, zcu)) { + args.appendAssumeCapacity(arg_ptr); + } else { + args.appendAssumeCapacity(try fg.load(arg_ptr, .none, param_ty, .normal)); + } + }, + .slice => { + assert(!it.byval_attr); + 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), + &.{ 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); + 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); + const arg_ptr = try fg.buildAlloca(llvm_ty, param_alignment.toLlvm()); + const llvm_args_start = it.llvm_index - it.types_len; + for (llvm_args_start.., it.offsets_buffer[0..it.types_len]) |llvm_arg_index, offset| { + const param = fg.wip.arg(@intCast(llvm_arg_index)); + const part_ptr = try fg.ptraddConst(arg_ptr, offset); + _ = try fg.wip.store(.normal, param, part_ptr, param_alignment.offset(offset).toLlvm()); + } + + if (isByRef(param_ty, zcu)) { + args.appendAssumeCapacity(arg_ptr); + } else { + args.appendAssumeCapacity(try fg.load(arg_ptr, .none, param_ty, .normal)); + } + }, + .float_array => { + const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); + const param = fg.wip.arg(it.llvm_index - 1); + + const alignment = param_ty.abiAlignment(zcu).toLlvm(); + const arg_ptr = try fg.buildZigAlloca(param_ty, .none); + _ = try fg.wip.store(.normal, param, arg_ptr, alignment); + + if (isByRef(param_ty, zcu)) { + args.appendAssumeCapacity(arg_ptr); + } else { + args.appendAssumeCapacity(try fg.load(arg_ptr, .none, param_ty, .normal)); + } + }, + .i32_array, .i64_array => { + const param_ty: Type = .fromInterned(param_types[it.zig_index - 1]); + const param = fg.wip.arg(it.llvm_index - 1); + + const alignment = param_ty.abiAlignment(zcu).toLlvm(); + const arg_ptr = try fg.buildAlloca(param.typeOfWip(&fg.wip), alignment); + _ = try fg.wip.store(.normal, param, arg_ptr, alignment); + + if (isByRef(param_ty, zcu)) { + args.appendAssumeCapacity(arg_ptr); + } else { + args.appendAssumeCapacity(try fg.load(arg_ptr, .none, param_ty, .normal)); + } + }, + } + } + + fg.args = args.items; + + try fg.genBody(fg.air.getMainBody(), .poi); +} + +fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.CoveragePoint) TodoError!void { const o = self.object; const zcu = self.object.zcu; const ip = &zcu.intern_pool; @@ -198,15 +348,16 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air try fuzz.pcs.append(gpa, pc); }, } - for (body, 0..) |inst, i| { + for (body) |inst| { if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue; const val: Builder.Value = switch (air_tags[@intFromEnum(inst)]) { // zig fmt: off - // No "scalarize" legalizations are enabled, so these instructions never appear. - .legalize_vec_elem_val => unreachable, - .legalize_vec_store_elem => unreachable, + // Required due to `.scalarize_bit_cast_vector_non_elementwise` being enabled. + .legalize_vec_elem_val => try self.airLegalizeVecElemVal(inst), + .legalize_vec_store_elem => try self.airLegalizeVecStoreElem(inst), + // No soft float legalizations are enabled. .legalize_compiler_rt_call => unreachable, @@ -309,29 +460,36 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air .is_err => try self.airIsErr(inst, .ne, false), .is_err_ptr => try self.airIsErr(inst, .ne, true), - .alloc => try self.airAlloc(inst), - .ret_ptr => try self.airRetPtr(inst), - .arg => try self.airArg(inst), - .bitcast => try self.airBitCast(inst), - .breakpoint => try self.airBreakpoint(inst), - .ret_addr => try self.airRetAddr(inst), - .frame_addr => try self.airFrameAddress(inst), - .@"try" => try self.airTry(inst, false), - .try_cold => try self.airTry(inst, true), - .try_ptr => try self.airTryPtr(inst, false), - .try_ptr_cold => try self.airTryPtr(inst, true), - .intcast => try self.airIntCast(inst, false), - .intcast_safe => try self.airIntCast(inst, true), - .trunc => try self.airTrunc(inst), - .fptrunc => try self.airFptrunc(inst), - .fpext => try self.airFpext(inst), - .load => try self.airLoad(inst), - .not => try self.airNot(inst), - .store => try self.airStore(inst, false), - .store_safe => try self.airStore(inst, true), - .assembly => try self.airAssembly(inst), - .slice_ptr => try self.airSliceField(inst, 0), - .slice_len => try self.airSliceField(inst, 1), + .alloc => try self.airAlloc(inst), + .ret_ptr => try self.airRetPtr(inst), + .arg => try self.airArg(inst), + .bit_cast => try self.airBitCast(inst), + .ptr_cast => try self.airNopCast(inst), + .ptr_from_int => try self.airPtrFromInt(inst), + .int_from_ptr => try self.airIntFromPtr(inst), + .error_cast => try self.airNopCast(inst), + .error_from_int => try self.airNopCast(inst), + .int_from_error => try self.airNopCast(inst), + .union_from_enum => try self.airUnionFromEnum(inst), + .breakpoint => try self.airBreakpoint(inst), + .ret_addr => try self.airRetAddr(inst), + .frame_addr => try self.airFrameAddress(inst), + .@"try" => try self.airTry(inst, false), + .try_cold => try self.airTry(inst, true), + .try_ptr => try self.airTryPtr(inst, false), + .try_ptr_cold => try self.airTryPtr(inst, true), + .int_cast => try self.airIntCast(inst, false), + .int_cast_safe => try self.airIntCast(inst, true), + .trunc => try self.airTrunc(inst), + .fptrunc => try self.airFptrunc(inst), + .fpext => try self.airFpext(inst), + .load => try self.airLoad(inst), + .not => try self.airNot(inst), + .store => try self.airStore(inst, false), + .store_safe => try self.airStore(inst, true), + .assembly => try self.airAssembly(inst), + .slice_ptr => try self.airSliceField(inst, 0), + .slice_len => try self.airSliceField(inst, 1), .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0), .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1), @@ -400,8 +558,8 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air .optional_payload_ptr => try self.airOptionalPayloadPtr(inst), .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst), - .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false), - .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true), + .unwrap_errunion_payload => try self.airErrUnionPayload(inst), + .unwrap_errunion_payload_ptr => try self.airErrUnionPayloadPtr(inst), .unwrap_errunion_err => try self.airErrUnionErr(inst, false), .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), @@ -409,9 +567,9 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air .set_err_return_trace => try self.airSetErrReturnTrace(inst), .save_err_return_trace_index => try self.airSaveErrReturnTraceIndex(inst), - .wrap_optional => try self.airWrapOptional(body[i..]), - .wrap_errunion_payload => try self.airWrapErrUnionPayload(body[i..]), - .wrap_errunion_err => try self.airWrapErrUnionErr(body[i..]), + .wrap_optional => try self.airWrapOptional(inst), + .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), + .wrap_errunion_err => try self.airWrapErrUnionErr(inst), .wasm_memory_size => try self.airWasmMemorySize(inst), .wasm_memory_grow => try self.airWasmMemoryGrow(inst), @@ -434,6 +592,7 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air .work_item_id => try self.airWorkItemId(inst), .work_group_size => try self.airWorkGroupSize(inst), .work_group_id => try self.airWorkGroupId(inst), + .spirv_runtime_array_len => unreachable, // Instructions that are known to always be `noreturn` based on their tag. .br => return self.airBr(inst), @@ -593,7 +752,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier break :llvm_fn try self.resolveInst(air_call.callee); }; const target = zcu.getTarget(); - const sret = firstParamSRet(fn_info, zcu, target); + const ret_strat = try fnReturnStrat(o, fn_info); var llvm_args = std.array_list.Managed(Builder.Value).init(self.gpa); defer llvm_args.deinit(); @@ -611,20 +770,21 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier .no_suspend, .always_inline, .compile_time => unreachable, } - const ret_ptr = if (sret) ret_ptr: { - const llvm_ret_ty = try o.lowerType(return_type); - try attributes.addParamAttr(0, .{ .sret = llvm_ret_ty }, &o.builder); + 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(); - const ret_ptr = try self.buildAlloca(llvm_ret_ty, alignment); - try llvm_args.append(ret_ptr); - break :ret_ptr ret_ptr; - } else ret_ptr: { - if (ccAbiPromoteInt(fn_info.cc, zcu, Type.fromInterned(fn_info.return_type))) |s| switch (s) { - .signed => try attributes.addRetAttr(.signext, &o.builder), - .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), - }; - break :ret_ptr null; + const ptr = try self.buildZigAlloca(return_type, .none); + try llvm_args.append(ptr); + break :sret_alloc ptr; + }, + else => sret_alloc: { + if (ccAbiPromoteInt(fn_info.cc, zcu, .fromInterned(fn_info.return_type))) |s| switch (s) { + .signed => try attributes.addRetAttr(.signext, &o.builder), + .unsigned => try attributes.addRetAttr(.zeroext, &o.builder), + }; + break :sret_alloc null; + }, }; const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing; @@ -640,9 +800,11 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier const arg = args[it.zig_index - 1]; const param_ty = self.typeOf(arg); const llvm_arg = try self.resolveInst(arg); - const llvm_param_ty = try o.lowerType(param_ty); 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 { @@ -656,10 +818,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier if (isByRef(param_ty, zcu)) { try llvm_args.append(llvm_arg); } else { - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const param_llvm_ty = llvm_arg.typeOfWip(&self.wip); - const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); - _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment); + 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); } }, @@ -668,15 +828,8 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier const param_ty = self.typeOf(arg); const llvm_arg = try self.resolveInst(arg); - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - const param_llvm_ty = try o.lowerType(param_ty); - const arg_ptr = try self.buildAlloca(param_llvm_ty, alignment); - if (isByRef(param_ty, zcu)) { - const loaded = try self.wip.load(.normal, param_llvm_ty, llvm_arg, alignment, ""); - _ = try self.wip.store(.normal, loaded, arg_ptr, alignment); - } else { - _ = try self.wip.store(.normal, llvm_arg, arg_ptr, alignment); - } + 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 => { @@ -693,9 +846,9 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier // 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 int_ptr = try self.buildAlloca(int_llvm_ty, alignment); - _ = try self.wip.store(.normal, llvm_arg, int_ptr, alignment); - const loaded = try self.wip.load(.normal, int_llvm_ty, int_ptr, alignment, ""); + 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); } }, @@ -710,19 +863,10 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier const arg = args[it.zig_index - 1]; const param_ty = self.typeOf(arg); const llvm_arg = try self.resolveInst(arg); - const is_by_ref = isByRef(param_ty, zcu); 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()); - if (is_by_ref) _ = try self.wip.callMemCpy( - arg_ptr, - param_alignment.toLlvm(), - llvm_arg, - param_alignment.toLlvm(), - try o.builder.intValue(try o.lowerType(.usize), param_ty.abiSize(zcu)), - .normal, - self.disable_intrinsics, - ) else _ = try self.wip.store(.normal, llvm_arg, arg_ptr, param_alignment.toLlvm()); + try self.store(arg_ptr, .none, llvm_arg, param_ty, .normal); 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| { @@ -734,35 +878,34 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier .float_array => |count| { const arg = args[it.zig_index - 1]; const arg_ty = self.typeOf(arg); - var llvm_arg = try self.resolveInst(arg); - const alignment = arg_ty.abiAlignment(zcu).toLlvm(); - if (!isByRef(arg_ty, zcu)) { - const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); - _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); - llvm_arg = ptr; - } + const arg_val = try self.resolveInst(arg); - const float_ty = try o.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, zcu).?); + 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 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 loaded = try self.wip.load(.normal, array_ty, llvm_arg, alignment, ""); + 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); - var llvm_arg = try self.resolveInst(arg); - const alignment = arg_ty.abiAlignment(zcu).toLlvm(); - if (!isByRef(arg_ty, zcu)) { - const ptr = try self.buildAlloca(llvm_arg.typeOfWip(&self.wip), alignment); - _ = try self.wip.store(.normal, llvm_arg, ptr, alignment); - llvm_arg = ptr; - } + const arg_val = try self.resolveInst(arg); - 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, llvm_arg, alignment, ""); + 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); }, }; @@ -772,7 +915,7 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier { // Add argument attributes. it = iterateParamTypes(o, fn_info); - it.llvm_index += @intFromBool(sret); + it.llvm_index += @intFromBool(ret_strat == .sret); it.llvm_index += @intFromBool(err_return_tracing); var remaining_inreg_int = cc_info.inreg_int_params; var remaining_inreg_float = cc_info.inreg_float_params; @@ -801,10 +944,8 @@ 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_llvm_ty = try o.lowerType(param_ty); - const alignment = param_ty.abiAlignment(zcu).toLlvm(); - try o.addByRefParamAttrs(&attributes, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); + const param_ty: Type = .fromInterned(fn_info.param_types.get(ip)[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), // No attributes needed for these. @@ -854,7 +995,7 @@ 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), + try o.lowerType(zig_fn_ty, .by_value), llvm_fn, llvm_args.items, "", @@ -864,45 +1005,27 @@ fn airCall(self: *FuncGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier return .none; } - if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits(zcu)) { + if (self.liveness.isUnused(inst)) { return .none; } - const llvm_ret_ty = try o.lowerType(return_type); - if (ret_ptr) |rp| { - if (isByRef(return_type, zcu)) { - return rp; - } else { - // our by-ref status disagrees with sret so we must load. - const return_alignment = return_type.abiAlignment(zcu).toLlvm(); - return self.wip.load(.normal, llvm_ret_ty, rp, return_alignment, ""); - } - } - - const abi_ret_ty = try lowerFnRetTy(o, fn_info); - - if (abi_ret_ty != llvm_ret_ty) { - // In this case the function return type is honoring the calling convention by having - // a different LLVM type than the usual one. We solve this here at the callsite - // by using our canonical type, then loading it if necessary. - const alignment = return_type.abiAlignment(zcu).toLlvm(); - const rp = try self.buildAlloca(abi_ret_ty, alignment); - _ = try self.wip.store(.normal, call, rp, alignment); - return if (isByRef(return_type, zcu)) - rp - else - try self.wip.load(.normal, llvm_ret_ty, rp, alignment, ""); - } + // We exit this `switch` if we have a pointer to the return value. + const ret_val_ptr: Builder.Value = switch (ret_strat) { + .void => return .none, + .by_val => return call, + .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); + break :ret_val_ptr ptr; + }, + }; if (isByRef(return_type, zcu)) { - // our by-ref status disagrees with sret so we must allocate, store, - // and return the allocation pointer. - const alignment = return_type.abiAlignment(zcu).toLlvm(); - const rp = try self.buildAlloca(llvm_ret_ty, alignment); - _ = try self.wip.store(.normal, call, rp, alignment); - return rp; + return ret_val_ptr; } else { - return call; + return self.load(ret_val_ptr, .none, return_type, .normal); } } @@ -912,7 +1035,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)); + const llvm_panic_fn_ty = try o.lowerType(.fromInterned(panic_func.ty), .by_value); const llvm_panic_fn_ref = try o.lowerNavRef(panic_func.owner_nav); @@ -936,72 +1059,24 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo const zcu = o.zcu; const ip = &zcu.intern_pool; const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; + const ret_ty = self.typeOf(un_op); - if (self.ret_ptr != .none) { - const operand = try self.resolveInst(un_op); - const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false; - if (val_is_undef and safety and !self.needMemsetWorkaround(ret_ty.abiSize(zcu))) { - const len = try o.builder.intValue(try o.lowerType(.usize), ret_ty.abiSize(zcu)); - _ = try self.wip.callMemSet( - self.ret_ptr, - ret_ty.abiAlignment(zcu).toLlvm(), - try o.builder.intValue(.i8, 0xaa), - len, - .normal, - self.disable_intrinsics, - ); - const owner_mod = self.ownerModule(); - if (owner_mod.valgrind) { - try self.valgrindMarkUndef(self.ret_ptr, len); - } - _ = try self.wip.retVoid(); - return; - } - - const unwrapped_operand = operand.unwrap(); - const unwrapped_ret = self.ret_ptr.unwrap(); - - // Return value was stored previously - if (unwrapped_operand == .instruction and unwrapped_ret == .instruction and unwrapped_operand.instruction == unwrapped_ret.instruction) { - _ = try self.wip.retVoid(); - return; - } - - try self.store( - self.ret_ptr, - .none, - operand, - ret_ty, - ); - _ = try self.wip.retVoid(); - return; - } const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?; - if (!ret_ty.hasRuntimeBits(zcu)) { - if (Type.fromInterned(fn_info.return_type).isError(zcu)) { - // Functions with an empty error set are emitted with an error code - // return type and return zero so they can be function pointers coerced - // to functions that return anyerror. - _ = try self.wip.ret(try o.builder.intValue(try o.errorIntType(), 0)); - } else { - _ = try self.wip.retVoid(); - } - return; - } - const abi_ret_ty = try lowerFnRetTy(o, fn_info); - const operand = try self.resolveInst(un_op); + const ret_strat = try fnReturnStrat(o, fn_info); const val_is_undef = if (un_op.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false; - const alignment = ret_ty.abiAlignment(zcu).toLlvm(); + const ret_ty_align = ret_ty.abiAlignment(zcu); if (val_is_undef and safety and !self.needMemsetWorkaround(ret_ty.abiSize(zcu))) { - const llvm_ret_ty = operand.typeOfWip(&self.wip); - const rp = try self.buildAlloca(llvm_ret_ty, alignment); - const len = try o.builder.intValue(try o.lowerType(.usize), ret_ty.abiSize(zcu)); + const rp = switch (self.ret_ptr) { + .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)); _ = try self.wip.callMemSet( rp, - alignment, + ret_ty_align.toLlvm(), try o.builder.intValue(.i8, 0xaa), len, .normal, @@ -1011,27 +1086,47 @@ fn airRet(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!vo if (owner_mod.valgrind) { try self.valgrindMarkUndef(rp, len); } - _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, rp, alignment, "")); + switch (ret_strat) { + .void => unreachable, // value is undef so return type cannot be OPV + .sret => { + // We just stored directly to `self.ret_ptr`. + _ = try self.wip.retVoid(); + }, + .by_val => { + const loaded = try self.load(rp, .none, ret_ty, .normal); + _ = try self.wip.ret(loaded); + }, + .mem_cast => |llvm_abi_ret_ty| { + const loaded = try self.wip.load(.normal, llvm_abi_ret_ty, rp, ret_ty_align.toLlvm(), ""); + _ = try self.wip.ret(loaded); + }, + } return; } - if (isByRef(ret_ty, zcu)) { - // operand is a pointer however self.ret_ptr is null so that means - // we need to return a value. - _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, operand, alignment, "")); - return; + switch (ret_strat) { + .void => _ = try self.wip.retVoid(), + .sret => { + const operand = try self.resolveInst(un_op); + try self.store(self.ret_ptr, .none, operand, ret_ty, .normal); + _ = try self.wip.retVoid(); + }, + .by_val => { + assert(!isByRef(ret_ty, zcu)); + const operand = try self.resolveInst(un_op); + _ = try self.wip.ret(operand); + }, + .mem_cast => |llvm_ret_ty| { + const operand = try self.resolveInst(un_op); + const ptr: Builder.Value = if (!isByRef(ret_ty, zcu)) ptr: { + const ptr = try self.buildZigAlloca(ret_ty, .none); + try self.store(ptr, .none, operand, ret_ty, .normal); + break :ptr ptr; + } else operand; + const ret_val = try self.wip.load(.normal, llvm_ret_ty, ptr, ret_ty_align.toLlvm(), ""); + _ = try self.wip.ret(ret_val); + }, } - - const llvm_ret_ty = operand.typeOfWip(&self.wip); - if (abi_ret_ty == llvm_ret_ty) { - _ = try self.wip.ret(operand); - return; - } - - const rp = try self.buildAlloca(llvm_ret_ty, alignment); - _ = try self.wip.store(.normal, operand, rp, alignment); - _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, rp, alignment, "")); - return; } fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!void { @@ -1042,33 +1137,32 @@ fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!void { const ptr_ty = self.typeOf(un_op); const ret_ty = ptr_ty.childType(zcu); const fn_info = zcu.typeToFunc(.fromInterned(ip.getNav(self.nav_index).resolved.?.type)).?; - if (!ret_ty.hasRuntimeBits(zcu)) { - if (Type.fromInterned(fn_info.return_type).isError(zcu)) { - // Functions with an empty error set are emitted with an error code - // return type and return zero so they can be function pointers coerced - // to functions that return anyerror. - _ = try self.wip.ret(try o.builder.intValue(try o.errorIntType(), 0)); - } else { - _ = try self.wip.retVoid(); - } - return; - } - if (self.ret_ptr != .none) { - _ = try self.wip.retVoid(); - return; - } const ptr = try self.resolveInst(un_op); - const abi_ret_ty = try lowerFnRetTy(o, fn_info); - const alignment = ret_ty.abiAlignment(zcu).toLlvm(); - _ = try self.wip.ret(try self.wip.load(.normal, abi_ret_ty, ptr, alignment, "")); - return; + switch (try fnReturnStrat(o, fn_info)) { + .void => _ = try self.wip.retVoid(), + .sret => { + assert(self.ret_ptr != .none); + _ = try self.wip.retVoid(); + }, + .by_val => { + assert(self.ret_ptr == .none); + const loaded = try self.load(ptr, .none, ret_ty, .normal); + _ = try self.wip.ret(loaded); + }, + .mem_cast => |llvm_abi_ret_ty| { + assert(self.ret_ptr == .none); + const ret_ty_align = ret_ty.abiAlignment(zcu); + const loaded = try self.wip.load(.normal, llvm_abi_ret_ty, ptr, ret_ty_align.toLlvm(), ""); + _ = try self.wip.ret(loaded); + }, + } } fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const ty_op = self.air.instructions.items(.data)[@intFromEnum(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); + const llvm_arg_ty = try self.object.lowerType(arg_ty, .by_value); return self.wip.vaArg(list, llvm_arg_ty, ""); } @@ -1079,16 +1173,14 @@ fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const src_list = try self.resolveInst(ty_op.operand); const va_list_ty = ty_op.ty.toType(); - const llvm_va_list_ty = try o.lowerType(va_list_ty); - const result_alignment = va_list_ty.abiAlignment(zcu).toLlvm(); - const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); + const dest_list = try self.buildZigAlloca(va_list_ty, .none); _ = try self.wip.callIntrinsic(.normal, .none, .va_copy, &.{dest_list.typeOfWip(&self.wip)}, &.{ dest_list, src_list }, ""); return if (isByRef(va_list_ty, zcu)) dest_list else - try self.wip.load(.normal, llvm_va_list_ty, dest_list, result_alignment, ""); + try self.load(dest_list, .none, va_list_ty, .normal); } fn airCVaEnd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -1103,16 +1195,14 @@ fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Val const o = self.object; const zcu = o.zcu; const va_list_ty = self.typeOfIndex(inst); - const llvm_va_list_ty = try o.lowerType(va_list_ty); - const result_alignment = va_list_ty.abiAlignment(zcu).toLlvm(); - const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); + const dest_list = try self.buildZigAlloca(va_list_ty, .none); _ = try self.wip.callIntrinsic(.normal, .none, .va_start, &.{dest_list.typeOfWip(&self.wip)}, &.{dest_list}, ""); return if (isByRef(va_list_ty, zcu)) dest_list else - try self.wip.load(.normal, llvm_va_list_ty, dest_list, result_alignment, ""); + try self.load(dest_list, .none, va_list_ty, .normal); } fn airCmp( @@ -1146,13 +1236,7 @@ fn airCmpLteErrorsLen(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Buil const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); const errors_len_ptr = try o.getErrorsLen(); - const errors_len_val = try self.wip.load( - .normal, - try o.errorIntType(), - errors_len_ptr.toValue(&o.builder), - Type.errorAbiAlignment(o.zcu).toLlvm(), - "", - ); + const errors_len_val = try self.load(errors_len_ptr.toValue(&o.builder), .none, .anyerror, .normal); return self.wip.icmp(.ule, operand, errors_len_val, ""); } @@ -1290,18 +1374,10 @@ fn lowerBlock( // Create a phi node only if the block returns a value. if (have_block_result) { - const raw_llvm_ty = try o.lowerType(inst_ty); - const llvm_ty: Builder.Type = ty: { - // If the zig tag type is a function, this represents an actual function body; not - // a pointer to it. LLVM IR allows the call instruction to use function bodies instead - // of function pointers, however the phi makes it a runtime value and therefore - // the LLVM type has to be wrapped in a pointer. - if (inst_ty.zigTypeTag(zcu) == .@"fn" or isByRef(inst_ty, zcu)) { - break :ty .ptr; - } - break :ty raw_llvm_ty; + const llvm_ty: Builder.Type = switch (isByRef(inst_ty, zcu)) { + true => .ptr, + false => try o.lowerType(inst_ty, .by_value), }; - parent_bb.ptr(&self.wip).incoming = @intCast(breaks.list.len); const phi = try self.wip.phi(llvm_ty, ""); phi.finish(breaks.list.items(.val), breaks.list.items(.bb), &self.wip); @@ -1407,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), + try o.lowerType(.usize, .by_value), "", ); const target_ptr_ptr = try self.ptraddScaled( @@ -1432,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); + const llvm_usize = try o.lowerType(.usize, .by_value); const cond_int = if (cond_ty.zigTypeTag(zcu) == .pointer) try self.wip.cast(.ptrtoint, cond, llvm_usize, "") else @@ -1627,37 +1703,27 @@ fn lowerTry( const zcu = o.zcu; const payload_ty = err_union_ty.errorUnionPayload(zcu); const payload_has_bits = payload_ty.hasRuntimeBits(zcu); - const error_type = try o.errorIntType(); - const err_set_align: InternPool.Alignment, const payload_align: InternPool.Alignment = if (operand_is_ptr) .{ - operand_ptr_align.minStrict(Type.anyerror.abiAlignment(zcu)), - operand_ptr_align.minStrict(payload_ty.abiAlignment(zcu)), - } else .{ .none, .none }; + const operand_align: InternPool.Alignment = if (operand_is_ptr) operand_ptr_align else err_union_ty.abiAlignment(zcu); if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) { const loaded = loaded: { - const access_kind: Builder.MemoryAccessKind = - if (err_union_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; - - if (!payload_has_bits) { - break :loaded if (operand_is_ptr) - try fg.wip.load(access_kind, error_type, err_union, err_set_align.toLlvm(), "") - else - err_union; + if (payload_has_bits) { + assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload has no bits + } else if (!operand_is_ptr) { + break :loaded err_union; } - assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload has no bits const offset = codegen.errUnionErrorOffset(payload_ty, zcu); const err_field_ptr = try fg.ptraddConst(err_union, offset); - break :loaded try fg.wip.load( - if (operand_is_ptr) access_kind else .normal, - error_type, + break :loaded try fg.load( err_field_ptr, - err_set_align.toLlvm(), - "", + operand_align.offset(offset), + .anyerror, + if (err_union_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, ); }; - const zero = try o.builder.intValue(error_type, 0); + const zero = try o.builder.intValue(try o.errorIntType(.by_value), 0); const is_err = try fg.wip.icmp(.ne, loaded, zero, ""); const return_block = try fg.wip.block(1, "TryRet"); @@ -1671,15 +1737,18 @@ fn lowerTry( fg.wip.cursor = .{ .block = continue_block }; } if (is_unused) return .none; - if (!payload_has_bits) return if (operand_is_ptr) err_union else .none; - assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload has no bits - const payload_ptr = try fg.ptraddConst(err_union, codegen.errUnionPayloadOffset(payload_ty, zcu)); + + if (!operand_is_ptr) { + assert(payload_has_bits); // otherwise the result should be comptime-known + assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload has no bits + } + + const offset = codegen.errUnionPayloadOffset(payload_ty, zcu); + const payload_ptr = try fg.ptraddConst(err_union, offset); if (operand_is_ptr) { return payload_ptr; - } else if (isByRef(payload_ty, zcu)) { - return fg.loadByRef(payload_ptr, payload_ty, payload_align.toLlvm(), .normal); } else { - return fg.wip.load(.normal, try o.lowerType(payload_ty), payload_ptr, payload_align.toLlvm(), ""); + return fg.load(payload_ptr, operand_align.offset(offset), payload_ty, .normal); } } @@ -1791,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()), - .max = try o.lowerValue(max.toIntern()), + .min = try o.lowerValue(min.toIntern(), .by_value), + .max = try o.lowerValue(max.toIntern(), .by_value), .in_bounds_hint = if (table_includes_else) .none else switch (switch_br.getElseHint()) { .none, .cold => .none, .unpredictable => .unpredictable, @@ -1950,9 +2019,9 @@ fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder const ty_op = self.air.instructions.items(.data)[@intFromEnum(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); + const llvm_usize = try o.lowerType(.usize, .by_value); const len = try o.builder.intValue(llvm_usize, array_ty.arrayLen(zcu)); - const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst)); + const slice_llvm_ty = try o.lowerType(self.typeOfIndex(inst), .by_value); const operand = try self.resolveInst(ty_op.operand); return self.wip.buildAggregate(slice_llvm_ty, &.{ operand, len }, ""); } @@ -1969,7 +2038,7 @@ fn airFloatFromInt(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value const dest_ty = self.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(zcu); - const dest_llvm_ty = try o.lowerType(dest_ty); + 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( @@ -2037,7 +2106,7 @@ fn airIntFromFloat( const dest_ty = self.typeOfIndex(inst); const dest_scalar_ty = dest_ty.scalarType(zcu); - const dest_llvm_ty = try o.lowerType(dest_ty); + const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); if (intrinsicsAllowed(operand_scalar_ty, target)) { // TODO set fast math flag @@ -2071,7 +2140,7 @@ fn airIntFromFloat( compiler_rt_dest_abbrev, }); - const operand_llvm_ty = try o.lowerType(operand_ty); + 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, @@ -2096,7 +2165,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); + const llvm_usize = try o.lowerType(.usize, .by_value); switch (ty.ptrSize(zcu)) { .slice => { const len = try fg.wip.extractValue(ptr, &.{1}, ""); @@ -2143,11 +2212,7 @@ fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder const elem_align = slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu)); const access_kind: Builder.MemoryAccessKind = if (slice_info.flags.is_volatile) .@"volatile" else .normal; self.maybeMarkAllowZeroAccess(slice_info); - if (isByRef(elem_ty, zcu)) { - return self.loadByRef(ptr, elem_ty, elem_align.toLlvm(), access_kind); - } else { - return self.loadTruncate(access_kind, elem_ty, ptr, elem_align.toLlvm()); - } + return self.load(ptr, elem_align, elem_ty, access_kind); } fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -2172,18 +2237,41 @@ fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder const elem_ty = array_ty.childType(zcu); if (isByRef(array_ty, zcu)) { const elem_ptr = try self.ptraddScaled(array_llvm_val, rhs, elem_ty.abiSize(zcu)); - if (isByRef(elem_ty, zcu)) { - const elem_align = elem_ty.abiAlignment(zcu).toLlvm(); - return self.loadByRef(elem_ptr, elem_ty, elem_align, .normal); - } else { - return self.loadTruncate(.normal, elem_ty, elem_ptr, .default); - } + return self.load(elem_ptr, .none, elem_ty, .normal); } // This branch can be reached for vectors, which are always by-value. return self.wip.extractElement(array_llvm_val, rhs, ""); } +fn airLegalizeVecElemVal(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const bin_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; + const vec = try fg.resolveInst(bin_op.lhs); + const index = try fg.resolveInst(bin_op.rhs); + return fg.wip.extractElement(vec, index, ""); +} +fn airLegalizeVecStoreElem(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const zcu = fg.object.zcu; + + const pl_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; + const extra = fg.air.extraData(Air.Bin, pl_op.payload).data; + + const ptr_ty = fg.typeOf(pl_op.operand); + const vec_ty = ptr_ty.childType(zcu); + + const ptr_align = ptr_ty.ptrAlignment(zcu); + + const vec_ptr = try fg.resolveInst(pl_op.operand); + const index = try fg.resolveInst(extra.lhs); + const elem = try fg.resolveInst(extra.rhs); + + const old_vec = try fg.load(vec_ptr, ptr_align, vec_ty, .normal); + const new_vec = try fg.wip.insertElement(old_vec, elem, index, ""); + try fg.store(vec_ptr, ptr_align, new_vec, vec_ty, .normal); + + return .none; +} + fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const zcu = self.object.zcu; const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; @@ -2196,8 +2284,8 @@ fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.V return self.load( try self.ptraddScaled(base_ptr, rhs, elem_ty.abiSize(zcu)), + ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu)), elem_ty, - ptr_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu)).toLlvm(), if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, ); } @@ -2213,9 +2301,6 @@ fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.V const base_ptr = try self.resolveInst(bin_op.lhs); const rhs = try self.resolveInst(bin_op.rhs); - const elem_ptr = ty_pl.ty.toType(); - if (elem_ptr.ptrInfo(zcu).flags.vector_index != .none) return base_ptr; - return self.ptraddScaled(base_ptr, rhs, elem_ty.abiSize(zcu)); } @@ -2278,7 +2363,7 @@ fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build }, .float => { // bitcast int->float - return self.wip.cast(.bitcast, field_int_val, try o.lowerType(field_ty), ""); + return self.wip.cast(.bitcast, field_int_val, try o.lowerType(field_ty, .by_value), ""); }, } } @@ -2293,11 +2378,7 @@ fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const field_ptr = try self.ptraddConst(struct_llvm_val, offset); const field_ptr_align = struct_ptr_align.offset(offset); - if (isByRef(field_ty, zcu)) { - return self.loadByRef(field_ptr, field_ty, field_ptr_align.toLlvm(), .normal); - } else { - return self.loadTruncate(.normal, field_ty, field_ptr, field_ptr_align.toLlvm()); - } + return self.load(field_ptr, field_ptr_align, field_ty, .normal); } fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -2312,8 +2393,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()); - const llvm_usize = try o.lowerType(.usize); + const res_ty = try o.lowerType(ty_pl.ty.toType(), .by_value); + const llvm_usize = try o.lowerType(.usize, .by_value); const field_ptr_int = try self.wip.cast(.ptrtoint, field_ptr, llvm_usize, ""); const base_ptr_int = try self.wip.bin( @@ -2437,9 +2518,8 @@ fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index, is_arg: bool) Allocator.Er // 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. - const alignment = operand_ty.abiAlignment(zcu).toLlvm(); - const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment); - _ = try self.wip.store(.normal, operand, alloca, alignment); + const alloca = try self.buildZigAlloca(operand_ty, .none); + try self.store(alloca, .none, operand, operand_ty, .normal); _ = try self.wip.callIntrinsic( .normal, .none, @@ -2512,7 +2592,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { var llvm_param_i: usize = 0; var total_i: usize = 0; - var name_map: std.StringArrayHashMapUnmanaged(u16) = .empty; + var name_map: std.array_hash_map.String(u16) = .empty; try name_map.ensureUnusedCapacity(arena, max_param_count); var it = unwrapped_asm.iterateOutputs(); @@ -2530,7 +2610,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)); + const elem_llvm_ty = try o.lowerType(output_ty.childType(zcu), .by_value); switch (constraint[0]) { '=' => {}, @@ -2568,7 +2648,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); + llvm_ret_types[llvm_ret_i] = try o.lowerType(ret_ty, .by_value); llvm_ret_i += 1; } @@ -2607,9 +2687,8 @@ 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); - const load_inst = - try self.wip.load(.normal, arg_llvm_ty, arg_llvm_value, alignment, ""); + const arg_llvm_ty = try o.lowerType(arg_ty, .by_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; } @@ -2620,7 +2699,7 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { } else { const alignment = arg_ty.abiAlignment(zcu).toLlvm(); const arg_ptr = try self.buildAlloca(arg_llvm_value.typeOfWip(&self.wip), alignment); - _ = try self.wip.store(.normal, arg_llvm_value, arg_ptr, alignment); + try self.store(arg_ptr, .none, arg_llvm_value, arg_ty, .normal); llvm_param_values[llvm_param_i] = arg_ptr; llvm_param_types[llvm_param_i] = arg_ptr.typeOfWip(&self.wip); } @@ -2648,7 +2727,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)); + break :blk try o.lowerType(if (is_by_ref) arg_ty else arg_ty.childType(zcu), .by_value); } else .none; llvm_param_i += 1; @@ -2662,19 +2741,13 @@ 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)); + const llvm_elem_ty = try o.lowerType(rw_ty.childType(zcu), .by_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); } else { - const alignment = rw_ty.abiAlignment(zcu).toLlvm(); - const loaded = try self.wip.load( - if (rw_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, - llvm_elem_ty, - llvm_rw_vals[output.index], - alignment, - "", - ); + const access_kind: Builder.MemoryAccessKind = if (rw_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; + const loaded = try self.load(llvm_rw_vals[output.index], .none, rw_ty.childType(zcu), access_kind); llvm_param_values[llvm_param_i] = loaded; llvm_param_types[llvm_param_i] = llvm_elem_ty; } @@ -2834,12 +2907,12 @@ fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) TodoError!Builder.Value { if (output != .none) { const output_ptr = try self.resolveInst(output); const output_ptr_ty = self.typeOf(output); - const alignment = output_ptr_ty.ptrAlignment(zcu).toLlvm(); - _ = try self.wip.store( - if (output_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, - output_value, + try self.store( output_ptr, - alignment, + output_ptr_ty.ptrAlignment(zcu), + output_value, + output_ptr_ty.childType(zcu), + if (output_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, ); } else { ret_val = output_value; @@ -2862,7 +2935,6 @@ fn airIsNonNull( const operand = try self.resolveInst(un_op); const operand_ty = self.typeOf(un_op); const optional_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty; - const optional_llvm_ty = try o.lowerType(optional_ty); const payload_ty = optional_ty.optionalChild(zcu); const access_kind: Builder.MemoryAccessKind = @@ -2872,7 +2944,7 @@ fn airIsNonNull( if (optional_ty.optionalReprIsPayload(zcu)) { const loaded = if (operand_is_ptr) - try self.wip.load(access_kind, optional_llvm_ty, operand, operand_ty.ptrAlignment(zcu).toLlvm(), "") + try self.load(operand, operand_ty.ptrAlignment(zcu), optional_ty, access_kind) else operand; if (payload_ty.isSlice(zcu)) { @@ -2883,14 +2955,14 @@ 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(optional_llvm_ty), ""); + return self.wip.icmp(cond, loaded, try o.builder.zeroInitValue(try o.lowerType(optional_ty, .by_value)), ""); } comptime assert(optional_layout_version == 3); if (!payload_ty.hasRuntimeBits(zcu)) { const loaded = if (operand_is_ptr) - try self.wip.load(access_kind, optional_llvm_ty, operand, operand_ty.ptrAlignment(zcu).toLlvm(), "") + try self.load(operand, operand_ty.ptrAlignment(zcu), optional_ty, access_kind) else operand; return self.wip.icmp(cond, loaded, try o.builder.intValue(.i8, 0), ""); @@ -2912,8 +2984,7 @@ 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 error_type = try o.errorIntType(); - const zero = try o.builder.intValue(error_type, 0); + const zero_err = try o.builder.intValue(try o.errorIntType(.by_value), 0); const access_kind: Builder.MemoryAccessKind = if (operand_is_ptr and operand_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -2931,10 +3002,10 @@ fn airIsErr( if (!payload_ty.hasRuntimeBits(zcu)) { const loaded = if (operand_is_ptr) - try self.wip.load(access_kind, try o.lowerType(err_union_ty), operand, operand_ty.ptrAlignment(zcu).toLlvm(), "") + try self.load(operand, operand_ty.ptrAlignment(zcu), err_union_ty, access_kind) else operand; - return self.wip.icmp(cond, loaded, zero, ""); + return self.wip.icmp(cond, loaded, zero_err, ""); } assert(isByRef(err_union_ty, zcu)); // error unions with runtime bits are always by-ref @@ -2943,8 +3014,8 @@ fn airIsErr( else .none; const err_field_ptr = try self.ptraddConst(operand, codegen.errUnionErrorOffset(payload_ty, zcu)); - const loaded = try self.wip.load(access_kind, error_type, err_field_ptr, err_align.toLlvm(), ""); - return self.wip.icmp(cond, loaded, zero, ""); + const loaded = try self.load(err_field_ptr, err_align, .anyerror, access_kind); + return self.wip.icmp(cond, loaded, zero_err, ""); } fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -2965,7 +3036,6 @@ fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) Allocator.Erro const optional_ptr_ty = self.typeOf(ty_op.operand); const optional_ty = optional_ptr_ty.childType(zcu); const payload_ty = optional_ty.optionalChild(zcu); - const non_null_bit = try o.builder.intValue(.i8, 1); const access_kind: Builder.MemoryAccessKind = if (optional_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -2975,7 +3045,7 @@ fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) Allocator.Erro // We have a pointer to a i8. We need to set it to 1 and then return the same pointer. // Default alignment store because align of the non null bit is 1 anyway. - _ = try self.wip.store(access_kind, non_null_bit, operand, .default); + try self.store(operand, .@"1", .true, .bool, access_kind); return operand; } if (optional_ty.optionalReprIsPayload(zcu)) { @@ -2991,7 +3061,7 @@ fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) Allocator.Erro self.maybeMarkAllowZeroAccess(optional_ptr_ty.ptrInfo(zcu)); // Default alignment store because align of the non null bit is 1 anyway. - _ = try self.wip.store(access_kind, non_null_bit, non_null_ptr, .default); + try self.store(non_null_ptr, .@"1", .true, .bool, access_kind); // Then return the payload pointer (only if it's used). if (self.liveness.isUnused(inst)) return .none; @@ -3015,31 +3085,29 @@ fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Buil return self.optPayloadHandle(operand, optional_ty, false); } -fn airErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index, operand_is_ptr: bool) Allocator.Error!Builder.Value { - const o = self.object; +fn airErrUnionPayload(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const o = fg.object; const zcu = o.zcu; - const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const operand = try self.resolveInst(ty_op.operand); - const operand_ty = self.typeOf(ty_op.operand); - const err_union_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty; - const result_ty = self.typeOfIndex(inst); - const payload_ty = if (operand_is_ptr) result_ty.childType(zcu) else result_ty; + const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const operand = try fg.resolveInst(ty_op.operand); + const err_union_ty = fg.typeOf(ty_op.operand); + const payload_ty = fg.typeOfIndex(inst); - if (!payload_ty.hasRuntimeBits(zcu)) { - return if (operand_is_ptr) operand else .none; - } - const payload_ptr = try self.ptraddConst(operand, codegen.errUnionPayloadOffset(payload_ty, zcu)); - if (operand_is_ptr) { - return payload_ptr; - } + assert(payload_ty.hasRuntimeBits(zcu)); assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload lacks runtime bits - const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm(); - if (isByRef(payload_ty, zcu)) { - return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); - } else { - const payload_llvm_ty = try o.lowerType(payload_ty); - return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); - } + + const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); + const payload_ptr = try fg.ptraddConst(operand, payload_offset); + return fg.load(payload_ptr, err_union_ty.abiAlignment(zcu).offset(payload_offset), payload_ty, .normal); +} + +fn airErrUnionPayloadPtr(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const o = fg.object; + const zcu = o.zcu; + const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const operand = try fg.resolveInst(ty_op.operand); + const payload_ty = fg.typeOfIndex(inst).childType(zcu); + return fg.ptraddConst(operand, codegen.errUnionPayloadOffset(payload_ty, zcu)); } fn airErrUnionErr( @@ -3052,40 +3120,28 @@ fn airErrUnionErr( const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); const operand_ty = self.typeOf(ty_op.operand); - const error_type = try o.errorIntType(); const err_union_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty; - if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) { - if (operand_is_ptr) { - return operand; - } else { - return o.builder.intValue(error_type, 0); - } - } const access_kind: Builder.MemoryAccessKind = if (operand_is_ptr and operand_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; const payload_ty = err_union_ty.errorUnionPayload(zcu); - if (!payload_ty.hasRuntimeBits(zcu)) { - if (!operand_is_ptr) return operand; - self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); - - return self.wip.load(access_kind, error_type, operand, operand_ty.ptrAlignment(zcu).toLlvm(), ""); + if (payload_ty.hasRuntimeBits(zcu)) { + assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload lacks runtime bits + } else if (!operand_is_ptr) { + return operand; } - assert(isByRef(err_union_ty, zcu)); // error unions are by-ref unless the payload lacks runtime bits - if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); - const err_align: InternPool.Alignment = a: { - const err_abi_align = Type.anyerror.abiAlignment(zcu); - if (!operand_is_ptr) break :a err_abi_align; - break :a err_abi_align.minStrict(operand_ty.ptrAlignment(zcu)); - }; + const ptr_align = if (operand_is_ptr) operand_ty.ptrAlignment(zcu) else err_union_ty.abiAlignment(zcu); - const err_field_ptr = try self.ptraddConst(operand, codegen.errUnionErrorOffset(payload_ty, zcu)); - return self.wip.load(access_kind, error_type, err_field_ptr, err_align.toLlvm(), ""); + const err_offset = codegen.errUnionErrorOffset(payload_ty, zcu); + const err_align = ptr_align.offset(err_offset); + const err_ptr = try self.ptraddConst(operand, err_offset); + + return self.load(err_ptr, err_align, .anyerror, access_kind); } fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -3098,7 +3154,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(), 0); + const non_error_val = try o.builder.intValue(try o.errorIntType(.by_value), 0); const access_kind: Builder.MemoryAccessKind = if (err_union_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -3106,10 +3162,10 @@ fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) Allocator.Erro self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu)); { - const error_align = Type.anyerror.abiAlignment(zcu).minStrict(err_union_ptr_align).toLlvm(); // First set the non-error value. - const error_ptr = try self.ptraddConst(operand, codegen.errUnionErrorOffset(payload_ty, zcu)); - _ = try self.wip.store(access_kind, non_error_val, error_ptr, error_align); + const error_off = codegen.errUnionErrorOffset(payload_ty, zcu); + const error_ptr = try self.ptraddConst(operand, error_off); + try self.store(error_ptr, err_union_ptr_align.offset(error_off), non_error_val, .anyerror, access_kind); } // Then return the payload pointer (only if it is used). @@ -3141,127 +3197,73 @@ fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) Allocator.Er const field_offset = struct_ty.structFieldOffset(field_index, zcu); const field_align = struct_ty.abiAlignment(zcu).offset(field_offset); const field_ptr = try self.ptraddConst(self.err_ret_trace, field_offset); - return self.load(field_ptr, field_ty, field_align.toLlvm(), .normal); + return self.load(field_ptr, field_align, field_ty, .normal); } -/// As an optimization, we want to avoid unnecessary copies of -/// error union/optional types when returning from a function. -/// Here, we scan forward in the current block, looking to see -/// if the next instruction is a return (ignoring debug instructions). -/// -/// The first instruction of `body_tail` is a wrap instruction. -fn isNextRet( - self: *FuncGen, - body_tail: []const Air.Inst.Index, -) bool { - const air_tags = self.air.instructions.items(.tag); - for (body_tail[1..]) |body_inst| { - switch (air_tags[@intFromEnum(body_inst)]) { - .ret => return true, - .dbg_stmt => continue, - else => return false, - } - } - // The only way to get here is to hit the end of a loop instruction - // (implicit repeat). - return false; -} - -fn airWrapOptional(self: *FuncGen, body_tail: []const Air.Inst.Index) Allocator.Error!Builder.Value { +fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const o = self.object; const zcu = o.zcu; - const inst = body_tail[0]; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const payload_ty = self.typeOf(ty_op.operand); - const non_null_bit = try o.builder.intValue(.i8, 1); comptime assert(optional_layout_version == 3); assert(payload_ty.hasRuntimeBits(zcu)); const operand = try self.resolveInst(ty_op.operand); const optional_ty = self.typeOfIndex(inst); if (optional_ty.optionalReprIsPayload(zcu)) return operand; assert(isByRef(optional_ty, zcu)); // optionals with runtime bits are by-ref unless `optionalReprIsPayload` - const llvm_optional_ty = try o.lowerType(optional_ty); - const optional_ptr = if (self.isNextRet(body_tail)) - self.ret_ptr - else brk: { - const alignment = optional_ty.abiAlignment(zcu).toLlvm(); - const optional_ptr = try self.buildAlloca(llvm_optional_ty, alignment); - break :brk optional_ptr; - }; + const optional_ptr = try self.buildZigAlloca(optional_ty, .none); const payload_ptr = optional_ptr; // payload always at offset 0 - try self.store( - payload_ptr, - .none, - operand, - payload_ty, - ); + try self.store(payload_ptr, .none, operand, payload_ty, .normal); + // Non-null bit immediately after payload (no padding because the bit has alignment 1). const non_null_ptr = try self.ptraddConst(optional_ptr, payload_ty.abiSize(zcu)); - _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default); + try self.store(non_null_ptr, .none, .true, .bool, .normal); + return optional_ptr; } -fn airWrapErrUnionPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) Allocator.Error!Builder.Value { +fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const o = self.object; const zcu = o.zcu; - const inst = body_tail[0]; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const err_un_ty = self.typeOfIndex(inst); const operand = try self.resolveInst(ty_op.operand); 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(), 0); - const err_un_llvm_ty = try o.lowerType(err_un_ty); + const ok_err_code = try o.builder.intValue(try o.errorIntType(.by_value), 0); - const result_ptr = if (self.isNextRet(body_tail)) - self.ret_ptr - else brk: { - const alignment = err_un_ty.abiAlignment(o.zcu).toLlvm(); - const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); - break :brk result_ptr; - }; + const result_ptr = try self.buildZigAlloca(err_un_ty, .none); const err_ptr = try self.ptraddConst(result_ptr, codegen.errUnionErrorOffset(payload_ty, zcu)); - const error_alignment = Type.anyerror.abiAlignment(o.zcu).toLlvm(); - _ = try self.wip.store(.normal, ok_err_code, err_ptr, error_alignment); + try self.store(err_ptr, .none, ok_err_code, .anyerror, .normal); + const payload_ptr = try self.ptraddConst(result_ptr, codegen.errUnionPayloadOffset(payload_ty, zcu)); - try self.store( - payload_ptr, - .none, - operand, - payload_ty, - ); + try self.store(payload_ptr, .none, operand, payload_ty, .normal); + return result_ptr; } -fn airWrapErrUnionErr(self: *FuncGen, body_tail: []const Air.Inst.Index) Allocator.Error!Builder.Value { +fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const o = self.object; const zcu = o.zcu; - const inst = body_tail[0]; const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const err_un_ty = self.typeOfIndex(inst); const payload_ty = err_un_ty.errorUnionPayload(zcu); const operand = try self.resolveInst(ty_op.operand); if (!payload_ty.hasRuntimeBits(zcu)) return operand; assert(isByRef(err_un_ty, zcu)); // error unions with runtime bits are always by-ref - const err_un_llvm_ty = try o.lowerType(err_un_ty); - const result_ptr = if (self.isNextRet(body_tail)) - self.ret_ptr - else brk: { - const alignment = err_un_ty.abiAlignment(zcu).toLlvm(); - const result_ptr = try self.buildAlloca(err_un_llvm_ty, alignment); - break :brk result_ptr; - }; + const result_ptr = try self.buildZigAlloca(err_un_ty, .none); const err_ptr = try self.ptraddConst(result_ptr, codegen.errUnionErrorOffset(payload_ty, zcu)); - const error_alignment = Type.anyerror.abiAlignment(zcu).toLlvm(); - _ = try self.wip.store(.normal, operand, err_ptr, error_alignment); + try self.store(err_ptr, .none, operand, .anyerror, .normal); + const payload_ptr = try self.ptraddConst(result_ptr, codegen.errUnionPayloadOffset(payload_ty, zcu)); // TODO store undef to payload_ptr _ = payload_ptr; + return result_ptr; } @@ -3269,7 +3271,7 @@ fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const o = self.object; const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const index = pl_op.payload; - const llvm_usize = try o.lowerType(.usize); + const llvm_usize = try o.lowerType(.usize, .by_value); return self.wip.callIntrinsic(.normal, .none, .@"wasm.memory.size", &.{llvm_usize}, &.{ try o.builder.intValue(.i32, index), }, ""); @@ -3279,7 +3281,7 @@ fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Build const o = self.object; const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; const index = pl_op.payload; - const llvm_isize = try o.lowerType(.isize); + const llvm_isize = try o.lowerType(.isize, .by_value); return self.wip.callIntrinsic(.normal, .none, .@"wasm.memory.grow", &.{llvm_isize}, &.{ try o.builder.intValue(.i32, index), try self.resolveInst(pl_op.operand), }, ""); @@ -3306,7 +3308,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)}, + &.{try o.lowerType(inst_ty, .by_value)}, &.{ lhs, rhs }, "", ); @@ -3326,7 +3328,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)}, + &.{try o.lowerType(inst_ty, .by_value)}, &.{ lhs, rhs }, "", ); @@ -3338,7 +3340,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), &.{ ptr, len }, ""); + return self.wip.buildAggregate(try self.object.lowerType(inst_ty, .by_value), &.{ ptr, len }, ""); } fn airAdd(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { @@ -3369,7 +3371,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); + const llvm_inst_ty = try o.lowerType(inst_ty, .by_value); const results = try fg.wip.callIntrinsic(.normal, .none, intrinsic, &.{llvm_inst_ty}, &.{ lhs, rhs }, ""); @@ -3419,7 +3421,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)}, + &.{try o.lowerType(inst_ty, .by_value)}, &.{ lhs, rhs }, "", ); @@ -3458,7 +3460,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)}, + &.{try o.lowerType(inst_ty, .by_value)}, &.{ lhs, rhs }, "", ); @@ -3497,7 +3499,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)}, + &.{try o.lowerType(inst_ty, .by_value)}, &.{ lhs, rhs, .@"0" }, "", ); @@ -3541,8 +3543,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); - const inst_llvm_ty = try o.lowerType(inst_ty); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); + const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); const ExpectedContents = [std.math.big.int.calcTwosCompLimbCount(256)]std.math.big.Limb; var bfa_buf: ExpectedContents = undefined; @@ -3616,7 +3618,7 @@ 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); + const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); const scalar_ty = inst_ty.scalarType(zcu); if (scalar_ty.isRuntimeFloat()) { @@ -3645,7 +3647,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), + try o.lowerType(scalar_ty, .by_value), smin_big_int.toConst(), )); @@ -3681,7 +3683,7 @@ fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value const ty_pl = self.air.instructions.items(.data)[@intFromEnum(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); + const llvm_usize_ty = try o.lowerType(.usize, .by_value); const ptr_ty = self.typeOf(bin_op.lhs); const elem_ty = ptr_ty.indexableElem(zcu); const ptr = switch (ptr_ty.ptrSize(zcu)) { @@ -3714,27 +3716,28 @@ 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_inst_ty = try o.lowerType(inst_ty); - const llvm_lhs_ty = try o.lowerType(lhs_ty); + const llvm_lhs_ty = try o.lowerType(lhs_ty, .by_value); const results = try self.wip.callIntrinsic(.normal, .none, intrinsic, &.{llvm_lhs_ty}, &.{ lhs, rhs }, ""); const result_val = try self.wip.extractValue(results, &.{0}, ""); const overflow_bit = try self.wip.extractValue(results, &.{1}, ""); - const result_alignment = inst_ty.abiAlignment(zcu).toLlvm(); - const alloca_inst = try self.buildAlloca(llvm_inst_ty, result_alignment); + const result_alignment = inst_ty.abiAlignment(zcu); + const alloca_inst = try self.buildZigAlloca(inst_ty, .none); { // Store to 'result: IntType' field - const field_ptr = try self.ptraddConst(alloca_inst, inst_ty.structFieldOffset(0, zcu)); - _ = try self.wip.store(.normal, result_val, field_ptr, lhs_ty.abiAlignment(zcu).toLlvm()); + const field_off = inst_ty.structFieldOffset(0, zcu); + const field_ptr = try self.ptraddConst(alloca_inst, field_off); + try self.store(field_ptr, result_alignment.offset(field_off), result_val, lhs_ty, .normal); } { // Store to 'overflow: u1' field - const field_ptr = try self.ptraddConst(alloca_inst, inst_ty.structFieldOffset(1, zcu)); - _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1)); + const field_off = inst_ty.structFieldOffset(1, zcu); + const field_ptr = try self.ptraddConst(alloca_inst, field_off); + try self.store(field_ptr, result_alignment.offset(field_off), overflow_bit, inst_ty.fieldType(1, zcu), .normal); } return alloca_inst; @@ -3786,7 +3789,7 @@ fn buildFloatCmp( const zcu = o.zcu; const target = zcu.getTarget(); const scalar_ty = ty.scalarType(zcu); - const scalar_llvm_ty = try o.lowerType(scalar_ty); + const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); if (intrinsicsAllowed(scalar_ty, target)) { const cond: Builder.FloatCondition = switch (pred) { @@ -3892,7 +3895,7 @@ fn buildFloatOp( const zcu = o.zcu; const target = zcu.getTarget(); const scalar_ty = ty.scalarType(zcu); - const llvm_ty = try o.lowerType(ty); + const llvm_ty = try o.lowerType(ty, .by_value); if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) { // Some operations are dedicated LLVM instructions, not available as intrinsics @@ -3997,7 +4000,7 @@ fn buildFloatOp( }), }; - const scalar_llvm_ty = try o.lowerType(scalar_ty); + 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], @@ -4051,9 +4054,8 @@ 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 llvm_dest_ty = try o.lowerType(dest_ty); - const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); const result = try self.wip.bin(.shl, lhs, casted_rhs, ""); const reconstructed = try self.wip.bin(if (lhs_scalar_ty.isSignedInt(zcu)) @@ -4063,19 +4065,21 @@ fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Buil const overflow_bit = try self.wip.icmp(.ne, lhs, reconstructed, ""); - const result_alignment = dest_ty.abiAlignment(zcu).toLlvm(); - const alloca_inst = try self.buildAlloca(llvm_dest_ty, result_alignment); + const result_alignment = dest_ty.abiAlignment(zcu); + const alloca_inst = try self.buildZigAlloca(dest_ty, .none); { // Store to 'result: IntType' field - const field_ptr = try self.ptraddConst(alloca_inst, dest_ty.structFieldOffset(0, zcu)); - _ = try self.wip.store(.normal, result, field_ptr, lhs_ty.abiAlignment(zcu).toLlvm()); + const field_off = dest_ty.structFieldOffset(0, zcu); + const field_ptr = try self.ptraddConst(alloca_inst, field_off); + try self.store(field_ptr, result_alignment.offset(field_off), result, lhs_ty, .normal); } { // Store to 'overflow: u1' field - const field_ptr = try self.ptraddConst(alloca_inst, dest_ty.structFieldOffset(1, zcu)); - _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1)); + const field_off = dest_ty.structFieldOffset(1, zcu); + const field_ptr = try self.ptraddConst(alloca_inst, field_off); + try self.store(field_ptr, result_alignment.offset(field_off), overflow_bit, dest_ty.fieldType(1, zcu), .normal); } return alloca_inst; @@ -4118,7 +4122,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), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); return self.wip.bin(if (lhs_scalar_ty.isSignedInt(zcu)) .@"shl nsw" else @@ -4139,7 +4143,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), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); return self.wip.bin(.shl, lhs, casted_rhs, ""); } @@ -4153,8 +4157,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); - const llvm_lhs_scalar_ty = try o.lowerType(lhs_ty.scalarType(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 rhs_ty = self.typeOf(bin_op.rhs); if (lhs_ty.isVector(zcu) and !rhs_ty.isVector(zcu)) { @@ -4164,8 +4168,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); - const llvm_rhs_scalar_ty = try o.lowerType(rhs_ty.scalarType(zcu)); + 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 result = try self.wip.callIntrinsic( .normal, @@ -4241,7 +4245,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), ""); + const casted_rhs = try self.wip.conv(.unsigned, rhs, try o.lowerType(lhs_ty, .by_value), ""); const is_signed_int = lhs_scalar_ty.isSignedInt(zcu); return self.wip.bin(if (is_exact) @@ -4262,8 +4266,8 @@ fn airAbs(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { .normal, .none, .abs, - &.{try o.lowerType(operand_ty)}, - &.{ operand, try o.builder.intValue(.i1, 0) }, + &.{try o.lowerType(operand_ty, .by_value)}, + &.{ operand, .false }, "", ), .float => return self.buildFloatOp(.fabs, .normal, operand_ty, 1, .{operand}), @@ -4276,7 +4280,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)[@intFromEnum(inst)].ty_op; const dest_ty = fg.typeOfIndex(inst); - const dest_llvm_ty = try o.lowerType(dest_ty); + const dest_llvm_ty = try o.lowerType(dest_ty, .by_value); const operand = try fg.resolveInst(ty_op.operand); const operand_ty = fg.typeOf(ty_op.operand); const operand_info = operand_ty.intInfo(zcu); @@ -4304,8 +4308,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); - const operand_scalar_llvm_ty = try o.lowerType(operand_scalar); + const operand_llvm_ty = try o.lowerType(operand_ty, .by_value); + const operand_scalar_llvm_ty = try o.lowerType(operand_scalar, .by_value); const is_vector = operand_ty.zigTypeTag(zcu) == .vector; assert(is_vector == (dest_ty.zigTypeTag(zcu) == .vector)); @@ -4383,7 +4387,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)[@intFromEnum(inst)].ty_op; const operand = try self.resolveInst(ty_op.operand); - const dest_llvm_ty = try self.object.lowerType(self.typeOfIndex(inst)); + const dest_llvm_ty = try self.object.lowerType(self.typeOfIndex(inst), .by_value); return self.wip.cast(.trunc, operand, dest_llvm_ty, ""); } @@ -4397,10 +4401,10 @@ fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Valu 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), ""); + return self.wip.cast(.fptrunc, operand, try o.lowerType(dest_ty, .by_value), ""); } else { - const operand_llvm_ty = try o.lowerType(operand_ty); - const dest_llvm_ty = try o.lowerType(dest_ty); + 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); @@ -4431,10 +4435,10 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value 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), ""); + return self.wip.cast(.fpext, operand, try o.lowerType(dest_ty, .by_value), ""); } else { - const operand_llvm_ty = try o.lowerType(operand_ty); - const dest_llvm_ty = try o.lowerType(dest_ty); + 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); @@ -4461,114 +4465,80 @@ fn airFpext(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value } } -fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { - const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const operand_ty = self.typeOf(ty_op.operand); - const inst_ty = self.typeOfIndex(inst); - const operand = try self.resolveInst(ty_op.operand); - return self.bitCast(operand, operand_ty, inst_ty); -} - -fn bitCast(self: *FuncGen, operand: Builder.Value, operand_ty: Type, inst_ty: Type) Allocator.Error!Builder.Value { - const o = self.object; +fn airBitCast(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const o = fg.object; const zcu = o.zcu; - const operand_is_ref = isByRef(operand_ty, zcu); - const result_is_ref = isByRef(inst_ty, zcu); - const llvm_dest_ty = try o.lowerType(inst_ty); - if (operand_is_ref and result_is_ref) { - // They are both pointers, so just return the same opaque pointer :) - return operand; - } + const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const operand_ty = fg.typeOf(ty_op.operand); + const dest_ty = fg.typeOfIndex(inst); + const operand = try fg.resolveInst(ty_op.operand); - if (inst_ty.isAbiInt(zcu) and operand_ty.isAbiInt(zcu)) { - return self.wip.conv(.unsigned, operand, llvm_dest_ty, ""); - } + // We have the following `Air.Legalize` features enabled: + // + // * `.scalarize_bit_cast_array` + // * `.scalarize_bit_cast_vector_non_elementwise` + // + // That means the `bit_cast` instructions we might see are limited to the following: + // + // * bool/int/float <-> bool/int/float + // * `@Vector(n, A)` <-> `@Vector(n, B)` + // + // All of these cases can be handled by LLVM's `bitcast` instruction. - const operand_scalar_ty = operand_ty.scalarType(zcu); - const inst_scalar_ty = inst_ty.scalarType(zcu); - if (operand_scalar_ty.zigTypeTag(zcu) == .int and inst_scalar_ty.isPtrAtRuntime(zcu)) { - return self.wip.cast(.inttoptr, operand, llvm_dest_ty, ""); - } - if (operand_scalar_ty.isPtrAtRuntime(zcu) and inst_scalar_ty.zigTypeTag(zcu) == .int) { - return self.wip.cast(.ptrtoint, operand, llvm_dest_ty, ""); - } + assert(!isByRef(operand_ty, zcu)); + assert(!isByRef(dest_ty, zcu)); - if (operand_ty.zigTypeTag(zcu) == .vector and inst_ty.zigTypeTag(zcu) == .array) { - const elem_ty = operand_scalar_ty; - assert(result_is_ref); // arrays are always by-ref provided they have runtime bits - const alignment = inst_ty.abiAlignment(zcu).toLlvm(); - const array_ptr = try self.buildAlloca(llvm_dest_ty, alignment); - const bitcast_ok = elem_ty.bitSize(zcu) == elem_ty.abiSize(zcu) * 8; - if (bitcast_ok) { - _ = try self.wip.store(.normal, operand, array_ptr, alignment); - } else { - // If the ABI size of the element type is not evenly divisible by size in bits; - // a simple bitcast will not work, and we fall back to extractelement. - const elem_size = elem_ty.abiSize(zcu); - const vector_len = operand_ty.arrayLen(zcu); - var i: u64 = 0; - while (i < vector_len) : (i += 1) { - const arr_elem_ptr = try self.ptraddConst(array_ptr, i * elem_size); - const vec_elem = try self.wip.extractElement(operand, try o.builder.intValue(.i32, i), ""); - _ = try self.wip.store(.normal, vec_elem, arr_elem_ptr, .default); - } - } - return array_ptr; - } else if (operand_ty.zigTypeTag(zcu) == .array and inst_ty.zigTypeTag(zcu) == .vector) { - const elem_ty = operand_ty.childType(zcu); - assert(operand_is_ref); // arrays are always by-ref provided they have runtime bits - const llvm_vector_ty = try o.lowerType(inst_ty); + const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + return fg.wip.cast(.bitcast, operand, llvm_dest_ty, ""); +} - const bitcast_ok = elem_ty.bitSize(zcu) == elem_ty.abiSize(zcu) * 8; - if (bitcast_ok) { - // The array is aligned to the element's alignment, while the vector might have a completely - // different alignment. This means we need to enforce the alignment of this load. - const alignment = elem_ty.abiAlignment(zcu).toLlvm(); - return self.wip.load(.normal, llvm_vector_ty, operand, alignment, ""); - } else { - // If the ABI size of the element type is not evenly divisible by size in bits; - // a simple bitcast will not work, and we fall back to extractelement. - const elem_llvm_ty = try o.lowerType(elem_ty); - const elem_size = elem_ty.abiSize(zcu); - const vector_len = operand_ty.arrayLen(zcu); - var vector = try o.builder.poisonValue(llvm_vector_ty); - var i: u64 = 0; - while (i < vector_len) : (i += 1) { - const arr_elem_ptr = try self.ptraddConst(operand, i * elem_size); - const arr_elem = try self.wip.load(.normal, elem_llvm_ty, arr_elem_ptr, .default, ""); - vector = try self.wip.insertElement(vector, arr_elem, try o.builder.intValue(.i32, i), ""); - } - return vector; - } - } +fn airNopCast(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const zcu = fg.object.zcu; + const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const operand_ty = fg.typeOf(ty_op.operand); + const dest_ty = fg.typeOfIndex(inst); + assert(isByRef(operand_ty, zcu) == isByRef(dest_ty, zcu)); + assert(operand_ty.abiSize(zcu) == dest_ty.abiSize(zcu)); + return fg.resolveInst(ty_op.operand); +} - if (operand_is_ref) { - const alignment = operand_ty.abiAlignment(zcu).toLlvm(); - return self.wip.load(.normal, llvm_dest_ty, operand, alignment, ""); - } +fn airPtrFromInt(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const o = fg.object; + const zcu = o.zcu; + const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const operand_ty = fg.typeOf(ty_op.operand); + const dest_ty = fg.typeOfIndex(inst); + assert(operand_ty.scalarType(zcu).toIntern() == .usize_type); + assert(dest_ty.scalarType(zcu).isPtrAtRuntime(zcu)); - if (result_is_ref) { - const alignment = operand_ty.abiAlignment(zcu).max(inst_ty.abiAlignment(zcu)).toLlvm(); - const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); - _ = try self.wip.store(.normal, operand, result_ptr, alignment); - return result_ptr; - } + const operand = try fg.resolveInst(ty_op.operand); + const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + return fg.wip.cast(.inttoptr, operand, llvm_dest_ty, ""); +} + +fn airIntFromPtr(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const o = fg.object; + const zcu = o.zcu; + const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const operand_ty = fg.typeOf(ty_op.operand); + const dest_ty = fg.typeOfIndex(inst); + assert(operand_ty.scalarType(zcu).isPtrAtRuntime(zcu)); + assert(dest_ty.scalarType(zcu).toIntern() == .usize_type); - if (inst_ty.isSliceAtRuntime(zcu) or - ((operand_ty.zigTypeTag(zcu) == .vector or inst_ty.zigTypeTag(zcu) == .vector) and - operand_ty.bitSize(zcu) != inst_ty.bitSize(zcu))) - { - // Both our operand and our result are values, not pointers, - // but LLVM won't let us bitcast struct values or vectors with padding bits. - // Therefore, we store operand to alloca, then load for result. - const alignment = operand_ty.abiAlignment(zcu).max(inst_ty.abiAlignment(zcu)).toLlvm(); - const result_ptr = try self.buildAlloca(llvm_dest_ty, alignment); - _ = try self.wip.store(.normal, operand, result_ptr, alignment); - return self.wip.load(.normal, llvm_dest_ty, result_ptr, alignment, ""); - } + const operand = try fg.resolveInst(ty_op.operand); + const llvm_dest_ty = try o.lowerType(dest_ty, .by_value); + return fg.wip.cast(.ptrtoint, operand, llvm_dest_ty, ""); +} - return self.wip.cast(.bitcast, operand, llvm_dest_ty, ""); +fn airUnionFromEnum(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { + const ty_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + const enum_ty = fg.typeOf(ty_op.operand); + const union_ty = fg.typeOfIndex(inst); + const enum_val = try fg.resolveInst(ty_op.operand); + const union_ptr = try fg.buildZigAlloca(union_ty, .none); + try fg.store(union_ptr, .none, enum_val, enum_ty, .normal); + return union_ptr; } fn airArg(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -4627,9 +4597,8 @@ fn airArg(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { "", ); } else if (mod.optimize_mode == .Debug) { - const alignment = inst_ty.abiAlignment(zcu).toLlvm(); - const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment); - _ = try self.wip.store(.normal, arg_val, alloca, alignment); + const alloca = try self.buildZigAlloca(inst_ty, .none); + try self.store(alloca, .none, arg_val, inst_ty, .normal); _ = try self.wip.callIntrinsic( .normal, .none, @@ -4670,8 +4639,7 @@ fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value if (!elem_ty.hasRuntimeBits(zcu)) { return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue(); } - const llvm_elem_ty = try o.lowerType(elem_ty); - return self.buildAlloca(llvm_elem_ty, ptr_align.toLlvm()); + return self.buildZigAlloca(elem_ty, ptr_align); } fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -4684,32 +4652,71 @@ fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value if (!elem_ty.hasRuntimeBits(zcu)) { return (try o.lowerPtrToVoid(ptr_align, ptr_ty.ptrAddressSpace(zcu))).toValue(); } - const llvm_elem_ty = try o.lowerType(elem_ty); - return self.buildAlloca(llvm_elem_ty, ptr_align.toLlvm()); + return self.buildZigAlloca(elem_ty, ptr_align); } -/// Use this instead of builder.buildAlloca, because this function makes sure to -/// put the alloca instruction at the top of the function! +fn buildZigAlloca(fg: *FuncGen, ty: Type, @"align": InternPool.Alignment) Allocator.Error!Builder.Value { + const o = fg.object; + const resolved_align: InternPool.Alignment = switch (@"align") { + .none => ty.abiAlignment(o.zcu), + else => |a| a, + }; + 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. fn buildAlloca( - self: *FuncGen, + fg: *FuncGen, llvm_ty: Builder.Type, alignment: Builder.Alignment, ) Allocator.Error!Builder.Value { - const target = self.object.zcu.getTarget(); - return buildAllocaInner(&self.wip, llvm_ty, alignment, target); + const wip = &fg.wip; + + const alloca = blk: { + const prev_cursor = wip.cursor; + const prev_debug_location = wip.debug_location; + defer { + wip.cursor = prev_cursor; + if (wip.cursor.block == .entry) wip.cursor.instruction += 1; + wip.debug_location = prev_debug_location; + } + + wip.cursor = .{ .block = .entry }; + wip.debug_location = .no_location; + const address_space = llvmAllocaAddressSpace(fg.object.zcu.getTarget()); + break :blk try wip.alloca(.normal, llvm_ty, .none, alignment, address_space, ""); + }; + + // The pointer returned from this function should have the generic address space, + // if this isn't the case then cast it to the generic address space. + return fg.wip.conv(.unneeded, alloca, .ptr, ""); } -fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Builder.Value { - const o = self.object; +fn airStore(fg: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error!Builder.Value { + const o = fg.object; const zcu = o.zcu; - const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; - const dest_ptr = try self.resolveInst(bin_op.lhs); - const ptr_ty = self.typeOf(bin_op.lhs); - const operand_ty = ptr_ty.childType(zcu); + const bin_op = fg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; + const ptr = try fg.resolveInst(bin_op.lhs); + const ptr_ty = fg.typeOf(bin_op.lhs); + const ptr_info = ptr_ty.ptrInfo(zcu); + const ptr_alignment = ptr_ty.ptrAlignment(zcu); + + const elem_ty = fg.typeOf(bin_op.rhs); + assert(elem_ty.hasRuntimeBits(zcu)); + + fg.maybeMarkAllowZeroAccess(ptr_info); + + const access_kind: Builder.MemoryAccessKind = switch (ptr_info.flags.is_volatile) { + true => .@"volatile", + false => .normal, + }; const val_is_undef = if (bin_op.rhs.toInterned()) |i| Value.fromInterned(i).isUndef(zcu) else false; - if (val_is_undef and !self.needMemsetWorkaround(operand_ty.abiSize(zcu))) { - const owner_mod = self.ownerModule(); + if (val_is_undef and !fg.needMemsetWorkaround(elem_ty.abiSize(zcu))) { + const owner_mod = fg.ownerModule(); // Even if safety is disabled, we still emit a memset to undefined since it conveys // extra information to LLVM, and LLVM will optimize it out. Safety makes the difference @@ -4724,7 +4731,6 @@ fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! return .none; } - const ptr_info = ptr_ty.ptrInfo(zcu); const needs_bitmask = (ptr_info.packed_offset.host_size != 0); if (needs_bitmask) { // TODO: only some bits are to be undef, we cannot write with a simple memset. @@ -4733,27 +4739,82 @@ fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error! return .none; } - self.maybeMarkAllowZeroAccess(ptr_info); - - const len = try o.builder.intValue(try o.lowerType(.usize), operand_ty.abiSize(zcu)); - _ = try self.wip.callMemSet( - dest_ptr, - ptr_ty.ptrAlignment(zcu).toLlvm(), + const len = try o.builder.intValue(try o.lowerType(.usize, .by_value), elem_ty.abiSize(zcu)); + _ = try fg.wip.callMemSet( + ptr, + ptr_alignment.toLlvm(), if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8), len, - if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, - self.disable_intrinsics, + access_kind, + fg.disable_intrinsics, ); if (safety and owner_mod.valgrind) { - try self.valgrindMarkUndef(dest_ptr, len); + try fg.valgrindMarkUndef(ptr, len); } return .none; } - self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); + const elem = try fg.resolveInst(bin_op.rhs); - const src_operand = try self.resolveInst(bin_op.rhs); - try self.storeFull(dest_ptr, ptr_ty, src_operand, .none); + 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 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); + 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 backing_int_val = try fg.load(ptr, ptr_alignment, backing_int_ty, access_kind); + + const elem_bits = ptr_ty.childType(zcu).bitSize(zcu); + const shift_amt = try o.builder.intConst(llvm_backing_int_ty, ptr_info.packed_offset.bit_offset); + + // Convert to equally-sized integer type in order to perform the bit + // operations on the value to store + const new_val_bits_type = try o.builder.intType(@intCast(elem_bits)); + const new_val_bits = if (elem_ty.isPtrAtRuntime(zcu)) + try fg.wip.cast(.ptrtoint, elem, new_val_bits_type, "") + else + try fg.wip.cast(.bitcast, elem, new_val_bits_type, ""); + + const mask_val = blk: { + const zext = try fg.wip.cast( + .zext, + try o.builder.intValue(new_val_bits_type, -1), + llvm_backing_int_ty, + "", + ); + const shl = try fg.wip.bin(.shl, zext, shift_amt.toValue(), ""); + break :blk try fg.wip.bin( + .xor, + shl, + try o.builder.intValue(llvm_backing_int_ty, -1), + "", + ); + }; + + const masked_backing_int_val = try fg.wip.bin(.@"and", backing_int_val, mask_val, ""); + const extended_new_val = try fg.wip.cast(.zext, new_val_bits, llvm_backing_int_ty, ""); + const shifted_new_val = try fg.wip.bin(.shl, extended_new_val, shift_amt.toValue(), ""); + const new_backing_int_val = try fg.wip.bin(.@"or", shifted_new_val, masked_backing_int_val, ""); + + try fg.store(ptr, ptr_alignment, new_backing_int_val, backing_int_ty, access_kind); + return .none; + } + + try fg.store(ptr, ptr_alignment, elem, elem_ty, access_kind); return .none; } @@ -4765,7 +4826,7 @@ fn airLoad(fg: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const ptr_info = ptr_ty.ptrInfo(zcu); const ptr = try fg.resolveInst(ty_op.operand); const elem_ty = ptr_ty.childType(zcu); - const llvm_ptr_align = ptr_ty.ptrAlignment(zcu).toLlvm(); + const ptr_align = ptr_ty.ptrAlignment(zcu); fg.maybeMarkAllowZeroAccess(ptr_info); @@ -4773,36 +4834,32 @@ 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) { - const index_u32 = try o.builder.intValue(.i32, ptr_info.flags.vector_index); - const vec_elem_ty = try o.lowerType(elem_ty); - const vec_ty = try o.builder.vectorType(.normal, ptr_info.packed_offset.host_size, vec_elem_ty); - - const loaded_vector = try fg.wip.load(access_kind, vec_ty, ptr, llvm_ptr_align, ""); - return fg.wip.extractElement(loaded_vector, index_u32, ""); + // 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, elem_ty, llvm_ptr_align, access_kind); + return fg.load(ptr, ptr_align, elem_ty, access_kind); } - const containing_int_ty = try o.builder.intType(@intCast(ptr_info.packed_offset.host_size * 8)); - const containing_int = - try fg.wip.load(access_kind, containing_int_ty, ptr, llvm_ptr_align, ""); + 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 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(containing_int_ty, ptr_info.packed_offset.bit_offset); - const shifted_value = try fg.wip.bin(.lshr, containing_int, shift_amt, ""); - const elem_llvm_ty = try o.lowerType(elem_ty); - - if (isByRef(elem_ty, zcu)) { - const result_align = elem_ty.abiAlignment(zcu).toLlvm(); - const result_ptr = try fg.buildAlloca(elem_llvm_ty, result_align); - - const same_size_int = try o.builder.intType(@intCast(elem_bits)); - const truncated_int = try fg.wip.cast(.trunc, shifted_value, same_size_int, ""); - _ = try fg.wip.store(.normal, truncated_int, result_ptr, result_align); - return result_ptr; - } + 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 (elem_ty.zigTypeTag(zcu) == .float or elem_ty.zigTypeTag(zcu) == .vector) { const same_size_int = try o.builder.intType(@intCast(elem_bits)); @@ -4852,7 +4909,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); + const llvm_usize = try o.lowerType(.usize, .by_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); @@ -4864,7 +4921,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), ""); + return self.wip.cast(.ptrtoint, result, try self.object.lowerType(.usize, .by_value), ""); } fn airCmpxchg( @@ -4881,7 +4938,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); + const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); const llvm_abi_ty = try self.getAtomicAbiType(operand_ty, false); if (llvm_abi_ty != .none) { // operand needs widening and truncating @@ -4917,21 +4974,22 @@ fn airCmpxchg( return self.wip.select(.normal, success_bit, zero, payload, ""); } - assert(isByRef(optional_ty, zcu)); + assert(!isByRef(operand_ty, zcu)); // can only cmpxchg non-by-ref types + assert(isByRef(optional_ty, zcu)); // all optionals are by-ref comptime assert(optional_layout_version == 3); const non_null_bit = try self.wip.not(success_bit, ""); - const payload_align = operand_ty.abiAlignment(zcu).toLlvm(); - const alloca_inst = try self.buildAlloca(try o.lowerType(optional_ty), payload_align); + const payload_align = operand_ty.abiAlignment(zcu); + const alloca_inst = try self.buildZigAlloca(optional_ty, .none); // Payload is always the first field at offset 0, so address is `alloca_inst` - _ = try self.wip.store(.normal, payload, alloca_inst, payload_align); + try self.store(alloca_inst, .none, payload, operand_ty, .normal); // Non-null bit is after payload with no padding because it has alignment 1 const non_null_ptr = try self.ptraddConst(alloca_inst, operand_ty.abiSize(zcu)); - _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, comptime .fromByteUnits(1)); + try self.store(non_null_ptr, payload_align, non_null_bit, .bool, .normal); return alloca_inst; } @@ -4950,7 +5008,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); + const llvm_operand_ty = try o.lowerType(operand_ty, .by_value); const access_kind: Builder.MemoryAccessKind = if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -4979,7 +5037,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), ""), + .pointer => try self.wip.cast(.ptrtoint, operand, try o.lowerType(.usize, .by_value), ""), else => operand, }; @@ -5018,7 +5076,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); + const elem_llvm_ty = try o.lowerType(elem_ty, .by_value); self.maybeMarkAllowZeroAccess(info); @@ -5072,7 +5130,17 @@ fn airAtomicStore( self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); - try self.storeFull(ptr, ptr_ty, element, ordering); + assert(!isByRef(operand_ty, zcu)); + + _ = try self.wip.storeAtomic( + if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, + element, + ptr, + self.sync_scope, + ordering, + ptr_ty.ptrAlignment(zcu).toLlvm(), + ); + return .none; } @@ -5083,7 +5151,7 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error const dest_slice = try self.resolveInst(bin_op.lhs); const ptr_ty = self.typeOf(bin_op.lhs); const elem_ty = self.typeOf(bin_op.rhs); - const dest_ptr_align = ptr_ty.ptrAlignment(zcu).toLlvm(); + const dest_ptr_align = ptr_ty.ptrAlignment(zcu); const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty); const access_kind: Builder.MemoryAccessKind = if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; @@ -5109,7 +5177,7 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); _ = try self.wip.callMemSet( dest_ptr, - dest_ptr_align, + dest_ptr_align.toLlvm(), fill_byte, len, access_kind, @@ -5131,7 +5199,7 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); _ = try self.wip.callMemSet( dest_ptr, - dest_ptr_align, + dest_ptr_align.toLlvm(), fill_byte, len, access_kind, @@ -5144,14 +5212,31 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error const value = try self.resolveInst(bin_op.rhs); const elem_abi_size = elem_ty.abiSize(zcu); - if (allow_byte_memset and elem_abi_size == 1 and elem_ty.bitSize(zcu) == 8) { - // In this case we can take advantage of LLVM's intrinsic. - const fill_byte = try self.bitCast(value, elem_ty, Type.u8); + intrinsic: { + if (!allow_byte_memset) break :intrinsic; + if (elem_abi_size != 1) break :intrinsic; + // To use LLVM's intrinsic, we need to convert the operand to a raw 8-bit integer value. + const fill_byte: Builder.Value = byte: { + if (isByRef(elem_ty, zcu)) { + break :byte try self.load(value, elem_ty.abiAlignment(zcu), .u8, .normal); + } + if (elem_ty.isAbiInt(zcu)) { + const info = elem_ty.intInfo(zcu); + break :byte try self.wip.conv(switch (info.signedness) { + .unsigned => .unsigned, + .signed => .signed, + }, value, .i8, ""); + } + if (elem_ty.toIntern() == .bool_type) { + break :byte try self.wip.cast(.zext, value, .i8, ""); + } + break :intrinsic; + }; + // Great, we can use the intrinsic! const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); - _ = try self.wip.callMemSet( dest_ptr, - dest_ptr_align, + dest_ptr_align.toLlvm(), fill_byte, len, access_kind, @@ -5181,7 +5266,6 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error const body_block = try self.wip.block(1, "InlineMemsetBody"); const end_block = try self.wip.block(1, "InlineMemsetEnd"); - const llvm_usize_ty = try o.lowerType(.usize); const end_ptr = switch (ptr_ty.ptrSize(zcu)) { .slice => try self.ptraddScaled( dest_ptr, @@ -5200,18 +5284,8 @@ fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) Allocator.Error self.wip.cursor = .{ .block = body_block }; const elem_abi_align = elem_ty.abiAlignment(zcu); - const it_ptr_align = InternPool.Alignment.fromLlvm(dest_ptr_align).min(elem_abi_align).toLlvm(); - if (isByRef(elem_ty, zcu)) { - _ = try self.wip.callMemCpy( - it_ptr.toValue(), - it_ptr_align, - value, - elem_abi_align.toLlvm(), - try o.builder.intValue(llvm_usize_ty, elem_abi_size), - access_kind, - self.disable_intrinsics, - ); - } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align); + const it_ptr_align: InternPool.Alignment = dest_ptr_align.min(elem_abi_align); + try self.store(it_ptr.toValue(), it_ptr_align, value, elem_ty, access_kind); const next_ptr = try self.ptraddConst(it_ptr.toValue(), elem_abi_size); _ = try self.wip.br(loop_block); @@ -5288,14 +5362,11 @@ fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder. const union_ptr = try self.resolveInst(bin_op.lhs); const new_tag = try self.resolveInst(bin_op.rhs); + const tag_ty = self.typeOf(bin_op.rhs); const union_ptr_align = un_ptr_ty.ptrAlignment(zcu); - if (layout.payload_size == 0) { - _ = try self.wip.store(access_kind, new_tag, union_ptr, union_ptr_align.toLlvm()); - return .none; - } const tag_field_ptr = try self.ptraddConst(union_ptr, layout.tagOffset()); const tag_ptr_align = union_ptr_align.offset(layout.tagOffset()); - _ = try self.wip.store(access_kind, new_tag, tag_field_ptr, tag_ptr_align.toLlvm()); + try self.store(tag_field_ptr, tag_ptr_align, new_tag, tag_ty, access_kind); return .none; } @@ -5307,16 +5378,9 @@ fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder. const layout = un_ty.unionGetLayout(zcu); assert(layout.tag_size != 0); const operand = try self.resolveInst(ty_op.operand); - if (isByRef(un_ty, zcu)) { - const llvm_tag_ty = try o.lowerType(un_ty.unionTagTypeRuntime(zcu).?); - const tag_field_ptr = try self.ptraddConst(operand, layout.tagOffset()); - return self.wip.load(.normal, llvm_tag_ty, tag_field_ptr, .default, ""); - } else { - // This is only possible if all fields are zero-bit, in which case `operand` is already an - // integer value (the union is lowered as its enum tag). - assert(layout.payload_size == 0); - return operand; - } + assert(isByRef(un_ty, zcu)); + const tag_field_ptr = try self.ptraddConst(operand, layout.tagOffset()); + return self.load(tag_field_ptr, .none, un_ty.unionTagTypeRuntime(zcu).?, .normal); } fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) Allocator.Error!Builder.Value { @@ -5346,11 +5410,11 @@ fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) .normal, .none, intrinsic, - &.{try o.lowerType(operand_ty)}, + &.{try o.lowerType(operand_ty, .by_value)}, &.{ operand, .false }, "", ); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); } fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) Allocator.Error!Builder.Value { @@ -5364,11 +5428,11 @@ fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, intrinsic: Builder.Intrinsic) .normal, .none, intrinsic, - &.{try o.lowerType(operand_ty)}, + &.{try o.lowerType(operand_ty, .by_value)}, &.{operand}, "", ); - return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); } fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5381,7 +5445,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); + var llvm_operand_ty = try o.lowerType(operand_ty, .by_value); if (bits % 16 == 8) { // If not an even byte-multiple, we need zero-extend + shift-left 1 byte @@ -5402,7 +5466,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), ""); + return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty, .by_value), ""); } fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5422,7 +5486,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(), err_int); + const this_tag_int_value = try o.builder.intConst(try o.errorIntType(.by_value), err_int); try wip_switch.addCase(this_tag_int_value, valid_block, &self.wip); } self.wip.cursor = .{ .block = valid_block }; @@ -5479,21 +5543,20 @@ fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand = try self.resolveInst(un_op); const slice_ty = self.typeOfIndex(inst); - const slice_llvm_ty = try o.lowerType(slice_ty); // 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), ""); + const operand_usize = try self.wip.conv(.unsigned, operand, try o.lowerType(.usize, .by_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)); - return self.wip.load(.normal, slice_llvm_ty, error_name_ptr, .default, ""); + return self.load(error_name_ptr, .none, slice_ty, .normal); } fn airSplat(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { const ty_op = self.air.instructions.items(.data)[@intFromEnum(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), scalar, ""); + return self.wip.splatVector(try self.object.lowerType(vector_ty, .by_value), scalar, ""); } fn airSelect(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value { @@ -5516,9 +5579,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); - const llvm_result_ty = try o.lowerType(unwrapped.result_ty); - const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu)); + 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_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); @@ -5548,7 +5611,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); + break :elem try o.lowerValue(val, .by_value); } else llvm_poison_elem, }; } @@ -5620,7 +5683,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)); + const llvm_elem_ty = try o.lowerType(unwrapped.result_ty.childType(zcu), .by_value); const llvm_mask_ty = try o.builder.vectorType(.normal, @intCast(mask.len), .i32); const llvm_poison_mask_elem = try o.builder.poisonConst(.i32); @@ -5695,15 +5758,13 @@ 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: -/// reduce: { -/// var i: usize = 0; -/// var accum: T = init; -/// while (i < vec.len) : (i += 1) { -/// accum = llvm_fn(accum, vec[i]); -/// } -/// break :reduce accum; -/// } -/// +/// ``` +/// 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, @@ -5712,56 +5773,54 @@ fn buildReducedCall( accum_init: Builder.Value, ) Allocator.Error!Builder.Value { const o = self.object; - const usize_ty = try o.lowerType(.usize); - const llvm_vector_len = try o.builder.intValue(usize_ty, vector_len); + 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); - // Allocate and initialize our mutable variables - const i_ptr = try self.buildAlloca(usize_ty, .default); - _ = try self.wip.store(.normal, try o.builder.intValue(usize_ty, 0), i_ptr, .default); - const accum_ptr = try self.buildAlloca(llvm_result_ty, .default); - _ = try self.wip.store(.normal, accum_init, accum_ptr, .default); + const entry_block = self.wip.cursor.block; - // Setup the loop - const loop = try self.wip.block(2, "ReduceLoop"); - const loop_exit = try self.wip.block(1, "AfterReduce"); - _ = try self.wip.br(loop); - { - self.wip.cursor = .{ .block = loop }; + 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"); - // while (i < vec.len) - const i = try self.wip.load(.normal, usize_ty, i_ptr, .default, ""); - const cond = try self.wip.icmp(.ult, i, llvm_vector_len, ""); - const loop_then = try self.wip.block(1, "ReduceLoopThen"); + _ = try self.wip.br(cond_block); - _ = try self.wip.brCond(cond, loop_then, loop_exit, .none); + // 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); - { - self.wip.cursor = .{ .block = loop_then }; + // 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); - // accum = f(accum, vec[i]); - const accum = try self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, ""); - const element = try self.wip.extractElement(operand_vector, i, ""); - const new_accum = try self.wip.call( - .normal, - .ccc, - .none, - llvm_fn.typeOf(&o.builder), - llvm_fn.toValue(&o.builder), - &.{ accum, element }, - "", - ); - _ = try self.wip.store(.normal, new_accum, accum_ptr, .default); + 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); - // i += 1 - const new_i = try self.wip.bin(.add, i, try o.builder.intValue(usize_ty, 1), ""); - _ = try self.wip.store(.normal, new_i, i_ptr, .default); - _ = try self.wip.br(loop); - } - } - - self.wip.cursor = .{ .block = loop_exit }; - return self.wip.load(.normal, llvm_result_ty, accum_ptr, .default, ""); + self.wip.cursor = .{ .block = exit_block }; + return accum.toValue(); } fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { @@ -5772,9 +5831,9 @@ fn airReduce(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) A const reduce = self.air.instructions.items(.data)[@intFromEnum(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); + 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); + const llvm_scalar_ty = try o.lowerType(scalar_ty, .by_value); switch (reduce.operation) { .And, .Or, .Xor => return self.wip.callIntrinsic(.normal, .none, switch (reduce.operation) { @@ -5881,10 +5940,10 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde const result_ty = self.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 llvm_result_ty = try o.lowerType(result_ty); switch (result_ty.zigTypeTag(zcu)) { .vector => { + const llvm_result_ty = try o.lowerType(result_ty, .by_value); var vector = try o.builder.poisonValue(llvm_result_ty); for (elements, 0..) |elem, i| { const index_u32 = try o.builder.intValue(.i32, i); @@ -5926,7 +5985,7 @@ 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.buildAlloca(llvm_result_ty, struct_align.toLlvm()); + const alloca_inst = try self.buildZigAlloca(result_ty, .none); for (elements, 0..) |elem, field_index| { if (result_ty.structFieldIsComptime(field_index, zcu)) continue; @@ -5938,24 +5997,7 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde const llvm_field_val = try self.resolveInst(elem); - if (isByRef(field_ty, zcu)) { - _ = try self.wip.callMemCpy( - field_ptr, - field_ptr_align.toLlvm(), - llvm_field_val, - field_ty.abiAlignment(zcu).toLlvm(), - try o.builder.intValue(try o.lowerType(.usize), field_ty.abiSize(zcu)), - .normal, - self.disable_intrinsics, - ); - } else { - _ = try self.wip.store( - .normal, - llvm_field_val, - field_ptr, - field_ptr_align.toLlvm(), - ); - } + try self.store(field_ptr, field_ptr_align, llvm_field_val, field_ty, .normal); } return alloca_inst; @@ -5964,8 +6006,7 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde .array => { assert(isByRef(result_ty, zcu)); - const alignment = result_ty.abiAlignment(zcu).toLlvm(); - const alloca_inst = try self.buildAlloca(llvm_result_ty, alignment); + const alloca_inst = try self.buildZigAlloca(result_ty, .none); const array_info = result_ty.arrayInfo(zcu); @@ -5974,12 +6015,12 @@ fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde 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); + try self.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); + try self.store(elem_ptr, .none, llvm_elem.toValue(), array_info.elem_type, .normal); } return alloca_inst; @@ -5995,7 +6036,6 @@ fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; const union_ty = self.typeOfIndex(inst); - const union_llvm_ty = try o.lowerType(union_ty); const union_obj = zcu.typeToUnion(union_ty).?; assert(union_obj.layout != .@"packed"); @@ -6005,28 +6045,28 @@ fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Va assert(layout.payload_size != 0); // otherwise the value would be comptime-known assert(isByRef(union_ty, zcu)); - const alignment = layout.abi_align.toLlvm(); - const result_ptr = try self.buildAlloca(union_llvm_ty, alignment); + const result_ptr = try self.buildZigAlloca(union_ty, layout.abi_align); const llvm_payload = try self.resolveInst(extra.init); const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]); assert(field_ty.hasRuntimeBits(zcu)); { const payload_ptr = try self.ptraddConst(result_ptr, layout.payloadOffset()); - try self.store(payload_ptr, layout.payload_align, llvm_payload, field_ty); + try self.store(payload_ptr, layout.payload_align, llvm_payload, field_ty, .normal); } if (layout.tag_size != 0) { - const loaded_enum = ip.loadEnumType(union_obj.enum_tag_type); + const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); + 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)), + try o.lowerType(.fromInterned(union_obj.enum_tag_type), .by_value), extra.field_index, // auto-numbered ), - else => |tag_val_ip| try o.lowerValue(tag_val_ip), + else => |tag_val_ip| try o.lowerValue(tag_val_ip, .by_value), }; const tag_ptr = try self.ptraddConst(result_ptr, layout.tagOffset()); - _ = try self.wip.store(.normal, llvm_tag_val.toValue(), tag_ptr, layout.tag_align.toLlvm()); + try self.store(tag_ptr, layout.tag_align, llvm_tag_val.toValue(), tag_ty, .normal); } return result_ptr; @@ -6085,7 +6125,7 @@ fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde const ty_op = self.air.instructions.items(.data)[@intFromEnum(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), ""); + return self.wip.cast(.addrspacecast, operand, try self.object.lowerType(inst_ty, .by_value), ""); } fn workIntrinsic( @@ -6133,7 +6173,7 @@ fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builde // Load the work_group_* member from the struct as u16. // Just treat the dispatch pointer as an array of u16 to keep things simple. const workgroup_size_ptr = try self.ptraddConst(dispatch_ptr, (2 + dimension) * 2); - return self.wip.load(.normal, .i16, workgroup_size_ptr, comptime .fromByteUnits(2), ""); + return self.load(workgroup_size_ptr, .@"2", .u16, .normal); }, .nvptx, .nvptx64 => { return self.workIntrinsic(dimension, 1, "nvvm.read.ptx.sreg.ntid"); @@ -6168,8 +6208,8 @@ fn optCmpNull( comptime assert(optional_layout_version == 3); // Non-null bit is always after the payload, with no padding because it has alignment 1. const non_null_ptr = try self.ptraddConst(opt_ptr, opt_ty.optionalChild(zcu).abiSize(zcu)); - const non_null = try self.wip.load(access_kind, .i8, non_null_ptr, .default, ""); - return self.wip.icmp(cond, non_null, try self.object.builder.intValue(.i8, 0), ""); + const non_null = try self.load(non_null_ptr, .@"1", .bool, access_kind); + return self.wip.icmp(cond, non_null, .false, ""); } /// Assumes that `Type.optionalReprIsPayload` is `false` for `opt_ty` and that the payload has bits. @@ -6186,13 +6226,9 @@ fn optPayloadHandle( // Payload is first field so always at the same address as the optional itself. const payload_ptr = opt_ptr; - const payload_align = payload_ty.abiAlignment(zcu).toLlvm(); - if (isByRef(payload_ty, zcu)) { - if (can_elide_load) return payload_ptr; - return fg.loadByRef(payload_ptr, payload_ty, payload_align, .normal); - } else { - return fg.loadTruncate(.normal, payload_ty, payload_ptr, payload_align); - } + if (can_elide_load and isByRef(payload_ty, zcu)) return payload_ptr; + + return fg.load(payload_ptr, .none, payload_ty, .normal); } fn fieldPtr( @@ -6216,220 +6252,156 @@ fn fieldPtr( return self.ptraddConst(aggregate_ptr, offset); } -/// Load a value and, if needed, mask out padding bits for non byte-sized integer values. -fn loadTruncate( - fg: *FuncGen, - access_kind: Builder.MemoryAccessKind, - payload_ty: Type, - payload_ptr: Builder.Value, - payload_alignment: Builder.Alignment, -) Allocator.Error!Builder.Value { - // from https://llvm.org/docs/LangRef.html#load-instruction : - // "When loading a value of a type like i20 with a size that is not an integral number of bytes, the result is undefined if the value was not originally written using a store of the same type. " - // => so load the byte aligned value and trunc the unwanted bits. - - const o = fg.object; - const zcu = o.zcu; - const payload_llvm_ty = try o.lowerType(payload_ty); - const abi_size = payload_ty.abiSize(zcu); - - const load_llvm_ty = if (payload_ty.isAbiInt(zcu)) - try o.builder.intType(@intCast(abi_size * 8)) - else - payload_llvm_ty; - const loaded = try fg.wip.load(access_kind, load_llvm_ty, payload_ptr, payload_alignment, ""); - const shifted = if (payload_llvm_ty != load_llvm_ty and zcu.getTarget().cpu.arch.endian() == .big) - try fg.wip.bin(.lshr, loaded, try o.builder.intValue( - load_llvm_ty, - (payload_ty.abiSize(zcu) - (std.math.divCeil(u64, payload_ty.bitSize(zcu), 8) catch unreachable)) * 8, - ), "") - else - loaded; - - return fg.wip.conv(.unneeded, shifted, payload_llvm_ty, ""); -} - -/// Load a by-ref type by constructing a new alloca and performing a memcpy. -fn loadByRef( - fg: *FuncGen, - ptr: Builder.Value, - pointee_type: Type, - ptr_alignment: Builder.Alignment, - access_kind: Builder.MemoryAccessKind, -) Allocator.Error!Builder.Value { - const o = fg.object; - const pointee_llvm_ty = try o.lowerType(pointee_type); - const result_align = InternPool.Alignment.fromLlvm(ptr_alignment) - .max(pointee_type.abiAlignment(o.zcu)).toLlvm(); - const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align); - const size_bytes = pointee_type.abiSize(o.zcu); - _ = try fg.wip.callMemCpy( - result_ptr, - result_align, - ptr, - ptr_alignment, - try o.builder.intValue(try o.lowerType(.usize), size_bytes), - access_kind, - fg.disable_intrinsics, - ); - return result_ptr; -} - -/// If `isByRef` returns `true` for `elem_ty`, this still performs a copy by memcpy'ing the value -/// into a new alloca. +/// Non-atomic, non-bitpacked load of type `load_ty` from pointer `ptr`. +/// +/// `ptr` has alignment `ptr_align`, or `load_ty.abiAlignment(zcu)` if `ptr_align` is `.none`. +/// +/// If `load_ty` is a by-ref type, then the value is copied to a new alloca with a memcpy, and a +/// pointer to that alloca is returned. fn load( fg: *FuncGen, ptr: Builder.Value, - elem_ty: Type, - ptr_alignment: Builder.Alignment, + ptr_align: InternPool.Alignment, + load_ty: Type, access_kind: Builder.MemoryAccessKind, ) Allocator.Error!Builder.Value { - const zcu = fg.object.zcu; - if (isByRef(elem_ty, zcu)) { - return fg.loadByRef(ptr, elem_ty, ptr_alignment, access_kind); - } else { - return fg.loadTruncate(access_kind, elem_ty, ptr, ptr_alignment); - } -} - -fn storeFull( - self: *FuncGen, - ptr: Builder.Value, - ptr_ty: Type, - elem: Builder.Value, - ordering: Builder.AtomicOrdering, -) Allocator.Error!void { - const o = self.object; + const o = fg.object; const zcu = o.zcu; - const info = ptr_ty.ptrInfo(zcu); - const elem_ty = Type.fromInterned(info.child); - if (!elem_ty.hasRuntimeBits(zcu)) { - return; - } - const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm(); - const access_kind: Builder.MemoryAccessKind = - if (info.flags.is_volatile) .@"volatile" else .normal; - if (info.flags.vector_index != .none) { - const index_u32 = try o.builder.intValue(.i32, info.flags.vector_index); - const vec_elem_ty = try o.lowerType(elem_ty); - const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty); + const abi_align = load_ty.abiAlignment(zcu); + const abi_size = load_ty.abiSize(zcu); - const loaded_vector = try self.wip.load(.normal, vec_ty, ptr, ptr_alignment, ""); + const llvm_ptr_align: Builder.Alignment = switch (ptr_align) { + .none => abi_align.toLlvm(), + else => |a| a.toLlvm(), + }; - const modified_vector = try self.wip.insertElement(loaded_vector, elem, index_u32, ""); - - assert(ordering == .none); - _ = try self.wip.store(access_kind, modified_vector, ptr, ptr_alignment); - return; - } - - if (info.packed_offset.host_size != 0) { - const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); - assert(ordering == .none); - const containing_int = - try self.wip.load(.normal, containing_int_ty, ptr, ptr_alignment, ""); - const elem_bits = ptr_ty.childType(zcu).bitSize(zcu); - const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset); - // Convert to equally-sized integer type in order to perform the bit - // operations on the value to store - const value_bits_type = try o.builder.intType(@intCast(elem_bits)); - const value_bits = if (elem_ty.isPtrAtRuntime(zcu)) - try self.wip.cast(.ptrtoint, elem, value_bits_type, "") - else - try self.wip.cast(.bitcast, elem, value_bits_type, ""); - - const mask_val = blk: { - const zext = try self.wip.cast( - .zext, - try o.builder.intValue(value_bits_type, -1), - containing_int_ty, - "", - ); - const shl = try self.wip.bin(.shl, zext, shift_amt.toValue(), ""); - break :blk try self.wip.bin( - .xor, - shl, - try o.builder.intValue(containing_int_ty, -1), - "", - ); - }; - - const anded_containing_int = try self.wip.bin(.@"and", containing_int, mask_val, ""); - const extended_value = try self.wip.cast(.zext, value_bits, containing_int_ty, ""); - const shifted_value = try self.wip.bin(.shl, extended_value, shift_amt.toValue(), ""); - const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, ""); - - assert(ordering == .none); - _ = try self.wip.store(access_kind, ored_value, ptr, ptr_alignment); - return; - } - if (!isByRef(elem_ty, zcu)) { - _ = try self.wip.storeAtomic( - access_kind, - elem, + if (isByRef(load_ty, zcu)) { + const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const result_ptr = try fg.buildZigAlloca(load_ty, .none); + _ = try fg.wip.callMemCpy( + result_ptr, + abi_align.toLlvm(), ptr, - self.sync_scope, - ordering, - ptr_alignment, + llvm_ptr_align, + try o.builder.intValue(llvm_usize_ty, abi_size), + access_kind, + fg.disable_intrinsics, ); - return; + return result_ptr; } - assert(ordering == .none); - _ = try self.wip.callMemCpy( - ptr, - ptr_alignment, - elem, - elem_ty.abiAlignment(zcu).toLlvm(), - try o.builder.intValue(try o.lowerType(.usize), elem_ty.abiSize(zcu)), - access_kind, - self.disable_intrinsics, - ); + + const llvm_memory_ty = try o.lowerType(load_ty, .in_memory); + const llvm_value_ty = try o.lowerType(load_ty, .by_value); + + if (llvm_memory_ty != llvm_value_ty) { + assert(load_ty.isAbiInt(zcu)); + // `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: + // + // * LLVM's lowering for these integer types generally leads to poor codegen, as integers + // are only extended to the next byte, instead of to the next "natural" integer type. + // + // * Clang never emits loads or stores of these types, so LLVM's support for them is rather + // flaky---we have encountered several LLVM bugs caused by incorrect handling of them. + // + // 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, ""); + // 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) { + .unsigned => .@"trunc nuw", + .signed => .@"trunc nsw", + }, + }, loaded, llvm_value_ty, ""); + } + + // `load_ty` is a simple by-val type which requires no special handling. + return fg.wip.load(access_kind, llvm_value_ty, ptr, llvm_ptr_align, ""); } -/// Non-atomic, non-volatile, non-packed store. +/// Non-atomic, non-bitpacked store of `elem` to pointer `ptr`. +/// +/// `ptr` has alignment `ptr_align`, or `elem_ty.abiAlignment(zcu)` if `ptr_align` is `.none`. +/// +/// If `elem_ty` is a by-ref type, then `elem` is itself a pointer, and a memcpy is emitted. fn store( fg: *FuncGen, ptr: Builder.Value, ptr_align: InternPool.Alignment, elem: Builder.Value, elem_ty: Type, + access_kind: Builder.MemoryAccessKind, ) Allocator.Error!void { const o = fg.object; const zcu = o.zcu; + + const abi_align = elem_ty.abiAlignment(zcu); + const abi_size = elem_ty.abiSize(zcu); + const llvm_ptr_align = switch (ptr_align) { - .none => elem_ty.abiAlignment(zcu).toLlvm(), + .none => abi_align.toLlvm(), else => ptr_align.toLlvm(), }; + if (isByRef(elem_ty, zcu)) { + const llvm_usize_ty = try o.lowerType(.usize, .by_value); _ = try fg.wip.callMemCpy( ptr, llvm_ptr_align, elem, - elem_ty.abiAlignment(zcu).toLlvm(), - try o.builder.intValue( - try o.lowerType(.usize), - elem_ty.abiSize(zcu), - ), - .normal, + abi_align.toLlvm(), + try o.builder.intValue(llvm_usize_ty, abi_size), + access_kind, fg.disable_intrinsics, ); - } else { + return; + } + + assert(elem.typeOfWip(&fg.wip) == try o.lowerType(elem_ty, .by_value)); + + const llvm_memory_ty = try o.lowerType(elem_ty, .in_memory); + const llvm_value_ty = try o.lowerType(elem_ty, .by_value); + + if (llvm_memory_ty != llvm_value_ty) { + assert(elem_ty.isAbiInt(zcu)); + // `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) { + .unsigned => .zext, + .signed => .sext, + }, elem, llvm_memory_ty, ""); _ = try fg.wip.storeAtomic( - .normal, - elem, + access_kind, + extended, ptr, fg.sync_scope, .none, 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, + ); } 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); + const usize_ty = try o.lowerType(.usize, .by_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, ""); @@ -6451,19 +6423,19 @@ fn valgrindClientRequest( const target = zcu.getTarget(); if (!target_util.hasValgrindSupport(target, .stage2_llvm)) return default_value; - const llvm_usize = try o.lowerType(.usize); - const usize_alignment = Type.usize.abiAlignment(zcu).toLlvm(); + const llvm_usize = try o.lowerType(.usize, .by_value); + const usize_align = Type.usize.abiAlignment(zcu).toLlvm(); const array_llvm_ty = try o.builder.arrayType(6, llvm_usize); const array_ptr = if (fg.valgrind_client_request_array == .none) a: { - const array_ptr = try fg.buildAlloca(array_llvm_ty, usize_alignment); + const array_ptr = try fg.buildAlloca(array_llvm_ty, usize_align); fg.valgrind_client_request_array = array_ptr; break :a array_ptr; } else fg.valgrind_client_request_array; const array_elements = [_]Builder.Value{ request, a1, a2, a3, a4, a5 }; for (array_elements, 0..) |elem, i| { const elem_ptr = try fg.ptraddConst(array_ptr, i * Type.usize.abiSize(zcu)); - _ = try fg.wip.store(.normal, elem, elem_ptr, usize_alignment); + try fg.store(elem_ptr, .none, elem, .usize, .normal); } const arch_specific: struct { @@ -6662,7 +6634,7 @@ const ParamTypeIterator = struct { .async => { @panic("TODO implement async function lowering in the LLVM backend"); }, - .x86_64_sysv => return it.nextSystemV(ty), + .x86_64_sysv, .x86_64_x32 => return it.nextSystemV(ty), .x86_64_win => return it.nextWin64(ty), .x86_stdcall => { it.zig_index += 1; @@ -6733,7 +6705,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); + it.types_buffer[it.types_len] = try it.object.lowerType(field_ty, .by_value); it.offsets_buffer[it.types_len] = ty.structFieldOffset(field_index, zcu); it.types_len += 1; } @@ -6750,7 +6722,7 @@ const ParamTypeIterator = struct { it.llvm_index += 1; return .byval; } else { - it.types_buffer[0..1].* = .{try it.object.lowerType(scalar_ty)}; + it.types_buffer[0..1].* = .{try it.object.lowerType(scalar_ty, .by_value)}; it.offsets_buffer[0..2].* = .{ 0, scalar_ty.abiSize(zcu) }; it.types_len = 1; it.llvm_index += 1; @@ -6788,22 +6760,30 @@ const ParamTypeIterator = struct { return .abi_sized_int; } }, - .win_i128 => { + .sse, + .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 .byref; + return .byval; }, + .sseup, .x87, .x87up, .none, .float, .float_combine => unreachable, .memory => { it.zig_index += 1; it.llvm_index += 1; return .byref_mut; }, - .sse => { + .win_i128 => { it.zig_index += 1; it.llvm_index += 1; - return .byval; + return .byref; }, - else => unreachable, } } @@ -6866,9 +6846,14 @@ const ParamTypeIterator = struct { .none => break, .memory => unreachable, // handled above .win_i128 => unreachable, // windows only - .integer_per_element => { - @panic("TODO"); - }, + .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; } @@ -6911,159 +6896,176 @@ pub fn iterateParamTypes(object: *Object, fn_info: InternPool.Key.FuncType) Para .fn_info = fn_info, .zig_index = 0, .llvm_index = 0, - .types_len = 0, + .types_len = undefined, .types_buffer = undefined, .offsets_buffer = undefined, .byval_attr = false, }; } -fn returnTypeByRef(zcu: *Zcu, target: *const std.Target, ty: Type) bool { - if (isByRef(ty, zcu)) { - return true; - } 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 true; - } else { - return false; +pub const FnReturnStrat = union(enum) { + /// The function return type is OPV (zero-bit), so the LLVM function return type is `void`. + void, + /// An sret parameter is used. The LLVM function return type is `void`. + sret, + /// The function's return type directly corresponds to the LLVM function return type. + /// + /// The return type is by-val, i.e. `isByRef` returns `false`. + by_val, + /// The LLVM function returns the given `Builder.Type` by reinterpreting memory containing the + /// actual return value. The actual return type may be by-val or by-ref. + mem_cast: Builder.Type, + + fn forceByVal(o: *Object, ret_ty: Type) Allocator.Error!FnReturnStrat { + if (!isByRef(ret_ty, o.zcu)) return .by_val; + return .{ .mem_cast = try o.lowerType(ret_ty, .in_memory) }; } -} - -pub fn firstParamSRet(fn_info: InternPool.Key.FuncType, zcu: *Zcu, target: *const std.Target) bool { - const return_type = Type.fromInterned(fn_info.return_type); - if (!return_type.hasRuntimeBits(zcu)) return false; - - return switch (fn_info.cc) { - .auto => returnTypeByRef(zcu, target, return_type), - .x86_64_sysv => firstParamSRetSystemV(return_type, zcu, target), - .x86_64_win => x86_64_abi.classifyWindows(return_type, zcu, target, .ret) == .memory, - .x86_sysv, .x86_win => isByRef(return_type, zcu), - .x86_stdcall => !isScalar(zcu, return_type), - .wasm_mvp => wasm_c_abi.classifyType(return_type, zcu) == .indirect, - .aarch64_aapcs, - .aarch64_aapcs_darwin, - .aarch64_aapcs_win, - => aarch64_c_abi.classifyType(return_type, zcu) == .memory, - .arm_aapcs, .arm_aapcs_vfp => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) { - .memory, .i64_array => true, - .i32_array => |size| size != 1, - .byval => false, - }, - .riscv64_lp64, .riscv32_ilp32 => riscv_c_abi.classifyType(return_type, zcu) == .memory, - .mips_o32 => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) { - .memory, .i32_array => true, - .byval => false, - }, - else => false, // TODO: investigate other targets/callconvs - }; -} - -fn firstParamSRetSystemV(ty: Type, zcu: *Zcu, target: *const std.Target) bool { - const class = x86_64_abi.classifySystemV(ty, zcu, target, .ret); - if (class[0] == .memory) return true; - if (class[0] == .x87 and class[2] != .none) return true; - return false; -} - +}; /// 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 lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { +pub fn fnReturnStrat(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const return_type = Type.fromInterned(fn_info.return_type); - if (!return_type.hasRuntimeBits(zcu)) { - assert(!return_type.isError(zcu)); - return .void; - } - const target = zcu.getTarget(); + const ret_ty: Type = .fromInterned(fn_info.return_type); + ret_ty.assertHasLayout(zcu); + if (!ret_ty.hasRuntimeBits(zcu)) return .void; switch (fn_info.cc) { .@"inline" => unreachable, - .auto => return if (returnTypeByRef(zcu, target, return_type)) .void else o.lowerType(return_type), + .auto => { + if (isByRef(ret_ty, zcu)) return .sret; - .x86_64_sysv => return lowerSystemVFnRetTy(o, fn_info), + 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; + }, + .x86_64_sysv, .x86_64_x32 => return lowerSystemVFnRetTy(o, fn_info), .x86_64_win => return lowerWin64FnRetTy(o, fn_info), - .x86_stdcall => return if (isScalar(zcu, return_type)) o.lowerType(return_type) else .void, - .x86_sysv, .x86_win => return if (isByRef(return_type, zcu)) .void else o.lowerType(return_type), - .aarch64_aapcs, .aarch64_aapcs_darwin, .aarch64_aapcs_win => switch (aarch64_c_abi.classifyType(return_type, zcu)) { - .memory => return .void, - .float_array => return o.lowerType(return_type), - .byval => return o.lowerType(return_type), - .integer => return .i64, - .double_integer => return o.builder.arrayType(2, .i64), + .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) }, }, - .arm_aapcs, .arm_aapcs_vfp => switch (arm_c_abi.classifyType(return_type, zcu, .ret)) { - .memory, .i64_array => return .void, - .i32_array => |len| return if (len == 1) .i32 else .void, - .byval => return o.lowerType(return_type), + .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), }, - .mips_o32 => switch (mips_c_abi.classifyType(return_type, zcu, .ret)) { - .memory, .i32_array => return .void, - .byval => return o.lowerType(return_type), + .mips_o32 => switch (mips_c_abi.classifyType(ret_ty, zcu, .ret)) { + .memory, .i32_array => return .sret, + .byval => return .forceByVal(o, ret_ty), }, - .riscv64_lp64, .riscv32_ilp32 => switch (riscv_c_abi.classifyType(return_type, zcu)) { - .memory => return .void, - .integer => return o.builder.intType(@intCast(return_type.bitSize(zcu))), + .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)) }, .double_integer => { const integer: Builder.Type = switch (zcu.getTarget().cpu.arch) { .riscv64, .riscv64be => .i64, .riscv32, .riscv32be => .i32, else => unreachable, }; - return o.builder.structType(.normal, &.{ integer, integer }); + return .{ .mem_cast = try o.builder.structType(.normal, &.{ integer, integer }) }; }, - .byval => return o.lowerType(return_type), + .byval => return .forceByVal(o, ret_ty), .fields => { var types_len: usize = 0; var types: [8]Builder.Type = undefined; - for (0..return_type.structFieldCount(zcu)) |field_index| { - const field_ty = return_type.fieldType(field_index, zcu); + 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); + types[types_len] = try o.lowerType(field_ty, .by_value); types_len += 1; } - return o.builder.structType(.normal, types[0..types_len]); + return .{ .mem_cast = try o.builder.structType(.normal, types[0..types_len]) }; }, }, - .wasm_mvp => switch (wasm_c_abi.classifyType(return_type, zcu)) { - .direct => |scalar_ty| return o.lowerType(scalar_ty), - .indirect => return .void, + .wasm_mvp => switch (wasm_c_abi.classifyType(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, }, // TODO investigate other callconvs - else => return o.lowerType(return_type), + else => return .forceByVal(o, ret_ty), } } -fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { +fn lowerX86FastcallFnRetTy(o: *Object, zcu: *Zcu, ty: Type) Allocator.Error!FnReturnStrat { + if (isScalar(zcu, ty)) { + assert(!isByRef(ty, zcu)); + return .by_val; + } + const tag = ty.zigTypeTag(zcu); + if (tag == .@"struct" or tag == .@"union") { + const size = ty.abiSize(zcu); + if (size == 1 or size == 2 or size == 4 or size == 8) { + return .{ .mem_cast = try o.builder.intType(@intCast(size * 8)) }; + } + } + return .sret; +} + +fn lowerWin64FnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { const zcu = o.zcu; - const return_type = Type.fromInterned(fn_info.return_type); - switch (x86_64_abi.classifyWindows(return_type, zcu, zcu.getTarget(), .ret)) { - .integer => { - if (isScalar(zcu, return_type)) { - return o.lowerType(return_type); - } else { - return o.builder.intType(@intCast(return_type.abiSize(zcu) * 8)); - } + 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)); + return .by_val; + } else { + return .{ .mem_cast = try o.builder.intType(@intCast(ret_ty.abiSize(zcu) * 8)) }; }, - .win_i128 => return o.builder.vectorType(.normal, 2, .i64), - .memory => return .void, - .sse => return o.lowerType(return_type), - else => unreachable, + .win_i128 => return .{ .mem_cast = try o.builder.vectorType(.normal, 2, .i64) }, + .memory => return .sret, + + .sse, + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => { + assert(!isByRef(ret_ty, zcu)); + return .by_val; + }, + .sseup, + .x87, + .x87up, + .none, + .float, + .float_combine, + => unreachable, } } -fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type { +fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!FnReturnStrat { const zcu = o.zcu; const ip = &zcu.intern_pool; - const return_type = Type.fromInterned(fn_info.return_type); - return_type.assertHasLayout(zcu); - if (isScalar(zcu, return_type)) { - return o.lowerType(return_type); + 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(return_type, zcu, zcu.getTarget(), .ret); + 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| { @@ -7093,22 +7095,30 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E types_index += 1; }, .x87 => { - if (types_index != 0 or classes[2] != .none) return .void; + if (types_index != 0 or classes[2] != .none) return .sret; types_buffer[types_index] = .x86_fp80; types_index += 1; }, .x87up => continue, .none => break, - .memory, .integer_per_element => return .void, + .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 } } 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(return_type.toIntern())) { + switch (ip.indexToKey(ret_ty.toIntern())) { .struct_type => { - const size = return_type.abiSize(zcu); + const size = ret_ty.abiSize(zcu); assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index); if (size % 8 > 0) { types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8)); @@ -7116,9 +7126,9 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E }, else => {}, } - if (types_index == 1) return types_buffer[0]; + if (types_index == 1) return .{ .mem_cast = types_buffer[0] }; } - return o.builder.structType(.normal, types_buffer[0..types_index]); + return .{ .mem_cast = try o.builder.structType(.normal, types_buffer[0..types_index]) }; } /// This function deliberately does not handle `_BitInt` because it typically @@ -7217,33 +7227,6 @@ fn isScalar(zcu: *Zcu, ty: Type) bool { }; } -pub fn buildAllocaInner( - wip: *Builder.WipFunction, - llvm_ty: Builder.Type, - alignment: Builder.Alignment, - target: *const std.Target, -) Allocator.Error!Builder.Value { - const address_space = llvmAllocaAddressSpace(target); - - const alloca = blk: { - const prev_cursor = wip.cursor; - const prev_debug_location = wip.debug_location; - defer { - wip.cursor = prev_cursor; - if (wip.cursor.block == .entry) wip.cursor.instruction += 1; - wip.debug_location = prev_debug_location; - } - - wip.cursor = .{ .block = .entry }; - wip.debug_location = .no_location; - break :blk try wip.alloca(.normal, llvm_ty, .none, alignment, address_space, ""); - }; - - // The pointer returned from this function should have the generic address space, - // if this isn't the case then cast it to the generic address space. - return wip.conv(.unneeded, alloca, .ptr, ""); -} - /// This is the one source of truth for whether a type is passed around as an LLVM pointer, /// or as an LLVM value. pub fn isByRef(ty: Type, zcu: *const Zcu) bool { @@ -7255,6 +7238,7 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool { .undefined, .null, .@"opaque", + .spirv, => unreachable, .noreturn, @@ -7284,7 +7268,7 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool { }, .@"union" => switch (ty.containerLayout(zcu)) { .@"packed" => false, - else => ty.hasRuntimeBits(zcu) and !ty.unionHasAllZeroBitFieldTypes(zcu), + else => ty.hasRuntimeBits(zcu), }, }; } @@ -7313,7 +7297,11 @@ 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 { - return fg.object.ptraddConst(&fg.wip, ptr, offset); + if (offset == 0) return ptr; + const o = fg.object; + const llvm_usize_ty = try o.lowerType(.usize, .by_value); + const offset_val = try o.builder.intValue(llvm_usize_ty, offset); + return fg.wip.gep(.inbounds, .i8, ptr, &.{offset_val}, ""); } fn ptraddScaled(fg: *FuncGen, ptr: Builder.Value, index: Builder.Value, scale: u64) Allocator.Error!Builder.Value { if (scale == 0) return ptr; diff --git a/src/codegen/mips/abi.zig b/src/codegen/mips/abi.zig index a27adb7ace40ff937a820a2e8bdfacea12f85d31..f512f1e6db98031dd581bc9cb19ef7be42b7ae29 100644 --- a/src/codegen/mips/abi.zig +++ b/src/codegen/mips/abi.zig @@ -18,24 +18,23 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { const max_direct_size = target.ptrBitWidth() * 2; switch (ty.zigTypeTag(zcu)) { .@"struct" => { - const bit_size = ty.bitSize(zcu); if (ty.containerLayout(zcu) == .@"packed") { - if (bit_size > max_direct_size) return .memory; + if (ty.bitSize(zcu) > max_direct_size) return .memory; return .byval; } + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > max_direct_size) return .memory; // TODO: for bit_size <= 32 using byval is more correct, but that needs inreg argument attribute const count = @as(u8, @intCast(std.mem.alignForward(u64, bit_size, 32) / 32)); return .{ .i32_array = count }; }, .@"union" => { - const bit_size = ty.bitSize(zcu); if (ty.containerLayout(zcu) == .@"packed") { - if (bit_size > max_direct_size) return .memory; + if (ty.bitSize(zcu) > max_direct_size) return .memory; return .byval; } + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > max_direct_size) return .memory; - return .byval; }, .bool => return .byval, @@ -77,6 +76,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { .null, .@"fn", .@"opaque", + .spirv, .enum_literal, .array, => unreachable, diff --git a/src/codegen/riscv64/CodeGen.zig b/src/codegen/riscv64/CodeGen.zig index 1c882c0270b3378a72508de2ab343a0e9d49d1d2..bbbe85884910a935e8b2501807993643030213f5 100644 --- a/src/codegen/riscv64/CodeGen.zig +++ b/src/codegen/riscv64/CodeGen.zig @@ -51,7 +51,7 @@ const InnerError = codegen.Error || error{OutOfRegisters}; pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { return comptime &.initMany(&.{ - .expand_intcast_safe, + .expand_int_cast_safe, .expand_int_from_float_safe, .expand_int_from_float_optimized_safe, .expand_add_safe, @@ -112,7 +112,7 @@ const_tracking: ConstTrackingMap = .{}, inst_tracking: InstTrackingMap = .{}, frame_allocs: std.MultiArrayList(FrameAlloc) = .{}, -free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .empty, +free_frame_indices: std.array_hash_map.Auto(FrameIndex, void) = .empty, frame_locs: std.MultiArrayList(Mir.FrameLoc) = .{}, loops: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { @@ -338,7 +338,7 @@ const MCValue = union(enum) { }; const Branch = struct { - inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .empty, + inst_table: std.array_hash_map.Auto(Air.Inst.Index, MCValue) = .empty, fn deinit(func: *Branch, gpa: Allocator) void { func.inst_table.deinit(gpa); @@ -346,8 +346,8 @@ const Branch = struct { } }; -const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking); -const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking); +const InstTrackingMap = std.array_hash_map.Auto(Air.Inst.Index, InstTracking); +const ConstTrackingMap = std.array_hash_map.Auto(InternPool.Index, InstTracking); const InstTracking = struct { long: MCValue, @@ -1453,7 +1453,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .add_safe, .sub_safe, .mul_safe, - .intcast_safe, + .int_cast_safe, .int_from_float_safe, .int_from_float_optimized_safe, => return func.fail("TODO implement safety_checked_instructions", .{}), @@ -1479,7 +1479,14 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .ret_ptr => try func.airRetPtr(inst), .arg => try func.airArg(inst), .assembly => try func.airAsm(inst), - .bitcast => try func.airBitCast(inst), + .bit_cast => try func.airBitCast(inst), + .ptr_cast => try func.airBitCast(inst), + .ptr_from_int => try func.airBitCast(inst), + .int_from_ptr => try func.airBitCast(inst), + .error_cast => try func.airBitCast(inst), + .error_from_int => try func.airBitCast(inst), + .int_from_error => try func.airBitCast(inst), + .union_from_enum => try func.airBitCast(inst), .block => try func.airBlock(inst), .br => try func.airBr(inst), .repeat => try func.airRepeat(inst), @@ -1493,7 +1500,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .dbg_empty_stmt => func.finishAirBookkeeping(), .fptrunc => try func.airFptrunc(inst), .fpext => try func.airFpext(inst), - .intcast => try func.airIntCast(inst), + .int_cast => try func.airIntCast(inst), .trunc => try func.airTrunc(inst), .is_non_null => try func.airIsNonNull(inst), .is_non_null_ptr => try func.airIsNonNullPtr(inst), @@ -1642,6 +1649,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { .work_item_id => unreachable, .work_group_size => unreachable, .work_group_id => unreachable, + .spirv_runtime_array_len => unreachable, // zig fmt: on } @@ -3162,7 +3170,7 @@ fn airMulWithOverflow(func: *Func, inst: Air.Inst.Index) !void { switch (lhs_ty.zigTypeTag(zcu)) { else => |x| return func.fail("TODO: airMulWithOverflow {s}", .{@tagName(x)}), .int => { - if (std.debug.runtime_safety) assert(lhs_ty.eql(rhs_ty, zcu)); + if (std.debug.runtime_safety) assert(lhs_ty.eql(rhs_ty)); const trunc_reg = try func.copyToTmpRegister(lhs_ty, .{ .register = dest_reg }); const trunc_reg_lock = func.register_manager.lockRegAssumeUnused(trunc_reg); @@ -3952,9 +3960,7 @@ fn airPtrElemPtr(func: *Func, inst: Air.Inst.Index) !void { const elem_ptr_ty = func.typeOfIndex(inst); const base_ptr_ty = func.typeOf(extra.lhs); - if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) { - @panic("audit"); - } + assert(elem_ptr_ty.ptrInfo(zcu).flags.vector_index == .none); const base_ptr_mcv = try func.resolveInst(extra.lhs); const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) { diff --git a/src/codegen/riscv64/abi.zig b/src/codegen/riscv64/abi.zig index 7c00ba13a55f8d284bdb20104d5a78d0b5a86521..5c89a35f7bd4e718e8e032093856f6068b751c9b 100644 --- a/src/codegen/riscv64/abi.zig +++ b/src/codegen/riscv64/abi.zig @@ -16,9 +16,8 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { const max_byval_size = target.ptrBitWidth() * 2; switch (ty.zigTypeTag(zcu)) { .@"struct" => { - const bit_size = ty.bitSize(zcu); if (ty.containerLayout(zcu) == .@"packed") { - if (bit_size > max_byval_size) return .memory; + if (ty.bitSize(zcu) > max_byval_size) return .memory; return .byval; } @@ -40,17 +39,18 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { } // TODO this doesn't exactly match what clang produces but its better than nothing + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > max_byval_size) return .memory; if (bit_size > max_byval_size / 2) return .double_integer; return .integer; }, .@"union" => { - const bit_size = ty.bitSize(zcu); if (ty.containerLayout(zcu) == .@"packed") { - if (bit_size > max_byval_size) return .memory; + if (ty.bitSize(zcu) > max_byval_size) return .memory; return .byval; } // TODO this doesn't exactly match what clang produces but its better than nothing + const bit_size = ty.abiSize(zcu) * 8; if (bit_size > max_byval_size) return .memory; if (bit_size > max_byval_size / 2) return .double_integer; return .integer; @@ -87,6 +87,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { .null, .@"fn", .@"opaque", + .spirv, .enum_literal, .array, => unreachable, @@ -152,13 +153,12 @@ pub fn classifySystem(ty: Type, zcu: *Zcu) [8]SystemClass { }, .error_union => { const payload_ty = ty.errorUnionPayload(zcu); - const payload_bits = payload_ty.bitSize(zcu); // the error union itself result[0] = .integer; // anyerror!void can fit into one register - if (payload_bits == 0) return result; + if (!payload_ty.hasRuntimeBits(zcu)) return result; return memory_class; }, diff --git a/src/codegen/sparc64/CodeGen.zig b/src/codegen/sparc64/CodeGen.zig index 7ad950d22e2e628187a384b814735ea292b06009..32bfd50773ac78455aa52ef2fd250a7c55f68abd 100644 --- a/src/codegen/sparc64/CodeGen.zig +++ b/src/codegen/sparc64/CodeGen.zig @@ -200,7 +200,7 @@ const MCValue = union(enum) { }; const Branch = struct { - inst_table: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, MCValue) = .empty, + inst_table: std.array_hash_map.Auto(Air.Inst.Index, MCValue) = .empty, fn deinit(self: *Branch, gpa: Allocator) void { self.inst_table.deinit(gpa); @@ -538,7 +538,14 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .ret_ptr => try self.airRetPtr(inst), .arg => try self.airArg(inst), .assembly => try self.airAsm(inst), - .bitcast => try self.airBitCast(inst), + .bit_cast => try self.airBitCast(inst), + .ptr_cast => try self.airBitCast(inst), + .ptr_from_int => try self.airBitCast(inst), + .int_from_ptr => try self.airBitCast(inst), + .error_cast => try self.airBitCast(inst), + .error_from_int => try self.airBitCast(inst), + .int_from_error => try self.airBitCast(inst), + .union_from_enum => try self.airBitCast(inst), .block => try self.airBlock(inst), .br => try self.airBr(inst), .repeat => return self.fail("TODO implement `repeat`", .{}), @@ -550,7 +557,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .cond_br => try self.airCondBr(inst), .fptrunc => @panic("TODO try self.airFptrunc(inst)"), .fpext => @panic("TODO try self.airFpext(inst)"), - .intcast => try self.airIntCast(inst), + .int_cast => try self.airIntCast(inst), .trunc => try self.airTrunc(inst), .is_non_null => try self.airIsNonNull(inst), .is_non_null_ptr => @panic("TODO try self.airIsNonNullPtr(inst)"), @@ -689,7 +696,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .add_safe, .sub_safe, .mul_safe, - .intcast_safe, + .int_cast_safe, .int_from_float_safe, .int_from_float_optimized_safe, => @panic("TODO implement safety_checked_instructions"), @@ -709,6 +716,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .work_item_id => unreachable, .work_group_size => unreachable, .work_group_id => unreachable, + .spirv_runtime_array_len => unreachable, // zig fmt: on } @@ -743,7 +751,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { switch (lhs_ty.zigTypeTag(zcu)) { .vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), .int => { - assert(lhs_ty.eql(rhs_ty, zcu)); + assert(lhs_ty.eql(rhs_ty)); const int_info = lhs_ty.intInfo(zcu); switch (int_info.bits) { 32, 64 => { @@ -1658,7 +1666,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { const info_a = operand_ty.intInfo(zcu); const info_b = self.typeOfIndex(inst).intInfo(zcu); if (info_a.signedness != info_b.signedness) - return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); + return self.fail("TODO gen int_cast sign safety in semantic analysis", .{}); if (info_a.bits == info_b.bits) return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); @@ -1796,7 +1804,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { const rhs = try self.resolveInst(bin_op.rhs); const lhs_ty = self.typeOf(bin_op.lhs); const rhs_ty = self.typeOf(bin_op.rhs); - assert(lhs_ty.eql(rhs_ty, self.pt.zcu)); + assert(lhs_ty.eql(rhs_ty)); if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); @@ -1949,7 +1957,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { switch (lhs_ty.zigTypeTag(zcu)) { .vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), .int => { - assert(lhs_ty.eql(rhs_ty, zcu)); + assert(lhs_ty.eql(rhs_ty)); const int_info = lhs_ty.intInfo(zcu); switch (int_info.bits) { 1...32 => { @@ -2779,7 +2787,7 @@ fn binOp( .float => return self.fail("TODO binary operations on floats", .{}), .vector => return self.fail("TODO binary operations on vectors", .{}), .int => { - assert(lhs_ty.eql(rhs_ty, zcu)); + assert(lhs_ty.eql(rhs_ty)); const int_info = lhs_ty.intInfo(zcu); if (int_info.bits <= 64) { // Only say yes if the operation is @@ -2869,7 +2877,7 @@ fn binOp( switch (lhs_ty.zigTypeTag(zcu)) { .vector => return self.fail("TODO binary operations on vectors", .{}), .int => { - assert(lhs_ty.eql(rhs_ty, zcu)); + assert(lhs_ty.eql(rhs_ty)); const int_info = lhs_ty.intInfo(zcu); if (int_info.bits <= 64) { const rhs_immediate_ok = switch (tag) { @@ -4225,7 +4233,7 @@ fn minMax( ) InnerError!MCValue { const pt = self.pt; const zcu = pt.zcu; - assert(lhs_ty.eql(rhs_ty, zcu)); + assert(lhs_ty.eql(rhs_ty)); switch (lhs_ty.zigTypeTag(zcu)) { .float => return self.fail("TODO min/max on floats", .{}), .vector => return self.fail("TODO min/max on vectors", .{}), diff --git a/src/codegen/spirv/Assembler.zig b/src/codegen/spirv/Assembler.zig index c80c246b10a4218b126155efb262885e3d4d0746..f18f9028212b4916ed70a89d080e28a3bad75f3f 100644 --- a/src/codegen/spirv/Assembler.zig +++ b/src/codegen/spirv/Assembler.zig @@ -3,7 +3,7 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const CodeGen = @import("CodeGen.zig"); -const Decl = @import("Module.zig").Decl; +const Decl = @import("CodeGen.zig").Decl; const spec = @import("spec.zig"); const Opcode = spec.Opcode; @@ -35,8 +35,8 @@ inst: struct { return null; } } = .{}, -value_map: std.StringArrayHashMapUnmanaged(AsmValue) = .{}, -inst_map: std.StringArrayHashMapUnmanaged(void) = .empty, +value_map: std.array_hash_map.String(AsmValue) = .{}, +inst_map: std.array_hash_map.String(void) = .empty, const Operand = union(enum) { /// Any 'simple' 32-bit value. This could be a mask or @@ -56,7 +56,7 @@ const Operand = union(enum) { }; pub fn deinit(ass: *Assembler) void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; for (ass.errors.items) |err| gpa.free(err.msg); ass.tokens.deinit(gpa); ass.errors.deinit(gpa); @@ -69,7 +69,7 @@ pub fn deinit(ass: *Assembler) void { const Error = error{ AssembleFail, OutOfMemory }; pub fn assemble(ass: *Assembler, src: []const u8) Error!void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; ass.src = src; ass.errors.clearRetainingCapacity(); @@ -100,7 +100,7 @@ const ErrorMsg = struct { }; fn addError(ass: *Assembler, offset: u32, comptime fmt: []const u8, args: anytype) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const msg = try std.fmt.allocPrint(gpa, fmt, args); errdefer gpa.free(msg); try ass.errors.append(gpa, .{ @@ -159,7 +159,7 @@ const AsmValue = union(enum) { /// If this function returns `error.AssembleFail`, an explanatory /// error message has already been emitted into `ass.errors`. fn processInstruction(ass: *Assembler) !void { - const module = ass.cg.module; + const cg = ass.cg; const result: AsmValue = switch (ass.inst.opcode) { .OpEntryPoint => { return ass.fail(ass.currentToken().start, "cannot export entry points in assembly", .{}); @@ -167,15 +167,8 @@ fn processInstruction(ass: *Assembler) !void { .OpExecutionMode, .OpExecutionModeId => { return ass.fail(ass.currentToken().start, "cannot set execution mode in assembly", .{}); }, - .OpCapability => { - try module.addCapability(@enumFromInt(ass.inst.operands.items[0].value)); - return; - }, - .OpExtension => { - const ext_name_offset = ass.inst.operands.items[0].string; - const ext_name = std.mem.sliceTo(ass.inst.string_bytes.items[ext_name_offset..], 0); - try module.addExtension(ext_name); - return; + .OpCapability, .OpExtension => { + return ass.fail(ass.currentToken().start, "cannot declare capabilities or extensions in assembly; use -mcpu instead", .{}); }, .OpExtInstImport => blk: { const set_name_offset = ass.inst.operands.items[1].string; @@ -183,7 +176,7 @@ fn processInstruction(ass: *Assembler) !void { const set_tag = std.meta.stringToEnum(spec.InstructionSet, set_name) orelse { return ass.fail(set_name_offset, "unknown instruction set: {s}", .{set_name}); }; - break :blk .{ .value = try module.importInstructionSet(set_tag) }; + break :blk .{ .value = try cg.importInstructionSet(set_tag) }; }, else => switch (ass.inst.opcode.class()) { .type_declaration => try ass.processTypeInstruction(), @@ -204,13 +197,12 @@ fn processInstruction(ass: *Assembler) !void { fn processTypeInstruction(ass: *Assembler) !AsmValue { const cg = ass.cg; - const gpa = cg.module.gpa; - const module = cg.module; + const gpa = cg.gpa; const operands = ass.inst.operands.items; - const section = &module.sections.globals; + const section = &cg.sections.globals; const id = switch (ass.inst.opcode) { - .OpTypeVoid => try module.voidType(), - .OpTypeBool => try module.boolType(), + .OpTypeVoid => try cg.voidType(), + .OpTypeBool => try cg.boolType(), .OpTypeInt => blk: { const signedness: std.lang.Signedness = switch (operands[2].literal32) { 0 => .unsigned, @@ -223,7 +215,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { const width = std.math.cast(u16, operands[1].literal32) orelse { return ass.fail(0, "int type of {} bits is too large", .{operands[1].literal32}); }; - break :blk try module.intType(signedness, width); + break :blk try cg.intType(signedness, width); }, .OpTypeFloat => blk: { const bits = operands[1].literal32; @@ -233,11 +225,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { return ass.fail(0, "{} is not a valid bit count for floats (expected 16, 32 or 64)", .{bits}); }, } - break :blk try module.floatType(@intCast(bits)); + break :blk try cg.floatType(@intCast(bits)); }, .OpTypeVector => blk: { const child_type = try ass.resolveRefId(operands[1].ref_id); - break :blk try module.vectorType(operands[2].literal32, child_type); + break :blk try cg.vectorType(operands[2].literal32, child_type); }, .OpTypeArray => { // TODO: The length of an OpTypeArray is determined by a constant (which may be a spec constant), @@ -246,8 +238,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { }, .OpTypeRuntimeArray => blk: { const element_type = try ass.resolveRefId(operands[1].ref_id); - const result_id = module.allocId(); - try section.emit(module.gpa, .OpTypeRuntimeArray, .{ + const result_id = cg.allocId(); + try section.emit(cg.gpa, .OpTypeRuntimeArray, .{ .id_result = result_id, .element_type = element_type, }); @@ -256,8 +248,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { .OpTypePointer => blk: { const storage_class: StorageClass = @enumFromInt(operands[1].value); const child_type = try ass.resolveRefId(operands[2].ref_id); - const result_id = module.allocId(); - try section.emit(module.gpa, .OpTypePointer, .{ + const result_id = cg.allocId(); + try section.emit(cg.gpa, .OpTypePointer, .{ .id_result = result_id, .storage_class = storage_class, .type = child_type, @@ -269,11 +261,11 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); const ids = try cg.id_scratch.addManyAsSlice(gpa, operands[1..].len); for (operands[1..], ids) |op, *id| id.* = try ass.resolveRefId(op.ref_id); - break :blk try module.structType(ids, null, null, .none); + break :blk try cg.structType(ids, null, .none); }, .OpTypeImage => blk: { const sampled_type = try ass.resolveRefId(operands[1].ref_id); - const result_id = module.allocId(); + const result_id = cg.allocId(); try section.emit(gpa, .OpTypeImage, .{ .id_result = result_id, .sampled_type = sampled_type, @@ -287,13 +279,13 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { break :blk result_id; }, .OpTypeSampler => blk: { - const result_id = module.allocId(); + const result_id = cg.allocId(); try section.emit(gpa, .OpTypeSampler, .{ .id_result = result_id }); break :blk result_id; }, .OpTypeSampledImage => blk: { const image_type = try ass.resolveRefId(operands[1].ref_id); - const result_id = module.allocId(); + const result_id = cg.allocId(); try section.emit(gpa, .OpTypeSampledImage, .{ .id_result = result_id, .image_type = image_type }); break :blk result_id; }, @@ -308,8 +300,8 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { for (param_types, param_operands) |*param, operand| { param.* = try ass.resolveRefId(operand.ref_id); } - const result_id = module.allocId(); - try section.emit(module.gpa, .OpTypeFunction, .{ + const result_id = cg.allocId(); + try section.emit(cg.gpa, .OpTypeFunction, .{ .id_result = result_id, .return_type = return_type, .id_ref_2 = param_types, @@ -325,27 +317,27 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { /// - No forward references are allowed in operands. /// - Target section is determined from instruction type. fn processGenericInstruction(ass: *Assembler) !?AsmValue { - const module = ass.cg.module; - const target = module.zcu.getTarget(); + const cg = ass.cg; + const target = cg.zcu.getTarget(); const operands = ass.inst.operands.items; var maybe_spv_decl_index: ?Decl.Index = null; const section = switch (ass.inst.opcode.class()) { - .constant_creation => &module.sections.globals, - .annotation => &module.sections.annotations, + .constant_creation => &cg.sections.globals, + .annotation => &cg.sections.annotations, .type_declaration => unreachable, // Handled elsewhere. else => switch (ass.inst.opcode) { .OpEntryPoint => unreachable, - .OpExecutionMode, .OpExecutionModeId => &module.sections.execution_modes, + .OpExecutionMode, .OpExecutionModeId => &cg.sections.execution_modes, .OpVariable => section: { const storage_class: spec.StorageClass = @enumFromInt(operands[2].value); if (storage_class == .function) break :section &ass.cg.prologue; - maybe_spv_decl_index = try module.allocDecl(.global); + maybe_spv_decl_index = try cg.allocDecl(.global); if (!target.cpu.has(.spirv, .v1_4) and storage_class != .input and storage_class != .output) { // Before version 1.4, the interface’s storage classes are limited to the Input and Output - break :section &module.sections.globals; + break :section &cg.sections.globals; } - try ass.cg.module.decl_deps.append(module.gpa, maybe_spv_decl_index.?); - break :section &module.sections.globals; + try ass.cg.decl_deps.append(cg.gpa, maybe_spv_decl_index.?); + break :section &cg.sections.globals; }, else => &ass.cg.body, }, @@ -355,36 +347,36 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue { 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(module.gpa, 1); + try section.ensureUnusedCapacity(cg.gpa, 1); section.writeWord(0); for (operands) |operand| { switch (operand) { .value, .literal32 => |word| { - try section.ensureUnusedCapacity(module.gpa, 1); + try section.ensureUnusedCapacity(cg.gpa, 1); section.writeWord(word); }, .literal64 => |dword| { - try section.ensureUnusedCapacity(module.gpa, 2); + try section.ensureUnusedCapacity(cg.gpa, 2); section.writeDoubleWord(dword); }, .result_id => { maybe_result_id = if (maybe_spv_decl_index) |spv_decl_index| - module.declPtr(spv_decl_index).result_id + cg.declPtr(spv_decl_index).result_id else - module.allocId(); - try section.ensureUnusedCapacity(module.gpa, 1); + 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(module.gpa, 1); + 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 = std.math.divCeil(usize, text.len + 1, @sizeOf(Word)) catch unreachable; - try section.ensureUnusedCapacity(module.gpa, size); + try section.ensureUnusedCapacity(cg.gpa, size); section.writeOperand(spec.LiteralString, text); }, } @@ -393,6 +385,15 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue { const actual_word_count = section.instructions.items.len - first_word; section.instructions.items[first_word] |= @as(u32, @as(u16, @intCast(actual_word_count))) << 16 | @intFromEnum(ass.inst.opcode); + switch (ass.inst.opcode) { + .OpKill, + .OpReturn, + .OpReturnValue, + .OpUnreachable, + => ass.cg.block_terminated = true, + else => {}, + } + if (maybe_result_id) |result| return .{ .value = result }; return null; } @@ -428,7 +429,7 @@ fn resolveRefId(ass: *Assembler, ref: AsmValue.Ref) !Id { } fn parseInstruction(ass: *Assembler) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; ass.inst.opcode = undefined; ass.inst.operands.clearRetainingCapacity(); @@ -520,7 +521,7 @@ fn parseOperand(ass: *Assembler, kind: spec.OperandKind) Error!void { /// Also handles parsing any required extra operands. fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; var tok = ass.currentToken(); try ass.expectToken(.value); @@ -569,7 +570,7 @@ fn parseBitEnum(ass: *Assembler, kind: spec.OperandKind) !void { /// Also handles parsing any required extra operands. fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const tok = ass.currentToken(); if (ass.eatToken(.placeholder)) { @@ -620,7 +621,7 @@ fn parseValueEnum(ass: *Assembler, kind: spec.OperandKind) !void { } fn parseRefId(ass: *Assembler) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const tok = ass.currentToken(); try ass.expectToken(.result_id); @@ -636,7 +637,7 @@ fn parseRefId(ass: *Assembler) !void { } fn parseLiteralInteger(ass: *Assembler) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const tok = ass.currentToken(); if (ass.eatToken(.placeholder)) { @@ -669,7 +670,7 @@ fn parseLiteralInteger(ass: *Assembler) !void { } fn parseLiteralExtInstInteger(ass: *Assembler) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const tok = ass.currentToken(); if (ass.eatToken(.placeholder)) { @@ -697,7 +698,7 @@ fn parseLiteralExtInstInteger(ass: *Assembler) !void { } fn parseString(ass: *Assembler) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const tok = ass.currentToken(); try ass.expectToken(.string); @@ -720,46 +721,36 @@ fn parseString(ass: *Assembler) !void { } fn parseContextDependentNumber(ass: *Assembler) !void { - const module = ass.cg.module; - - // For context dependent numbers, the actual type to parse is determined by the instruction. - // Currently, this operand appears in OpConstant and OpSpecConstant, where the too-be-parsed type - // is determined by the result type. That means that in this instructions we have to resolve the - // operand type early and look at the result to see how we need to proceed. + const cg = ass.cg; assert(ass.inst.opcode == .OpConstant or ass.inst.opcode == .OpSpecConstant); const tok = ass.currentToken(); const result = try ass.resolveRef(ass.inst.operands.items[0].ref_id); const result_id = result.resultId(); - // We are going to cheat a little bit: The types we are interested in, int and float, - // are added to the module and cached via module.intType and module.floatType. Therefore, - // we can determine the width of these types by directly checking the cache. - // This only works if the Assembler and codegen both use spv.intType and spv.floatType though. - // We don't expect there to be many of these types, so just look it up every time. - // TODO: Count be improved to be a little bit more efficent. - { - var it = module.cache.int_types.iterator(); - while (it.next()) |entry| { - const id = entry.value_ptr.*; - if (id != result_id) continue; - const info = entry.key_ptr.*; - return try ass.parseContextDependentInt(info.signedness, info.bits); - } - } - - { - var it = module.cache.float_types.iterator(); - while (it.next()) |entry| { - const id = entry.value_ptr.*; - if (id != result_id) continue; - const info = entry.key_ptr.*; - switch (info.bits) { - 16 => try ass.parseContextDependentFloat(16), - 32 => try ass.parseContextDependentFloat(32), - 64 => try ass.parseContextDependentFloat(64), - else => return ass.fail(tok.start, "cannot parse {}-bit info literal", .{info.bits}), - } + const words = cg.sections.globals.instructions.items; + var offset: usize = 0; + while (offset < words.len) { + const word_count = words[offset] >> 16; + const opcode: Opcode = @enumFromInt(words[offset] & 0xFFFF); + defer offset += word_count; + if (word_count == 0) break; + switch (opcode) { + .OpTypeInt => if (word_count >= 4 and @as(Id, @enumFromInt(words[offset + 1])) == result_id) { + const width: u16 = @intCast(words[offset + 2]); + const signedness: std.lang.Signedness = if (words[offset + 3] == 0) .unsigned else .signed; + return ass.parseContextDependentInt(signedness, width); + }, + .OpTypeFloat => if (word_count >= 3 and @as(Id, @enumFromInt(words[offset + 1])) == result_id) { + const bits = words[offset + 2]; + return switch (bits) { + 16 => ass.parseContextDependentFloat(16), + 32 => ass.parseContextDependentFloat(32), + 64 => ass.parseContextDependentFloat(64), + else => ass.fail(tok.start, "cannot parse {}-bit info literal", .{bits}), + }; + }, + else => {}, } } @@ -767,7 +758,7 @@ fn parseContextDependentNumber(ass: *Assembler) !void { } fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, width: u32) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const tok = ass.currentToken(); if (ass.eatToken(.placeholder)) { @@ -818,7 +809,7 @@ fn parseContextDependentInt(ass: *Assembler, signedness: std.lang.Signedness, wi } fn parseContextDependentFloat(ass: *Assembler, comptime width: u16) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; const Float = std.meta.Float(width); const Int = @Int(.unsigned, width); @@ -891,7 +882,7 @@ fn tokenText(ass: Assembler, tok: Token) []const u8 { /// Tokenize `ass.src` and put the tokens in `ass.tokens`. /// Any errors encountered are appended to `ass.errors`. fn tokenize(ass: *Assembler) !void { - const gpa = ass.cg.module.gpa; + const gpa = ass.cg.gpa; ass.tokens.clearRetainingCapacity(); diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig index e2969777c165c416ab68578b10d2eebaf3492ba1..80b8ceafb3f0dc84b12c878665784441597b5add 100644 --- a/src/codegen/spirv/CodeGen.zig +++ b/src/codegen/spirv/CodeGen.zig @@ -1,177 +1,723 @@ -const std = @import("std"); -const Allocator = std.mem.Allocator; -const Target = std.Target; -const Signedness = std.lang.Signedness; -const assert = std.debug.assert; -const log = std.log.scoped(.codegen); - -const Zcu = @import("../../Zcu.zig"); -const Type = @import("../../Type.zig"); -const Value = @import("../../Value.zig"); -const Air = @import("../../Air.zig"); -const InternPool = @import("../../InternPool.zig"); -const Section = @import("Section.zig"); -const Assembler = @import("Assembler.zig"); - -const spec = @import("spec.zig"); -const Opcode = spec.Opcode; -const Word = spec.Word; -const Id = spec.Id; -const IdRange = spec.IdRange; -const StorageClass = spec.StorageClass; - -const Module = @import("Module.zig"); -const Decl = Module.Decl; -const Repr = Module.Repr; -const InternMap = Module.InternMap; -const PtrTypeMap = Module.PtrTypeMap; - -const CodeGen = @This(); - -pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { - return comptime &.initMany(&.{ - .expand_intcast_safe, - .expand_int_from_float_safe, - .expand_int_from_float_optimized_safe, - .expand_add_safe, - .expand_sub_safe, - .expand_mul_safe, - }); -} - -pub const zig_call_abi_ver = 3; - -const ControlFlow = union(enum) { - const Structured = struct { - /// This type indicates the way that a block is terminated. The - /// state of a particular block is used to track how a jump from - /// inside the block must reach the outside. - const Block = union(enum) { - const Incoming = struct { - src_label: Id, - /// Instruction that returns an u32 value of the - /// `Air.Inst.Index` that control flow should jump to. - next_block: Id, - }; - - const SelectionMerge = struct { - /// Incoming block from the `then` label. - /// Note that hte incoming block from the `else` label is - /// either given by the next element in the stack. - incoming: Incoming, - /// The label id of the cond_br's merge block. - /// For the top-most element in the stack, this - /// value is undefined. - merge_block: Id, - }; - - /// For a `selection` type block, we cannot use early exits, and we - /// must generate a 'merge ladder' of OpSelection instructions. To that end, - /// we keep a stack of the merges that still must be closed at the end of - /// a block. - /// - /// This entire structure basically just resembles a tree like - /// a x - /// \ / - /// b o merge - /// \ / - /// c o merge - /// \ / - /// o merge - /// / - /// o jump to next block - selection: struct { - /// In order to know which merges we still need to do, we need to keep - /// a stack of those. - merge_stack: std.ArrayList(SelectionMerge) = .empty, - }, - /// For a `loop` type block, we can early-exit the block by - /// jumping to the loop exit node, and we don't need to generate - /// an entire stack of merges. - loop: struct { - /// The next block to jump to can be determined from any number - /// of conditions that jump to the loop exit. - merges: std.ArrayList(Incoming) = .empty, - /// The label id of the loop's merge block. - merge_block: Id, - }, - - fn deinit(block: *Structured.Block, gpa: Allocator) void { - switch (block.*) { - .selection => |*merge| merge.merge_stack.deinit(gpa), - .loop => |*merge| merge.merges.deinit(gpa), - } - block.* = undefined; - } - }; - /// This determines how exits from the current block must be handled. - block_stack: std.ArrayList(*Structured.Block) = .empty, - block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty, - }; - - const Unstructured = struct { - const Incoming = struct { - src_label: Id, - break_value_id: Id, - }; - - const Block = struct { - label: ?Id = null, - incoming_blocks: std.ArrayList(Incoming) = .empty, - }; - - /// We need to keep track of result ids for block labels, as well as the 'incoming' - /// blocks for a block. - blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *Block) = .empty, - }; - - structured: Structured, - unstructured: Unstructured, - - pub fn deinit(cg: *ControlFlow, gpa: Allocator) void { - switch (cg.*) { - .structured => |*cf| { - cf.block_stack.deinit(gpa); - cf.block_results.deinit(gpa); - }, - .unstructured => |*cf| { - cf.blocks.deinit(gpa); - }, - } - cg.* = undefined; - } -}; - +// Compilation pt: Zcu.PerThread, +zcu: *Zcu, +gpa: Allocator, +arena: Allocator, air: Air, liveness: Air.Liveness, owner_nav: InternPool.Nav.Index, -module: *Module, -control_flow: ControlFlow, base_line: u32, -block_label: Id = .none, -next_arg_index: u32 = 0, + +// Module-level output (accumulated across the nav's codegen) +next_result_id: Word = 1, +decls: std.ArrayList(Decl) = .empty, +decl_deps: std.ArrayList(Decl.Index) = .empty, +nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty, +uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty, +entry_points: std.array_hash_map.Auto(Id, EntryPoint) = .empty, +error_buffer: ?Decl.Index = null, +struct_types: std.array_hash_map.Custom(StructType, Id, StructType.HashContext, true) = .empty, +builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty, +sections: struct { + // Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module". + extended_instruction_set: Section = .{}, + memory_model: Section = .{}, + execution_modes: Section = .{}, + debug_strings: Section = .{}, + debug_names: Section = .{}, + annotations: Section = .{}, + globals: Section = .{}, + functions: Section = .{}, +} = .{}, + +// Per-function state (reset between top-level genNav calls) +prologue: Section = .{}, +body: Section = .{}, args: std.ArrayList(Id) = .empty, +next_arg_index: u32 = 0, +block_stack: std.ArrayList(*Block) = .empty, +block_label: Id = .none, +/// Whether the current block has been terminated by a terminator +/// instruction (e.g. OpKill from inline assembly). When true, no further +/// branch instructions should be emitted for the current block. +block_terminated: bool = false, +block_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty, inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty, +tracked_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty, +loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, LoopSwitch) = .empty, id_scratch: std.ArrayList(Id) = .empty, -prologue: Section = .{}, -body: Section = .{}, + +const big_int_bits = @bitSizeOf(u32); + +/// Data can be lowered into in two basic representations: indirect, which is when +/// a type is stored in memory, and direct, which is how a type is stored when its +/// a direct SPIR-V value. +pub const Repr = enum { + /// A SPIR-V value as it would be used in operations. + direct, + /// A SPIR-V value as it is stored in memory. + indirect, +}; + +/// A function or global, tracked here so the linker can order globals and build +/// per-entry-point interface lists. +pub const Decl = struct { + pub const Index = enum(u32) { _ }; + pub const Kind = enum { func, global, invocation_global }; + + kind: Kind, + /// Result-id of the associated OpFunction / OpVariable / InvocationGlobal. + result_id: Id, + /// Range into `decl_deps` for this decl's dependencies. + begin_dep: usize = 0, + end_dep: usize = 0, + /// Whether an extern-function stub has been emitted. + has_extern_stub: bool = false, +}; + +pub const EntryPoint = struct { + decl_index: Decl.Index, + name: []const u8, + cc: std.builtin.CallingConvention, +}; + +const StructType = struct { + fields: []const Id, + ip_index: InternPool.Index, + + const HashContext = struct { + pub fn hash(_: @This(), ty: StructType) u32 { + var hasher = std.hash.Wyhash.init(0); + hasher.update(std.mem.sliceAsBytes(ty.fields)); + hasher.update(std.mem.asBytes(&ty.ip_index)); + return @truncate(hasher.final()); + } + + pub fn eql(_: @This(), a: StructType, b: StructType, _: usize) bool { + return a.ip_index == b.ip_index and std.mem.eql(Id, a.fields, b.fields); + } + }; +}; + +pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { + return comptime &.initMany(&.{ + .expand_int_cast_safe, + .expand_int_from_float_safe, + .expand_int_from_float_optimized_safe, + .expand_add_safe, + .expand_sub_safe, + .expand_mul_safe, + }); +} + +const LoopSwitch = struct { cond_var: Id, continue_label: Id }; + +/// Pointer-typed AIR refs should resolve through `resolvePtr` to handle the +/// `tracked_allocas` case explicitly at every use site. +const Ptr = union(enum) { + id: Id, + /// Function-local pointer whose value lives in `tracked_allocas` rather + /// than a real OpVariable. `slot` is the current pointee value. + tracked: struct { id: Id, slot: *?Id }, +}; + +/// Tracks how control flow leaves a Zig `block` under SPIR-V's structured +/// control flow rules. +const Block = union(enum) { + const Incoming = struct { + src_label: Id, + /// Block index (u32) that control flow should jump to next. + next_block: Id, + }; + + const SelectionMerge = struct { + incoming: Incoming, + /// Label of the cond_br's merge block (undefined for top-of-stack). + merge_block: Id, + }; + + /// Selection blocks can't use early exits. Closing requires a "merge ladder" + /// of nested OpSelectionMerge instructions, one per pending merge. + selection: struct { + merge_stack: std.ArrayList(SelectionMerge) = .empty, + }, + /// Loop blocks early-exit by jumping to the loop merge label. + loop: struct { + merges: std.ArrayList(Incoming) = .empty, + merge_block: Id, + }, + + fn deinit(block: *Block, gpa: Allocator) void { + switch (block.*) { + .selection => |*merge| merge.merge_stack.deinit(gpa), + .loop => |*merge| merge.merges.deinit(gpa), + } + block.* = undefined; + } +}; pub fn deinit(cg: *CodeGen) void { - const gpa = cg.module.gpa; - cg.control_flow.deinit(gpa); + const gpa = cg.gpa; + cg.block_stack.deinit(gpa); + cg.block_results.deinit(gpa); cg.args.deinit(gpa); + cg.tracked_allocas.deinit(gpa); cg.inst_results.deinit(gpa); + cg.loop_switches.deinit(gpa); cg.id_scratch.deinit(gpa); cg.prologue.deinit(gpa); cg.body.deinit(gpa); + + cg.nav_link.deinit(gpa); + cg.uav_link.deinit(gpa); + + cg.sections.extended_instruction_set.deinit(gpa); + cg.sections.memory_model.deinit(gpa); + cg.sections.execution_modes.deinit(gpa); + cg.sections.debug_strings.deinit(gpa); + cg.sections.debug_names.deinit(gpa); + cg.sections.annotations.deinit(gpa); + cg.sections.globals.deinit(gpa); + cg.sections.functions.deinit(gpa); + + cg.struct_types.deinit(gpa); + cg.builtins.deinit(gpa); + + cg.decls.deinit(gpa); + cg.decl_deps.deinit(gpa); + cg.entry_points.deinit(gpa); +} + +pub fn generate( + _: *link.File, + pt: Zcu.PerThread, + func_index: InternPool.Index, + air: *const Air, + liveness: *const ?Air.Liveness, +) codegen.Error!Mir { + const zcu = pt.zcu; + const gpa = zcu.gpa; + const nav = zcu.funcInfo(func_index).owner_nav; + + var arena = std.heap.ArenaAllocator.init(gpa); + defer arena.deinit(); + + var cg: CodeGen = .{ + .pt = pt, + .gpa = gpa, + .arena = arena.allocator(), + .zcu = zcu, + .air = air.*, + .liveness = liveness.*.?, + .owner_nav = nav, + .base_line = zcu.navSrcLine(nav), + }; + defer cg.deinit(); + + cg.genNav(true) catch |err| switch (err) { + error.AlreadyReported => return error.AlreadyReported, + error.OutOfMemory => return error.OutOfMemory, + }; + + return cg.serializeToMir(gpa); +} + +pub fn generateNav( + pt: Zcu.PerThread, + nav_index: InternPool.Nav.Index, +) codegen.Error!Mir { + const zcu = pt.zcu; + const gpa = zcu.gpa; + + var arena = std.heap.ArenaAllocator.init(gpa); + defer arena.deinit(); + + var cg: CodeGen = .{ + .pt = pt, + .gpa = gpa, + .arena = arena.allocator(), + .zcu = zcu, + .air = undefined, + .liveness = undefined, + .owner_nav = nav_index, + .base_line = zcu.navSrcLine(nav_index), + }; + defer cg.deinit(); + + cg.genNav(false) catch |err| switch (err) { + error.AlreadyReported => return error.AlreadyReported, + error.OutOfMemory => return error.OutOfMemory, + }; + + return cg.serializeToMir(gpa); +} + +fn serializeToMir(cg: *CodeGen, gpa: Allocator) codegen.Error!Mir { + const owner_entry = cg.nav_link.get(cg.owner_nav); + const owner_decl_index = owner_entry orelse return .{ + .id_bound = cg.next_result_id, + .owner_nav = cg.owner_nav, + .kind = .func, + .decl_result_id = .none, + .extended_instruction_set = &.{}, + .globals = &.{}, + .functions = &.{}, + .annotations = &.{}, + .debug_names = &.{}, + .debug_strings = &.{}, + .execution_modes = &.{}, + .nav_refs = &.{}, + .uav_refs = &.{}, + .decl_deps = &.{}, + .internal_globals = &.{}, + .entry_points = &.{}, + }; + + const owner_decl = cg.declPtr(owner_decl_index); + + var nav_refs: std.ArrayList(Mir.NavRef) = .empty; + defer nav_refs.deinit(gpa); + var nav_it = cg.nav_link.iterator(); + while (nav_it.next()) |entry| { + if (entry.key_ptr.* == cg.owner_nav) continue; + const decl = cg.declPtr(entry.value_ptr.*); + try nav_refs.append(gpa, .{ + .local_id = decl.result_id, + .nav = entry.key_ptr.*, + .kind = decl.kind, + }); + } + + var uav_refs: std.ArrayList(Mir.UavRef) = .empty; + defer uav_refs.deinit(gpa); + var uav_it = cg.uav_link.iterator(); + while (uav_it.next()) |entry| { + const decl = cg.declPtr(entry.value_ptr.*); + try uav_refs.append(gpa, .{ + .local_id = decl.result_id, + .val = entry.key_ptr.*[0], + .storage_class = entry.key_ptr.*[1], + .kind = decl.kind, + }); + } + + var decl_deps: std.ArrayList(Mir.DeclDep) = .empty; + defer decl_deps.deinit(gpa); + var internal_globals: std.ArrayList(Id) = .empty; + defer internal_globals.deinit(gpa); + + const deps = cg.decl_deps.items[owner_decl.begin_dep..owner_decl.end_dep]; + for (deps) |dep_index| { + const dep_decl = cg.declPtr(dep_index); + var found = false; + nav_it.index = 0; + while (nav_it.next()) |entry| { + if (entry.value_ptr.* == dep_index) { + try decl_deps.append(gpa, .{ + .kind = dep_decl.kind, + .nav = entry.key_ptr.*, + }); + found = true; + break; + } + } + if (!found and dep_decl.kind == .global) { + try internal_globals.append(gpa, dep_decl.result_id); + } + } + + var ep_list: std.ArrayList(Mir.EntryPoint) = .empty; + defer ep_list.deinit(gpa); + var ep_it = cg.entry_points.iterator(); + while (ep_it.next()) |entry| { + const ep = entry.value_ptr; + const ep_decl = cg.declPtr(ep.decl_index); + try ep_list.append(gpa, .{ + .local_id = ep_decl.result_id, + .name = try gpa.dupe(u8, ep.name), + .cc = ep.cc, + }); + } + + return .{ + .id_bound = cg.next_result_id, + .owner_nav = cg.owner_nav, + .kind = owner_decl.kind, + .decl_result_id = owner_decl.result_id, + .extended_instruction_set = try cg.sections.extended_instruction_set.instructions.toOwnedSlice(gpa), + .globals = try cg.sections.globals.instructions.toOwnedSlice(gpa), + .functions = try cg.sections.functions.instructions.toOwnedSlice(gpa), + .annotations = try cg.sections.annotations.instructions.toOwnedSlice(gpa), + .debug_names = try cg.sections.debug_names.instructions.toOwnedSlice(gpa), + .debug_strings = try cg.sections.debug_strings.instructions.toOwnedSlice(gpa), + .execution_modes = try cg.sections.execution_modes.instructions.toOwnedSlice(gpa), + .nav_refs = try nav_refs.toOwnedSlice(gpa), + .uav_refs = try uav_refs.toOwnedSlice(gpa), + .decl_deps = try decl_deps.toOwnedSlice(gpa), + .internal_globals = try internal_globals.toOwnedSlice(gpa), + .entry_points = try ep_list.toOwnedSlice(gpa), + }; +} + +fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type { + const zcu = cg.zcu; + return cg.air.typeOf(inst, &zcu.intern_pool); +} + +fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type { + const zcu = cg.zcu; + return cg.air.typeOfIndex(inst, &zcu.intern_pool); +} + +/// Does not generate the nav. +pub fn resolveNav(cg: *CodeGen, ip: *InternPool, nav_index: InternPool.Nav.Index) !Decl.Index { + const entry = try cg.nav_link.getOrPut(cg.gpa, nav_index); + if (!entry.found_existing) { + const nav = ip.getNav(nav_index); + // TODO: Extern fn? + const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type)) + .func + else switch (nav.resolved.?.@"addrspace") { + .generic => .invocation_global, + else => .global, + }; + entry.value_ptr.* = try cg.allocDecl(kind); + } + + return entry.value_ptr.*; +} + +pub fn allocIds(cg: *CodeGen, n: u32) spec.IdRange { + defer cg.next_result_id += n; + return .{ .base = cg.next_result_id, .len = n }; +} + +pub fn allocId(cg: *CodeGen) Id { + return cg.allocIds(1).at(0); +} + +pub fn idBound(cg: *const CodeGen) Word { + return cg.next_result_id; +} + +pub fn addEntryPointDeps( + cg: *CodeGen, + decl_index: Decl.Index, + seen: *std.bit_set.Dynamic, + interface: *std.array_list.Managed(Id), +) !void { + const decl = cg.declPtr(decl_index); + const deps = cg.decl_deps.items[decl.begin_dep..decl.end_dep]; + + if (seen.isSet(@intFromEnum(decl_index))) { + return; + } + + seen.set(@intFromEnum(decl_index)); + + if (decl.kind == .global) { + try interface.append(decl.result_id); + } + + for (deps) |dep| { + try cg.addEntryPointDeps(dep, seen, interface); + } +} + +pub fn importInstructionSet(cg: *CodeGen, set: spec.InstructionSet) !Id { + assert(set != .core); + const result_id = cg.allocId(); + try cg.sections.extended_instruction_set.emit(cg.gpa, .OpExtInstImport, .{ + .id_result = result_id, + .name = @tagName(set), + }); + return result_id; +} + +pub fn boolType(cg: *CodeGen) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeBool, .{ + .id_result = result_id, + }); + return result_id; +} + +pub fn voidType(cg: *CodeGen) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeVoid, .{ + .id_result = result_id, + }); + try cg.debugName(result_id, "void"); + return result_id; +} + +pub fn opaqueType(cg: *CodeGen, name: []const u8) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeOpaque, .{ + .id_result = result_id, + .literal_string = name, + }); + try cg.debugName(result_id, name); + return result_id; +} + +pub fn backingIntBits(cg: *const CodeGen, bits: u16) struct { u16, bool } { + assert(bits != 0); + const target = cg.zcu.getTarget(); + const ints = [_]struct { bits: u16, enabled: bool }{ + .{ .bits = 8, .enabled = target.cpu.has(.spirv, .int8) }, + .{ .bits = 16, .enabled = target.cpu.has(.spirv, .int16) }, + .{ .bits = 32, .enabled = true }, + .{ .bits = 64, .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64 }, + }; + + for (ints) |int| { + if (bits <= int.bits and int.enabled) return .{ int.bits, false }; + } + + return .{ std.mem.alignForward(u16, bits, big_int_bits), true }; +} + +pub fn intType(cg: *CodeGen, signedness: std.lang.Signedness, bits: u16) !Id { + assert(bits > 0); + + const target = cg.zcu.getTarget(); + const actual_signedness = switch (target.os.tag) { + // Kernel only supports unsigned ints. + .opencl, .amdhsa => .unsigned, + else => signedness, + }; + const backing_bits, const big_int = cg.backingIntBits(bits); + if (big_int) { + const u32_ty = try cg.intType(.unsigned, 32); + const len_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpConstant, .{ + .id_result_type = u32_ty, + .id_result = len_id, + .value = .{ .uint32 = backing_bits / big_int_bits }, + }); + return cg.arrayType(len_id, u32_ty); + } + + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeInt, .{ + .id_result = result_id, + .width = backing_bits, + .signedness = switch (actual_signedness) { + .signed => 1, + .unsigned => 0, + }, + }); + switch (actual_signedness) { + .signed => try cg.debugNameFmt(result_id, "i{}", .{backing_bits}), + .unsigned => try cg.debugNameFmt(result_id, "u{}", .{backing_bits}), + } + return result_id; +} + +pub fn floatType(cg: *CodeGen, bits: u16) !Id { + assert(bits > 0); + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeFloat, .{ + .id_result = result_id, + .width = bits, + }); + try cg.debugNameFmt(result_id, "f{}", .{bits}); + return result_id; +} + +pub fn vectorType(cg: *CodeGen, len: u32, child_ty_id: Id) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeVector, .{ + .id_result = result_id, + .component_type = child_ty_id, + .component_count = len, + }); + return result_id; +} + +pub fn arrayType(cg: *CodeGen, len_id: Id, child_ty_id: Id) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeArray, .{ + .id_result = result_id, + .element_type = child_ty_id, + .length = len_id, + }); + return result_id; +} + +pub fn ptrType(cg: *CodeGen, child_ty_id: Id, storage_class: spec.StorageClass) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypePointer, .{ + .id_result = result_id, + .storage_class = storage_class, + .type = child_ty_id, + }); + return result_id; +} + +pub fn structType( + cg: *CodeGen, + types: []const Id, + maybe_names: ?[]const []const u8, + ip_index: InternPool.Index, +) !Id { + const actual_ip_index = if (cg.zcu.comp.config.root_strip) .none else ip_index; + + if (cg.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id; + const result_id = cg.allocId(); + const types_dup = try cg.arena.dupe(Id, types); + try cg.sections.globals.emit(cg.gpa, .OpTypeStruct, .{ + .id_result = result_id, + .id_ref = types_dup, + }); + + if (maybe_names) |names| { + assert(names.len == types.len); + for (names, 0..) |name, i| { + try cg.memberDebugName(result_id, @intCast(i), name); + } + } + + try cg.struct_types.put( + cg.gpa, + .{ .fields = types_dup, .ip_index = actual_ip_index }, + result_id, + ); + return result_id; +} + +pub fn functionType(cg: *CodeGen, return_ty_id: Id, param_type_ids: []const Id) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpTypeFunction, .{ + .id_result = result_id, + .return_type = return_ty_id, + .id_ref_2 = param_type_ids, + }); + return result_id; +} + +pub fn constUndef(cg: *CodeGen, ty_id: Id) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpUndef, .{ + .id_result_type = ty_id, + .id_result = result_id, + }); + return result_id; +} + +pub fn constNull(cg: *CodeGen, ty_id: Id) !Id { + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpConstantNull, .{ + .id_result_type = ty_id, + .id_result = result_id, + }); + return result_id; +} + +pub fn decorate( + cg: *CodeGen, + target: Id, + decoration: spec.Decoration.Extended, +) !void { + try cg.sections.annotations.emit(cg.gpa, .OpDecorate, .{ + .target = target, + .decoration = decoration, + }); +} + +pub fn decorateMember( + cg: *CodeGen, + structure_type: Id, + member: u32, + decoration: spec.Decoration.Extended, +) !void { + try cg.sections.annotations.emit(cg.gpa, .OpMemberDecorate, .{ + .structure_type = structure_type, + .member = member, + .decoration = decoration, + }); +} + +pub fn allocDecl(cg: *CodeGen, kind: Decl.Kind) !Decl.Index { + try cg.decls.append(cg.gpa, .{ + .kind = kind, + .result_id = cg.allocId(), + }); + + return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(cg.decls.items.len - 1)))); +} + +pub fn declPtr(cg: *CodeGen, index: Decl.Index) *Decl { + return &cg.decls.items[@intFromEnum(index)]; +} + +pub fn debugName(cg: *CodeGen, target: Id, name: []const u8) !void { + if (cg.zcu.comp.config.root_strip) return; + try cg.sections.debug_names.emit(cg.gpa, .OpName, .{ + .target = target, + .name = name, + }); +} + +pub fn debugNameFmt(cg: *CodeGen, target: Id, comptime fmt: []const u8, args: anytype) !void { + if (cg.zcu.comp.config.root_strip) return; + const name = try std.fmt.allocPrint(cg.gpa, fmt, args); + defer cg.gpa.free(name); + try cg.debugName(target, name); +} + +pub fn memberDebugName(cg: *CodeGen, target: Id, member: u32, name: []const u8) !void { + if (cg.zcu.comp.config.root_strip) return; + try cg.sections.debug_names.emit(cg.gpa, .OpMemberName, .{ + .type = target, + .member = member, + .name = name, + }); +} + +pub fn storageClass(cg: *const CodeGen, as: std.lang.AddressSpace) spec.StorageClass { + const target = cg.zcu.getTarget(); + return switch (as) { + .generic => .function, + .global => switch (target.os.tag) { + .opencl, .amdhsa => .cross_workgroup, + else => .storage_buffer, + }, + .push_constant => .push_constant, + .output => .output, + .uniform => .uniform, + .storage_buffer => .storage_buffer, + .physical_storage_buffer => .physical_storage_buffer, + .constant => .uniform_constant, + .shared => .workgroup, + .local => .function, + .input => .input, + .gs, + .fs, + .ss, + .far, + .param, + .flash, + .flash1, + .flash2, + .flash3, + .flash4, + .flash5, + .cog, + .lut, + .hub, + .externref, + .funcref, + => unreachable, + }; } const Error = error{ AlreadyReported, OutOfMemory }; pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const target = zcu.getTarget(); @@ -179,20 +725,30 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { const val = zcu.navValue(cg.owner_nav); const ty = val.typeOf(zcu); - if (!do_codegen and !ty.hasRuntimeBits(zcu)) return; + if (!do_codegen and !ty.hasRuntimeBits(zcu)) { + const child_ty = if (ty.zigTypeTag(zcu) == .pointer) ty.childType(zcu) else ty; + if (child_ty.zigTypeTag(zcu) != .spirv) return; + } - const spv_decl_index = try cg.module.resolveNav(ip, cg.owner_nav); - const decl = cg.module.declPtr(spv_decl_index); + const spv_decl_index = try cg.resolveNav(ip, cg.owner_nav); + const decl = cg.declPtr(spv_decl_index); const result_id = decl.result_id; - decl.begin_dep = cg.module.decl_deps.items.len; + decl.begin_dep = cg.decl_deps.items.len; switch (decl.kind) { .func => { + if (nav.resolved.?.is_extern_decl) { + _ = try cg.resolveType(ty, .direct); + try emitExternFnStub(cg, nav, decl, ty); + decl.end_dep = cg.decl_deps.items.len; + return; + } + const fn_info = zcu.typeToFunc(ty).?; const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type)); const is_test = zcu.test_functions.contains(cg.owner_nav); - const func_result_id = if (is_test) cg.module.allocId() else result_id; + const func_result_id = if (is_test) cg.allocId() else result_id; const prototype_ty_id = try cg.resolveType(ty, .direct); try cg.prologue.emit(gpa, .OpFunction, .{ .id_result_type = return_ty_id, @@ -203,14 +759,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { .function_control = .{}, }); - comptime assert(zig_call_abi_ver == 3); try cg.args.ensureUnusedCapacity(gpa, fn_info.param_types.len); for (fn_info.param_types.get(ip)) |param_ty_index| { const param_ty: Type = .fromInterned(param_ty_index); if (!param_ty.hasRuntimeBits(zcu)) continue; const param_type_id = try cg.resolveType(param_ty, .direct); - const arg_result_id = cg.module.allocId(); + const arg_result_id = cg.allocId(); try cg.prologue.emit(gpa, .OpFunctionParameter, .{ .id_result_type = param_type_id, .id_result = arg_result_id, @@ -219,7 +774,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { } // TODO: This could probably be done in a better way... - const root_block_id = cg.module.allocId(); + const root_block_id = cg.allocId(); // The root block of a function declaration should appear before OpVariable instructions, // so it is generated into the function's prologue. @@ -229,39 +784,32 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { cg.block_label = root_block_id; const main_body = cg.air.getMainBody(); - switch (cg.control_flow) { - .structured => { - _ = try cg.genStructuredBody(.selection, main_body); - // We always expect paths to here to end, but we still need the block - // to act as a dummy merge block. - try cg.body.emit(gpa, .OpUnreachable, {}); - }, - .unstructured => { - try cg.genBody(main_body); - }, - } + _ = try cg.genStructuredBody(.selection, main_body); + // We always expect paths to here to end, but we still need the block + // to act as a dummy merge block. + try cg.body.emit(gpa, .OpUnreachable, {}); try cg.body.emit(gpa, .OpFunctionEnd, {}); // Append the actual code into the functions section. - try cg.module.sections.functions.append(gpa, cg.prologue); - try cg.module.sections.functions.append(gpa, cg.body); + try cg.sections.functions.append(gpa, cg.prologue); + try cg.sections.functions.append(gpa, cg.body); // Temporarily generate a test kernel declaration if this is a test function. if (is_test) { try cg.generateTestEntryPoint(nav.fqn.toSlice(ip), spv_decl_index, func_result_id); } - try cg.module.debugName(func_result_id, nav.fqn.toSlice(ip)); + try cg.debugName(func_result_id, nav.fqn.toSlice(ip)); }, .global => { const key = ip.indexToKey(val.toIntern()).@"extern"; - const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace"); + const storage_class = cg.storageClass(nav.resolved.?.@"addrspace"); assert(storage_class != .generic); // These should be instance globals const ty_id = try cg.resolveType(ty, .indirect); - const ptr_ty_id = try cg.module.ptrType(ty_id, storage_class); + const ptr_ty_id = try cg.ptrType(ty_id, storage_class); - try cg.module.sections.globals.emit(gpa, .OpVariable, .{ + try cg.sections.globals.emit(gpa, .OpVariable, .{ .id_result_type = ptr_ty_id, .id_result = result_id, .storage_class = storage_class, @@ -269,35 +817,44 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { switch (target.os.tag) { .vulkan, .opengl => { - if (ty.zigTypeTag(zcu) == .@"struct") { - switch (storage_class) { - .uniform, .push_constant => try cg.module.decorate(ty_id, .block), - else => {}, - } - } + switch (storage_class) { + .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => { + if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) { + try cg.decorate(ty_id, .block); + } - try cg.module.decorate(ptr_ty_id, .{ - .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) }, - }); + if (ty.hasRuntimeBits(zcu)) { + try cg.decorate(ptr_ty_id, .{ + .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) }, + }); + try cg.decorateLayout(ty, ty_id); + } + }, + else => {}, + } if (key.decoration) |decoration| switch (decoration) { .location => |location| { if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) { return cg.fail("storage class must be one of (output, input, uniform_constant) but is {s}", .{@tagName(storage_class)}); } - try cg.module.decorate(result_id, .{ + try cg.decorate(result_id, .{ .location = .{ .location = location }, }); }, + .flat => |location| { + try cg.decorate(result_id, .{ .location = .{ .location = location } }); + try cg.decorate(result_id, .flat); + }, .descriptor => |descriptor| { if (storage_class != .storage_buffer and storage_class != .uniform and storage_class != .uniform_constant) { return cg.fail("storage class must be one of (storage_buffer, uniform, uniform_constant) but is {s}", .{@tagName(storage_class)}); } - try cg.module.decorate(result_id, .{ + try cg.decorate(result_id, .{ .binding = .{ .binding_point = descriptor.binding }, }); - try cg.module.decorate(result_id, .{ + try cg.decorate(result_id, .{ .descriptor_set = .{ .descriptor_set = descriptor.set }, }); }, @@ -306,21 +863,33 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { else => {}, } - if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| { - try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = builtin } }); + if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |built_in| { + try cg.decorate(result_id, .{ .built_in = .{ .built_in = built_in } }); } - try cg.module.debugName(result_id, nav.fqn.toSlice(ip)); + try cg.debugName(result_id, nav.fqn.toSlice(ip)); }, .invocation_global => { + // `@extern()` produces an invocation_global whose value is a + // comptime-known pointer to an underlying extern symbol's Nav. + // The pointer is inlined at use sites so we don't need a Function-scope wrapper here. + if (ip.indexToKey(val.toIntern()) == .ptr) alias: { + const ptr_key = ip.indexToKey(val.toIntern()).ptr; + if (ptr_key.base_addr != .nav or ptr_key.byte_offset != 0) break :alias; + const underlying_nav = ip.getNav(ptr_key.base_addr.nav); + if (!underlying_nav.resolved.?.is_extern_decl) break :alias; + cg.declPtr(spv_decl_index).end_dep = cg.decl_deps.items.len; + return; + } + const ty_id = try cg.resolveType(ty, .indirect); - const ptr_ty_id = try cg.module.ptrType(ty_id, .function); + const ptr_ty_id = try cg.ptrType(ty_id, .function); // TODO: Combine with resolveAnonDecl? const void_ty_id = try cg.resolveType(.void, .direct); - const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{}); + const initializer_proto_ty_id = try cg.functionType(void_ty_id, &.{}); - const initializer_id = cg.module.allocId(); + const initializer_id = cg.allocId(); try cg.prologue.emit(gpa, .OpFunction, .{ .id_result_type = try cg.resolveType(.void, .direct), .id_result = initializer_id, @@ -328,7 +897,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { .function_type = initializer_proto_ty_id, }); - const root_block_id = cg.module.allocId(); + const root_block_id = cg.allocId(); try cg.prologue.emit(gpa, .OpLabel, .{ .id_result = root_block_id, }); @@ -342,27 +911,107 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { try cg.body.emit(gpa, .OpReturn, {}); try cg.body.emit(gpa, .OpFunctionEnd, {}); - try cg.module.sections.functions.append(gpa, cg.prologue); - try cg.module.sections.functions.append(gpa, cg.body); + try cg.sections.functions.append(gpa, cg.prologue); + try cg.sections.functions.append(gpa, cg.body); - try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)}); + try cg.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)}); + try cg.debugName(result_id, nav.fqn.toSlice(ip)); - try cg.module.sections.globals.emit(gpa, .OpExtInst, .{ + try cg.sections.globals.emit(gpa, .OpExtInst, .{ .id_result_type = ptr_ty_id, .id_result = result_id, - .set = try cg.module.importInstructionSet(.zig), + .set = try cg.importInstructionSet(.zig), .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, .id_ref_4 = &.{initializer_id}, }); }, } - cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len; + cg.declPtr(spv_decl_index).end_dep = cg.decl_deps.items.len; +} + +fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void { + const zcu = cg.zcu; + const ip = &zcu.intern_pool; + switch (ty.zigTypeTag(zcu)) { + .array => { + const elem_ty = ty.childType(zcu); + if (!elem_ty.hasRuntimeBits(zcu)) return; + try cg.decorate(ty_id, .{ + .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) }, + }); + try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect)); + }, + .vector => { + const elem_ty = ty.childType(zcu); + try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect)); + if (cg.isSpvVector(ty)) return; + try cg.decorate(ty_id, .{ + .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) }, + }); + }, + .@"struct" => switch (ip.indexToKey(ty.toIntern())) { + .struct_type => { + const struct_type = ip.loadStructType(ty.toIntern()); + if (struct_type.layout == .@"packed") return; + var it = struct_type.iterateRuntimeOrder(ip); + var member: u32 = 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 offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu)); + try cg.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } }); + try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect)); + member += 1; + } + }, + .tuple_type => |tuple| { + for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| { + if (field_val != .none) continue; + const ft: Type = .fromInterned(field_ty); + if (ft.hasRuntimeBits(zcu)) try cg.decorateLayout(ft, try cg.resolveType(ft, .indirect)); + } + }, + else => {}, + }, + .@"union" => { + const union_obj = zcu.typeToUnion(ty).?; + if (union_obj.layout == .@"packed") return; + const layout = cg.unionLayout(ty); + if (layout.tag_size != 0) { + const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); + try cg.decorateLayout(tag_ty, try cg.resolveType(tag_ty, .indirect)); + } + if (layout.has_payload) { + try cg.decorateLayout(layout.payload_ty, try cg.resolveType(layout.payload_ty, .indirect)); + } + const u8_id = try cg.resolveType(.u8, .direct); + if (layout.payload_padding_size != 0) { + const len_id = try cg.constInt(.u32, layout.payload_padding_size); + const arr_id = try cg.arrayType(len_id, u8_id); + try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } }); + } + if (layout.padding_size != 0) { + const len_id = try cg.constInt(.u32, layout.padding_size); + const arr_id = try cg.arrayType(len_id, u8_id); + try cg.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } }); + } + }, + .optional => { + const payload_ty = ty.optionalChild(zcu); + if (payload_ty.hasRuntimeBits(zcu)) try cg.decorateLayout(payload_ty, try cg.resolveType(payload_ty, .indirect)); + }, + .error_union => { + const payload_ty = ty.errorUnionPayload(zcu); + if (payload_ty.hasRuntimeBits(zcu)) try cg.decorateLayout(payload_ty, try cg.resolveType(payload_ty, .indirect)); + }, + else => {}, + } } pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error { @branchHint(.cold); - return cg.module.zcu.codegenFail(cg.owner_nav, format, args); + return cg.zcu.codegenFail(cg.owner_nav, format, args); } pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error { @@ -372,29 +1021,36 @@ pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error { /// This imports the "default" extended instruction set for the target /// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450. fn importExtendedSet(cg: *CodeGen) !Id { - const target = cg.module.zcu.getTarget(); + const target = cg.zcu.getTarget(); return switch (target.os.tag) { - .opencl, .amdhsa => try cg.module.importInstructionSet(.@"OpenCL.std"), - .vulkan, .opengl => try cg.module.importInstructionSet(.@"GLSL.std.450"), + .opencl, .amdhsa => try cg.importInstructionSet(.@"OpenCL.std"), + .vulkan, .opengl => try cg.importInstructionSet(.@"GLSL.std.450"), else => unreachable, }; } /// Fetch the result-id for a previously generated instruction or constant. fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; if (inst.toInterned()) |val_ip_index| { const ty = cg.typeOf(inst); if (ty.zigTypeTag(zcu) == .@"fn") { - const fn_nav = switch (zcu.intern_pool.indexToKey(val_ip_index)) { + const val_key = zcu.intern_pool.indexToKey(val_ip_index); + const fn_nav = switch (val_key) { .@"extern" => |@"extern"| @"extern".owner_nav, .func => |func| func.owner_nav, else => unreachable, }; - const spv_decl_index = try cg.module.resolveNav(ip, fn_nav); - try cg.module.decl_deps.append(cg.module.gpa, spv_decl_index); - return cg.module.declPtr(spv_decl_index).result_id; + const spv_decl_index = try cg.resolveNav(ip, fn_nav); + try cg.decl_deps.append(cg.gpa, spv_decl_index); + const decl = cg.declPtr(spv_decl_index); + if (val_key == .@"extern") { + const nav = ip.getNav(fn_nav); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); + try emitExternFnStub(cg, nav, decl, nav_ty); + } + return decl.result_id; } return try cg.constant(ty, .fromInterned(val_ip_index), .direct); @@ -404,22 +1060,22 @@ fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id { } fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { - const gpa = cg.module.gpa; + const gpa = cg.gpa; // TODO: This cannot be a function at this point, but it should probably be handled anyway. - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val)); const ty_id = try cg.resolveType(ty, .indirect); const spv_decl_index = blk: { - const entry = try cg.module.uav_link.getOrPut(gpa, .{ val, .function }); + const entry = try cg.uav_link.getOrPut(gpa, .{ val, .function }); if (entry.found_existing) { try cg.addFunctionDep(entry.value_ptr.*, .function); - return cg.module.declPtr(entry.value_ptr.*).result_id; + return cg.declPtr(entry.value_ptr.*).result_id; } - const spv_decl_index = try cg.module.allocDecl(.invocation_global); + const spv_decl_index = try cg.allocDecl(.invocation_global); try cg.addFunctionDep(spv_decl_index, .function); entry.value_ptr.* = spv_decl_index; break :blk spv_decl_index; @@ -431,7 +1087,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { // constant lowering of this value will need to be deferred to an initializer similar to // other globals. - const result_id = cg.module.declPtr(spv_decl_index).result_id; + const result_id = cg.declPtr(spv_decl_index).result_id; { // Save the current state so that we can temporarily generate into a different function. @@ -453,16 +1109,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { } const void_ty_id = try cg.resolveType(.void, .direct); - const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{}); + const initializer_proto_ty_id = try cg.functionType(void_ty_id, &.{}); - const initializer_id = cg.module.allocId(); + const initializer_id = cg.allocId(); try cg.prologue.emit(gpa, .OpFunction, .{ .id_result_type = try cg.resolveType(.void, .direct), .id_result = initializer_id, .function_control = .{}, .function_type = initializer_proto_ty_id, }); - const root_block_id = cg.module.allocId(); + const root_block_id = cg.allocId(); try cg.prologue.emit(gpa, .OpLabel, .{ .id_result = root_block_id, }); @@ -477,16 +1133,16 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { try cg.body.emit(gpa, .OpReturn, {}); try cg.body.emit(gpa, .OpFunctionEnd, {}); - try cg.module.sections.functions.append(gpa, cg.prologue); - try cg.module.sections.functions.append(gpa, cg.body); + try cg.sections.functions.append(gpa, cg.prologue); + try cg.sections.functions.append(gpa, cg.body); - try cg.module.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)}); + try cg.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)}); - const fn_decl_ptr_ty_id = try cg.module.ptrType(ty_id, .function); - try cg.module.sections.globals.emit(gpa, .OpExtInst, .{ + const fn_decl_ptr_ty_id = try cg.ptrType(ty_id, .function); + try cg.sections.globals.emit(gpa, .OpExtInst, .{ .id_result_type = fn_decl_ptr_ty_id, .id_result = result_id, - .set = try cg.module.importInstructionSet(.zig), + .set = try cg.importInstructionSet(.zig), .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) }, .id_ref_4 = &.{initializer_id}, }); @@ -495,15 +1151,21 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { return result_id; } -fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void { - const gpa = cg.module.gpa; - const target = cg.module.zcu.getTarget(); +fn resolvePtr(cg: *CodeGen, ref: Air.Inst.Ref) !Ptr { + const id = try cg.resolve(ref); + if (cg.tracked_allocas.getPtr(id)) |slot| return .{ .tracked = .{ .id = id, .slot = slot } }; + return .{ .id = id }; +} + +fn addFunctionDep(cg: *CodeGen, decl_index: Decl.Index, storage_class: StorageClass) !void { + const gpa = cg.gpa; + const target = cg.zcu.getTarget(); if (target.cpu.has(.spirv, .v1_4)) { - try cg.module.decl_deps.append(gpa, decl_index); + try cg.decl_deps.append(gpa, decl_index); } else { // Before version 1.4, the interface’s storage classes are limited to the Input and Output if (storage_class == .input or storage_class == .output) { - try cg.module.decl_deps.append(gpa, decl_index); + try cg.decl_deps.append(gpa, decl_index); } } } @@ -513,22 +1175,9 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St /// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to /// keep track of the previous block. fn beginSpvBlock(cg: *CodeGen, label: Id) !void { - try cg.body.emit(cg.module.gpa, .OpLabel, .{ .id_result = label }); + try cg.body.emit(cg.gpa, .OpLabel, .{ .id_result = label }); cg.block_label = label; -} - -/// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if -/// the Int64 capability is enabled). -/// Note: The extension SPV_INTEL_arbitrary_precision_integers allows any integer size (at least up to 32 bits). -/// In theory that could also be used, but since the spec says that it only guarantees support up to 32-bit ints there -/// is no way of knowing whether those are actually supported. -/// TODO: Maybe this should be cached? -fn largestSupportedIntBits(cg: *CodeGen) u16 { - const target = cg.module.zcu.getTarget(); - if (target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64) { - return 64; - } - return 32; + cg.block_terminated = false; } const ArithmeticTypeInfo = struct { @@ -568,8 +1217,8 @@ const ArithmeticTypeInfo = struct { }; fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo { - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); var scalar_ty = ty.scalarType(zcu); if (scalar_ty.zigTypeTag(zcu) == .@"enum") { scalar_ty = scalar_ty.intTagType(zcu); @@ -578,7 +1227,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo { return switch (scalar_ty.zigTypeTag(zcu)) { .bool => .{ .bits = 1, // Doesn't matter for this class. - .backing_bits = cg.module.backingIntBits(1).@"0", + .backing_bits = cg.backingIntBits(1).@"0", .vector_len = vector_len, .signedness = .unsigned, // Technically, but doesn't matter for this class. .class = .bool, @@ -593,7 +1242,7 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo { .int => blk: { const int_info = scalar_ty.intInfo(zcu); // TODO: Maybe it's useful to also return this value. - const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits); + const backing_bits, const big_int = cg.backingIntBits(int_info.bits); break :blk .{ .bits = int_info.bits, .backing_bits = backing_bits, @@ -613,8 +1262,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo { /// Checks whether the type can be directly translated to SPIR-V vectors fn isSpvVector(cg: *CodeGen, ty: Type) bool { - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); if (ty.zigTypeTag(zcu) != .vector) return false; // TODO: This check must be expanded for types that can be represented @@ -642,22 +1291,34 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool { /// Emits a bool constant in a particular representation. fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id { - return switch (repr) { - .indirect => cg.constInt(.u1, @intFromBool(value)), - .direct => cg.module.constBool(value), - }; + switch (repr) { + .indirect => return cg.constInt(.u1, @intFromBool(value)), + .direct => { + const result_ty_id = try cg.boolType(); + const result_id = cg.allocId(); + switch (value) { + inline else => |value_ct| try cg.sections.globals.emit( + cg.gpa, + if (value_ct) .OpConstantTrue else .OpConstantFalse, + .{ .id_result_type = result_ty_id, .id_result = result_id }, + ), + } + return result_id; + }, + } } /// Emits an integer constant. -/// This function, unlike Module.constInt, takes care to bitcast +/// This function, unlike cg.constInt, takes care to bitcast /// the value to an unsigned int first for Kernels. fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); + const gpa = cg.gpa; + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); const scalar_ty = ty.scalarType(zcu); const int_info = scalar_ty.intInfo(zcu); // Use backing bits so that negatives are sign extended - const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits); + const backing_bits, const big_int = cg.backingIntBits(int_info.bits); assert(backing_bits != 0); // u0 is comptime const result_ty_id = try cg.resolveType(scalar_ty, .indirect); @@ -671,11 +1332,18 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { .signed => @bitCast(@as(i64, @intCast(value))), .unsigned => @as(u64, @intCast(value)), }; - assert(backing_bits == 64); - return cg.constructComposite(result_ty_id, &.{ - try cg.constInt(.u32, @as(u32, @truncate(value64))), - try cg.constInt(.u32, @as(u32, @truncate(value64 << 32))), - }); + const n_limbs = backing_bits / big_int_bits; + const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0; + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); + for (constituents, 0..) |*c, i| { + c.* = try cg.constInt( + .u32, + if (i < 2) @as(u32, @truncate(value64 >> @intCast(i * 32))) else fill, + ); + } + return cg.constructComposite(result_ty_id, constituents); } const final_value: spec.LiteralContextDependentNumber = switch (target.os.tag) { @@ -704,15 +1372,54 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { }, }; - const result_id = try cg.module.constant(result_ty_id, final_value); + const result_id = cg.allocId(); + try cg.sections.globals.emit(cg.gpa, .OpConstant, .{ + .id_result_type = result_ty_id, + .id_result = result_id, + .value = final_value, + }); if (!ty.isVector(zcu)) return result_id; return cg.constructCompositeSplat(ty, result_id); } +/// Construct a composite value from its constituents. +/// In logical addressing mode (Vulkan/OpenGL), OpCompositeConstruct cannot accept +/// pointer operands, so for struct types we use alloc, store for each field and load instead. pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id { - const gpa = cg.module.gpa; - const result_id = cg.module.allocId(); + const gpa = cg.gpa; + + const maybe_fields: ?[]const Id = for (cg.struct_types.keys(), cg.struct_types.values()) |key, val| { + if (val == result_ty_id) break key.fields; + } else null; + if (maybe_fields) |fields| { + assert(fields.len == constituents.len); + const u32_ty_id = try cg.intType(.unsigned, 32); + const var_id = try cg.alloc(result_ty_id, null); + for (fields, constituents, 0..) |field_ty_id, constituent, i| { + const field_ptr_ty_id = try cg.ptrType(field_ty_id, .function); + const index_id = cg.allocId(); + try cg.sections.globals.emit(gpa, .OpConstant, .{ + .id_result_type = u32_ty_id, + .id_result = index_id, + .value = .{ .uint32 = @intCast(i) }, + }); + const field_ptr = try cg.accessChainId(field_ptr_ty_id, var_id, &.{index_id}); + try cg.body.emit(gpa, .OpStore, .{ + .pointer = field_ptr, + .object = constituent, + }); + } + const result_id = cg.allocId(); + try cg.body.emit(gpa, .OpLoad, .{ + .id_result_type = result_ty_id, + .id_result = result_id, + .pointer = var_id, + }); + return result_id; + } + + const result_id = cg.allocId(); try cg.body.emit(gpa, .OpCompositeConstruct, .{ .id_result_type = result_ty_id, .id_result = result_id, @@ -724,8 +1431,8 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const /// Construct a composite at runtime with all lanes set to the same value. /// ty must be an aggregate type. fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const n: usize = @intCast(ty.arrayLen(zcu)); const scratch_top = cg.id_scratch.items.len; @@ -745,24 +1452,17 @@ fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id { // /// This function should only be called during function code generation. fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { - const gpa = cg.module.gpa; - - // Note: Using intern_map can only be used with constants that DO NOT generate any runtime code!! - // Ideally that should be all constants in the future, or it should be cleaned up somehow. For - // now, only use the intern_map on case-by-case basis by breaking to :cache. - if (cg.module.intern_map.get(.{ val.toIntern(), repr })) |id| { - return id; - } + const gpa = cg.gpa; const pt = cg.pt; - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); const result_ty_id = try cg.resolveType(ty, repr); const ip = &zcu.intern_pool; log.debug("lowering constant: ty = {f}, val = {f}, key = {s}", .{ ty.fmt(pt), val.fmtValue(pt), @tagName(ip.indexToKey(val.toIntern())) }); if (val.isUndef(zcu)) { - return cg.module.constUndef(result_ty_id); + return cg.constUndef(result_ty_id); } const cacheable_id = cache: { @@ -779,6 +1479,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { .tuple_type, .union_type, .opaque_type, + .spirv_type, .enum_type, .func_type, .error_set_type, @@ -801,6 +1502,27 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { .false, .true => break :cache try cg.constBool(val.toBool(), repr), }, .int => { + const int_info = ty.intInfo(zcu); + const backing_bits, const is_big_int = cg.backingIntBits(int_info.bits); + if (is_big_int) { + const n_limbs = backing_bits / big_int_bits; + const big_result_ty_id = try cg.resolveType(ty, .indirect); + var bigint_space: Value.BigIntSpace = undefined; + const bigint = val.toBigInt(&bigint_space, zcu); + const limb_values = try gpa.alloc(u32, n_limbs); + defer gpa.free(limb_values); + bigint.writeTwosComplement(std.mem.sliceAsBytes(limb_values), .little); + if (builtin.cpu.arch.endian() == .big) { + for (limb_values) |*limb| limb.* = @byteSwap(limb.*); + } + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); + for (constituents, 0..) |*c, i| { + c.* = try cg.constInt(.u32, limb_values[i]); + } + break :cache try cg.constructComposite(big_result_ty_id, constituents); + } if (ty.isSignedInt(zcu)) { break :cache try cg.constInt(ty, val.toSignedInt(zcu)); } else { @@ -815,7 +1537,13 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { 80, 128 => unreachable, // TODO else => unreachable, }; - break :cache try cg.module.constant(result_ty_id, lit); + const lit_id = cg.allocId(); + try cg.sections.globals.emit(gpa, .OpConstant, .{ + .id_result_type = result_ty_id, + .id_result = lit_id, + .value = lit, + }); + break :cache lit_id; }, .err => |err| { const value = try pt.getErrorValue(err.name); @@ -882,7 +1610,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { if (maybe_payload_val) |payload_val| { return try cg.constant(payload_ty, payload_val, .indirect); } else { - break :cache try cg.module.constNull(result_ty_id); + break :cache try cg.constNull(result_ty_id); } } @@ -893,7 +1621,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { const payload_id = if (maybe_payload_val) |payload_val| try cg.constant(payload_ty, payload_val, .indirect) else - try cg.module.constUndef(try cg.resolveType(payload_ty, .indirect)); + try cg.constUndef(try cg.resolveType(payload_ty, .indirect)); const comp_ty_id = try cg.resolveType(ty, .direct); return try cg.constructComposite(comp_ty_id, &.{ payload_id, has_pl_id }); @@ -962,7 +1690,23 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { const comp_ty_id = try cg.resolveType(ty, .direct); return try cg.constructComposite(comp_ty_id, constituents.items); }, - .tuple_type => return cg.todo("implement tuple types", .{}), + .tuple_type => |tuple| { + var constituents: std.ArrayList(Id) = .empty; + defer constituents.deinit(gpa); + + for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| { + if (field_val != .none) continue; + const ft: Type = .fromInterned(field_ty); + if (!ft.hasRuntimeBits(zcu)) continue; + + const fv = try val.fieldValue(pt, i); + const field_id = try cg.constant(ft, fv, .indirect); + try constituents.append(gpa, field_id); + } + + const comp_ty_id = try cg.resolveType(ty, .direct); + return try cg.constructComposite(comp_ty_id, constituents.items); + }, else => unreachable, }, .un => |un| { @@ -987,21 +1731,18 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { .memoized_call => unreachable, } }; - - try cg.module.intern_map.putNoClobber(gpa, .{ val.toIntern(), repr }, cacheable_id); - return cacheable_id; } fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id { const pt = cg.pt; - const zcu = cg.module.zcu; - const gpa = cg.module.gpa; + const zcu = cg.zcu; + const gpa = cg.gpa; if (ptr_val.isUndef(zcu)) { const result_ty = ptr_val.typeOf(zcu); const result_ty_id = try cg.resolveType(result_ty, .direct); - return cg.module.constUndef(result_ty_id); + return cg.constUndef(result_ty_id); } var arena = std.heap.ArenaAllocator.init(gpa); @@ -1012,9 +1753,9 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id { } fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { - const gpa = cg.module.gpa; + const gpa = cg.gpa; const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const target = zcu.getTarget(); switch (derivation) { .comptime_alloc_ptr, .comptime_field_ptr => unreachable, @@ -1031,7 +1772,7 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { // TODO: This can probably be an OpSpecConstantOp Bitcast, but // that is not implemented by Mesa yet. Therefore, just generate it // as a runtime operation. - const result_ptr_id = cg.module.allocId(); + const result_ptr_id = cg.allocId(); const value_id = try cg.constInt(.usize, int.addr); try cg.body.emit(gpa, .OpConvertUToPtr, .{ .id_result_type = result_ty_id, @@ -1040,13 +1781,87 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { }); return result_ptr_id; }, - .nav_ptr => |nav| { - const result_ptr_ty = try pt.navPtrType(nav); - return cg.constantNavRef(result_ptr_ty, nav); + .nav_ptr => |nav_index| { + const ip = &zcu.intern_pool; + const result_ptr_ty = try pt.navPtrType(nav_index); + const ty_id = try cg.resolveType(result_ptr_ty, .direct); + const nav = ip.getNav(nav_index); + const nav_ty: Type = .fromInterned(nav.resolved.?.type); + + switch (nav.resolved.?.value) { + .none => {}, + else => |value| switch (ip.indexToKey(value)) { + // TODO: Properly lower function pointers; for now substitute undef. + .func => return try cg.constUndef(ty_id), + .@"extern" => if (ip.isFunctionType(nav_ty.toIntern())) { + const spv_decl_index = try cg.resolveNav(ip, nav_index); + const decl = cg.declPtr(spv_decl_index); + try emitExternFnStub(cg, nav, decl, nav_ty); + return decl.result_id; + }, + else => {}, + }, + } + + if (!nav_ty.hasRuntimeBits(zcu) and nav_ty.zigTypeTag(zcu) != .spirv) { + return cg.constUndef(ty_id); + } + + const spv_decl_index = try cg.resolveNav(ip, nav_index); + const spv_decl = cg.declPtr(spv_decl_index); + assert(spv_decl.kind != .func); + const storage_class = cg.storageClass(nav.resolved.?.@"addrspace"); + try cg.addFunctionDep(spv_decl_index, storage_class); + + const nav_ty_id = try cg.resolveType(nav_ty, .indirect); + const decl_ptr_ty_id = try cg.ptrType(nav_ty_id, storage_class); + if (decl_ptr_ty_id == ty_id) return spv_decl.result_id; + switch (target.os.tag) { + .vulkan, .opengl => return spv_decl.result_id, + else => {}, + } + const casted_ptr_id = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = ty_id, + .id_result = casted_ptr_id, + .operand = spv_decl.result_id, + }); + return casted_ptr_id; }, .uav_ptr => |uav| { + const ip = &zcu.intern_pool; const result_ptr_ty: Type = .fromInterned(uav.orig_ty); - return cg.constantUavRef(result_ptr_ty, uav); + const ty_id = try cg.resolveType(result_ptr_ty, .direct); + const uav_ty: Type = .fromInterned(ip.typeOf(uav.val)); + + switch (ip.indexToKey(uav.val)) { + .func => unreachable, // TODO + .@"extern" => assert(!ip.isFunctionType(uav_ty.toIntern())), + else => {}, + } + + if (!uav_ty.hasRuntimeBits(zcu) and uav_ty.zigTypeTag(zcu) != .spirv) { + return cg.constUndef(ty_id); + } + + // Uav refs are always generic. + assert(result_ptr_ty.ptrAddressSpace(zcu) == .generic); + const uav_ty_id = try cg.resolveType(uav_ty, .indirect); + const decl_ptr_ty_id = try cg.ptrType(uav_ty_id, .function); + const ptr_id = try cg.resolveUav(uav.val); + + if (decl_ptr_ty_id == ty_id) return ptr_id; + switch (target.os.tag) { + .vulkan, .opengl => return ptr_id, + else => {}, + } + const casted_ptr_id = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = ty_id, + .id_result = casted_ptr_id, + .operand = ptr_id, + }); + return casted_ptr_id; }, .eu_payload_ptr => @panic("TODO"), .opt_payload_ptr => @panic("TODO"), @@ -1065,28 +1880,47 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { const parent_ptr_id = try cg.derivePtr(oac.parent.*); const parent_ptr_ty = try oac.parent.ptrType(pt); const result_ty_id = try cg.resolveType(oac.new_ptr_ty, .direct); - const child_size = oac.new_ptr_ty.childType(zcu).abiSize(zcu); - if (parent_ptr_ty.childType(zcu).isVector(zcu) and oac.byte_offset % child_size == 0) { + if (parent_ptr_ty.childType(zcu).isVector(zcu)) { // Vector element ptr accesses are derived as offset_and_cast. // We can just use OpAccessChain. - return cg.accessChain( - result_ty_id, - parent_ptr_id, - &.{@intCast(@divExact(oac.byte_offset, child_size))}, - ); + const child_size = oac.new_ptr_ty.childType(zcu).abiSize(zcu); + if (oac.byte_offset % child_size == 0) { + return cg.accessChain( + result_ty_id, + parent_ptr_id, + &.{@intCast(@divExact(oac.byte_offset, child_size))}, + ); + } } if (oac.byte_offset == 0) { - // Allow changing the pointer type child only to restructure arrays. - // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T. - const result_ptr_id = cg.module.allocId(); - try cg.body.emit(gpa, .OpBitcast, .{ - .id_result_type = result_ty_id, - .id_result = result_ptr_id, - .operand = parent_ptr_id, - }); - return result_ptr_id; + var depth: u32 = 0; + var cur = parent_ptr_ty.childType(zcu); + const dst_child = oac.new_ptr_ty.childType(zcu); + while (cur.toIntern() != dst_child.toIntern()) { + if (cur.zigTypeTag(zcu) == .array) { + cur = cur.childType(zcu); + depth += 1; + } else break; + } + if (depth > 0 and cur.toIntern() == dst_child.toIntern()) { + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const zero = try cg.constInt(.u32, 0); + const ids = try cg.id_scratch.addManyAsSlice(gpa, depth); + @memset(ids, zero); + return cg.accessChainId(result_ty_id, parent_ptr_id, ids); + } + if (target.os.tag == .opencl) { + const result_ptr_id = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = result_ty_id, + .id_result = result_ptr_id, + .operand = parent_ptr_id, + }); + return result_ptr_id; + } } return cg.fail("cannot perform pointer cast: '{f}' to '{f}'", .{ @@ -1097,103 +1931,53 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { } } -fn constantUavRef( - cg: *CodeGen, - ty: Type, - uav: InternPool.Key.Ptr.BaseAddr.Uav, -) !Id { - // TODO: Merge this function with constantDeclRef. - - const zcu = cg.module.zcu; +/// Emit a stub OpFunction/OpFunctionEnd + Import linkage decoration for an +/// extern function so the module is structurally valid. The stub will be +/// replaced by the real definition at link time. +fn emitExternFnStub(cg: *CodeGen, nav: InternPool.Nav, decl: *Decl, fn_ty: Type) !void { + if (decl.has_extern_stub) return; + decl.has_extern_stub = true; + + const gpa = cg.gpa; + const zcu = cg.zcu; const ip = &zcu.intern_pool; - const ty_id = try cg.resolveType(ty, .direct); - const uav_ty: Type = .fromInterned(ip.typeOf(uav.val)); - - switch (ip.indexToKey(uav.val)) { - .func => unreachable, // TODO - .@"extern" => assert(!ip.isFunctionType(uav_ty.toIntern())), - else => {}, - } - - // const is_fn_body = decl_ty.zigTypeTag(zcu) == .@"fn"; - if (!uav_ty.hasRuntimeBits(zcu)) { - // Pointer to nothing - return undefined - return cg.module.constUndef(ty_id); - } - - // Uav refs are always generic. - assert(ty.ptrAddressSpace(zcu) == .generic); - const uav_ty_id = try cg.resolveType(uav_ty, .indirect); - const decl_ptr_ty_id = try cg.module.ptrType(uav_ty_id, .function); - const ptr_id = try cg.resolveUav(uav.val); - - if (decl_ptr_ty_id != ty_id) { - // Differing pointer types, insert a cast. - const casted_ptr_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpBitcast, .{ - .id_result_type = ty_id, - .id_result = casted_ptr_id, - .operand = ptr_id, + const fn_info = zcu.typeToFunc(fn_ty).?; + const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type)); + const prototype_ty_id = try cg.resolveType(fn_ty, .direct); + + var stub: Section = .{}; + defer stub.deinit(gpa); + try stub.emit(gpa, .OpFunction, .{ + .id_result_type = return_ty_id, + .id_result = decl.result_id, + .function_type = prototype_ty_id, + .function_control = .{}, + }); + for (fn_info.param_types.get(ip)) |param_ty_index| { + const param_ty: Type = .fromInterned(param_ty_index); + if (!param_ty.hasRuntimeBits(zcu)) continue; + const param_type_id = try cg.resolveType(param_ty, .direct); + try stub.emit(gpa, .OpFunctionParameter, .{ + .id_result_type = param_type_id, + .id_result = cg.allocId(), }); - return casted_ptr_id; - } else { - return ptr_id; } + try stub.emit(gpa, .OpFunctionEnd, {}); + try cg.sections.functions.append(gpa, stub); + + const extern_name = nav.getExtern(ip).?.name.toSlice(ip); + try cg.sections.annotations.emit(gpa, .OpDecorate, .{ + .target = decl.result_id, + .decoration = .{ .linkage_attributes = .{ + .name = extern_name, + .linkage_type = .import, + } }, + }); + try cg.debugName(decl.result_id, extern_name); } -fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { - const zcu = cg.module.zcu; - const ip = &zcu.intern_pool; - const ty_id = try cg.resolveType(ty, .direct); - const nav = ip.getNav(nav_index); - const nav_ty: Type = .fromInterned(nav.resolved.?.type); - - switch (nav.resolved.?.value) { - .none => {}, // this is not a function or extern - else => |value| switch (ip.indexToKey(value)) { - .func => { - // TODO: Properly lower function pointers. For now we are going to hack around it and - // just generate an empty pointer. Function pointers are represented by a pointer to usize. - return try cg.module.constUndef(ty_id); - }, - .@"extern" => if (ip.isFunctionType(nav_ty.toIntern())) @panic("TODO"), - else => {}, - }, - } - - if (!nav_ty.hasRuntimeBits(zcu)) { - // Pointer to nothing - return undefined. - return cg.module.constUndef(ty_id); - } - - const spv_decl_index = try cg.module.resolveNav(ip, nav_index); - const spv_decl = cg.module.declPtr(spv_decl_index); - const spv_decl_result_id = spv_decl.result_id; - assert(spv_decl.kind != .func); - - const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace"); - try cg.addFunctionDep(spv_decl_index, storage_class); - - const nav_ty_id = try cg.resolveType(nav_ty, .indirect); - const decl_ptr_ty_id = try cg.module.ptrType(nav_ty_id, storage_class); - - if (decl_ptr_ty_id != ty_id) { - // Differing pointer types, insert a cast. - const casted_ptr_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpBitcast, .{ - .id_result_type = ty_id, - .id_result = casted_ptr_id, - .operand = spv_decl_result_id, - }); - return casted_ptr_id; - } - - return spv_decl_result_id; -} - -// Turn a Zig type's name into a cache reference. fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 { - const gpa = cg.module.gpa; + const gpa = cg.gpa; var aw: std.Io.Writer.Allocating = .init(gpa); defer aw.deinit(); ty.print(&aw.writer, cg.pt, null) catch |err| switch (err) { @@ -1220,68 +2004,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 { /// padding: [padding_size]u8, /// } /// If any of the fields' size is 0, it will be omitted. -fn resolveUnionType(cg: *CodeGen, ty: Type) !Id { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; - const union_obj = zcu.typeToUnion(ty).?; - - if (union_obj.layout == .@"packed") { - return try cg.module.intType(.unsigned, @intCast(ty.bitSize(zcu))); - } - - const layout = cg.unionLayout(ty); - if (!layout.has_payload) { - // No payload, so represent this as just the tag type. - return try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect); - } - - var member_types: [4]Id = undefined; - var member_names: [4][]const u8 = undefined; - - const u8_ty_id = try cg.resolveType(.u8, .direct); - - if (layout.tag_size != 0) { - const tag_ty_id = try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect); - member_types[layout.tag_index] = tag_ty_id; - member_names[layout.tag_index] = "(tag)"; - } - - if (layout.payload_size != 0) { - const payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect); - member_types[layout.payload_index] = payload_ty_id; - member_names[layout.payload_index] = "(payload)"; - } - - if (layout.payload_padding_size != 0) { - const len_id = try cg.constInt(.u32, layout.payload_padding_size); - const payload_padding_ty_id = try cg.module.arrayType(len_id, u8_ty_id); - member_types[layout.payload_padding_index] = payload_padding_ty_id; - member_names[layout.payload_padding_index] = "(payload padding)"; - } - - if (layout.padding_size != 0) { - const len_id = try cg.constInt(.u32, layout.padding_size); - const padding_ty_id = try cg.module.arrayType(len_id, u8_ty_id); - member_types[layout.padding_index] = padding_ty_id; - member_names[layout.padding_index] = "(padding)"; - } - - const result_id = try cg.module.structType( - member_types[0..layout.total_fields], - member_names[0..layout.total_fields], - null, - .none, - ); - - const type_name = try cg.resolveTypeName(ty); - defer gpa.free(type_name); - try cg.module.debugName(result_id, type_name); - - return result_id; -} - fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; if (!ret_ty.hasRuntimeBits(zcu)) { // If the return type is an error set or an error union, then we make this // anyerror return type instead, so that it can be coerced into a function @@ -1297,38 +2021,38 @@ fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id { } fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { - const gpa = cg.module.gpa; + const gpa = cg.gpa; const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; - const target = cg.module.zcu.getTarget(); + const target = cg.zcu.getTarget(); log.debug("resolveType: ty = {f}", .{ty.fmt(pt)}); switch (ty.zigTypeTag(zcu)) { .noreturn => { assert(repr == .direct); - return try cg.module.voidType(); + return try cg.voidType(); }, .void => switch (repr) { - .direct => return try cg.module.voidType(), + .direct => return try cg.voidType(), .indirect => { if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); - return try cg.module.opaqueType("void"); + return try cg.opaqueType("void"); }, }, .bool => switch (repr) { - .direct => return try cg.module.boolType(), + .direct => return try cg.boolType(), .indirect => return try cg.resolveType(.u1, .indirect), }, .int => { if (ty.toIntern() == .u0_type) { assert(repr == .indirect); if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); - return try cg.module.opaqueType("u0"); + return try cg.opaqueType("u0"); } const int_info = ty.intInfo(zcu); - return try cg.module.intType(int_info.signedness, int_info.bits); + return try cg.intType(int_info.signedness, int_info.bits); }, .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr), .float => { @@ -1347,7 +2071,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { ); } - return try cg.module.floatType(bits); + return try cg.floatType(bits); }, .array => { const elem_ty = ty.childType(zcu); @@ -1359,7 +2083,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { if (!elem_ty.hasRuntimeBits(zcu)) { assert(repr == .indirect); if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); - return try cg.module.opaqueType("zero-sized-array"); + return try cg.opaqueType("zero-sized-array"); } else if (total_len == 0) { // The size of the array would be 0, but that is not allowed in SPIR-V. // This path can be reached for example when there is a slicing of a pointer @@ -1370,36 +2094,24 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { // generate an array of 1 element instead, so that ptr_elem_ptr instructions // can be lowered to ptrAccessChain instead of manually performing the math. const len_id = try cg.constInt(.u32, 1); - return try cg.module.arrayType(len_id, elem_ty_id); + return try cg.arrayType(len_id, elem_ty_id); } else { const total_len_id = try cg.constInt(.u32, total_len); - const result_id = try cg.module.arrayType(total_len_id, elem_ty_id); - switch (target.os.tag) { - .vulkan, .opengl => { - try cg.module.decorate(result_id, .{ - .array_stride = .{ - .array_stride = @intCast(elem_ty.abiSize(zcu)), - }, - }); - }, - else => {}, - } - return result_id; + return try cg.arrayType(total_len_id, elem_ty_id); } }, .vector => { const elem_ty = ty.childType(zcu); const elem_ty_id = try cg.resolveType(elem_ty, repr); const len = ty.vectorLen(zcu); - if (cg.isSpvVector(ty)) return try cg.module.vectorType(len, elem_ty_id); + if (cg.isSpvVector(ty)) return try cg.vectorType(len, elem_ty_id); const len_id = try cg.constInt(.u32, len); - return try cg.module.arrayType(len_id, elem_ty_id); + return try cg.arrayType(len_id, elem_ty_id); }, .@"fn" => switch (repr) { .direct => { const fn_info = zcu.typeToFunc(ty).?; - comptime assert(zig_call_abi_ver == 3); assert(!fn_info.is_var_args); switch (fn_info.cc) { .auto, @@ -1407,6 +2119,8 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { .spirv_fragment, .spirv_vertex, .spirv_device, + .spirv_task, + .spirv_mesh, => {}, else => unreachable, } @@ -1426,7 +2140,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { param_index += 1; } - return try cg.module.functionType(return_ty_id, param_ty_ids[0..param_index]); + return try cg.functionType(return_ty_id, param_ty_ids[0..param_index]); }, .indirect => { // TODO: Represent function pointers properly. @@ -1437,20 +2151,29 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { .pointer => { const ptr_info = ty.ptrInfo(zcu); - const child_ty: Type = .fromInterned(ptr_info.child); + const child_ty: Type = switch (ptr_info.packed_offset.host_size) { + 0 => .fromInterned(ptr_info.child), + else => switch (ptr_info.flags.vector_index) { + // Accepted proposal https://github.com/ziglang/zig/issues/24061 will eliminate these usages of `pt`. + .none => try pt.intType(.unsigned, ptr_info.packed_offset.host_size * 8), + else => try pt.vectorType(.{ + .child = ptr_info.child, + .len = ptr_info.packed_offset.host_size, + }), + }, + }; const child_ty_id = try cg.resolveType(child_ty, .indirect); - const storage_class = cg.module.storageClass(ptr_info.flags.address_space); - const ptr_ty_id = try cg.module.ptrType(child_ty_id, storage_class); + const storage_class = cg.storageClass(ptr_info.flags.address_space); + const ptr_ty_id = try cg.ptrType(child_ty_id, storage_class); if (ptr_info.flags.size != .slice) { return ptr_ty_id; } const size_ty_id = try cg.resolveType(.usize, .direct); - return try cg.module.structType( + return try cg.structType( &.{ ptr_ty_id, size_ty_id }, &.{ "ptr", "len" }, - null, .none, ); }, @@ -1469,15 +2192,14 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { member_index += 1; } - const result_id = try cg.module.structType( + const result_id = try cg.structType( member_types[0..member_index], null, - null, .none, ); const type_name = try cg.resolveTypeName(ty); defer gpa.free(type_name); - try cg.module.debugName(result_id, type_name); + try cg.debugName(result_id, type_name); return result_id; }, .struct_type => ip.loadStructType(ty.toIntern()), @@ -1494,9 +2216,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { var member_names = std.array_list.Managed([]const u8).init(gpa); defer member_names.deinit(); - var member_offsets = std.array_list.Managed(u32).init(gpa); - defer member_offsets.deinit(); - var it = struct_type.iterateRuntimeOrder(ip); while (it.next()) |field_index| { const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); @@ -1505,19 +2224,17 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { const field_name = struct_type.field_names.get(ip)[field_index]; try member_types.append(try cg.resolveType(field_ty, .indirect)); try member_names.append(field_name.toSlice(ip)); - try member_offsets.append(@intCast(ty.structFieldOffset(field_index, zcu))); } - const result_id = try cg.module.structType( + const result_id = try cg.structType( member_types.items, member_names.items, - member_offsets.items, ty.toIntern(), ); const type_name = try cg.resolveTypeName(ty); defer gpa.free(type_name); - try cg.module.debugName(result_id, type_name); + try cg.debugName(result_id, type_name); return result_id; }, @@ -1538,14 +2255,52 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { const bool_ty_id = try cg.resolveType(.bool, .indirect); - return try cg.module.structType( + return try cg.structType( &.{ payload_ty_id, bool_ty_id }, &.{ "payload", "valid" }, - null, .none, ); }, - .@"union" => return try cg.resolveUnionType(ty), + .@"union" => { + const union_obj = zcu.typeToUnion(ty).?; + if (union_obj.layout == .@"packed") { + return try cg.intType(.unsigned, @intCast(ty.bitSize(zcu))); + } + const layout = cg.unionLayout(ty); + if (!layout.has_payload) { + return try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect); + } + var member_types: [4]Id = undefined; + var member_names: [4][]const u8 = undefined; + const u8_ty_id = try cg.resolveType(.u8, .direct); + if (layout.tag_size != 0) { + member_types[layout.tag_index] = try cg.resolveType(.fromInterned(union_obj.enum_tag_type), .indirect); + member_names[layout.tag_index] = "(tag)"; + } + if (layout.payload_size != 0) { + member_types[layout.payload_index] = try cg.resolveType(layout.payload_ty, .indirect); + member_names[layout.payload_index] = "(payload)"; + } + if (layout.payload_padding_size != 0) { + const len_id = try cg.constInt(.u32, layout.payload_padding_size); + member_types[layout.payload_padding_index] = try cg.arrayType(len_id, u8_ty_id); + member_names[layout.payload_padding_index] = "(payload padding)"; + } + if (layout.padding_size != 0) { + const len_id = try cg.constInt(.u32, layout.padding_size); + member_types[layout.padding_index] = try cg.arrayType(len_id, u8_ty_id); + member_names[layout.padding_index] = "(padding)"; + } + const result_id = try cg.structType( + member_types[0..layout.total_fields], + member_names[0..layout.total_fields], + .none, + ); + const type_name = try cg.resolveTypeName(ty); + defer gpa.free(type_name); + try cg.debugName(result_id, type_name); + return result_id; + }, .error_set => { const err_int_ty = try pt.errorIntType(); return try cg.resolveType(err_int_ty, repr); @@ -1576,13 +2331,88 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { // TODO: ABI padding? } - return try cg.module.structType(&member_types, &member_names, null, .none); + return try cg.structType(&member_types, &member_names, .none); }, .@"opaque" => { if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); const type_name = try cg.resolveTypeName(ty); defer gpa.free(type_name); - return try cg.module.opaqueType(type_name); + return try cg.opaqueType(type_name); + }, + .spirv => { + const spirv_type = ip.loadSpirvType(ty.toIntern()); + const result_id = cg.allocId(); + switch (spirv_type.flags.tag) { + .sampler => try cg.sections.globals.emit(gpa, .OpTypeSampler, .{ .id_result = result_id }), + .image => { + const sampled_type_id = try cg.resolveType(.fromInterned(spirv_type.ty), .direct); + try cg.sections.globals.emit(gpa, .OpTypeImage, .{ + .id_result = result_id, + .sampled_type = sampled_type_id, + .dim = switch (spirv_type.flags.dim) { + .@"1d" => .@"1d", + .@"2d" => .@"2d", + .@"3d" => .@"3d", + .cube => .cube, + }, + .depth = switch (spirv_type.flags.depth) { + .not_depth => 0, + .depth => 1, + .unknown => 2, + }, + .arrayed = @intFromBool(spirv_type.flags.is_arrayed), + .ms = @intFromBool(spirv_type.flags.is_multisampled), + .sampled = switch (spirv_type.flags.usage) { + .unknown => 0, + .sampled => 1, + .storage => 2, + }, + .image_format = switch (spirv_type.flags.format) { + .unknown => .unknown, + .rgba32f => .rgba32f, + .rgba32i => .rgba32i, + .rgba32u => .rgba32ui, + .rgba16f => .rgba16f, + .rgba16i => .rgba16i, + .rgba16u => .rgba16ui, + .rgba8unorm => .rgba8, + .rgba8snorm => .rgba8snorm, + .rgba8i => .rgba8i, + .rgba8u => .rgba8ui, + .r32f => .r32f, + .r32i => .r32i, + .r32u => .r32ui, + }, + .access_qualifier = switch (spirv_type.flags.access) { + .unknown => null, + .read_only => .read_only, + .write_only => .write_only, + .read_write => .read_write, + }, + }); + }, + .sampled_image => { + const image_ty_id = try cg.resolveType(.fromInterned(spirv_type.ty), .indirect); + try cg.sections.globals.emit(gpa, .OpTypeSampledImage, .{ + .id_result = result_id, + .image_type = image_ty_id, + }); + }, + .runtime_array => { + const elem_ty: Type = .fromInterned(spirv_type.ty); + const elem_ty_id = try cg.resolveType(elem_ty, .indirect); + try cg.sections.globals.emit(gpa, .OpTypeRuntimeArray, .{ + .id_result = result_id, + .element_type = elem_ty_id, + }); + if (elem_ty.hasRuntimeBits(zcu)) { + try cg.decorate(result_id, .{ .array_stride = .{ + .array_stride = @intCast(elem_ty.abiSize(zcu)), + } }); + } + }, + } + return result_id; }, .null, @@ -1613,7 +2443,7 @@ const ErrorUnionLayout = struct { }; fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const error_align = Type.abiAlignment(.anyerror, zcu); const payload_align = payload_ty.abiAlignment(zcu); @@ -1644,7 +2474,7 @@ const UnionLayout = struct { }; fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const layout = ty.unionGetLayout(zcu); const union_obj = zcu.typeToUnion(ty).?; @@ -1734,8 +2564,8 @@ const Temporary = struct { } fn materialize(temp: Temporary, cg: *CodeGen) !Id { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; switch (temp.value) { .singleton => |id| return id, .exploded_vector => |range| { @@ -1769,7 +2599,7 @@ const Temporary = struct { /// 'Explode' a temporary into separate elements. This turns a vector /// into a bag of elements. fn explode(temp: Temporary, cg: *CodeGen) !IdRange { - const zcu = cg.module.zcu; + const zcu = cg.zcu; // If the value is a scalar, then this is a no-op. if (!temp.ty.isVector(zcu)) { @@ -1781,7 +2611,7 @@ const Temporary = struct { const ty_id = try cg.resolveType(temp.ty.scalarType(zcu), .direct); const n = temp.ty.vectorLen(zcu); - const results = cg.module.allocIds(n); + const results = cg.allocIds(n); const id = switch (temp.value) { .singleton => |id| id, @@ -1790,7 +2620,7 @@ const Temporary = struct { for (0..n) |i| { const indexes = [_]u32{@intCast(i)}; - try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{ + try cg.body.emit(cg.gpa, .OpCompositeExtract, .{ .id_result_type = ty_id, .id_result = results.at(i), .composite = id, @@ -1802,6 +2632,715 @@ const Temporary = struct { } }; +/// composite integers are represented as [N]u32 arrays +const CompositeInt = struct { + cg: *CodeGen, + limbs: []Id, + n_limbs: u16, + info: ArithmeticTypeInfo, + + fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt { + const n_limbs: u16 = info.backing_bits / big_int_bits; + const gpa = cg.gpa; + const u32_ty_id = try cg.resolveType(.u32, .direct); + const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); + for (limbs, 0..) |*limb, i| { + const result_id = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = result_id, + .composite = composite_id, + .indexes = &.{@as(u32, @intCast(i))}, + }); + limb.* = result_id; + } + return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; + } + + fn fromLimbs(cg: *CodeGen, limbs: []Id, info: ArithmeticTypeInfo) CompositeInt { + return .{ + .cg = cg, + .limbs = limbs, + .n_limbs = @intCast(limbs.len), + .info = info, + }; + } + + fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt { + const n_limbs: u16 = info.backing_bits / big_int_bits; + const limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, n_limbs); + const zero_id = try cg.constInt(.u32, @as(u32, 0)); + for (limbs) |*limb| limb.* = zero_id; + return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; + } + + fn materialize(ci: CompositeInt, ty: Type) !Id { + const result_ty_id = try ci.cg.resolveType(ty, .indirect); + return ci.cg.constructComposite(result_ty_id, ci.limbs); + } + + fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id { + const cg = ci.cg; + const gpa = cg.gpa; + const u32_ty_id = try cg.resolveType(.u32, .direct); + const result_id = cg.allocId(); + try cg.body.emitRaw(gpa, opcode, 4); + cg.body.writeOperand(Id, u32_ty_id); + cg.body.writeOperand(Id, result_id); + cg.body.writeOperand(Id, lhs); + cg.body.writeOperand(Id, rhs); + return result_id; + } + + fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id { + const cg = ci.cg; + const gpa = cg.gpa; + const u32_ty_id = try cg.resolveType(.u32, .direct); + const result_id = cg.allocId(); + try cg.body.emitRaw(gpa, opcode, 3); + cg.body.writeOperand(Id, u32_ty_id); + cg.body.writeOperand(Id, result_id); + cg.body.writeOperand(Id, operand); + return result_id; + } + + fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt { + const cg = ci.cg; + const gpa = cg.gpa; + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); + for (result_limbs, 0..) |*r, i| { + r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]); + } + return .fromLimbs(cg, result_limbs, ci.info); + } + + fn bitwiseNot(ci: CompositeInt) !CompositeInt { + const cg = ci.cg; + const gpa = cg.gpa; + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); + for (result_limbs, 0..) |*r, i| { + r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]); + } + return .fromLimbs(cg, result_limbs, ci.info); + } + + fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id { + const cg = ci.cg; + const gpa = cg.gpa; + const bool_ty_id = try cg.resolveType(.bool, .direct); + + switch (op) { + .eq, .neq => { + var result = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = r, + .operand_1 = ci.limbs[0], + .operand_2 = other.limbs[0], + }); + break :blk r; + }; + for (1..ci.n_limbs) |i| { + const limb_eq = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = limb_eq, + .operand_1 = ci.limbs[i], + .operand_2 = other.limbs[i], + }); + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalAnd, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = result, + .operand_2 = limb_eq, + }); + result = combined; + } + if (op == .neq) { + const negated = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalNot, .{ + .id_result_type = bool_ty_id, + .id_result = negated, + .operand = result, + }); + result = negated; + } + return result; + }, + .lt, .lte, .gt, .gte => { + const is_lt = (op == .lt or op == .lte); + const is_strict = (op == .lt or op == .gt); + var result = try cg.constBool(!is_strict, .direct); + + for (0..ci.n_limbs) |i| { + const l = ci.limbs[i]; + const r = other.limbs[i]; + const limb_ne = cg.allocId(); + try cg.body.emit(gpa, .OpINotEqual, .{ + .id_result_type = bool_ty_id, + .id_result = limb_ne, + .operand_1 = l, + .operand_2 = r, + }); + + const is_top = (i == ci.n_limbs - 1); + const use_signed = is_top and ci.info.signedness == .signed; + var cmp_l = l; + var cmp_r = r; + if (use_signed) { + const i32_ty_id = try cg.resolveType(.i32, .direct); + const sl = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = sl, + .operand = l, + }); + const sr = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = sr, + .operand = r, + }); + cmp_l = sl; + cmp_r = sr; + } + + const cmp_opcode: Opcode = if (is_lt) + (if (use_signed) .OpSLessThan else .OpULessThan) + else + (if (use_signed) .OpSGreaterThan else .OpUGreaterThan); + + const limb_cmp = cg.allocId(); + try cg.body.emitRaw(gpa, cmp_opcode, 4); + cg.body.writeOperand(Id, bool_ty_id); + cg.body.writeOperand(Id, limb_cmp); + cg.body.writeOperand(Id, cmp_l); + cg.body.writeOperand(Id, cmp_r); + + const selected = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = bool_ty_id, + .id_result = selected, + .condition = limb_ne, + .object_1 = limb_cmp, + .object_2 = result, + }); + result = selected; + } + return result; + }, + } + } + + fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt { + const cg = ci.cg; + const gpa = cg.gpa; + const pt = cg.pt; + const zcu = cg.zcu; + const ip = &zcu.intern_pool; + const comp = zcu.comp; + const io = comp.io; + + const u32_zig = try pt.intType(.unsigned, 32); + const u32_ty_id = try cg.resolveType(.u32, .direct); + const carry_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{ + .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() }, + .values = &.{ .none, .none }, + })); + const carry_struct_ty_id = try cg.resolveType(carry_struct_ty, .direct); + + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); + var carry_id = try cg.constInt(.u32, @as(u32, 0)); + + const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow; + + for (0..ci.n_limbs) |i| { + const op1 = cg.allocId(); + try cg.body.emitRaw(gpa, opcode, 4); + cg.body.writeOperand(Id, carry_struct_ty_id); + cg.body.writeOperand(Id, op1); + cg.body.writeOperand(Id, ci.limbs[i]); + cg.body.writeOperand(Id, other.limbs[i]); + + const sum1 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = sum1, + .composite = op1, + .indexes = &.{0}, + }); + const carry1 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = carry1, + .composite = op1, + .indexes = &.{1}, + }); + + const op2 = cg.allocId(); + try cg.body.emitRaw(gpa, opcode, 4); + cg.body.writeOperand(Id, carry_struct_ty_id); + cg.body.writeOperand(Id, op2); + cg.body.writeOperand(Id, sum1); + cg.body.writeOperand(Id, carry_id); + + result_limbs[i] = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = result_limbs[i], + .composite = op2, + .indexes = &.{0}, + }); + const carry2 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = carry2, + .composite = op2, + .indexes = &.{1}, + }); + + carry_id = try ci.limbBinOp(.OpBitwiseOr, carry1, carry2); + } + + return .fromLimbs(cg, result_limbs, ci.info); + } + + fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt { + const cg = ci.cg; + const gpa = cg.gpa; + const u32_ty_id = try cg.resolveType(.u32, .direct); + const bool_ty_id = try cg.resolveType(.bool, .direct); + const zero_id = try cg.constInt(.u32, @as(u32, 0)); + const five_id = try cg.constInt(.u32, @as(u32, 5)); + const thirty_one_id = try cg.constInt(.u32, @as(u32, 31)); + const thirty_two_id = try cg.constInt(.u32, @as(u32, 32)); + + const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id); + const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id); + const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac); + const frac_is_zero = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = r, + .operand_1 = frac, + .operand_2 = zero_id, + }); + break :blk r; + }; + + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); + + for (0..ci.n_limbs) |i| { + const i_id = try cg.constInt(.u32, @as(u32, @intCast(i))); + var main_val = zero_id; + var carry_val = zero_id; + + for (0..ci.n_limbs) |j| { + const j_id = try cg.constInt(.u32, @as(u32, @intCast(j))); + const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole); + + const is_main = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = r, + .operand_1 = j_plus_whole, + .operand_2 = i_id, + }); + break :blk r; + }; + const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac); + main_val = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = r, + .condition = is_main, + .object_1 = shifted, + .object_2 = main_val, + }); + break :blk r; + }; + + const one_id = try cg.constInt(.u32, @as(u32, 1)); + const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id); + const is_carry = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = r, + .operand_1 = j_plus_whole_plus_1, + .operand_2 = i_id, + }); + break :blk r; + }; + const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac); + const guarded_carry = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = r, + .condition = frac_is_zero, + .object_1 = zero_id, + .object_2 = carry_shifted, + }); + break :blk r; + }; + carry_val = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = r, + .condition = is_carry, + .object_1 = guarded_carry, + .object_2 = carry_val, + }); + break :blk r; + }; + } + + result_limbs[i] = try ci.limbBinOp(.OpBitwiseOr, main_val, carry_val); + } + + return .fromLimbs(cg, result_limbs, ci.info); + } + + fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt { + const cg = ci.cg; + const gpa = cg.gpa; + const u32_ty_id = try cg.resolveType(.u32, .direct); + const bool_ty_id = try cg.resolveType(.bool, .direct); + const zero_id = try cg.constInt(.u32, @as(u32, 0)); + const five_id = try cg.constInt(.u32, @as(u32, 5)); + const thirty_one_id = try cg.constInt(.u32, @as(u32, 31)); + const thirty_two_id = try cg.constInt(.u32, @as(u32, 32)); + + const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id); + const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id); + const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac); + const frac_is_zero = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = r, + .operand_1 = frac, + .operand_2 = zero_id, + }); + break :blk r; + }; + + const fill_id = if (is_arithmetic) blk: { + const i32_ty_id = try cg.resolveType(.i32, .direct); + const msb_signed = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = msb_signed, + .operand = ci.limbs[ci.n_limbs - 1], + }); + const shift31 = try cg.constInt(.i32, @as(i32, 31)); + const sign_ext = cg.allocId(); + try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ + .id_result_type = i32_ty_id, + .id_result = sign_ext, + .base = msb_signed, + .shift = shift31, + }); + const back = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = u32_ty_id, + .id_result = back, + .operand = sign_ext, + }); + break :blk back; + } else zero_id; + + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); + + const arith_carry_init = if (is_arithmetic) blk: { + const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac); + const guarded = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = guarded, + .condition = frac_is_zero, + .object_1 = zero_id, + .object_2 = shifted_fill, + }); + break :blk guarded; + } else zero_id; + + for (0..ci.n_limbs) |i| { + const i_id = try cg.constInt(.u32, @as(u32, @intCast(i))); + var main_val = fill_id; + var carry_val = arith_carry_init; + + for (0..ci.n_limbs) |j| { + const j_id = try cg.constInt(.u32, @as(u32, @intCast(j))); + const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole); + const is_main = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = r, + .operand_1 = j_id, + .operand_2 = i_plus_whole, + }); + break :blk r; + }; + const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac); + main_val = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = r, + .condition = is_main, + .object_1 = shifted, + .object_2 = main_val, + }); + break :blk r; + }; + + const one_id = try cg.constInt(.u32, @as(u32, 1)); + const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id); + const is_carry = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = r, + .operand_1 = j_id, + .operand_2 = i_plus_whole_plus_1, + }); + break :blk r; + }; + const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac); + const guarded_carry = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = r, + .condition = frac_is_zero, + .object_1 = zero_id, + .object_2 = carry_shifted, + }); + break :blk r; + }; + carry_val = blk: { + const r = cg.allocId(); + try cg.body.emit(gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = r, + .condition = is_carry, + .object_1 = guarded_carry, + .object_2 = carry_val, + }); + break :blk r; + }; + } + + result_limbs[i] = try ci.limbBinOp(.OpBitwiseOr, main_val, carry_val); + } + + return .fromLimbs(cg, result_limbs, ci.info); + } + + fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id { + const cg = ci.cg; + const gpa = cg.gpa; + const pt = cg.pt; + const zcu = cg.zcu; + const ip = &zcu.intern_pool; + const comp = zcu.comp; + const io = comp.io; + const target = zcu.getTarget(); + + const n: usize = ci.n_limbs; + const total: usize = if (wide) 2 * n else n; + const u32_zig = try pt.intType(.unsigned, 32); + const u32_ty_id = try cg.resolveType(.u32, .direct); + + const pair_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{ + .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() }, + .values = &.{ .none, .none }, + })); + const pair_struct_ty_id = try cg.resolveType(pair_struct_ty, .direct); + + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, total); + const zero_id = try cg.constInt(.u32, @as(u32, 0)); + for (result_limbs) |*r| r.* = zero_id; + + for (0..n) |i| { + var carry_id = zero_id; + for (0..n) |j| { + const k = i + j; + if (k >= total) break; + + var lo: Id = undefined; + var hi: Id = undefined; + switch (target.os.tag) { + .opencl => { + lo = cg.allocId(); + try cg.body.emit(gpa, .OpIMul, .{ + .id_result_type = u32_ty_id, + .id_result = lo, + .operand_1 = ci.limbs[i], + .operand_2 = other.limbs[j], + }); + + const set = try cg.importExtendedSet(); + hi = cg.allocId(); + try cg.body.emit(gpa, .OpExtInst, .{ + .id_result_type = u32_ty_id, + .id_result = hi, + .set = set, + .instruction = .{ .inst = @intFromEnum(spec.OpenClOpcode.u_mul_hi) }, + .id_ref_4 = &.{ ci.limbs[i], other.limbs[j] }, + }); + }, + else => { + const mul_result = cg.allocId(); + try cg.body.emit(gpa, .OpUMulExtended, .{ + .id_result_type = pair_struct_ty_id, + .id_result = mul_result, + .operand_1 = ci.limbs[i], + .operand_2 = other.limbs[j], + }); + + lo = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = lo, + .composite = mul_result, + .indexes = &.{0}, + }); + hi = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = hi, + .composite = mul_result, + .indexes = &.{1}, + }); + }, + } + + const add1 = cg.allocId(); + try cg.body.emit(gpa, .OpIAddCarry, .{ + .id_result_type = pair_struct_ty_id, + .id_result = add1, + .operand_1 = result_limbs[k], + .operand_2 = lo, + }); + + const sum1 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = sum1, + .composite = add1, + .indexes = &.{0}, + }); + const c1 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = c1, + .composite = add1, + .indexes = &.{1}, + }); + + const add2 = cg.allocId(); + try cg.body.emit(gpa, .OpIAddCarry, .{ + .id_result_type = pair_struct_ty_id, + .id_result = add2, + .operand_1 = sum1, + .operand_2 = carry_id, + }); + + result_limbs[k] = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = result_limbs[k], + .composite = add2, + .indexes = &.{0}, + }); + const c2 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = c2, + .composite = add2, + .indexes = &.{1}, + }); + + const hi_plus_c1 = try ci.limbBinOp(.OpIAdd, hi, c1); + carry_id = try ci.limbBinOp(.OpIAdd, hi_plus_c1, c2); + } + if (wide and i + n < 2 * n) { + result_limbs[i + n] = try ci.limbBinOp(.OpIAdd, result_limbs[i + n], carry_id); + } + } + + return result_limbs; + } + + fn normalize(ci: CompositeInt) !CompositeInt { + if (ci.info.bits == ci.info.backing_bits) return ci; + const cg = ci.cg; + const gpa = cg.gpa; + const top_bits: u16 = ci.info.bits % big_int_bits; + assert(top_bits != 0); + + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); + for (0..ci.n_limbs - 1) |i| { + result_limbs[i] = ci.limbs[i]; + } + + const top_limb = ci.limbs[ci.n_limbs - 1]; + switch (ci.info.signedness) { + .unsigned => { + const mask_val: u32 = (@as(u32, 1) << @as(u5, @intCast(top_bits))) - 1; + const mask_id = try cg.constInt(.u32, mask_val); + result_limbs[ci.n_limbs - 1] = try ci.limbBinOp(.OpBitwiseAnd, top_limb, mask_id); + }, + .signed => { + const u32_ty_id = try cg.resolveType(.u32, .direct); + const i32_ty_id = try cg.resolveType(.i32, .direct); + const shift_amt: u32 = 32 - top_bits; + const shift_id = try cg.constInt(.u32, shift_amt); + + const as_signed = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = as_signed, + .operand = top_limb, + }); + const shifted_left = cg.allocId(); + try cg.body.emit(gpa, .OpShiftLeftLogical, .{ + .id_result_type = i32_ty_id, + .id_result = shifted_left, + .base = as_signed, + .shift = shift_id, + }); + const shifted_right = cg.allocId(); + try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ + .id_result_type = i32_ty_id, + .id_result = shifted_right, + .base = shifted_left, + .shift = shift_id, + }); + const back = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = u32_ty_id, + .id_result = back, + .operand = shifted_right, + }); + result_limbs[ci.n_limbs - 1] = back; + }, + } + + return .fromLimbs(cg, result_limbs, ci.info); + } +}; + /// Initialize a `Temporary` from an AIR value. fn temporary(cg: *CodeGen, inst: Air.Inst.Ref) !Temporary { return .{ @@ -1823,7 +3362,7 @@ const Vectorization = union(enum) { /// Derive a vectorization from a particular type fn fromType(ty: Type, cg: *CodeGen) Vectorization { - const zcu = cg.module.zcu; + const zcu = cg.zcu; if (!ty.isVector(zcu)) return .scalar; return .{ .unrolled = ty.vectorLen(zcu) }; } @@ -1857,7 +3396,7 @@ const Vectorization = union(enum) { /// `ty` may be a scalar or vector, it doesn't matter. fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type { const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const scalar_ty = ty.scalarType(zcu); return switch (vec) { .scalar => scalar_ty, @@ -1869,7 +3408,7 @@ const Vectorization = union(enum) { /// this setup, and returns a new type that holds the relevant information on how to access /// elements of the input. fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const is_vector = tmp.ty.isVector(zcu); const value: PreparedOperand.Value = switch (tmp.value) { .singleton => |id| switch (vec) { @@ -1969,26 +3508,28 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization { /// This function builds an OpSConvert of OpUConvert depending on the /// signedness of the types. fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { - const zcu = cg.module.zcu; - - const dst_ty_id = try cg.resolveType(dst_ty.scalarType(zcu), .direct); - const src_ty_id = try cg.resolveType(src.ty.scalarType(zcu), .direct); + const zcu = cg.zcu; const v = cg.vectorization(.{ dst_ty, src }); const result_ty = try v.resultType(cg, dst_ty); - // We can directly compare integers, because those type-IDs are cached. - if (dst_ty_id == src_ty_id) { - // Nothing to do, type-pun to the right value. - // Note, Caller guarantees that the types fit (or caller will normalize after), - // so we don't have to normalize here. - // Note, dst_ty may be a scalar type even if we expect a vector, so we have to - // convert to the right type here. + const dst_scalar = dst_ty.scalarType(zcu); + const src_scalar = src.ty.scalarType(zcu); + if (dst_scalar.toIntern() == src_scalar.toIntern()) { return src.pun(result_ty); } + if (dst_scalar.isInt(zcu) and src_scalar.isInt(zcu)) { + const dst_info = dst_scalar.intInfo(zcu); + const src_info = src_scalar.intInfo(zcu); + if (cg.backingIntBits(dst_info.bits).@"0" == cg.backingIntBits(src_info.bits).@"0" and + dst_info.signedness == src_info.signedness) + { + return src.pun(result_ty); + } + } const ops = v.components(); - const results = cg.module.allocIds(ops); + const results = cg.allocIds(ops); const op_result_ty = dst_ty.scalarType(zcu); const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); @@ -2002,7 +3543,7 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { const op_src = try v.prepare(cg, src); for (0..ops) |i| { - try cg.body.emitRaw(cg.module.gpa, opcode, 3); + try cg.body.emitRaw(cg.gpa, opcode, 3); cg.body.writeOperand(Id, op_result_ty_id); cg.body.writeOperand(Id, results.at(i)); cg.body.writeOperand(Id, op_src.at(i)); @@ -2011,51 +3552,12 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary { return v.finalize(result_ty, results); } -fn buildFma(cg: *CodeGen, a: Temporary, b: Temporary, c: Temporary) !Temporary { - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); - - const v = cg.vectorization(.{ a, b, c }); - const ops = v.components(); - const results = cg.module.allocIds(ops); - - const op_result_ty = a.ty.scalarType(zcu); - const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); - const result_ty = try v.resultType(cg, a.ty); - - const op_a = try v.prepare(cg, a); - const op_b = try v.prepare(cg, b); - const op_c = try v.prepare(cg, c); - - const set = try cg.importExtendedSet(); - const opcode: u32 = switch (target.os.tag) { - .opencl => @intFromEnum(spec.OpenClOpcode.fma), - // NOTE: Vulkan's FMA instruction does *NOT* produce the right values! - // its precision guarantees do NOT match zigs and it does NOT match OpenCLs! - // it needs to be emulated! - .vulkan, .opengl => @intFromEnum(spec.GlslOpcode.Fma), - else => unreachable, - }; - - for (0..ops) |i| { - try cg.body.emit(cg.module.gpa, .OpExtInst, .{ - .id_result_type = op_result_ty_id, - .id_result = results.at(i), - .set = set, - .instruction = .{ .inst = opcode }, - .id_ref_4 = &.{ op_a.at(i), op_b.at(i), op_c.at(i) }, - }); - } - - return v.finalize(result_ty, results); -} - fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const v = cg.vectorization(.{ condition, lhs, rhs }); const ops = v.components(); - const results = cg.module.allocIds(ops); + const results = cg.allocIds(ops); const op_result_ty = lhs.ty.scalarType(zcu); const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); @@ -2068,7 +3570,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar const object_2 = try v.prepare(cg, rhs); for (0..ops) |i| { - try cg.body.emit(cg.module.gpa, .OpSelect, .{ + try cg.body.emit(cg.gpa, .OpSelect, .{ .id_result_type = op_result_ty_id, .id_result = results.at(i), .condition = cond.at(i), @@ -2083,7 +3585,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary { const v = cg.vectorization(.{ lhs, rhs }); const ops = v.components(); - const results = cg.module.allocIds(ops); + const results = cg.allocIds(ops); const op_result_ty: Type = .bool; const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); @@ -2093,7 +3595,7 @@ fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Tempo const op_rhs = try v.prepare(cg, rhs); for (0..ops) |i| { - try cg.body.emitRaw(cg.module.gpa, opcode, 4); + try cg.body.emitRaw(cg.gpa, opcode, 4); cg.body.writeOperand(Id, op_result_ty_id); cg.body.writeOperand(Id, results.at(i)); cg.body.writeOperand(Id, op_lhs.at(i)); @@ -2174,11 +3676,11 @@ const UnaryOp = enum { }; fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); const v = cg.vectorization(.{operand}); const ops = v.components(); - const results = cg.module.allocIds(ops); + const results = cg.allocIds(ops); const op_result_ty = operand.ty.scalarType(zcu); const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); const result_ty = try v.resultType(cg, operand.ty); @@ -2187,7 +3689,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { if (op.extInstOpcode(target)) |opcode| { const set = try cg.importExtendedSet(); for (0..ops) |i| { - try cg.body.emit(cg.module.gpa, .OpExtInst, .{ + try cg.body.emit(cg.gpa, .OpExtInst, .{ .id_result_type = op_result_ty_id, .id_result = results.at(i), .set = set, @@ -2207,7 +3709,7 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { ), }; for (0..ops) |i| { - try cg.body.emitRaw(cg.module.gpa, opcode, 3); + try cg.body.emitRaw(cg.gpa, opcode, 3); cg.body.writeOperand(Id, op_result_ty_id); cg.body.writeOperand(Id, results.at(i)); cg.body.writeOperand(Id, op_operand.at(i)); @@ -2218,11 +3720,11 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { } fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const v = cg.vectorization(.{ lhs, rhs }); const ops = v.components(); - const results = cg.module.allocIds(ops); + const results = cg.allocIds(ops); const op_result_ty = lhs.ty.scalarType(zcu); const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); @@ -2232,7 +3734,7 @@ fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Te const op_rhs = try v.prepare(cg, rhs); for (0..ops) |i| { - try cg.body.emitRaw(cg.module.gpa, opcode, 4); + try cg.body.emitRaw(cg.gpa, opcode, 4); cg.body.writeOperand(Id, op_result_ty_id); cg.body.writeOperand(Id, results.at(i)); cg.body.writeOperand(Id, op_lhs.at(i)); @@ -2251,11 +3753,11 @@ fn buildWideMul( rhs: Temporary, ) !struct { Temporary, Temporary } { const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const comp = zcu.comp; const gpa = comp.gpa; const io = comp.io; - const target = cg.module.zcu.getTarget(); + const target = cg.zcu.getTarget(); const ip = &zcu.intern_pool; const v = lhs.vectorization(cg).unify(rhs.vectorization(cg)); @@ -2267,8 +3769,8 @@ fn buildWideMul( const lhs_op = try v.prepare(cg, lhs); const rhs_op = try v.prepare(cg, rhs); - const value_results = cg.module.allocIds(ops); - const overflow_results = cg.module.allocIds(ops); + const value_results = cg.allocIds(ops); + const overflow_results = cg.allocIds(ops); switch (target.os.tag) { .opencl => { @@ -2313,7 +3815,7 @@ fn buildWideMul( }; for (0..ops) |i| { - const op_result = cg.module.allocId(); + const op_result = cg.allocId(); try cg.body.emitRaw(gpa, opcode, 4); cg.body.writeOperand(Id, op_result_ty_id); @@ -2373,12 +3875,12 @@ fn buildWideMul( fn generateTestEntryPoint( cg: *CodeGen, name: []const u8, - spv_decl_index: Module.Decl.Index, + spv_decl_index: Decl.Index, test_id: Id, ) !void { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); + const gpa = cg.gpa; + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); const anyerror_ty_id = try cg.resolveType(.anyerror, .direct); const ptr_anyerror_ty = try cg.pt.ptrType(.{ @@ -2387,15 +3889,15 @@ fn generateTestEntryPoint( }); const ptr_anyerror_ty_id = try cg.resolveType(ptr_anyerror_ty, .direct); - const kernel_id = cg.module.declPtr(spv_decl_index).result_id; + const kernel_id = cg.declPtr(spv_decl_index).result_id; - const section = &cg.module.sections.functions; + const section = &cg.sections.functions; - const p_error_id = cg.module.allocId(); + const p_error_id = cg.allocId(); switch (target.os.tag) { .opencl, .amdhsa => { const void_ty_id = try cg.resolveType(.void, .direct); - const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{ptr_anyerror_ty_id}); + const kernel_proto_ty_id = try cg.functionType(void_ty_id, &.{ptr_anyerror_ty_id}); try section.emit(gpa, .OpFunction, .{ .id_result_type = try cg.resolveType(.void, .direct), @@ -2410,52 +3912,43 @@ fn generateTestEntryPoint( }); try section.emit(gpa, .OpLabel, .{ - .id_result = cg.module.allocId(), + .id_result = cg.allocId(), }); }, .vulkan, .opengl => { - if (cg.module.error_buffer == null) { - const spv_err_decl_index = try cg.module.allocDecl(.global); - const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id; + if (cg.error_buffer == null) { + const spv_err_decl_index = try cg.allocDecl(.global); + const err_buf_result_id = cg.declPtr(spv_err_decl_index).result_id; - const buffer_struct_ty_id = try cg.module.structType( - &.{anyerror_ty_id}, - &.{"error_out"}, - null, - .none, - ); - try cg.module.decorate(buffer_struct_ty_id, .block); - try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } }); + const buffer_struct_ty_id = cg.allocId(); + try cg.sections.globals.emit(gpa, .OpTypeStruct, .{ + .id_result = buffer_struct_ty_id, + .id_ref = &.{anyerror_ty_id}, + }); + try cg.memberDebugName(buffer_struct_ty_id, 0, "error_out"); + try cg.decorate(buffer_struct_ty_id, .block); + try cg.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } }); - const ptr_buffer_struct_ty_id = cg.module.allocId(); - try cg.module.sections.globals.emit(gpa, .OpTypePointer, .{ + const ptr_buffer_struct_ty_id = cg.allocId(); + try cg.sections.globals.emit(gpa, .OpTypePointer, .{ .id_result = ptr_buffer_struct_ty_id, - .storage_class = cg.module.storageClass(.global), + .storage_class = cg.storageClass(.global), .type = buffer_struct_ty_id, }); - try cg.module.sections.globals.emit(gpa, .OpVariable, .{ + try cg.sections.globals.emit(gpa, .OpVariable, .{ .id_result_type = ptr_buffer_struct_ty_id, .id_result = err_buf_result_id, - .storage_class = cg.module.storageClass(.global), + .storage_class = cg.storageClass(.global), }); - try cg.module.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } }); - try cg.module.decorate(err_buf_result_id, .{ .binding = .{ .binding_point = 0 } }); + try cg.decorate(err_buf_result_id, .{ .descriptor_set = .{ .descriptor_set = 0 } }); + try cg.decorate(err_buf_result_id, .{ .binding = .{ .binding_point = 0 } }); - cg.module.error_buffer = spv_err_decl_index; + cg.error_buffer = spv_err_decl_index; } - try cg.module.sections.execution_modes.emit(gpa, .OpExecutionMode, .{ - .entry_point = kernel_id, - .mode = .{ .local_size = .{ - .x_size = 1, - .y_size = 1, - .z_size = 1, - } }, - }); - const void_ty_id = try cg.resolveType(.void, .direct); - const kernel_proto_ty_id = try cg.module.functionType(void_ty_id, &.{}); + const kernel_proto_ty_id = try cg.functionType(void_ty_id, &.{}); try section.emit(gpa, .OpFunction, .{ .id_result_type = try cg.resolveType(.void, .direct), .id_result = kernel_id, @@ -2463,12 +3956,12 @@ fn generateTestEntryPoint( .function_type = kernel_proto_ty_id, }); try section.emit(gpa, .OpLabel, .{ - .id_result = cg.module.allocId(), + .id_result = cg.allocId(), }); - const spv_err_decl_index = cg.module.error_buffer.?; - const buffer_id = cg.module.declPtr(spv_err_decl_index).result_id; - try cg.module.decl_deps.append(gpa, spv_err_decl_index); + const spv_err_decl_index = cg.error_buffer.?; + const buffer_id = cg.declPtr(spv_err_decl_index).result_id; + try cg.decl_deps.append(gpa, spv_err_decl_index); const zero_id = try cg.constInt(.u32, 0); try section.emit(gpa, .OpInBoundsAccessChain, .{ @@ -2481,7 +3974,7 @@ fn generateTestEntryPoint( else => unreachable, } - const error_id = cg.module.allocId(); + const error_id = cg.allocId(); try section.emit(gpa, .OpFunctionCall, .{ .id_result_type = anyerror_ty_id, .id_result = error_id, @@ -2500,15 +3993,14 @@ fn generateTestEntryPoint( // Just generate a quick other name because the intel runtime crashes when the entry- // point name is the same as a different OpName. - const test_name = try std.fmt.allocPrint(cg.module.arena, "test {s}", .{name}); + const test_name = try std.fmt.allocPrint(cg.arena, "test {s}", .{name}); - const execution_mode: spec.ExecutionModel = switch (target.os.tag) { - .vulkan, .opengl => .gl_compute, - .opencl, .amdhsa => .kernel, - else => unreachable, + const ep_gop = try cg.entry_points.getOrPut(cg.gpa, cg.declPtr(spv_decl_index).result_id); + ep_gop.value_ptr.* = .{ + .decl_index = spv_decl_index, + .name = test_name, + .cc = .{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }, }; - - try cg.module.declareEntryPoint(spv_decl_index, test_name, execution_mode, null); } fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary { @@ -2526,7 +4018,7 @@ fn intFromBool(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary { /// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct). fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id { const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; switch (ty.scalarType(zcu).zigTypeTag(zcu)) { .bool => { const false_id = try cg.constBool(false, .indirect); @@ -2552,7 +4044,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id { /// Convert representation from direct (in 'register) to direct (in memory) /// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect). fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; switch (ty.scalarType(zcu).zigTypeTag(zcu)) { .bool => { const result = try cg.intFromBool(.init(ty, operand_id), .u1); @@ -2564,9 +4056,9 @@ fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id { fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id { const result_ty_id = try cg.resolveType(result_ty, .indirect); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); const indexes = [_]u32{field}; - try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{ + try cg.body.emit(cg.gpa, .OpCompositeExtract, .{ .id_result_type = result_ty_id, .id_result = result_id, .composite = object, @@ -2578,9 +4070,9 @@ fn extractField(cg: *CodeGen, result_ty: Type, object: Id, field: u32) !Id { fn extractVectorComponent(cg: *CodeGen, result_ty: Type, vector_id: Id, field: u32) !Id { const result_ty_id = try cg.resolveType(result_ty, .direct); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); const indexes = [_]u32{field}; - try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{ + try cg.body.emit(cg.gpa, .OpCompositeExtract, .{ .id_result_type = result_ty_id, .id_result = result_id, .composite = vector_id, @@ -2595,15 +4087,15 @@ const MemoryOptions = struct { }; fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?); const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); const access: spec.MemoryAccess.Extended = .{ .@"volatile" = options.is_volatile, .aligned = .{ .literal_integer = alignment }, }; - try cg.body.emit(cg.module.gpa, .OpLoad, .{ + try cg.body.emit(cg.gpa, .OpLoad, .{ .id_result_type = indirect_value_ty_id, .id_result = result_id, .pointer = ptr_id, @@ -2615,7 +4107,7 @@ fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id { fn store(cg: *CodeGen, value_ty: Type, ptr_id: Id, value_id: Id, options: MemoryOptions) !void { const indirect_value_id = try cg.convertToIndirect(value_ty, value_id); const access: spec.MemoryAccess.Extended = .{ .@"volatile" = options.is_volatile }; - try cg.body.emit(cg.module.gpa, .OpStore, .{ + try cg.body.emit(cg.gpa, .OpStore, .{ .pointer = ptr_id, .object = indirect_value_id, .memory_access = access, @@ -2629,8 +4121,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void { } fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const ip = &zcu.intern_pool; if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) return; @@ -2685,9 +4177,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { .ptr_add => try cg.airPtrAdd(inst), .ptr_sub => try cg.airPtrSub(inst), - .bit_and => try cg.airBinOpSimple(inst, .OpBitwiseAnd), - .bit_or => try cg.airBinOpSimple(inst, .OpBitwiseOr), - .xor => try cg.airBinOpSimple(inst, .OpBitwiseXor), + .bit_and => try cg.airBitwiseOp(inst, .bit_and), + .bit_or => try cg.airBitwiseOp(inst, .bit_or), + .xor => try cg.airBitwiseOp(inst, .xor), .shl, .shl_exact => try cg.airShift(inst, .OpShiftLeftLogical, .OpShiftLeftLogical), .shr, .shr_exact => try cg.airShift(inst, .OpShiftRightLogical, .OpShiftRightArithmetic), @@ -2695,12 +4187,19 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { .min => try cg.airMinMax(inst, .min), .max => try cg.airMinMax(inst, .max), - .bitcast => try cg.airBitCast(inst), - .intcast, .trunc => try cg.airIntCast(inst), - .float_from_int => try cg.airFloatFromInt(inst), - .int_from_float => try cg.airIntFromFloat(inst), - .fpext, .fptrunc => try cg.airFloatCast(inst), - .not => try cg.airNot(inst), + .bit_cast => try cg.airBitCast(inst), + .ptr_cast => try cg.airBitCast(inst), + .ptr_from_int => try cg.airBitCast(inst), + .int_from_ptr => try cg.airBitCast(inst), + .error_cast => try cg.airBitCast(inst), + .error_from_int => try cg.airBitCast(inst), + .int_from_error => try cg.airBitCast(inst), + .union_from_enum => try cg.airBitCast(inst), + .int_cast, .trunc => try cg.airIntCast(inst), + .float_from_int => try cg.airFloatFromInt(inst), + .int_from_float => try cg.airIntFromFloat(inst), + .fpext, .fptrunc => try cg.airFloatCast(inst), + .not => try cg.airNot(inst), .array_to_slice => try cg.airArrayToSlice(inst), .slice => try cg.airSlice(inst), @@ -2708,13 +4207,16 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { .memcpy => return cg.airMemcpy(inst), .memmove => return cg.airMemmove(inst), - .slice_ptr => try cg.airSliceField(inst, 0), - .slice_len => try cg.airSliceField(inst, 1), - .slice_elem_ptr => try cg.airSliceElemPtr(inst), - .slice_elem_val => try cg.airSliceElemVal(inst), - .ptr_elem_ptr => try cg.airPtrElemPtr(inst), - .ptr_elem_val => try cg.airPtrElemVal(inst), - .array_elem_val => try cg.airArrayElemVal(inst), + .slice_ptr => try cg.airSliceField(inst, 0), + .slice_len => try cg.airSliceField(inst, 1), + .ptr_slice_ptr_ptr => try cg.airStructFieldPtrIndex(inst, 0), + .ptr_slice_len_ptr => try cg.airStructFieldPtrIndex(inst, 1), + .spirv_runtime_array_len => try cg.airSpirvRuntimeArrayLen(inst), + .slice_elem_ptr => try cg.airSliceElemPtr(inst), + .slice_elem_val => try cg.airSliceElemVal(inst), + .ptr_elem_ptr => try cg.airPtrElemPtr(inst), + .ptr_elem_val => try cg.airPtrElemVal(inst), + .array_elem_val => try cg.airArrayElemVal(inst), .set_union_tag => return cg.airSetUnionTag(inst), .get_union_tag => try cg.airGetUnionTag(inst), @@ -2747,19 +4249,21 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { .load => try cg.airLoad(inst), .store, .store_safe => return cg.airStore(inst), - .br => return cg.airBr(inst), + .br => return cg.airBr(inst), // For now just ignore this instruction. This effectively falls back on the old implementation, // this doesn't change anything for us. - .repeat => return, - .breakpoint => return, - .cond_br => return cg.airCondBr(inst), - .loop => return cg.airLoop(inst), - .ret => return cg.airRet(inst), - .ret_safe => return cg.airRet(inst), // TODO - .ret_load => return cg.airRetLoad(inst), - .@"try" => try cg.airTry(inst), - .switch_br => return cg.airSwitchBr(inst), - .unreach, .trap => return cg.airUnreach(), + .repeat => return, + .breakpoint => return, + .cond_br => return cg.airCondBr(inst), + .loop => return cg.airLoop(inst), + .ret => return cg.airRet(inst), + .ret_safe => return cg.airRet(inst), // TODO + .ret_load => return cg.airRetLoad(inst), + .@"try" => try cg.airTry(inst), + .switch_br => return cg.airSwitchBr(inst), + .loop_switch_br => return cg.airLoopSwitchBr(inst), + .switch_dispatch => return cg.airSwitchDispatch(inst), + .unreach, .trap => return cg.airUnreach(), .dbg_empty_stmt => return, .dbg_stmt => return cg.airDbgStmt(inst), @@ -2811,8 +4315,50 @@ fn airBinOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: Opcode) !?Id { return try result.materialize(cg); } +const BitwiseOp = enum { bit_and, bit_or, xor }; + +fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id { + const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; + const lhs = try cg.temporary(bin_op.lhs); + const rhs = try cg.temporary(bin_op.rhs); + const info = cg.arithmeticTypeInfo(lhs.ty); + + // SPIR-V requires logical opcodes for booleans, bitwise opcodes for integers. + const opcode: Opcode = switch (info.class) { + .bool => switch (op) { + .bit_and => .OpLogicalAnd, + .bit_or => .OpLogicalOr, + .xor => .OpLogicalNotEqual, + }, + .integer, .strange_integer => switch (op) { + .bit_and => .OpBitwiseAnd, + .bit_or => .OpBitwiseOr, + .xor => .OpBitwiseXor, + }, + .float => unreachable, + .composite_integer => { + const spv_opcode: Opcode = switch (op) { + .bit_and => .OpBitwiseAnd, + .bit_or => .OpBitwiseOr, + .xor => .OpBitwiseXor, + }; + const lhs_id = try lhs.materialize(cg); + const rhs_id = try rhs.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci_lhs = try CompositeInt.init(cg, lhs_id, info); + const ci_rhs = try CompositeInt.init(cg, rhs_id, info); + const ci_result = try ci_lhs.bitwiseOp(ci_rhs, spv_opcode); + return try ci_result.materialize(lhs.ty); + }, + }; + + const result = try cg.buildBinary(opcode, lhs, rhs); + return try result.materialize(cg); +} + fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) { @@ -2826,7 +4372,39 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode const info = cg.arithmeticTypeInfo(result_ty); switch (info.class) { - .composite_integer => return cg.todo("shift ops for composite integers", .{}), + .composite_integer => { + const shift_info = cg.arithmeticTypeInfo(shift.ty); + const shift_amt_id = switch (shift_info.class) { + .composite_integer => blk: { + const shift_id = try shift.materialize(cg); + const u32_ty_id = try cg.resolveType(.u32, .direct); + const result_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = result_id, + .composite = shift_id, + .indexes = &.{@as(u32, 0)}, + }); + break :blk result_id; + }, + else => blk: { + const converted = try cg.buildConvert(.u32, shift); + break :blk try converted.materialize(cg); + }, + }; + const base_id = try base.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci = try CompositeInt.init(cg, base_id, info); + const ci_result = if (unsigned == .OpShiftLeftLogical) + try ci.shl(shift_amt_id) + else switch (info.signedness) { + .unsigned => try ci.shr(shift_amt_id, false), + .signed => try ci.shr(shift_amt_id, true), + }; + const normalized = try ci_result.normalize(); + return try normalized.materialize(result_ty); + }, .integer, .strange_integer => {}, .float, .bool => unreachable, } @@ -2908,13 +4486,13 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id { } fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const target = zcu.getTarget(); const info = cg.arithmeticTypeInfo(lhs.ty); const v = cg.vectorization(.{ lhs, rhs }); const ops = v.components(); - const results = cg.module.allocIds(ops); + const results = cg.allocIds(ops); const op_result_ty = lhs.ty.scalarType(zcu); const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); @@ -2926,7 +4504,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary { const set = try cg.importExtendedSet(); const opcode = op.extInstOpcode(target, info); for (0..ops) |i| { - try cg.body.emit(cg.module.gpa, .OpExtInst, .{ + try cg.body.emit(cg.gpa, .OpExtInst, .{ .id_result_type = op_result_ty_id, .id_result = results.at(i), .set = set, @@ -2947,10 +4525,19 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary { /// All other values are returned unmodified (this makes strange integer /// wrapping easier to use in generic operations). fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty = value.ty; switch (info.class) { - .composite_integer, .integer, .bool, .float => return value, + .integer, .bool, .float => return value, + .composite_integer => { + if (info.bits == info.backing_bits) return value; + const val_id = try value.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci = try CompositeInt.init(cg, val_id, info); + const normalized = try ci.normalize(); + return .init(ty, try normalized.materialize(ty)); + }, .strange_integer => switch (info.signedness) { .unsigned => { const mask_value = @as(u64, std.math.maxInt(u64)) >> @as(u6, @intCast(64 - info.bits)); @@ -2976,7 +4563,7 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const info = cg.arithmeticTypeInfo(lhs.ty); switch (info.class) { - .composite_integer => unreachable, // TODO + .composite_integer => return cg.todo("div_floor for composite integers", .{}), .integer, .strange_integer => { switch (info.signedness) { .unsigned => { @@ -3015,7 +4602,7 @@ fn airDivTrunc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const rhs = try cg.temporary(bin_op.rhs); const info = cg.arithmeticTypeInfo(lhs.ty); switch (info.class) { - .composite_integer => unreachable, // TODO + .composite_integer => return cg.todo("div_trunc for composite integers", .{}), .integer, .strange_integer => switch (info.signedness) { .unsigned => { const result = try cg.buildBinary(.OpUDiv, lhs, rhs); @@ -3054,10 +4641,28 @@ fn airArithOp( const rhs = try cg.temporary(bin_op.rhs); const info = cg.arithmeticTypeInfo(lhs.ty); const result = switch (info.class) { - .composite_integer => unreachable, // TODO - .integer, .strange_integer => switch (info.signedness) { - .signed => try cg.buildBinary(sop, lhs, rhs), - .unsigned => try cg.buildBinary(uop, lhs, rhs), + .composite_integer => res: { + const lhs_id = try lhs.materialize(cg); + const rhs_id = try rhs.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci_lhs = try CompositeInt.init(cg, lhs_id, info); + const ci_rhs = try CompositeInt.init(cg, rhs_id, info); + const ci_result = switch (uop) { + .OpIAdd => try ci_lhs.addSub(ci_rhs, true), + .OpISub => try ci_lhs.addSub(ci_rhs, false), + .OpIMul => CompositeInt.fromLimbs(cg, try ci_lhs.mul(ci_rhs, false), info), + else => return cg.todo("arith op for composite integers", .{}), + }; + const normalized = try ci_result.normalize(); + break :res Temporary.init(lhs.ty, try normalized.materialize(lhs.ty)); + }, + .integer, .strange_integer => res: { + const raw = switch (info.signedness) { + .signed => try cg.buildBinary(sop, lhs, rhs), + .unsigned => try cg.buildBinary(uop, lhs, rhs), + }; + break :res try cg.normalize(raw, info); }, .float => try cg.buildBinary(fop, lhs, rhs), .bool => unreachable, @@ -3066,35 +4671,63 @@ fn airArithOp( } fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id { + const zcu = cg.zcu; + const target = zcu.getTarget(); const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const operand = try cg.temporary(ty_op.operand); - // Note: operand_ty may be signed, while ty is always unsigned! + const value = try cg.temporary(ty_op.operand); + // Note: operand_ty may be signed, while ty is always unsigned. const result_ty = cg.typeOfIndex(inst); - const result = try cg.abs(result_ty, operand); - return try result.materialize(cg); -} - -fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary { - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); const operand_info = cg.arithmeticTypeInfo(value.ty); - switch (operand_info.class) { - .float => return try cg.buildUnary(.f_abs, value), - .integer, .strange_integer => { - const abs_value = try cg.buildUnary(.i_abs, value); + const result: Temporary = switch (operand_info.class) { + .float => try cg.buildUnary(.f_abs, value), + .integer, .strange_integer => abs: { + var abs_value = try cg.buildUnary(.i_abs, value); switch (target.os.tag) { .vulkan, .opengl => { if (value.ty.intInfo(zcu).signedness == .signed) { - return cg.todo("perform bitcast after @abs", .{}); + const abs_id = try abs_value.materialize(cg); + const dst_ty_id = try cg.resolveType(result_ty, .direct); + const cast_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpBitcast, .{ + .id_result_type = dst_ty_id, + .id_result = cast_id, + .operand = abs_id, + }); + abs_value = .init(result_ty, cast_id); } }, else => {}, } - return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty)); + break :abs try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty)); + }, + .composite_integer => abs: { + const val_id = try value.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci = try CompositeInt.init(cg, val_id, operand_info); + const ci_z = try CompositeInt.zero(cg, operand_info); + const is_neg = try ci.cmp(ci_z, .lt); + const ci_neg = try ci_z.addSub(ci, false); + const result_info = cg.arithmeticTypeInfo(result_ty); + const u32_ty_id = try cg.resolveType(.u32, .direct); + const result_limbs = try cg.id_scratch.addManyAsSlice(cg.gpa, ci.n_limbs); + for (0..ci.n_limbs) |i| { + result_limbs[i] = cg.allocId(); + try cg.body.emit(cg.gpa, .OpSelect, .{ + .id_result_type = u32_ty_id, + .id_result = result_limbs[i], + .condition = is_neg, + .object_1 = ci_neg.limbs[i], + .object_2 = ci.limbs[i], + }); + } + const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info); + const normalized = try ci_result.normalize(); + break :abs .init(result_ty, try normalized.materialize(result_ty)); }, - .composite_integer => unreachable, // TODO .bool => unreachable, - } + }; + return try result.materialize(cg); } fn airAddSubOverflow( @@ -3120,7 +4753,73 @@ fn airAddSubOverflow( const info = cg.arithmeticTypeInfo(lhs.ty); switch (info.class) { - .composite_integer => unreachable, // TODO + .composite_integer => { + const lhs_id = try lhs.materialize(cg); + const rhs_id = try rhs.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci_lhs = try CompositeInt.init(cg, lhs_id, info); + const ci_rhs = try CompositeInt.init(cg, rhs_id, info); + const ci_sum = if (add == .OpIAdd) try ci_lhs.addSub(ci_rhs, true) else try ci_lhs.addSub(ci_rhs, false); + const ci_result = try ci_sum.normalize(); + const result_val_id = try ci_result.materialize(lhs.ty); + + const ov_bool = switch (info.signedness) { + .unsigned => blk: { + const ci_res2 = try CompositeInt.init(cg, result_val_id, info); + const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info); + break :blk if (add == .OpIAdd) + try ci_res2.cmp(ci_lhs2, .lt) + else + try ci_res2.cmp(ci_lhs2, .gt); + }, + .signed => blk: { + const ci_res2 = try CompositeInt.init(cg, result_val_id, info); + const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info); + const ci_rhs2 = try CompositeInt.init(cg, rhs_id, info); + const ci_z = try CompositeInt.zero(cg, info); + const lhs_neg = try ci_lhs2.cmp(ci_z, .lt); + const rhs_neg = try ci_rhs2.cmp(ci_z, .lt); + const res_neg = try ci_res2.cmp(ci_z, .lt); + + const bool_ty_id = try cg.resolveType(.bool, .direct); + const signs_match = cg.allocId(); + try cg.body.emit(cg.gpa, .OpLogicalEqual, .{ + .id_result_type = bool_ty_id, + .id_result = signs_match, + .operand_1 = lhs_neg, + .operand_2 = rhs_neg, + }); + const res_sign_diff = cg.allocId(); + try cg.body.emit(cg.gpa, .OpLogicalNotEqual, .{ + .id_result_type = bool_ty_id, + .id_result = res_sign_diff, + .operand_1 = lhs_neg, + .operand_2 = res_neg, + }); + const ov_cond = if (add == .OpIAdd) signs_match else blk2: { + const not_match = cg.allocId(); + try cg.body.emit(cg.gpa, .OpLogicalNot, .{ + .id_result_type = bool_ty_id, + .id_result = not_match, + .operand = signs_match, + }); + break :blk2 not_match; + }; + const ov_result = cg.allocId(); + try cg.body.emit(cg.gpa, .OpLogicalAnd, .{ + .id_result_type = bool_ty_id, + .id_result = ov_result, + .operand_1 = ov_cond, + .operand_2 = res_sign_diff, + }); + break :blk ov_result; + }, + }; + const ov = try cg.intFromBool(.init(.bool, ov_bool), .u1); + const result_ty_id = try cg.resolveType(result_ty, .direct); + return try cg.constructComposite(result_ty_id, &.{ result_val_id, try ov.materialize(cg) }); + }, .strange_integer, .integer => {}, .float, .bool => unreachable, } @@ -3162,6 +4861,7 @@ fn airAddSubOverflow( fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const pt = cg.pt; + const gpa = cg.gpa; const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data; const lhs = try cg.temporary(extra.lhs); @@ -3170,7 +4870,168 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const info = cg.arithmeticTypeInfo(lhs.ty); switch (info.class) { - .composite_integer => unreachable, // TODO + .composite_integer => { + const lhs_id = try lhs.materialize(cg); + const rhs_id = try rhs.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci_lhs = try CompositeInt.init(cg, lhs_id, info); + const ci_rhs = try CompositeInt.init(cg, rhs_id, info); + + const low_limbs = try ci_lhs.mul(ci_rhs, false); + const ci_result = try CompositeInt.fromLimbs(cg, low_limbs, info).normalize(); + const result_val_id = try ci_result.materialize(lhs.ty); + + const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info); + const ci_rhs2 = try CompositeInt.init(cg, rhs_id, info); + const wide_limbs = try ci_lhs2.mul(ci_rhs2, true); + const high_limbs = wide_limbs[ci_lhs2.n_limbs..]; + + const bool_ty_id = try cg.resolveType(.bool, .direct); + const u32_ty_id = try cg.resolveType(.u32, .direct); + const n: usize = info.backing_bits / big_int_bits; + + const ov_bool = switch (info.signedness) { + .unsigned => blk: { + const zero_id = try cg.constInt(.u32, @as(u32, 0)); + var any_nonzero = cg.allocId(); + try cg.body.emit(gpa, .OpINotEqual, .{ + .id_result_type = bool_ty_id, + .id_result = any_nonzero, + .operand_1 = high_limbs[0], + .operand_2 = zero_id, + }); + + for (1..n) |i| { + const limb_nz = cg.allocId(); + try cg.body.emit(gpa, .OpINotEqual, .{ + .id_result_type = bool_ty_id, + .id_result = limb_nz, + .operand_1 = high_limbs[i], + .operand_2 = zero_id, + }); + + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalOr, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = any_nonzero, + .operand_2 = limb_nz, + }); + any_nonzero = combined; + } + + break :blk any_nonzero; + }, + .signed => blk: { + const ci_res = try CompositeInt.init(cg, result_val_id, info); + const top_limb = ci_res.limbs[n - 1]; + const i32_ty_id = try cg.resolveType(.i32, .direct); + + const top_bits: u16 = if (info.bits % big_int_bits == 0) + big_int_bits + else + info.bits % big_int_bits; + + const shift_amt: u32 = top_bits - 1; + const shift_id = try cg.constInt(.u32, shift_amt); + + const as_signed = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = as_signed, + .operand = top_limb, + }); + const sign_ext = cg.allocId(); + try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ + .id_result_type = i32_ty_id, + .id_result = sign_ext, + .base = as_signed, + .shift = shift_id, + }); + const expected = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = u32_ty_id, + .id_result = expected, + .operand = sign_ext, + }); + + var any_mismatch = cg.allocId(); + try cg.body.emit(gpa, .OpINotEqual, .{ + .id_result_type = bool_ty_id, + .id_result = any_mismatch, + .operand_1 = high_limbs[0], + .operand_2 = expected, + }); + + for (1..n) |i| { + const limb_ne = cg.allocId(); + try cg.body.emit(gpa, .OpINotEqual, .{ + .id_result_type = bool_ty_id, + .id_result = limb_ne, + .operand_1 = high_limbs[i], + .operand_2 = expected, + }); + + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalOr, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = any_mismatch, + .operand_2 = limb_ne, + }); + any_mismatch = combined; + } + + if (info.bits != info.backing_bits) { + const top_bits_s: u16 = info.bits % big_int_bits; + const s_shift_id = try cg.constInt(.u32, top_bits_s - 1); + + const top_as_signed = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = top_as_signed, + .operand = top_limb, + }); + const top_sign_ext = cg.allocId(); + try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ + .id_result_type = i32_ty_id, + .id_result = top_sign_ext, + .base = top_as_signed, + .shift = s_shift_id, + }); + const top_expected = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = u32_ty_id, + .id_result = top_expected, + .operand = top_sign_ext, + }); + const top_mismatch = cg.allocId(); + try cg.body.emit(gpa, .OpINotEqual, .{ + .id_result_type = bool_ty_id, + .id_result = top_mismatch, + .operand_1 = top_limb, + .operand_2 = top_expected, + }); + + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalOr, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = any_mismatch, + .operand_2 = top_mismatch, + }); + any_mismatch = combined; + } + + break :blk any_mismatch; + }, + }; + + const ov = try cg.intFromBool(.init(.bool, ov_bool), .u1); + const result_ty_id = try cg.resolveType(result_ty, .direct); + return try cg.constructComposite(result_ty_id, &.{ result_val_id, try ov.materialize(cg) }); + }, .strange_integer, .integer => {}, .float, .bool => unreachable, } @@ -3181,7 +5042,8 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { // - Additionally, if info.bits != 32, we'll have to check the high bits // of the result too. - const largest_int_bits = cg.largestSupportedIntBits(); + const target = cg.zcu.getTarget(); + const largest_int_bits: u16 = if (target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64) 64 else 32; // If non-null, the number of bits that the multiplication should be performed in. If // null, we have to use wide multiplication. const maybe_op_ty_bits: ?u16 = switch (info.bits) { @@ -3189,7 +5051,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { 1...16 => 32, 17...32 => if (largest_int_bits > 32) 64 else null, // Upcast if we can. 33...64 => null, // Always use wide multiplication. - else => unreachable, // TODO: Composite integers + else => unreachable, }; const result, const overflowed = switch (info.signedness) { @@ -3325,7 +5187,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data; @@ -3341,7 +5203,7 @@ fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const info = cg.arithmeticTypeInfo(base.ty); switch (info.class) { - .composite_integer => unreachable, // TODO + .composite_integer => return cg.todo("shl-with-overflow for composite integers", .{}), .integer, .strange_integer => {}, .float, .bool => unreachable, } @@ -3377,14 +5239,48 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const info = cg.arithmeticTypeInfo(result_ty); assert(info.class == .float); // .mul_add is only emitted for floats - const result = try cg.buildFma(a, b, c); + const zcu = cg.zcu; + const target = zcu.getTarget(); + + const v = cg.vectorization(.{ a, b, c }); + const ops = v.components(); + const results = cg.allocIds(ops); + + const op_result_ty = a.ty.scalarType(zcu); + const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); + const result_temp_ty = try v.resultType(cg, a.ty); + + const op_a = try v.prepare(cg, a); + const op_b = try v.prepare(cg, b); + const op_c = try v.prepare(cg, c); + + const set = try cg.importExtendedSet(); + const opcode: u32 = switch (target.os.tag) { + .opencl => @intFromEnum(spec.OpenClOpcode.fma), + // NOTE: Vulkan's FMA does not meet Zig's nor OpenCL's precision guarantees and needs + // to be emulated. + .vulkan, .opengl => @intFromEnum(spec.GlslOpcode.Fma), + else => unreachable, + }; + + for (0..ops) |i| { + try cg.body.emit(cg.gpa, .OpExtInst, .{ + .id_result_type = op_result_ty_id, + .id_result = results.at(i), + .set = set, + .instruction = .{ .inst = opcode }, + .id_ref_4 = &.{ op_a.at(i), op_b.at(i), op_c.at(i) }, + }); + } + + const result = v.finalize(result_temp_ty, results); return try result.materialize(cg); } fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id { if (cg.liveness.isUnused(inst)) return null; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand = try cg.temporary(ty_op.operand); @@ -3392,7 +5288,7 @@ fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id { const info = cg.arithmeticTypeInfo(operand.ty); switch (info.class) { - .composite_integer => unreachable, // TODO + .composite_integer => return cg.todo("@clz/@ctz for composite integers", .{}), .integer, .strange_integer => {}, .float, .bool => unreachable, } @@ -3427,12 +5323,11 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce; const operand = try cg.resolve(reduce.operand); const operand_ty = cg.typeOf(reduce.operand); const scalar_ty = operand_ty.scalarType(zcu); - const scalar_ty_id = try cg.resolveType(scalar_ty, .direct); const info = cg.arithmeticTypeInfo(operand_ty); const len = operand_ty.vectorLen(zcu); const first = try cg.extractVectorComponent(scalar_ty, operand, 0); @@ -3458,8 +5353,6 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id { else => {}, } - var result_id = first; - const opcode: Opcode = switch (info.class) { .bool => switch (reduce.operation) { .And => .OpLogicalAnd, @@ -3480,26 +5373,25 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id { .Mul => .OpFMul, else => unreachable, }, - .composite_integer => unreachable, // TODO + .composite_integer => return cg.todo("@reduce for composite integers", .{}), }; + const needs_normalize = info.class == .strange_integer and + (reduce.operation == .Add or reduce.operation == .Mul); + + var result: Temporary = .init(scalar_ty, first); for (1..len) |i| { - const lhs = result_id; - const rhs = try cg.extractVectorComponent(scalar_ty, operand, @intCast(i)); - result_id = cg.module.allocId(); - - try cg.body.emitRaw(cg.module.gpa, opcode, 4); - cg.body.writeOperand(Id, scalar_ty_id); - cg.body.writeOperand(Id, result_id); - cg.body.writeOperand(Id, lhs); - cg.body.writeOperand(Id, rhs); + const rhs_id = try cg.extractVectorComponent(scalar_ty, operand, @intCast(i)); + const rhs: Temporary = .init(scalar_ty, rhs_id); + const stepped = try cg.buildBinary(opcode, result, rhs); + result = if (needs_normalize) try cg.normalize(stepped, info) else stepped; } - return result_id; + return try result.materialize(cg); } fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const gpa = zcu.gpa; const unwrapped = cg.air.unwrapShuffleOne(zcu, inst); @@ -3524,7 +5416,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const gpa = zcu.gpa; const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst); @@ -3543,7 +5435,7 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id { id.* = switch (mask_elem.unwrap()) { .a_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_a, idx), .b_elem => |idx| try cg.extractVectorComponent(elem_ty, operand_b, idx), - .undef => try cg.module.constUndef(elem_ty_id), + .undef => try cg.constUndef(elem_ty_id), }; } @@ -3557,8 +5449,8 @@ fn accessChainId( base: Id, indices: []const Id, ) !Id { - const result_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpInBoundsAccessChain, .{ + const result_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpInBoundsAccessChain, .{ .id_result_type = result_ty_id, .id_result = result_id, .base = base, @@ -3577,7 +5469,7 @@ fn accessChain( base: Id, indices: []const u32, ) !Id { - const gpa = cg.module.gpa; + const gpa = cg.gpa; const scratch_top = cg.id_scratch.items.len; defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); const ids = try cg.id_scratch.addManyAsSlice(gpa, indices.len); @@ -3594,8 +5486,8 @@ fn ptrAccessChain( element: Id, indices: []const u32, ) !Id { - const gpa = cg.module.gpa; - const target = cg.module.zcu.getTarget(); + const gpa = cg.gpa; + const target = cg.zcu.getTarget(); const scratch_top = cg.id_scratch.items.len; defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); @@ -3604,7 +5496,7 @@ fn ptrAccessChain( id.* = try cg.constInt(.u32, index); } - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); switch (target.os.tag) { .opencl, .amdhsa => { try cg.body.emit(gpa, .OpInBoundsPtrAccessChain, .{ @@ -3630,7 +5522,7 @@ fn ptrAccessChain( } fn ptrAdd(cg: *CodeGen, result_ty: Type, ptr_ty: Type, ptr_id: Id, offset_id: Id) !Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const result_ty_id = try cg.resolveType(result_ty, .direct); switch (ptr_ty.ptrSize(zcu)) { @@ -3671,8 +5563,8 @@ fn airPtrSub(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const offset_ty_id = try cg.resolveType(offset_ty, .direct); const result_ty = cg.typeOfIndex(inst); - const negative_offset_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpSNegate, .{ + const negative_offset_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpSNegate, .{ .id_result_type = offset_ty_id, .id_result = negative_offset_id, .operand = offset_id, @@ -3686,9 +5578,9 @@ fn cmp( lhs: Temporary, rhs: Temporary, ) !Temporary { - const gpa = cg.module.gpa; + const gpa = cg.gpa; const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const scalar_ty = lhs.ty.scalarType(zcu); const is_vector = lhs.ty.isVector(zcu); @@ -3717,14 +5609,14 @@ fn cmp( const usize_ty_id = try cg.resolveType(.usize, .direct); - const lhs_int_id = cg.module.allocId(); + const lhs_int_id = cg.allocId(); try cg.body.emit(gpa, .OpConvertPtrToU, .{ .id_result_type = usize_ty_id, .id_result = lhs_int_id, .pointer = try lhs.materialize(cg), }); - const rhs_int_id = cg.module.allocId(); + const rhs_int_id = cg.allocId(); try cg.body.emit(gpa, .OpConvertPtrToU, .{ .id_result_type = usize_ty_id, .id_result = rhs_int_id, @@ -3816,7 +5708,16 @@ fn cmp( const info = cg.arithmeticTypeInfo(scalar_ty); const pred: Opcode = switch (info.class) { - .composite_integer => unreachable, // TODO + .composite_integer => { + const lhs_id = try lhs.materialize(cg); + const rhs_id = try rhs.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci_lhs = try CompositeInt.init(cg, lhs_id, info); + const ci_rhs = try CompositeInt.init(cg, rhs_id, info); + const result_id = try ci_lhs.cmp(ci_rhs, op); + return .init(.bool, result_id); + }, .float => switch (op) { .eq => .OpFOrdEqual, .neq => .OpFUnordNotEqual, @@ -3884,14 +5785,29 @@ fn bitCast( src_ty: Type, src_id: Id, ) !Id { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const target = zcu.getTarget(); - const src_ty_id = try cg.resolveType(src_ty, .direct); + + if (src_ty.toIntern() == dst_ty.toIntern()) return src_id; + if (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu)) switch (target.os.tag) { + .vulkan, .opengl => if (src_ty.ptrAddressSpace(zcu) != .physical_storage_buffer) return src_id, + else => {}, + }; + const dst_ty_id = try cg.resolveType(dst_ty, .direct); - const result_id = blk: { - if (src_ty_id == dst_ty_id) break :blk src_id; + // Big-int ↔ big-int bitcast: the indirect representation is an array, + // which OpBitcast cannot operate on. The arrays are bitwise identical + // apart from the top limb's padding; the normalize pass below fixes + // the padding. + if (src_ty.isInt(zcu) and dst_ty.isInt(zcu)) { + const src_info = src_ty.intInfo(zcu); + const dst_info = dst_ty.intInfo(zcu); + const src_backing, const src_big = cg.backingIntBits(src_info.bits); + const dst_backing, const dst_big = cg.backingIntBits(dst_info.bits); + if (src_backing == dst_backing and src_big and dst_big) break :blk src_id; + } // TODO: Some more cases are missing here // See fn bitCast in llvm.zig @@ -3906,7 +5822,7 @@ fn bitCast( } } - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); try cg.body.emit(gpa, .OpConvertUToPtr, .{ .id_result_type = dst_ty_id, .id_result = result_id, @@ -3920,7 +5836,7 @@ fn bitCast( // otherwise use a temporary and perform a pointer cast. const can_bitcast = (src_ty.isNumeric(zcu) and dst_ty.isNumeric(zcu)) or (src_ty.isPtrAtRuntime(zcu) and dst_ty.isPtrAtRuntime(zcu)); if (can_bitcast) { - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); try cg.body.emit(gpa, .OpBitcast, .{ .id_result_type = dst_ty_id, .id_result = result_id, @@ -3930,12 +5846,24 @@ fn bitCast( break :blk result_id; } - const dst_ptr_ty_id = try cg.module.ptrType(dst_ty_id, .function); + switch (target.os.tag) { + .vulkan, .opengl => { + // Logical addressing forbids OpBitcast on pointers. Allocate + // the temp with dst_ty so the load reads through a slot of the right type. + const dst_ty_indirect_id = try cg.resolveType(dst_ty, .indirect); + const tmp_id = try cg.alloc(dst_ty_indirect_id, null); + try cg.store(dst_ty, tmp_id, src_id, .{}); + break :blk try cg.load(dst_ty, tmp_id, .{}); + }, + else => {}, + } + + const dst_ptr_ty_id = try cg.ptrType(dst_ty_id, .function); const src_ty_indirect_id = try cg.resolveType(src_ty, .indirect); const tmp_id = try cg.alloc(src_ty_indirect_id, null); try cg.store(src_ty, tmp_id, src_id, .{}); - const casted_ptr_id = cg.module.allocId(); + const casted_ptr_id = cg.allocId(); try cg.body.emit(gpa, .OpBitcast, .{ .id_result_type = dst_ptr_ty_id, .id_result = casted_ptr_id, @@ -3966,6 +5894,12 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const result = try cg.intFromBool(operand, .u1); return try result.materialize(cg); } + if (operand_ty.zigTypeTag(cg.zcu) == .pointer) { + switch (try cg.resolvePtr(ty_op.operand)) { + .tracked => |t| return t.id, // TODO + .id => |operand_id| return try cg.bitCast(result_ty, operand_ty, operand_id), + } + } const operand_id = try cg.resolve(ty_op.operand); return try cg.bitCast(result_ty, operand_ty, operand_id); } @@ -3978,8 +5912,207 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const src_info = cg.arithmeticTypeInfo(src.ty); const dst_info = cg.arithmeticTypeInfo(dst_ty); + const src_composite = src_info.class == .composite_integer; + const dst_composite = dst_info.class == .composite_integer; + + if (src_composite or dst_composite) { + const gpa = cg.gpa; + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + + if (src_composite and dst_composite) { + const src_id = try src.materialize(cg); + const src_n: u16 = src_info.backing_bits / big_int_bits; + const dst_n: u16 = dst_info.backing_bits / big_int_bits; + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); + const min_n = @min(src_n, dst_n); + const u32_ty_id = try cg.resolveType(.u32, .direct); + for (0..min_n) |i| { + result_limbs[i] = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = result_limbs[i], + .composite = src_id, + .indexes = &.{@as(u32, @intCast(i))}, + }); + } + if (dst_n > src_n) { + const fill = if (src_info.signedness == .signed) blk: { + const i32_ty_id = try cg.resolveType(.i32, .direct); + const msb = result_limbs[src_n - 1]; + const msb_signed = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = msb_signed, + .operand = msb, + }); + const shift31 = try cg.constInt(.i32, @as(i32, 31)); + const sign_ext = cg.allocId(); + try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ + .id_result_type = i32_ty_id, + .id_result = sign_ext, + .base = msb_signed, + .shift = shift31, + }); + const back = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = u32_ty_id, + .id_result = back, + .operand = sign_ext, + }); + break :blk back; + } else try cg.constInt(.u32, @as(u32, 0)); + for (min_n..dst_n) |i| { + result_limbs[i] = fill; + } + } + const ci = CompositeInt.fromLimbs(cg, result_limbs, dst_info); + const normalized = try ci.normalize(); + return try normalized.materialize(dst_ty); + } else if (src_composite and !dst_composite) { + const src_id = try src.materialize(cg); + const u32_ty_id = try cg.resolveType(.u32, .direct); + if (dst_info.backing_bits <= 32) { + const limb0 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = limb0, + .composite = src_id, + .indexes = &.{@as(u32, 0)}, + }); + const tmp: Temporary = .init(.u32, limb0); + const converted = try cg.buildConvert(dst_ty, tmp); + const result = if (dst_info.bits < src_info.bits) + try cg.normalize(converted, dst_info) + else + converted; + return try result.materialize(cg); + } else { + const limb0 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = limb0, + .composite = src_id, + .indexes = &.{@as(u32, 0)}, + }); + const limb1 = cg.allocId(); + try cg.body.emit(gpa, .OpCompositeExtract, .{ + .id_result_type = u32_ty_id, + .id_result = limb1, + .composite = src_id, + .indexes = &.{@as(u32, 1)}, + }); + const u64_ty_id = try cg.resolveType(.u64, .direct); + const lo = cg.allocId(); + try cg.body.emit(gpa, .OpUConvert, .{ + .id_result_type = u64_ty_id, + .id_result = lo, + .unsigned_value = limb0, + }); + const hi = cg.allocId(); + try cg.body.emit(gpa, .OpUConvert, .{ + .id_result_type = u64_ty_id, + .id_result = hi, + .unsigned_value = limb1, + }); + const shift32 = try cg.constInt(.u64, @as(u64, 32)); + const hi_shifted = cg.allocId(); + try cg.body.emit(gpa, .OpShiftLeftLogical, .{ + .id_result_type = u64_ty_id, + .id_result = hi_shifted, + .base = hi, + .shift = shift32, + }); + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpBitwiseOr, .{ + .id_result_type = u64_ty_id, + .id_result = combined, + .operand_1 = lo, + .operand_2 = hi_shifted, + }); + const tmp: Temporary = .init(.u64, combined); + const converted = try cg.buildConvert(dst_ty, tmp); + const result = if (dst_info.bits < src_info.bits) + try cg.normalize(converted, dst_info) + else + converted; + return try result.materialize(cg); + } + } else { + const dst_n: u16 = dst_info.backing_bits / big_int_bits; + const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); + const u32_ty_id = try cg.resolveType(.u32, .direct); + + if (src_info.backing_bits <= 32) { + const converted = try cg.buildConvert(.u32, src); + result_limbs[0] = try converted.materialize(cg); + } else { + const src_as_u64 = try cg.buildConvert(.u64, src); + const src_id = try src_as_u64.materialize(cg); + result_limbs[0] = cg.allocId(); + try cg.body.emit(gpa, .OpUConvert, .{ + .id_result_type = u32_ty_id, + .id_result = result_limbs[0], + .unsigned_value = src_id, + }); + const u64_ty_id = try cg.resolveType(.u64, .direct); + const shift32 = try cg.constInt(.u64, @as(u64, 32)); + const hi = cg.allocId(); + try cg.body.emit(gpa, .OpShiftRightLogical, .{ + .id_result_type = u64_ty_id, + .id_result = hi, + .base = src_id, + .shift = shift32, + }); + result_limbs[1] = cg.allocId(); + try cg.body.emit(gpa, .OpUConvert, .{ + .id_result_type = u32_ty_id, + .id_result = result_limbs[1], + .unsigned_value = hi, + }); + } + // Sign/zero-extend remaining limbs. + const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2; + const fill = if (src_info.signedness == .signed) blk: { + const i32_ty_id = try cg.resolveType(.i32, .direct); + const msb = result_limbs[fill_start - 1]; + const msb_signed = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = i32_ty_id, + .id_result = msb_signed, + .operand = msb, + }); + const shift31 = try cg.constInt(.i32, @as(i32, 31)); + const sign_ext = cg.allocId(); + try cg.body.emit(gpa, .OpShiftRightArithmetic, .{ + .id_result_type = i32_ty_id, + .id_result = sign_ext, + .base = msb_signed, + .shift = shift31, + }); + const back = cg.allocId(); + try cg.body.emit(gpa, .OpBitcast, .{ + .id_result_type = u32_ty_id, + .id_result = back, + .operand = sign_ext, + }); + break :blk back; + } else try cg.constInt(.u32, @as(u32, 0)); + for (fill_start..dst_n) |i| { + result_limbs[i] = fill; + } + const ci = CompositeInt.fromLimbs(cg, result_limbs, dst_info); + const normalized = try ci.normalize(); + return try normalized.materialize(dst_ty); + } + } + if (src_info.backing_bits == dst_info.backing_bits) { - return try src.materialize(cg); + const result = if (dst_info.bits < src_info.bits) + try cg.normalize(src.pun(dst_ty), dst_info) + else + src.pun(dst_ty); + return try result.materialize(cg); } const converted = try cg.buildConvert(dst_ty, src); @@ -3998,8 +6131,8 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id { const result_type_id = try cg.resolveType(.usize, .direct); - const result_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpConvertPtrToU, .{ + const result_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{ .id_result_type = result_type_id, .id_result = result_id, .pointer = operand_id, @@ -4008,17 +6141,13 @@ fn intFromPtr(cg: *CodeGen, operand_id: Id) !Id { } fn airFloatFromInt(cg: *CodeGen, inst: Air.Inst.Index) !?Id { + const gpa = cg.gpa; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand_ty = cg.typeOf(ty_op.operand); const operand_id = try cg.resolve(ty_op.operand); const result_ty = cg.typeOfIndex(inst); - return try cg.floatFromInt(result_ty, operand_ty, operand_id); -} - -fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id) !Id { - const gpa = cg.module.gpa; const operand_info = cg.arithmeticTypeInfo(operand_ty); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); const result_ty_id = try cg.resolveType(result_ty, .direct); switch (operand_info.signedness) { .signed => try cg.body.emit(gpa, .OpConvertSToF, .{ @@ -4036,17 +6165,13 @@ fn floatFromInt(cg: *CodeGen, result_ty: Type, operand_ty: Type, operand_id: Id) } fn airIntFromFloat(cg: *CodeGen, inst: Air.Inst.Index) !?Id { + const gpa = cg.gpa; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand_id = try cg.resolve(ty_op.operand); const result_ty = cg.typeOfIndex(inst); - return try cg.intFromFloat(result_ty, operand_id); -} - -fn intFromFloat(cg: *CodeGen, result_ty: Type, operand_id: Id) !Id { - const gpa = cg.module.gpa; const result_info = cg.arithmeticTypeInfo(result_ty); const result_ty_id = try cg.resolveType(result_ty, .direct); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); switch (result_info.signedness) { .signed => try cg.body.emit(gpa, .OpConvertFToS, .{ .id_result_type = result_ty_id, @@ -4079,7 +6204,15 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const result = switch (info.class) { .bool => try cg.buildUnary(.l_not, operand), .float => unreachable, - .composite_integer => unreachable, // TODO + .composite_integer => blk: { + const op_id = try operand.materialize(cg); + const scratch_top = cg.id_scratch.items.len; + defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); + const ci = try CompositeInt.init(cg, op_id, info); + const notted = try ci.bitwiseNot(); + const normalized = try notted.normalize(); + break :blk Temporary.init(result_ty, try normalized.materialize(result_ty)); + }, .strange_integer, .integer => blk: { const complement = try cg.buildUnary(.bit_not, operand); break :blk try cg.normalize(complement, info); @@ -4090,7 +6223,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const array_ptr_ty = cg.typeOf(ty_op.operand); const array_ty = array_ptr_ty.childType(zcu); @@ -4124,11 +6257,11 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const gpa = cg.module.gpa; + const gpa = cg.gpa; const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; - const target = cg.module.zcu.getTarget(); + const target = cg.zcu.getTarget(); const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const result_ty = cg.typeOfIndex(inst); const len: usize = @intCast(result_ty.arrayLen(zcu)); @@ -4253,23 +6386,8 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } } -fn sliceOrArrayLen(cg: *CodeGen, operand_id: Id, ty: Type) !Id { - const zcu = cg.module.zcu; - switch (ty.ptrSize(zcu)) { - .slice => return cg.extractField(.usize, operand_id, 1), - .one => { - const array_ty = ty.childType(zcu); - const elem_ty = array_ty.childType(zcu); - const abi_size = elem_ty.abiSize(zcu); - const size = array_ty.arrayLenIncludingSentinel(zcu) * abi_size; - return try cg.constInt(.usize, size); - }, - .many, .c => unreachable, - } -} - fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; if (ty.isSlice(zcu)) { const ptr_ty = ty.slicePtrFieldType(zcu); return cg.extractField(ptr_ty, operand_id, 0); @@ -4285,8 +6403,17 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) !void { const src_ty = cg.typeOf(bin_op.rhs); const dest_ptr = try cg.sliceOrArrayPtr(dest_slice, dest_ty); const src_ptr = try cg.sliceOrArrayPtr(src_slice, src_ty); - const len = try cg.sliceOrArrayLen(dest_slice, dest_ty); - try cg.body.emit(cg.module.gpa, .OpCopyMemorySized, .{ + const len = switch (dest_ty.ptrSize(cg.zcu)) { + .slice => try cg.extractField(.usize, dest_slice, 1), + .one => len: { + const array_ty = dest_ty.childType(cg.zcu); + const elem_ty = array_ty.childType(cg.zcu); + const size = array_ty.arrayLenIncludingSentinel(cg.zcu) * elem_ty.abiSize(cg.zcu); + break :len try cg.constInt(.usize, size); + }, + .many, .c => unreachable, + }; + try cg.body.emit(cg.gpa, .OpCopyMemorySized, .{ .target = dest_ptr, .source = src_ptr, .size = len, @@ -4305,8 +6432,24 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id { return try cg.extractField(field_ty, operand_id, field); } +fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id { + const gpa = cg.gpa; + const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; + const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data; + const struct_ptr_id = try cg.resolve(extra.struct_operand); + const u32_ty_id = try cg.intType(.unsigned, 32); + const result_id = cg.allocId(); + try cg.body.emit(gpa, .OpArrayLength, .{ + .id_result_type = u32_ty_id, + .id_result = result_id, + .structure = struct_ptr_id, + .array_member = extra.field_index, + }); + return result_id; +} + fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; const slice_ty = cg.typeOf(bin_op.lhs); @@ -4323,7 +6466,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const slice_ty = cg.typeOf(bin_op.lhs); if (!slice_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null; @@ -4340,11 +6483,11 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; // Construct new pointer type for the resulting pointer const elem_ty = ptr_ty.indexableElem(zcu); const elem_ty_id = try cg.resolveType(elem_ty, .indirect); - const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu))); + const elem_ptr_ty_id = try cg.ptrType(elem_ty_id, cg.storageClass(ptr_ty.ptrAddressSpace(zcu))); if (ptr_ty.isSinglePointer(zcu)) { // Pointer-to-array. In this case, the resulting pointer is not of the same type // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. @@ -4356,7 +6499,7 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id { } fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; const src_ptr_ty = cg.typeOf(bin_op.lhs); @@ -4370,8 +6513,8 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const array_ty = cg.typeOf(bin_op.lhs); const elem_ty = array_ty.childType(zcu); @@ -4386,10 +6529,10 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const elem_repr: Repr = if (is_vector) .direct else .indirect; const array_ty_id = try cg.resolveType(array_ty, .direct); const elem_ty_id = try cg.resolveType(elem_ty, elem_repr); - const ptr_array_ty_id = try cg.module.ptrType(array_ty_id, .function); - const ptr_elem_ty_id = try cg.module.ptrType(elem_ty_id, .function); + const ptr_array_ty_id = try cg.ptrType(array_ty_id, .function); + const ptr_elem_ty_id = try cg.ptrType(elem_ty_id, .function); - const tmp_id = cg.module.allocId(); + const tmp_id = cg.allocId(); try cg.prologue.emit(gpa, .OpVariable, .{ .id_result_type = ptr_array_ty_id, .id_result = tmp_id, @@ -4403,7 +6546,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const elem_ptr_id = try cg.accessChainId(ptr_elem_ty_id, tmp_id, &.{index_id}); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); try cg.body.emit(gpa, .OpLoad, .{ .id_result_type = try cg.resolveType(elem_ty, elem_repr), .id_result = result_id, @@ -4422,7 +6565,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ptr_ty = cg.typeOf(bin_op.lhs); const elem_ty = cg.typeOfIndex(inst); @@ -4433,7 +6576,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const un_ptr_ty = cg.typeOf(bin_op.lhs); const un_ty = un_ptr_ty.childType(zcu); @@ -4443,7 +6586,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void { const tag_ty = un_ty.unionTagTypeRuntime(zcu).?; const tag_ty_id = try cg.resolveType(tag_ty, .indirect); - const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, cg.module.storageClass(un_ptr_ty.ptrAddressSpace(zcu))); + const tag_ptr_ty_id = try cg.ptrType(tag_ty_id, cg.storageClass(un_ptr_ty.ptrAddressSpace(zcu))); const union_ptr_id = try cg.resolve(bin_op.lhs); const new_tag_id = try cg.resolve(bin_op.rhs); @@ -4460,7 +6603,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const un_ty = cg.typeOf(ty_op.operand); - const zcu = cg.module.zcu; + const zcu = cg.zcu; const layout = cg.unionLayout(un_ty); if (layout.tag_size == 0) return null; @@ -4484,7 +6627,7 @@ fn unionInit( // Note: The result here is not cached, because it generates runtime code. const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const union_ty = zcu.typeToUnion(ty).?; const tag_ty: Type = .fromInterned(union_ty.enum_tag_type); @@ -4509,7 +6652,7 @@ fn unionInit( if (layout.tag_size != 0) { const tag_ty_id = try cg.resolveType(tag_ty, .indirect); - const tag_ptr_ty_id = try cg.module.ptrType(tag_ty_id, .function); + const tag_ptr_ty_id = try cg.ptrType(tag_ty_id, .function); const ptr_id = try cg.accessChain(tag_ptr_ty_id, tmp_id, &.{@as(u32, @intCast(layout.tag_index))}); const tag_id = try cg.constInt(tag_ty, tag_int); try cg.store(tag_ty, ptr_id, tag_id, .{}); @@ -4517,13 +6660,13 @@ fn unionInit( if (payload_ty.hasRuntimeBits(zcu)) { const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect); - const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, .function); + const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, .function); const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index}); - const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty, zcu)) blk: { + const active_pl_ptr_id = if (!layout.payload_ty.eql(payload_ty)) blk: { const payload_ty_id = try cg.resolveType(payload_ty, .indirect); - const active_pl_ptr_ty_id = try cg.module.ptrType(payload_ty_id, .function); - const active_pl_ptr_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpBitcast, .{ + const active_pl_ptr_ty_id = try cg.ptrType(payload_ty_id, .function); + const active_pl_ptr_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpBitcast, .{ .id_result_type = active_pl_ptr_ty_id, .id_result = active_pl_ptr_id, .operand = pl_ptr_id, @@ -4543,7 +6686,7 @@ fn unionInit( } fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data; @@ -4560,7 +6703,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id { fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const pt = cg.pt; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data; @@ -4575,7 +6718,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { .@"struct" => switch (object_ty.containerLayout(zcu)) { .@"packed" => { const struct_ty = zcu.typeToPackedStruct(object_ty).?; - const struct_backing_int_bits = cg.module.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0"; + const struct_backing_int_bits = cg.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0"; const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index); // We use the same int type the packed struct is backed by, because even though it would // be valid SPIR-V to use an smaller type like u16, some implementations like PoCL will complain. @@ -4588,7 +6731,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); const masked = try cg.buildBinary(.OpBitwiseAnd, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } }); const result_id = blk: { - if (cg.module.backingIntBits(field_bit_size).@"0" == struct_backing_int_bits) + if (cg.backingIntBits(field_bit_size).@"0" == struct_backing_int_bits) break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg)); const trunc = try cg.buildConvert(field_int_ty, masked); break :blk try trunc.materialize(cg); @@ -4612,7 +6755,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } }, ); const result_id = blk: { - if (cg.module.backingIntBits(field_bit_size).@"0" == cg.module.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0") + if (cg.backingIntBits(field_bit_size).@"0" == cg.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0") break :blk try cg.bitCast(int_ty, backing_int_ty, try masked.materialize(cg)); const trunc = try cg.buildConvert(int_ty, masked); break :blk try trunc.materialize(cg); @@ -4631,13 +6774,13 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { try cg.store(object_ty, tmp_id, object_id, .{}); const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect); - const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, .function); + const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, .function); const pl_ptr_id = try cg.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index}); const field_ty_id = try cg.resolveType(field_ty, .indirect); - const active_pl_ptr_ty_id = try cg.module.ptrType(field_ty_id, .function); - const active_pl_ptr_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpBitcast, .{ + const active_pl_ptr_ty_id = try cg.ptrType(field_ty_id, .function); + const active_pl_ptr_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpBitcast, .{ .id_result_type = active_pl_ptr_ty_id, .id_result = active_pl_ptr_id, .operand = pl_ptr_id, @@ -4650,7 +6793,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const target = zcu.getTarget(); const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; @@ -4683,8 +6826,8 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } } - const base_ptr = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpConvertUToPtr, .{ + const base_ptr = cg.allocId(); + try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{ .id_result_type = result_ty_id, .id_result = base_ptr, .integer_value = base_ptr_int, @@ -4702,7 +6845,7 @@ fn structFieldPtr( ) !Id { const result_ty_id = try cg.resolveType(result_ptr_ty, .direct); - const zcu = cg.module.zcu; + const zcu = cg.zcu; const object_ty = object_ptr_ty.childType(zcu); switch (object_ty.zigTypeTag(zcu)) { .pointer => { @@ -4710,7 +6853,27 @@ fn structFieldPtr( return cg.accessChain(result_ty_id, object_ptr, &.{field_index}); }, .@"struct" => switch (object_ty.containerLayout(zcu)) { - .@"packed" => return cg.todo("implement field access for packed structs", .{}), + .@"packed" => { + const byte_offset = codegen.fieldOffset(object_ptr_ty, result_ptr_ty, field_index, zcu); + if (byte_offset == 0) return object_ptr; + const usize_ty_id = try cg.resolveType(.usize, .direct); + const base_int = cg.allocId(); + try cg.body.emit(cg.gpa, .OpConvertPtrToU, .{ + .id_result_type = usize_ty_id, + .id_result = base_int, + .pointer = object_ptr, + }); + const offset_id = try cg.constInt(.usize, byte_offset); + const adjusted = try cg.buildBinary(.OpIAdd, .{ .ty = .usize, .value = .{ .singleton = base_int } }, .{ .ty = .usize, .value = .{ .singleton = offset_id } }); + const adjusted_id = try adjusted.materialize(cg); + const result_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpConvertUToPtr, .{ + .id_result_type = result_ty_id, + .id_result = result_id, + .integer_value = adjusted_id, + }); + return result_id; + }, .auto, .@"extern" => { return try cg.accessChain(result_ty_id, object_ptr, &.{field_index}); }, @@ -4722,19 +6885,19 @@ fn structFieldPtr( if (!layout.has_payload) { // Asked to get a pointer to a zero-sized field. Just lower this // to undefined, there is no reason to make it be a valid pointer. - return try cg.module.constUndef(result_ty_id); + return try cg.constUndef(result_ty_id); } - const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu)); + const storage_class = cg.storageClass(object_ptr_ty.ptrAddressSpace(zcu)); const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect); - const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, storage_class); + const pl_ptr_ty_id = try cg.ptrType(layout_payload_ty_id, storage_class); const pl_ptr_id = blk: { if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr; break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index}); }; - const active_pl_ptr_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpBitcast, .{ + const active_pl_ptr_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpBitcast, .{ .id_result_type = result_ty_id, .id_result = active_pl_ptr_id, .operand = pl_ptr_id, @@ -4764,9 +6927,9 @@ fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, field_index: u32) } fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id { - const ptr_ty_id = try cg.module.ptrType(ty_id, .function); - const result_id = cg.module.allocId(); - try cg.prologue.emit(cg.module.gpa, .OpVariable, .{ + const ptr_ty_id = try cg.ptrType(ty_id, .function); + const result_id = cg.allocId(); + try cg.prologue.emit(cg.gpa, .OpVariable, .{ .id_result_type = ptr_ty_id, .id_result = result_id, .storage_class = .function, @@ -4776,16 +6939,31 @@ fn alloc(cg: *CodeGen, ty_id: Id, initializer: ?Id) !Id { } fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const target = zcu.getTarget(); const ptr_ty = cg.typeOfIndex(inst); const child_ty = ptr_ty.childType(zcu); + + switch (target.os.tag) { + .vulkan, .opengl => { + if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) { + const as = child_ty.ptrAddressSpace(zcu); + if (cg.storageClass(as) == .function) { + const result_id = cg.allocId(); + try cg.tracked_allocas.put(cg.gpa, result_id, null); + return result_id; + } + } + }, + else => {}, + } + const child_ty_id = try cg.resolveType(child_ty, .indirect); const ptr_align = ptr_ty.ptrAlignment(zcu); const result_id = try cg.alloc(child_ty_id, null); if (ptr_align != child_ty.abiAlignment(zcu)) { if (target.os.tag != .opencl) return cg.fail("cannot apply alignment to variables", .{}); - try cg.module.decorate(result_id, .{ + try cg.decorate(result_id, .{ .alignment = .{ .alignment = @intCast(ptr_align.toByteUnits().?) }, }); } @@ -4801,12 +6979,10 @@ fn airArg(cg: *CodeGen) Id { /// block to jump to. This function emits instructions, so it should be emitted /// inside the merge block of the block. /// This function should only be called with structured control flow generation. -fn structuredNextBlock(cg: *CodeGen, incoming: []const ControlFlow.Structured.Block.Incoming) !Id { - assert(cg.control_flow == .structured); - - const result_id = cg.module.allocId(); +fn structuredNextBlock(cg: *CodeGen, incoming: []const Block.Incoming) !Id { + const result_id = cg.allocId(); const block_id_ty_id = try cg.resolveType(.u32, .direct); - try cg.body.emitRaw(cg.module.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent... + try cg.body.emitRaw(cg.gpa, .OpPhi, @intCast(2 + incoming.len * 2)); // result type + result + variable/parent... cg.body.writeOperand(Id, block_id_ty_id); cg.body.writeOperand(Id, result_id); @@ -4821,13 +6997,13 @@ fn structuredNextBlock(cg: *CodeGen, incoming: []const ControlFlow.Structured.Bl /// terminating a body, there should be no instructions after it. /// This function should only be called with structured control flow generation. fn structuredBreak(cg: *CodeGen, target_block: Id) !void { - assert(cg.control_flow == .structured); + if (cg.block_terminated) return; - const gpa = cg.module.gpa; - const sblock = cg.control_flow.structured.block_stack.getLast().?; + const gpa = cg.gpa; + const sblock = cg.block_stack.getLast().?; const merge_block = switch (sblock.*) { .selection => |*merge| blk: { - const merge_label = cg.module.allocId(); + const merge_label = cg.allocId(); try merge.merge_stack.append(gpa, .{ .incoming = .{ .src_label = cg.block_label, @@ -4867,11 +7043,9 @@ fn genStructuredBody( }, body: []const Air.Inst.Index, ) !Id { - assert(cg.control_flow == .structured); + const gpa = cg.gpa; - const gpa = cg.module.gpa; - - var sblock: ControlFlow.Structured.Block = switch (block_merge_type) { + var sblock: Block = switch (block_merge_type) { .loop => |merge| .{ .loop = .{ .merge_block = merge.merge_label, } }, @@ -4880,8 +7054,8 @@ fn genStructuredBody( defer sblock.deinit(gpa); { - try cg.control_flow.structured.block_stack.append(gpa, &sblock); - defer _ = cg.control_flow.structured.block_stack.pop(); + try cg.block_stack.append(gpa, &sblock); + defer _ = cg.block_stack.pop(); try cg.genBody(body); } @@ -4907,9 +7081,9 @@ fn genStructuredBody( // Make sure that we are still in a block when exiting the function. // TODO: Can we get rid of that? - try cg.beginSpvBlock(cg.module.allocId()); + try cg.beginSpvBlock(cg.allocId()); const block_id_ty_id = try cg.resolveType(.u32, .direct); - return try cg.module.constUndef(block_id_ty_id); + return try cg.constUndef(block_id_ty_id); } // The top-most merge actually only has a single source, the @@ -4919,7 +7093,7 @@ fn genStructuredBody( try cg.beginSpvBlock(merge_stack[merge_stack.len - 1].merge_block); // Now generate a merge ladder for the remaining merges in the stack. - var incoming: ControlFlow.Structured.Block.Incoming = .{ + var incoming: Block.Incoming = .{ .src_label = cg.block_label, .next_block = merge_stack[merge_stack.len - 1].incoming.next_block, }; @@ -4963,74 +7137,28 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) // of the block, then a label, and then generate the rest of the current // ir.Block in a different SPIR-V block. - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const ty = cg.typeOfIndex(inst); const have_block_result = ty.hasRuntimeBits(zcu); - const cf = switch (cg.control_flow) { - .structured => |*cf| cf, - .unstructured => |*cf| { - var block: ControlFlow.Unstructured.Block = .{}; - defer block.incoming_blocks.deinit(gpa); - - // 4 chosen as arbitrary initial capacity. - try block.incoming_blocks.ensureUnusedCapacity(gpa, 4); - - try cf.blocks.putNoClobber(gpa, inst, &block); - defer assert(cf.blocks.remove(inst)); - - try cg.genBody(body); - - // Only begin a new block if there were actually any breaks towards it. - if (block.label) |label| { - try cg.beginSpvBlock(label); - } - - if (!have_block_result) - return null; - - assert(block.label != null); - const result_id = cg.module.allocId(); - const result_type_id = try cg.resolveType(ty, .direct); - - try cg.body.emitRaw( - gpa, - .OpPhi, - // result type + result + variable/parent... - 2 + @as(u16, @intCast(block.incoming_blocks.items.len * 2)), - ); - cg.body.writeOperand(Id, result_type_id); - cg.body.writeOperand(Id, result_id); - - for (block.incoming_blocks.items) |incoming| { - cg.body.writeOperand( - spec.PairIdRefIdRef, - .{ incoming.break_value_id, incoming.src_label }, - ); - } - - return result_id; - }, - }; - const maybe_block_result_var_id = if (have_block_result) blk: { const ty_id = try cg.resolveType(ty, .indirect); const block_result_var_id = try cg.alloc(ty_id, null); - try cf.block_results.putNoClobber(gpa, inst, block_result_var_id); + try cg.block_results.putNoClobber(gpa, inst, block_result_var_id); break :blk block_result_var_id; } else null; - defer if (have_block_result) assert(cf.block_results.remove(inst)); + defer if (have_block_result) assert(cg.block_results.remove(inst)); const next_block = try cg.genStructuredBody(.selection, body); // When encountering a block instruction, we are always at least in the function's scope, // so there always has to be another entry. - assert(cf.block_stack.items.len > 0); + assert(cg.block_stack.items.len > 0); // Check if the target of the branch was this current block. const this_block = try cg.constInt(.u32, @intFromEnum(inst)); - const jump_to_this_block_id = cg.module.allocId(); + const jump_to_this_block_id = cg.allocId(); const bool_ty_id = try cg.resolveType(.bool, .direct); try cg.body.emit(gpa, .OpIEqual, .{ .id_result_type = bool_ty_id, @@ -5039,7 +7167,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) .operand_2 = this_block, }); - const sblock = cf.block_stack.getLast().?; + const sblock = cg.block_stack.getLast().?; if (ty.isNoReturn(zcu)) { // If this block is noreturn, this instruction is the last of a block, @@ -5050,8 +7178,8 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) .selection => |*merge| { // To jump out of a selection block, push a new entry onto its merge stack and // generate a conditional branch to there and to the instructions following this block. - const merge_label = cg.module.allocId(); - const then_label = cg.module.allocId(); + const merge_label = cg.allocId(); + const then_label = cg.allocId(); try cg.body.emit(gpa, .OpSelectionMerge, .{ .merge_block = merge_label, .selection_control = .{}, @@ -5074,7 +7202,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) .loop => |*merge| { // To jump out of a loop block, generate a conditional that exits the block // to the loop merge if the target ID is not the one of this block. - const continue_label = cg.module.allocId(); + const continue_label = cg.allocId(); try cg.body.emit(gpa, .OpBranchConditional, .{ .condition = jump_to_this_block_id, .true_label = continue_label, @@ -5097,180 +7225,237 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) } fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const zcu = cg.zcu; const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br; const operand_ty = cg.typeOf(br.operand); - switch (cg.control_flow) { - .structured => |*cf| { - if (operand_ty.hasRuntimeBits(zcu)) { - const operand_id = try cg.resolve(br.operand); - const block_result_var_id = cf.block_results.get(br.block_inst).?; - try cg.store(operand_ty, block_result_var_id, operand_id, .{}); - } - - const next_block = try cg.constInt(.u32, @intFromEnum(br.block_inst)); - try cg.structuredBreak(next_block); - }, - .unstructured => |cf| { - const block = cf.blocks.get(br.block_inst).?; - if (operand_ty.hasRuntimeBits(zcu)) { - const operand_id = try cg.resolve(br.operand); - // block_label should not be undefined here, lest there - // is a br or br_void in the function's body. - try block.incoming_blocks.append(gpa, .{ - .src_label = cg.block_label, - .break_value_id = operand_id, - }); - } - - if (block.label == null) { - block.label = cg.module.allocId(); - } - - try cg.body.emit(gpa, .OpBranch, .{ .target_label = block.label.? }); - }, + if (operand_ty.hasRuntimeBits(zcu)) { + const operand_id = try cg.resolve(br.operand); + const block_result_var_id = cg.block_results.get(br.block_inst).?; + try cg.store(operand_ty, block_result_var_id, operand_id, .{}); } + + const next_block = try cg.constInt(.u32, @intFromEnum(br.block_inst)); + try cg.structuredBreak(next_block); } fn airCondBr(cg: *CodeGen, inst: Air.Inst.Index) !void { - const gpa = cg.module.gpa; + const gpa = cg.gpa; const cond_br = cg.air.unwrapCondBr(inst); const then_body = cond_br.then_body; const else_body = cond_br.else_body; const condition_id = try cg.resolve(cond_br.condition); - const then_label = cg.module.allocId(); - const else_label = cg.module.allocId(); - - switch (cg.control_flow) { - .structured => { - const merge_label = cg.module.allocId(); - - try cg.body.emit(gpa, .OpSelectionMerge, .{ - .merge_block = merge_label, - .selection_control = .{}, - }); - try cg.body.emit(gpa, .OpBranchConditional, .{ - .condition = condition_id, - .true_label = then_label, - .false_label = else_label, - }); - - try cg.beginSpvBlock(then_label); - const then_next = try cg.genStructuredBody(.selection, then_body); - const then_incoming: ControlFlow.Structured.Block.Incoming = .{ - .src_label = cg.block_label, - .next_block = then_next, - }; - - try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label }); - - try cg.beginSpvBlock(else_label); - const else_next = try cg.genStructuredBody(.selection, else_body); - const else_incoming: ControlFlow.Structured.Block.Incoming = .{ - .src_label = cg.block_label, - .next_block = else_next, - }; - - try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label }); - - try cg.beginSpvBlock(merge_label); - const next_block = try cg.structuredNextBlock(&.{ then_incoming, else_incoming }); - - try cg.structuredBreak(next_block); - }, - .unstructured => { - try cg.body.emit(gpa, .OpBranchConditional, .{ - .condition = condition_id, - .true_label = then_label, - .false_label = else_label, - }); - - try cg.beginSpvBlock(then_label); - try cg.genBody(then_body); - try cg.beginSpvBlock(else_label); - try cg.genBody(else_body); - }, + const then_label = cg.allocId(); + const else_label = cg.allocId(); + + const merge_label = cg.allocId(); + + try cg.body.emit(gpa, .OpSelectionMerge, .{ + .merge_block = merge_label, + .selection_control = .{}, + }); + try cg.body.emit(gpa, .OpBranchConditional, .{ + .condition = condition_id, + .true_label = then_label, + .false_label = else_label, + }); + + try cg.beginSpvBlock(then_label); + const then_next = try cg.genStructuredBody(.selection, then_body); + const then_incoming: Block.Incoming = .{ + .src_label = cg.block_label, + .next_block = then_next, + }; + + if (!cg.block_terminated) { + try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label }); } + + try cg.beginSpvBlock(else_label); + const else_next = try cg.genStructuredBody(.selection, else_body); + const else_incoming: Block.Incoming = .{ + .src_label = cg.block_label, + .next_block = else_next, + }; + + if (!cg.block_terminated) { + try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label }); + } + + try cg.beginSpvBlock(merge_label); + const next_block = try cg.structuredNextBlock(&.{ then_incoming, else_incoming }); + + try cg.structuredBreak(next_block); } fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void { - const gpa = cg.module.gpa; + const gpa = cg.gpa; const block = cg.air.unwrapBlock(inst); - const body_label = cg.module.allocId(); - - switch (cg.control_flow) { - .structured => { - const header_label = cg.module.allocId(); - const merge_label = cg.module.allocId(); - const continue_label = cg.module.allocId(); - - // The back-edge must point to the loop header, so generate a separate block for the - // loop header so that we don't accidentally include some instructions from there - // in the loop. - - try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label }); - try cg.beginSpvBlock(header_label); - - // Emit loop header and jump to loop body - try cg.body.emit(gpa, .OpLoopMerge, .{ - .merge_block = merge_label, - .continue_target = continue_label, - .loop_control = .{}, - }); - - try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label }); - - try cg.beginSpvBlock(body_label); - - const next_block = try cg.genStructuredBody(.{ .loop = .{ - .merge_label = merge_label, - .continue_label = continue_label, - } }, block.body); - try cg.structuredBreak(next_block); - - try cg.beginSpvBlock(continue_label); - - try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label }); - }, - .unstructured => { - try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label }); - try cg.beginSpvBlock(body_label); - try cg.genBody(block.body); - - try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label }); - }, - } + const body_label = cg.allocId(); + + const header_label = cg.allocId(); + const merge_label = cg.allocId(); + const continue_label = cg.allocId(); + + // The back-edge must point to the loop header, so generate a separate block for the + // loop header so that we don't accidentally include some instructions from there + // in the loop. + + try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label }); + try cg.beginSpvBlock(header_label); + + // Emit loop header and jump to loop body + try cg.body.emit(gpa, .OpLoopMerge, .{ + .merge_block = merge_label, + .continue_target = continue_label, + .loop_control = .{}, + }); + + try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label }); + + try cg.beginSpvBlock(body_label); + + const next_block = try cg.genStructuredBody(.{ .loop = .{ + .merge_label = merge_label, + .continue_label = continue_label, + } }, block.body); + try cg.structuredBreak(next_block); + + try cg.beginSpvBlock(continue_label); + + try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label }); } fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; + const pt = cg.pt; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const ptr_ty = cg.typeOf(ty_op.operand); + const ptr_info = ptr_ty.ptrInfo(zcu); const elem_ty = cg.typeOfIndex(inst); - const operand = try cg.resolve(ty_op.operand); - if (!ptr_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null; + const ptr = try cg.resolvePtr(ty_op.operand); + assert(ptr_info.child == elem_ty.toIntern()); - return try cg.load(elem_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }); + const operand_ptr_id = switch (ptr) { + .tracked => |t| return t.slot.*.?, + .id => |id| id, + }; + + if (ptr_info.packed_offset.host_size != 0 and + ptr_info.flags.vector_index == .none) + { + const host_bits: u16 = ptr_info.packed_offset.host_size * 8; + const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu)); + const host_int_ty = try pt.intType(.unsigned, host_bits); + const host_val = try cg.load(host_int_ty, operand_ptr_id, .{ .is_volatile = ptr_info.flags.is_volatile }); + const signedness: Signedness = if (elem_ty.isInt(zcu)) elem_ty.intInfo(zcu).signedness else .unsigned; + const field_int_ty = try pt.intType(signedness, elem_bit_size); + const narrowed = if (ptr_info.packed_offset.bit_offset > 0) blk: { + const bit_offset_id = try cg.constInt(host_int_ty, ptr_info.packed_offset.bit_offset); + const shifted = try cg.buildBinary(.OpShiftRightLogical, .{ .ty = host_int_ty, .value = .{ .singleton = host_val } }, .{ .ty = host_int_ty, .value = .{ .singleton = bit_offset_id } }); + break :blk try shifted.materialize(cg); + } else host_val; + const result_id = blk: { + if (cg.backingIntBits(elem_bit_size).@"0" == cg.backingIntBits(host_bits).@"0") + break :blk try cg.bitCast(field_int_ty, host_int_ty, narrowed); + const trunc = try cg.buildConvert(field_int_ty, .{ .ty = host_int_ty, .value = .{ .singleton = narrowed } }); + break :blk try trunc.materialize(cg); + }; + if (elem_ty.ip_index == .bool_type) return try cg.convertToDirect(.bool, result_id); + if (elem_ty.isInt(zcu)) return result_id; + return try cg.bitCast(elem_ty, field_int_ty, result_id); + } + + const ptr_id = switch (ptr_info.flags.vector_index) { + .none => operand_ptr_id, + else => |index| ptr_id: { + const elem_ptr_ty_id = try cg.ptrType( + try cg.resolveType(elem_ty, .indirect), + cg.storageClass(ptr_info.flags.address_space), + ); + break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)}); + }, + }; + return try cg.load(elem_ty, ptr_id, .{ .is_volatile = ptr_info.flags.is_volatile }); } fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void { - const zcu = cg.module.zcu; + const zcu = cg.zcu; + const pt = cg.pt; const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; const ptr_ty = cg.typeOf(bin_op.lhs); - const elem_ty = ptr_ty.childType(zcu); - const ptr = try cg.resolve(bin_op.lhs); - const value = try cg.resolve(bin_op.rhs); + const ptr_info = ptr_ty.ptrInfo(zcu); + const elem_ty: Type = .fromInterned(ptr_info.child); + const value_id = try cg.resolve(bin_op.rhs); + const operand_ptr_id = switch (try cg.resolvePtr(bin_op.lhs)) { + .tracked => |t| { + t.slot.* = value_id; + return; + }, + .id => |id| id, + }; - try cg.store(elem_ty, ptr, value, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }); + if (ptr_info.packed_offset.host_size != 0 and + ptr_info.flags.vector_index == .none) + { + const host_bits: u16 = ptr_info.packed_offset.host_size * 8; + const host_int_ty = try pt.intType(.unsigned, host_bits); + const host_val = try cg.load(host_int_ty, operand_ptr_id, .{ .is_volatile = ptr_info.flags.is_volatile }); + const elem_bit_size: u16 = @intCast(elem_ty.bitSize(zcu)); + const signedness: Signedness = if (elem_ty.isInt(zcu)) elem_ty.intInfo(zcu).signedness else .unsigned; + const field_int_ty = try pt.intType(signedness, elem_bit_size); + + var value_as_int: Id = undefined; + if (elem_ty.ip_index == .bool_type) { + value_as_int = try cg.convertToIndirect(.bool, value_id); + value_as_int = try cg.bitCast(field_int_ty, .u1, value_as_int); + } else if (elem_ty.isInt(zcu)) { + value_as_int = value_id; + } else { + value_as_int = try cg.bitCast(field_int_ty, elem_ty, value_id); + } + + const extended = blk: { + if (cg.backingIntBits(elem_bit_size).@"0" == cg.backingIntBits(host_bits).@"0") + break :blk try cg.bitCast(host_int_ty, field_int_ty, value_as_int); + const conv = try cg.buildConvert(host_int_ty, .{ .ty = field_int_ty, .value = .{ .singleton = value_as_int } }); + break :blk try conv.materialize(cg); + }; + + const bit_offset = ptr_info.packed_offset.bit_offset; + const field_mask = (@as(u64, 1) << @as(u6, @intCast(elem_bit_size))) - 1; + const host_mask = if (host_bits == 64) @as(u64, std.math.maxInt(u64)) else (@as(u64, 1) << @as(u6, @intCast(host_bits))) - 1; + const clear_mask = ~(field_mask << @as(u6, @intCast(bit_offset))) & host_mask; + const clear_mask_id = try cg.constInt(host_int_ty, clear_mask); + const cleared = try cg.buildBinary(.OpBitwiseAnd, .{ .ty = host_int_ty, .value = .{ .singleton = host_val } }, .{ .ty = host_int_ty, .value = .{ .singleton = clear_mask_id } }); + const bit_offset_id = try cg.constInt(host_int_ty, bit_offset); + const shifted_val = try cg.buildBinary(.OpShiftLeftLogical, .{ .ty = host_int_ty, .value = .{ .singleton = extended } }, .{ .ty = host_int_ty, .value = .{ .singleton = bit_offset_id } }); + const combined = try cg.buildBinary(.OpBitwiseOr, cleared, shifted_val); + const combined_id = try combined.materialize(cg); + + try cg.store(host_int_ty, operand_ptr_id, combined_id, .{ .is_volatile = ptr_info.flags.is_volatile }); + return; + } + + const ptr_id = switch (ptr_info.flags.vector_index) { + .none => operand_ptr_id, + else => |index| ptr_id: { + const elem_ptr_ty_id = try cg.ptrType( + try cg.resolveType(elem_ty, .indirect), + cg.storageClass(ptr_info.flags.address_space), + ); + break :ptr_id try cg.accessChain(elem_ptr_ty_id, operand_ptr_id, &.{@intFromEnum(index)}); + }, + }; + + try cg.store(elem_ty, ptr_id, value_id, .{ .is_volatile = ptr_info.flags.is_volatile }); } fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ret_ty = cg.typeOf(operand); if (!ret_ty.hasRuntimeBits(zcu)) { @@ -5291,8 +7476,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void { } fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const ptr_ty = cg.typeOf(un_op); const ret_ty = ptr_ty.childType(zcu); @@ -5310,16 +7495,18 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void { } } - const ptr = try cg.resolve(un_op); - const value = try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }); + const value = switch (try cg.resolvePtr(un_op)) { + .tracked => |t| t.slot.*.?, + .id => |ptr| try cg.load(ret_ty, ptr, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) }), + }; try cg.body.emit(gpa, .OpReturnValue, .{ .value = value, }); } fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const unwrapped_try = cg.air.unwrapTry(inst); const body = unwrapped_try.else_body; @@ -5338,7 +7525,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id { err_union_id; const zero_id = try cg.constInt(.anyerror, 0); - const is_err_id = cg.module.allocId(); + const is_err_id = cg.allocId(); try cg.body.emit(gpa, .OpINotEqual, .{ .id_result_type = bool_ty_id, .id_result = is_err_id, @@ -5350,22 +7537,16 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id { // with the current body. // Just generate a new block here, then generate a new block inline for the remainder of the body. - const err_block = cg.module.allocId(); - const ok_block = cg.module.allocId(); + const err_block = cg.allocId(); + const ok_block = cg.allocId(); - switch (cg.control_flow) { - .structured => { - // According to AIR documentation, this block is guaranteed - // to not break and end in a return instruction. Thus, - // for structured control flow, we can just naively use - // the ok block as the merge block here. - try cg.body.emit(gpa, .OpSelectionMerge, .{ - .merge_block = ok_block, - .selection_control = .{}, - }); - }, - .unstructured => {}, - } + // According to AIR documentation, this block is guaranteed + // to not break and end in a return instruction. Thus, + // we can just naively use the ok block as the merge block here. + try cg.body.emit(gpa, .OpSelectionMerge, .{ + .merge_block = ok_block, + .selection_control = .{}, + }); try cg.body.emit(gpa, .OpBranchConditional, .{ .condition = is_err_id, @@ -5388,7 +7569,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand_id = try cg.resolve(ty_op.operand); const err_union_ty = cg.typeOf(ty_op.operand); @@ -5396,7 +7577,7 @@ fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { if (err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) { // No error possible, so just return undefined. - return try cg.module.constUndef(err_ty_id); + return try cg.constUndef(err_ty_id); } const payload_ty = err_union_ty.errorUnionPayload(zcu); @@ -5424,7 +7605,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const err_union_ty = cg.typeOfIndex(inst); const payload_ty = err_union_ty.errorUnionPayload(zcu); @@ -5439,7 +7620,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { var members: [2]Id = undefined; members[eu_layout.errorFieldIndex()] = operand_id; - members[eu_layout.payloadFieldIndex()] = try cg.module.constUndef(payload_ty_id); + members[eu_layout.payloadFieldIndex()] = try cg.constUndef(payload_ty_id); var types: [2]Type = undefined; types[eu_layout.errorFieldIndex()] = .anyerror; @@ -5473,7 +7654,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand_id = try cg.resolve(un_op); const operand_ty = cg.typeOf(un_op); @@ -5500,7 +7681,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { loaded_id; const ptr_ty_id = try cg.resolveType(ptr_ty, .direct); - const null_id = try cg.module.constNull(ptr_ty_id); + const null_id = try cg.constNull(ptr_ty_id); const null_tmp: Temporary = .init(ptr_ty, null_id); const ptr: Temporary = .init(ptr_ty, ptr_id); @@ -5515,9 +7696,9 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { const is_non_null_id = blk: { if (is_pointer) { if (payload_ty.hasRuntimeBits(zcu)) { - const storage_class = cg.module.storageClass(operand_ty.ptrAddressSpace(zcu)); + const storage_class = cg.storageClass(operand_ty.ptrAddressSpace(zcu)); const bool_indirect_ty_id = try cg.resolveType(.bool, .indirect); - const bool_ptr_ty_id = try cg.module.ptrType(bool_indirect_ty_id, storage_class); + const bool_ptr_ty_id = try cg.ptrType(bool_indirect_ty_id, storage_class); const tag_ptr_id = try cg.accessChain(bool_ptr_ty_id, operand_id, &.{1}); break :blk try cg.load(.bool, tag_ptr_id, .{}); } @@ -5537,8 +7718,8 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { return switch (pred) { .is_null => blk: { // Invert condition - const result_id = cg.module.allocId(); - try cg.body.emit(cg.module.gpa, .OpLogicalNot, .{ + const result_id = cg.allocId(); + try cg.body.emit(cg.gpa, .OpLogicalNot, .{ .id_result_type = bool_ty_id, .id_result = result_id, .operand = is_non_null_id, @@ -5550,7 +7731,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { } fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; const operand_id = try cg.resolve(un_op); const err_union_ty = cg.typeOf(un_op); @@ -5568,10 +7749,10 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err else try cg.extractField(.anyerror, operand_id, eu_layout.errorFieldIndex()); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); switch (pred) { inline else => |pred_ct| try cg.body.emit( - cg.module.gpa, + cg.gpa, switch (pred_ct) { .is_err => .OpINotEqual, .is_non_err => .OpIEqual, @@ -5588,7 +7769,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err } fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand_id = try cg.resolve(ty_op.operand); const optional_ty = cg.typeOf(ty_op.operand); @@ -5604,7 +7785,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand_id = try cg.resolve(ty_op.operand); const operand_ty = cg.typeOf(ty_op.operand); @@ -5628,7 +7809,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const payload_ty = cg.typeOf(ty_op.operand); @@ -5648,9 +7829,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id { } fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; - const target = cg.module.zcu.getTarget(); + const gpa = cg.gpa; + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); const switch_br = cg.air.unwrapSwitch(inst); const cond_ty = cg.typeOf(switch_br.operand); const cond = try cg.resolve(switch_br.operand); @@ -5660,14 +7841,14 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void { .bool, .error_set => 1, .int => blk: { const bits = cond_ty.intInfo(zcu).bits; - const backing_bits, const big_int = cg.module.backingIntBits(bits); + const backing_bits, const big_int = cg.backingIntBits(bits); if (big_int) return cg.todo("implement composite int switch", .{}); break :blk if (backing_bits <= 32) 1 else 2; }, .@"enum" => blk: { const int_ty = cond_ty.intTagType(zcu); const int_info = int_ty.intInfo(zcu); - const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits); + const backing_bits, const big_int = cg.backingIntBits(int_info.bits); if (big_int) return cg.todo("implement composite int switch", .{}); break :blk if (backing_bits <= 32) 1 else 2; }, @@ -5681,54 +7862,51 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void { const num_cases = switch_br.cases_len; - // Compute the total number of arms that we need. - // Zig switches are grouped by condition, so we need to loop through all of them - const num_conditions = blk: { - var num_conditions: u32 = 0; + // compute the total number of scalar arms and find the last range case + var num_conditions: u32 = 0; + var last_range_case: ?u32 = null; + { var it = switch_br.iterateCases(); while (it.next()) |case| { - if (case.ranges.len > 0) return cg.todo("switch with ranges", .{}); - num_conditions += @intCast(case.items.len); + if (case.ranges.len > 0) { + last_range_case = case.idx; + } else { + num_conditions += @intCast(case.items.len); + } } - break :blk num_conditions; - }; + } // First, pre-allocate the labels for the cases. - const case_labels = cg.module.allocIds(num_cases); + const case_labels = cg.allocIds(num_cases); // We always need the default case - if zig has none, we will generate unreachable there. - const default = cg.module.allocId(); + const default_label = cg.allocId(); + const switch_default = if (last_range_case != null) cg.allocId() else default_label; - const merge_label = switch (cg.control_flow) { - .structured => cg.module.allocId(), - .unstructured => null, - }; + const merge_label = cg.allocId(); - if (cg.control_flow == .structured) { - try cg.body.emit(gpa, .OpSelectionMerge, .{ - .merge_block = merge_label.?, - .selection_control = .{}, - }); - } + try cg.body.emit(gpa, .OpSelectionMerge, .{ + .merge_block = merge_label, + .selection_control = .{}, + }); // Emit the instruction before generating the blocks. try cg.body.emitRaw(gpa, .OpSwitch, 2 + (cond_words + 1) * num_conditions); cg.body.writeOperand(Id, cond_indirect); - cg.body.writeOperand(Id, default); + cg.body.writeOperand(Id, switch_default); - // Emit each of the cases + // Emit the non-range cases into the OpSwitch. + // Cases with ranges are handled by the conditional chain below. { var it = switch_br.iterateCases(); while (it.next()) |case| { - // SPIR-V needs a literal here, which' width depends on the case condition. + if (case.ranges.len > 0) continue; const label = case_labels.at(case.idx); for (case.items) |item| { const value: Value = .fromInterned(item.toInterned().?); const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) { .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu), - .@"enum" => blk: { - break :blk value.intFromEnum(zcu).toUnsignedInt(zcu); // TODO: composite integer constants - }, + .@"enum" => value.intFromEnum(zcu).toUnsignedInt(zcu), .error_set => value.getErrorInt(zcu), .pointer => value.toUnsignedInt(zcu), else => unreachable, @@ -5744,84 +7922,427 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void { } } - var incoming_structured_blocks: std.ArrayList(ControlFlow.Structured.Block.Incoming) = .empty; + var incoming_structured_blocks: std.ArrayList(Block.Incoming) = .empty; defer incoming_structured_blocks.deinit(gpa); + try incoming_structured_blocks.ensureUnusedCapacity(gpa, num_cases + 1); - if (cg.control_flow == .structured) { - try incoming_structured_blocks.ensureUnusedCapacity(gpa, num_cases + 1); + // emit the range-checking chain as nested if-else inside the switch's default branch. + // each range case becomes: + // - check condition, + // - if true emit case body and branch to merge, + // - else continue to next check or default + if (last_range_case != null) { + const cond_tmp: Temporary = .init(cond_ty, cond); + const bool_ty_id = try cg.resolveType(.bool, .direct); + + try cg.beginSpvBlock(switch_default); + + var it_range = switch_br.iterateCases(); + while (it_range.next()) |case| { + if (case.ranges.len == 0) continue; + + var case_cond: ?Id = null; + + for (case.items) |item| { + const item_tmp: Temporary = try cg.temporary(item); + const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg); + case_cond = if (case_cond) |prev| blk: { + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalOr, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = prev, + .operand_2 = eq, + }); + break :blk combined; + } else eq; + } + + for (case.ranges) |range| { + const lo_tmp: Temporary = try cg.temporary(range[0]); + const hi_tmp: Temporary = try cg.temporary(range[1]); + const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg); + const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg); + const in_range = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalAnd, .{ + .id_result_type = bool_ty_id, + .id_result = in_range, + .operand_1 = ge, + .operand_2 = le, + }); + case_cond = if (case_cond) |prev| blk: { + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalOr, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = prev, + .operand_2 = in_range, + }); + break :blk combined; + } else in_range; + } + + const case_label = case_labels.at(case.idx); + const is_last = case.idx == last_range_case.?; + const next_check = if (is_last) default_label else cg.allocId(); + + try cg.body.emit(gpa, .OpSelectionMerge, .{ + .merge_block = next_check, + .selection_control = .{}, + }); + + try cg.body.emit(gpa, .OpBranchConditional, .{ + .condition = case_cond.?, + .true_label = case_label, + .false_label = next_check, + }); + + if (!is_last) { + try cg.beginSpvBlock(next_check); + } + } } - // Now, finally, we can start emitting each of the cases. + // emit bodies var it = switch_br.iterateCases(); while (it.next()) |case| { const label = case_labels.at(case.idx); try cg.beginSpvBlock(label); - switch (cg.control_flow) { - .structured => { - const next_block = try cg.genStructuredBody(.selection, case.body); - incoming_structured_blocks.appendAssumeCapacity(.{ - .src_label = cg.block_label, - .next_block = next_block, - }); + const next_block = try cg.genStructuredBody(.selection, case.body); + incoming_structured_blocks.appendAssumeCapacity(.{ + .src_label = cg.block_label, + .next_block = next_block, + }); - try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label.? }); - }, - .unstructured => { - try cg.genBody(case.body); - }, - } + try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label }); } - const else_body = it.elseBody(); - try cg.beginSpvBlock(default); + const else_body = blk: { + var it_else = switch_br.iterateCases(); + while (it_else.next()) |_| {} + break :blk it_else.elseBody(); + }; + try cg.beginSpvBlock(default_label); if (else_body.len != 0) { - switch (cg.control_flow) { - .structured => { - const next_block = try cg.genStructuredBody(.selection, else_body); - incoming_structured_blocks.appendAssumeCapacity(.{ - .src_label = cg.block_label, - .next_block = next_block, + const next_block = try cg.genStructuredBody(.selection, else_body); + incoming_structured_blocks.appendAssumeCapacity(.{ + .src_label = cg.block_label, + .next_block = next_block, + }); + + try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label }); + } else { + try cg.body.emit(gpa, .OpUnreachable, {}); + } + + try cg.beginSpvBlock(merge_label); + const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items); + try cg.structuredBreak(next_block); +} + +fn airLoopSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void { + const gpa = cg.gpa; + const zcu = cg.zcu; + const target = cg.zcu.getTarget(); + const switch_br = cg.air.unwrapSwitch(inst); + const cond_ty = cg.typeOf(switch_br.operand); + const initial_cond = try cg.resolve(switch_br.operand); + var initial_cond_indirect = try cg.convertToIndirect(cond_ty, initial_cond); + + const cond_words: u32 = switch (cond_ty.zigTypeTag(zcu)) { + .bool, .error_set => 1, + .int => blk: { + const bits = cond_ty.intInfo(zcu).bits; + const backing_bits, const big_int = cg.backingIntBits(bits); + if (big_int) return cg.todo("implement composite int loop switch", .{}); + break :blk if (backing_bits <= 32) 1 else 2; + }, + .@"enum" => blk: { + const int_ty = cond_ty.intTagType(zcu); + const int_info = int_ty.intInfo(zcu); + const backing_bits, const big_int = cg.backingIntBits(int_info.bits); + if (big_int) return cg.todo("implement composite int loop switch", .{}); + break :blk if (backing_bits <= 32) 1 else 2; + }, + .pointer => blk: { + initial_cond_indirect = try cg.intFromPtr(initial_cond_indirect); + break :blk target.ptrBitWidth() / 32; + }, + else => return cg.todo("implement loop switch for type {s}", .{@tagName(cond_ty.zigTypeTag(zcu))}), + }; + + const cond_ty_id = try cg.resolveType(cond_ty, .indirect); + const cond_var = try cg.alloc(cond_ty_id, null); + try cg.store(cond_ty, cond_var, initial_cond_indirect, .{}); + + const num_cases = switch_br.cases_len; + + var num_conditions: u32 = 0; + var last_range_case: ?u32 = null; + { + var it = switch_br.iterateCases(); + while (it.next()) |case| { + if (case.ranges.len > 0) { + last_range_case = case.idx; + } else { + num_conditions += @intCast(case.items.len); + } + } + } + + const case_labels = cg.allocIds(num_cases); + const default_label = cg.allocId(); + const switch_default = if (last_range_case != null) cg.allocId() else default_label; + + const header_label = cg.allocId(); + const loop_merge = cg.allocId(); + const continue_label = cg.allocId(); + const switch_merge = cg.allocId(); + const body_label = cg.allocId(); + + // switch_dispatch signals "continue the loop" by using this sentinel as the + // next_block in structuredBreak. at switch_merge, a phi + comparison distinguishes + // dispatch (continue) from break (exit) + const dispatch_sentinel = try cg.constInt(.u32, @intFromEnum(inst)); + + try cg.loop_switches.putNoClobber(gpa, inst, .{ + .cond_var = cond_var, + .continue_label = dispatch_sentinel, + }); + defer assert(cg.loop_switches.remove(inst)); + + try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label }); + try cg.beginSpvBlock(header_label); + + try cg.body.emit(gpa, .OpLoopMerge, .{ + .merge_block = loop_merge, + .continue_target = continue_label, + .loop_control = .{}, + }); + + try cg.body.emit(gpa, .OpBranch, .{ .target_label = body_label }); + try cg.beginSpvBlock(body_label); + + const cond = try cg.load(cond_ty, cond_var, .{}); + const cond_indirect = try cg.convertToIndirect(cond_ty, cond); + + try cg.body.emit(gpa, .OpSelectionMerge, .{ + .merge_block = switch_merge, + .selection_control = .{}, + }); + + try cg.body.emitRaw(gpa, .OpSwitch, 2 + (cond_words + 1) * num_conditions); + cg.body.writeOperand(Id, cond_indirect); + cg.body.writeOperand(Id, switch_default); + + { + var it = switch_br.iterateCases(); + while (it.next()) |case| { + if (case.ranges.len > 0) continue; + const label = case_labels.at(case.idx); + for (case.items) |item| { + const value: Value = .fromInterned(item.toInterned().?); + const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) { + .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu), + .@"enum" => value.intFromEnum(zcu).toUnsignedInt(zcu), + .error_set => value.getErrorInt(zcu), + .pointer => value.toUnsignedInt(zcu), + else => unreachable, + }; + const int_lit: spec.LiteralContextDependentNumber = switch (cond_words) { + 1 => .{ .uint32 = @intCast(int_val) }, + 2 => .{ .uint64 = int_val }, + else => unreachable, + }; + cg.body.writeOperand(spec.LiteralContextDependentNumber, int_lit); + cg.body.writeOperand(Id, label); + } + } + } + + var incoming_structured_blocks: std.ArrayList(Block.Incoming) = .empty; + defer incoming_structured_blocks.deinit(gpa); + try incoming_structured_blocks.ensureUnusedCapacity(gpa, num_cases + 1); + + if (last_range_case != null) { + const cond_tmp: Temporary = .init(cond_ty, cond); + const bool_ty_id = try cg.resolveType(.bool, .direct); + + try cg.beginSpvBlock(switch_default); + + var it_range = switch_br.iterateCases(); + while (it_range.next()) |case| { + if (case.ranges.len == 0) continue; + + var case_cond: ?Id = null; + + for (case.items) |item| { + const item_tmp: Temporary = try cg.temporary(item); + const eq = try (try cg.cmp(.eq, cond_tmp, item_tmp)).materialize(cg); + case_cond = if (case_cond) |prev| blk: { + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalOr, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = prev, + .operand_2 = eq, + }); + break :blk combined; + } else eq; + } + + for (case.ranges) |range| { + const lo_tmp: Temporary = try cg.temporary(range[0]); + const hi_tmp: Temporary = try cg.temporary(range[1]); + const ge = try (try cg.cmp(.gte, cond_tmp, lo_tmp)).materialize(cg); + const le = try (try cg.cmp(.lte, cond_tmp, hi_tmp)).materialize(cg); + const in_range = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalAnd, .{ + .id_result_type = bool_ty_id, + .id_result = in_range, + .operand_1 = ge, + .operand_2 = le, }); + case_cond = if (case_cond) |prev| blk: { + const combined = cg.allocId(); + try cg.body.emit(gpa, .OpLogicalOr, .{ + .id_result_type = bool_ty_id, + .id_result = combined, + .operand_1 = prev, + .operand_2 = in_range, + }); + break :blk combined; + } else in_range; + } + + const case_label = case_labels.at(case.idx); + const is_last = case.idx == last_range_case.?; + const next_check = if (is_last) default_label else cg.allocId(); + + try cg.body.emit(gpa, .OpSelectionMerge, .{ + .merge_block = next_check, + .selection_control = .{}, + }); + + try cg.body.emit(gpa, .OpBranchConditional, .{ + .condition = case_cond.?, + .true_label = case_label, + .false_label = next_check, + }); + + if (!is_last) { + try cg.beginSpvBlock(next_check); + } + } + } - try cg.body.emit(gpa, .OpBranch, .{ .target_label = merge_label.? }); - }, - .unstructured => { - try cg.genBody(else_body); - }, + { + var it = switch_br.iterateCases(); + while (it.next()) |case| { + const label = case_labels.at(case.idx); + try cg.beginSpvBlock(label); + + const next_block = try cg.genStructuredBody(.selection, case.body); + incoming_structured_blocks.appendAssumeCapacity(.{ + .src_label = cg.block_label, + .next_block = next_block, + }); + try cg.body.emit(gpa, .OpBranch, .{ .target_label = switch_merge }); } + } + + const else_body = blk: { + var it_else = switch_br.iterateCases(); + while (it_else.next()) |_| {} + break :blk it_else.elseBody(); + }; + try cg.beginSpvBlock(default_label); + if (else_body.len != 0) { + const next_block = try cg.genStructuredBody(.selection, else_body); + incoming_structured_blocks.appendAssumeCapacity(.{ + .src_label = cg.block_label, + .next_block = next_block, + }); + try cg.body.emit(gpa, .OpBranch, .{ .target_label = switch_merge }); } else { try cg.body.emit(gpa, .OpUnreachable, {}); } - if (cg.control_flow == .structured) { - try cg.beginSpvBlock(merge_label.?); - const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items); - try cg.structuredBreak(next_block); - } + try cg.beginSpvBlock(switch_merge); + const next_block = try cg.structuredNextBlock(incoming_structured_blocks.items); + + const is_dispatch = cg.allocId(); + const bool_ty_id = try cg.resolveType(.bool, .direct); + try cg.body.emit(gpa, .OpIEqual, .{ + .id_result_type = bool_ty_id, + .id_result = is_dispatch, + .operand_1 = next_block, + .operand_2 = dispatch_sentinel, + }); + + const dispatch_check_merge = cg.allocId(); + try cg.body.emit(gpa, .OpSelectionMerge, .{ + .merge_block = dispatch_check_merge, + .selection_control = .{}, + }); + const exit_block = cg.allocId(); + try cg.body.emit(gpa, .OpBranchConditional, .{ + .condition = is_dispatch, + .true_label = dispatch_check_merge, + .false_label = exit_block, + }); + + try cg.beginSpvBlock(exit_block); + try cg.body.emit(gpa, .OpBranch, .{ .target_label = loop_merge }); + + try cg.beginSpvBlock(dispatch_check_merge); + try cg.body.emit(gpa, .OpBranch, .{ .target_label = continue_label }); + + try cg.beginSpvBlock(continue_label); + try cg.body.emit(gpa, .OpBranch, .{ .target_label = header_label }); + + try cg.beginSpvBlock(loop_merge); + try cg.structuredBreak(next_block); +} + +fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) !void { + const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br; + const loop_switch = cg.loop_switches.get(br.block_inst).?; + const cond_ty = cg.typeOf(br.operand); + const operand = try cg.resolve(br.operand); + const operand_indirect = try cg.convertToIndirect(cond_ty, operand); + + try cg.store(cond_ty, loop_switch.cond_var, operand_indirect, .{}); + try cg.structuredBreak(loop_switch.continue_label); } fn airUnreach(cg: *CodeGen) !void { - try cg.body.emit(cg.module.gpa, .OpUnreachable, {}); + try cg.body.emit(cg.gpa, .OpUnreachable, {}); } fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; const path = zcu.navFileScope(cg.owner_nav).sub_file_path; if (zcu.comp.config.root_strip) return; - try cg.body.emit(cg.module.gpa, .OpLine, .{ - .file = try cg.module.debugString(path), + const path_id = cg.allocId(); + try cg.sections.debug_strings.emit(cg.gpa, .OpString, .{ + .id_result = path_id, + .string = path, + }); + try cg.body.emit(cg.gpa, .OpLine, .{ + .file = path_id, .line = cg.base_line + dbg_stmt.line + 1, .column = dbg_stmt.column + 1, }); } fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const zcu = cg.module.zcu; + const zcu = cg.zcu; const block = cg.air.unwrapDbgBlock(inst); const old_base_line = cg.base_line; defer cg.base_line = old_base_line; @@ -5831,14 +8352,17 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id { fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void { const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; - const target_id = try cg.resolve(pl_op.operand); + const target_id = switch (try cg.resolvePtr(pl_op.operand)) { + .tracked => return, + .id => |id| id, + }; const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload); - try cg.module.debugName(target_id, name.toSlice(cg.air)); + try cg.debugName(target_id, name.toSlice(cg.air)); } fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const unwrapped_asm = cg.air.unwrapAsm(inst); const is_volatile = unwrapped_asm.is_volatile; @@ -5870,7 +8394,6 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{}); }); - // TODO: This entire function should be handled a bit better... const ip = &zcu.intern_pool; switch (ip.indexToKey(val.toIntern())) { .int_type, @@ -5884,6 +8407,7 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { .struct_type, .union_type, .opaque_type, + .spirv_type, .enum_type, .func_type, .error_set_type, @@ -5975,8 +8499,8 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) !?Id { _ = modifier; - const gpa = cg.module.gpa; - const zcu = cg.module.zcu; + const gpa = cg.gpa; + const zcu = cg.zcu; const air_call = cg.air.unwrapCall(inst); const args = air_call.args; const callee_ty = cg.typeOf(air_call.callee); @@ -5989,11 +8513,9 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) const return_type = fn_info.return_type; const result_type_id = try cg.resolveFnReturnType(.fromInterned(return_type)); - const result_id = cg.module.allocId(); + const result_id = cg.allocId(); const callee_id = try cg.resolve(air_call.callee); - comptime assert(zig_call_abi_ver == 3); - const scratch_top = cg.id_scratch.items.len; defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); const params = try cg.id_scratch.addManyAsSlice(gpa, args.len); @@ -6005,9 +8527,20 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) // temporary params buffer. const arg_ty = cg.typeOf(arg); if (!arg_ty.hasRuntimeBits(zcu)) continue; - const arg_id = try cg.resolve(arg); - params[n_params] = arg_id; + if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and + !arg_ty.childType(zcu).hasRuntimeBits(zcu) and + cg.storageClass(arg_ty.ptrAddressSpace(zcu)) == .function) + { + // in logical addressing, pointer arguments to function calls + // must be memory object declarations (OpVariable). for pointers to + // zero-sized types, the source value may not be a variable, so just + // allocate a dummy one. + const child_ty_id = try cg.resolveType(arg_ty.childType(zcu), .indirect); + params[n_params] = try cg.alloc(child_ty_id, null); + } else { + params[n_params] = try cg.resolve(arg); + } n_params += 1; } @@ -6028,19 +8561,30 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) fn builtin3D( cg: *CodeGen, result_ty: Type, - builtin: spec.BuiltIn, + built_in: spec.BuiltIn, dimension: u32, out_of_range_value: anytype, ) !Id { - const gpa = cg.module.gpa; + const gpa = cg.gpa; if (dimension >= 3) return try cg.constInt(result_ty, out_of_range_value); - const u32_ty_id = try cg.module.intType(.unsigned, 32); - const vec_ty_id = try cg.module.vectorType(3, u32_ty_id); - const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input); - const spv_decl_index = try cg.module.builtin(ptr_ty_id, builtin, .input); - try cg.module.decl_deps.append(gpa, spv_decl_index); - const ptr_id = cg.module.declPtr(spv_decl_index).result_id; - const vec_id = cg.module.allocId(); + const u32_ty_id = try cg.intType(.unsigned, 32); + const vec_ty_id = try cg.vectorType(3, u32_ty_id); + const ptr_ty_id = try cg.ptrType(vec_ty_id, .input); + const builtins_gop = try cg.builtins.getOrPut(gpa, .{ built_in, .input }); + if (!builtins_gop.found_existing) { + builtins_gop.value_ptr.* = try cg.allocDecl(.global); + const decl = cg.declPtr(builtins_gop.value_ptr.*); + try cg.sections.globals.emit(gpa, .OpVariable, .{ + .id_result_type = ptr_ty_id, + .id_result = decl.result_id, + .storage_class = .input, + }); + try cg.decorate(decl.result_id, .{ .built_in = .{ .built_in = built_in } }); + } + const spv_decl_index = builtins_gop.value_ptr.*; + try cg.decl_deps.append(gpa, spv_decl_index); + const ptr_id = cg.declPtr(spv_decl_index).result_id; + const vec_id = cg.allocId(); try cg.body.emit(gpa, .OpLoad, .{ .id_result_type = vec_ty_id, .id_result = vec_id, @@ -6071,12 +8615,30 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id { return try cg.builtin3D(.u32, .workgroup_id, dimension, 0); } -fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type { - const zcu = cg.module.zcu; - return cg.air.typeOf(inst, &zcu.intern_pool); -} +const std = @import("std"); +const Allocator = std.mem.Allocator; +const Target = std.Target; +const Signedness = std.lang.Signedness; +const assert = std.debug.assert; +const log = std.log.scoped(.codegen); -fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type { - const zcu = cg.module.zcu; - return cg.air.typeOfIndex(inst, &zcu.intern_pool); -} +const builtin = @import("builtin"); +const link = @import("../../link.zig"); +const codegen = @import("../../codegen.zig"); +const Zcu = @import("../../Zcu.zig"); +const Type = @import("../../Type.zig"); +const Value = @import("../../Value.zig"); +const Air = @import("../../Air.zig"); +const InternPool = @import("../../InternPool.zig"); +const Section = @import("Section.zig"); +const Assembler = @import("Assembler.zig"); +const Mir = @import("Mir.zig"); + +const spec = @import("spec.zig"); +const Opcode = spec.Opcode; +const Word = spec.Word; +const Id = spec.Id; +const IdRange = spec.IdRange; +const StorageClass = spec.StorageClass; + +const CodeGen = @This(); diff --git a/src/codegen/spirv/Mir.zig b/src/codegen/spirv/Mir.zig new file mode 100644 index 0000000000000000000000000000000000000000..c91c362426f83d8b458bce82e2b872e9d24722ff --- /dev/null +++ b/src/codegen/spirv/Mir.zig @@ -0,0 +1,71 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; + +const spec = @import("spec.zig"); +const Word = spec.Word; +const Id = spec.Id; + +const InternPool = @import("../../InternPool.zig"); +const CodeGen = @import("CodeGen.zig"); + +const Mir = @This(); + +id_bound: Word, +owner_nav: InternPool.Nav.Index, +kind: CodeGen.Decl.Kind, +decl_result_id: Id, +extended_instruction_set: []const Word, +globals: []const Word, +functions: []const Word, +annotations: []const Word, +debug_names: []const Word, +debug_strings: []const Word, +execution_modes: []const Word, +nav_refs: []const NavRef, +uav_refs: []const UavRef, +decl_deps: []const DeclDep, +internal_globals: []const Id, +entry_points: []const EntryPoint, + +pub const NavRef = struct { + local_id: Id, + nav: InternPool.Nav.Index, + kind: CodeGen.Decl.Kind, +}; + +pub const UavRef = struct { + local_id: Id, + val: InternPool.Index, + storage_class: spec.StorageClass, + kind: CodeGen.Decl.Kind, +}; + +pub const DeclDep = struct { + kind: CodeGen.Decl.Kind, + nav: InternPool.Nav.Index, +}; + +pub const EntryPoint = struct { + local_id: Id, + name: []const u8, + cc: std.builtin.CallingConvention, +}; + +pub fn deinit(mir: *Mir, gpa: Allocator) void { + gpa.free(mir.extended_instruction_set); + gpa.free(mir.globals); + gpa.free(mir.functions); + gpa.free(mir.annotations); + gpa.free(mir.debug_names); + gpa.free(mir.debug_strings); + gpa.free(mir.execution_modes); + gpa.free(mir.nav_refs); + gpa.free(mir.uav_refs); + gpa.free(mir.decl_deps); + gpa.free(mir.internal_globals); + for (mir.entry_points) |ep| { + gpa.free(ep.name); + } + gpa.free(mir.entry_points); + mir.* = undefined; +} diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig deleted file mode 100644 index f2fe02873c914723f2cb847470556133df4631b5..0000000000000000000000000000000000000000 --- a/src/codegen/spirv/Module.zig +++ /dev/null @@ -1,954 +0,0 @@ -//! This structure represents a SPIR-V (sections) module being compiled, and keeps -//! track of all relevant information. That includes the actual instructions, the -//! current result-id bound, and data structures for querying result-id's of data -//! which needs to be persistent over different calls to Decl code generation. -//! -//! A SPIR-V binary module supports both little- and big endian layout. The layout -//! is detected by the magic word in the header. Therefore, we can ignore any byte -//! order throughout the implementation, and just use the host byte order, and make -//! this a problem for the consumer. -const std = @import("std"); -const Allocator = std.mem.Allocator; -const assert = std.debug.assert; - -const Zcu = @import("../../Zcu.zig"); -const InternPool = @import("../../InternPool.zig"); -const Section = @import("Section.zig"); -const spec = @import("spec.zig"); -const Word = spec.Word; -const Id = spec.Id; - -const Module = @This(); - -gpa: Allocator, -arena: Allocator, -zcu: *Zcu, -nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty, -uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty, -intern_map: std.AutoHashMapUnmanaged(struct { InternPool.Index, Repr }, Id) = .empty, -decls: std.ArrayList(Decl) = .empty, -decl_deps: std.ArrayList(Decl.Index) = .empty, -entry_points: std.AutoArrayHashMapUnmanaged(Id, EntryPoint) = .empty, -/// This map serves a dual purpose: -/// - It keeps track of pointers that are currently being emitted, so that we can tell -/// if they are recursive and need an OpTypeForwardPointer. -/// - It caches pointers by child-type. This is required because sometimes we rely on -/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned -/// via the usual `intern_map` mechanism. -ptr_types: std.AutoHashMapUnmanaged(struct { Id, spec.StorageClass }, Id) = .{}, -/// For test declarations compiled for Vulkan target, we have to add a buffer. -/// We only need to generate this once, this holds the link information related to that. -error_buffer: ?Decl.Index = null, -/// SPIR-V instructions return result-ids. -/// This variable holds the module-wide counter for these. -next_result_id: Word = 1, -/// Some types shouldn't be emitted more than one time, but cannot be caught by -/// the `intern_map` during codegen. Sometimes, IDs are compared to check if -/// types are the same, so we can't delay until the dedup pass. Therefore, -/// this is an ad-hoc structure to cache types where required. -/// According to the SPIR-V specification, section 2.8, this includes all non-aggregate -/// non-pointer types. -/// Additionally, this is used for other values which can be cached, for example, -/// built-in variables. -cache: struct { - bool_type: ?Id = null, - void_type: ?Id = null, - opaque_types: std.StringHashMapUnmanaged(Id) = .empty, - int_types: std.AutoHashMapUnmanaged(std.lang.Type.Int, Id) = .empty, - float_types: std.AutoHashMapUnmanaged(std.lang.Type.Float, Id) = .empty, - vector_types: std.AutoHashMapUnmanaged(struct { Id, u32 }, Id) = .empty, - array_types: std.AutoHashMapUnmanaged(struct { Id, Id }, Id) = .empty, - struct_types: std.ArrayHashMapUnmanaged(StructType, Id, StructType.HashContext, true) = .empty, - fn_types: std.ArrayHashMapUnmanaged(FnType, Id, FnType.HashContext, true) = .empty, - - capabilities: std.AutoHashMapUnmanaged(spec.Capability, void) = .empty, - extensions: std.StringHashMapUnmanaged(void) = .empty, - extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty, - decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty, - builtins: std.AutoHashMapUnmanaged(struct { spec.BuiltIn, spec.StorageClass }, Decl.Index) = .empty, - strings: std.StringArrayHashMapUnmanaged(Id) = .empty, - - bool_const: [2]?Id = .{ null, null }, - constants: std.ArrayHashMapUnmanaged(Constant, Id, Constant.HashContext, true) = .empty, -} = .{}, -/// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module". -sections: struct { - capabilities: Section = .{}, - extensions: Section = .{}, - extended_instruction_set: Section = .{}, - memory_model: Section = .{}, - execution_modes: Section = .{}, - debug_strings: Section = .{}, - debug_names: Section = .{}, - annotations: Section = .{}, - globals: Section = .{}, - functions: Section = .{}, -} = .{}, - -pub const big_int_bits = 32; - -/// Data can be lowered into in two basic representations: indirect, which is when -/// a type is stored in memory, and direct, which is how a type is stored when its -/// a direct SPIR-V value. -pub const Repr = enum { - /// A SPIR-V value as it would be used in operations. - direct, - /// A SPIR-V value as it is stored in memory. - indirect, -}; - -/// Declarations, both functions and globals, can have dependencies. These are used for 2 things: -/// - Globals must be declared before they are used, also between globals. The compiler processes -/// globals unordered, so we must use the dependencies here to figure out how to order the globals -/// in the final module. The Globals structure is also used for that. -/// - Entry points must declare the complete list of OpVariable instructions that they access. -/// For these we use the same dependency structure. -/// In this mechanism, globals will only depend on other globals, while functions may depend on -/// globals or other functions. -pub const Decl = struct { - /// Index to refer to a Decl by. - pub const Index = enum(u32) { _ }; - - /// Useful to tell what kind of decl this is, and hold the result-id or field index - /// to be used for this decl. - pub const Kind = enum { - func, - global, - invocation_global, - }; - - /// See comment on Kind - kind: Kind, - /// The result-id associated to this decl. The specific meaning of this depends on `kind`: - /// - For `func`, this is the result-id of the associated OpFunction instruction. - /// - For `global`, this is the result-id of the associated OpVariable instruction. - /// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction. - result_id: Id, - /// The offset of the first dependency of this decl in the `decl_deps` array. - begin_dep: usize = 0, - /// The past-end offset of the dependencies of this decl in the `decl_deps` array. - end_dep: usize = 0, -}; - -/// This models a kernel entry point. -pub const EntryPoint = struct { - /// The declaration that should be exported. - decl_index: Decl.Index, - /// The name of the kernel to be exported. - name: []const u8, - /// Calling Convention - exec_model: spec.ExecutionModel, - exec_mode: ?spec.ExecutionMode = null, -}; - -const StructType = struct { - fields: []const Id, - ip_index: InternPool.Index, - - const HashContext = struct { - pub fn hash(_: @This(), ty: StructType) u32 { - var hasher = std.hash.Wyhash.init(0); - hasher.update(std.mem.sliceAsBytes(ty.fields)); - hasher.update(std.mem.asBytes(&ty.ip_index)); - return @truncate(hasher.final()); - } - - pub fn eql(_: @This(), a: StructType, b: StructType, _: usize) bool { - return a.ip_index == b.ip_index and std.mem.eql(Id, a.fields, b.fields); - } - }; -}; - -const FnType = struct { - return_ty: Id, - params: []const Id, - - const HashContext = struct { - pub fn hash(_: @This(), ty: FnType) u32 { - var hasher = std.hash.Wyhash.init(0); - hasher.update(std.mem.asBytes(&ty.return_ty)); - hasher.update(std.mem.sliceAsBytes(ty.params)); - return @truncate(hasher.final()); - } - - pub fn eql(_: @This(), a: FnType, b: FnType, _: usize) bool { - return a.return_ty == b.return_ty and - std.mem.eql(Id, a.params, b.params); - } - }; -}; - -const Constant = struct { - ty: Id, - value: spec.LiteralContextDependentNumber, - - const HashContext = struct { - pub fn hash(_: @This(), value: Constant) u32 { - const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?; - var hasher = std.hash.Wyhash.init(0); - hasher.update(std.mem.asBytes(&value.ty)); - hasher.update(std.mem.asBytes(&@as(Tag, value.value))); - switch (value.value) { - inline else => |v| hasher.update(std.mem.asBytes(&v)), - } - return @truncate(hasher.final()); - } - - pub fn eql(_: @This(), a: Constant, b: Constant, _: usize) bool { - if (a.ty != b.ty) return false; - const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?; - if (@as(Tag, a.value) != @as(Tag, b.value)) return false; - return switch (a.value) { - inline else => |v, tag| v == @field(b.value, @tagName(tag)), - }; - } - }; -}; - -pub fn deinit(module: *Module) void { - module.nav_link.deinit(module.gpa); - module.uav_link.deinit(module.gpa); - module.intern_map.deinit(module.gpa); - module.ptr_types.deinit(module.gpa); - - module.sections.capabilities.deinit(module.gpa); - module.sections.extensions.deinit(module.gpa); - module.sections.extended_instruction_set.deinit(module.gpa); - module.sections.memory_model.deinit(module.gpa); - module.sections.execution_modes.deinit(module.gpa); - module.sections.debug_strings.deinit(module.gpa); - module.sections.debug_names.deinit(module.gpa); - module.sections.annotations.deinit(module.gpa); - module.sections.globals.deinit(module.gpa); - module.sections.functions.deinit(module.gpa); - - module.cache.opaque_types.deinit(module.gpa); - module.cache.int_types.deinit(module.gpa); - module.cache.float_types.deinit(module.gpa); - module.cache.vector_types.deinit(module.gpa); - module.cache.array_types.deinit(module.gpa); - module.cache.struct_types.deinit(module.gpa); - module.cache.fn_types.deinit(module.gpa); - module.cache.capabilities.deinit(module.gpa); - module.cache.extensions.deinit(module.gpa); - module.cache.extended_instruction_set.deinit(module.gpa); - module.cache.decorations.deinit(module.gpa); - module.cache.builtins.deinit(module.gpa); - module.cache.strings.deinit(module.gpa); - - module.cache.constants.deinit(module.gpa); - - module.decls.deinit(module.gpa); - module.decl_deps.deinit(module.gpa); - module.entry_points.deinit(module.gpa); - - module.* = undefined; -} - -/// Fetch or allocate a result id for nav index. This function also marks the nav as alive. -/// Note: Function does not actually generate the nav, it just allocates an index. -pub fn resolveNav(module: *Module, ip: *InternPool, nav_index: InternPool.Nav.Index) !Decl.Index { - const entry = try module.nav_link.getOrPut(module.gpa, nav_index); - if (!entry.found_existing) { - const nav = ip.getNav(nav_index); - // TODO: Extern fn? - const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type)) - .func - else switch (nav.resolved.?.@"addrspace") { - .generic => .invocation_global, - else => .global, - }; - entry.value_ptr.* = try module.allocDecl(kind); - } - - return entry.value_ptr.*; -} - -pub fn allocIds(module: *Module, n: u32) spec.IdRange { - defer module.next_result_id += n; - return .{ .base = module.next_result_id, .len = n }; -} - -pub fn allocId(module: *Module) Id { - return module.allocIds(1).at(0); -} - -pub fn idBound(module: Module) Word { - return module.next_result_id; -} - -pub fn addEntryPointDeps( - module: *Module, - decl_index: Decl.Index, - seen: *std.bit_set.Dynamic, - interface: *std.array_list.Managed(Id), -) !void { - const decl = module.declPtr(decl_index); - const deps = module.decl_deps.items[decl.begin_dep..decl.end_dep]; - - if (seen.isSet(@intFromEnum(decl_index))) { - return; - } - - seen.set(@intFromEnum(decl_index)); - - if (decl.kind == .global) { - try interface.append(decl.result_id); - } - - for (deps) |dep| { - try module.addEntryPointDeps(dep, seen, interface); - } -} - -fn entryPoints(module: *Module) !Section { - const target = module.zcu.getTarget(); - - var entry_points = Section{}; - errdefer entry_points.deinit(module.gpa); - - var interface = std.array_list.Managed(Id).init(module.gpa); - defer interface.deinit(); - - var seen: std.bit_set.Dynamic = try .initEmpty(module.gpa, module.decls.items.len); - defer seen.deinit(module.gpa); - - for (module.entry_points.keys(), module.entry_points.values()) |entry_point_id, entry_point| { - interface.items.len = 0; - seen.setRangeValue(.{ .start = 0, .end = module.decls.items.len }, false); - - try module.addEntryPointDeps(entry_point.decl_index, &seen, &interface); - try entry_points.emit(module.gpa, .OpEntryPoint, .{ - .execution_model = entry_point.exec_model, - .entry_point = entry_point_id, - .name = entry_point.name, - .interface = interface.items, - }); - - if (entry_point.exec_mode == null and entry_point.exec_model == .fragment) { - switch (target.os.tag) { - .vulkan, .opengl => |tag| { - try module.sections.execution_modes.emit(module.gpa, .OpExecutionMode, .{ - .entry_point = entry_point_id, - .mode = if (tag == .vulkan) .origin_upper_left else .origin_lower_left, - }); - }, - .opencl => {}, - else => unreachable, - } - } - } - - return entry_points; -} - -pub fn finalize(module: *Module, gpa: Allocator) ![]Word { - const target = module.zcu.getTarget(); - - // Emit capabilities and extensions - switch (target.os.tag) { - .opengl => { - try module.addCapability(.shader); - try module.addCapability(.matrix); - }, - .vulkan => { - try module.addCapability(.shader); - try module.addCapability(.matrix); - if (target.cpu.arch == .spirv64) { - try module.addExtension("SPV_KHR_physical_storage_buffer"); - try module.addCapability(.physical_storage_buffer_addresses); - } - }, - .opencl, .amdhsa => { - try module.addCapability(.kernel); - try module.addCapability(.addresses); - }, - else => unreachable, - } - if (target.cpu.arch == .spirv64) try module.addCapability(.int64); - if (target.cpu.has(.spirv, .int64)) try module.addCapability(.int64); - if (target.cpu.has(.spirv, .float16)) { - if (target.os.tag == .opencl) try module.addExtension("cl_khr_fp16"); - try module.addCapability(.float16); - } - if (target.cpu.has(.spirv, .float64)) try module.addCapability(.float64); - if (target.cpu.has(.spirv, .generic_pointer)) try module.addCapability(.generic_pointer); - if (target.cpu.has(.spirv, .vector16)) try module.addCapability(.vector16); - if (target.cpu.has(.spirv, .storage_push_constant16)) { - try module.addExtension("SPV_KHR_16bit_storage"); - try module.addCapability(.storage_push_constant16); - } - if (target.cpu.has(.spirv, .arbitrary_precision_integers)) { - try module.addExtension("SPV_INTEL_arbitrary_precision_integers"); - try module.addCapability(.arbitrary_precision_integers_intel); - } - if (target.cpu.has(.spirv, .variable_pointers)) { - try module.addExtension("SPV_KHR_variable_pointers"); - try module.addCapability(.variable_pointers_storage_buffer); - try module.addCapability(.variable_pointers); - } - // These are well supported - try module.addCapability(.int8); - try module.addCapability(.int16); - - // Emit memory model - const addressing_model: spec.AddressingModel = switch (target.os.tag) { - .opengl => .logical, - .vulkan => if (target.cpu.arch == .spirv32) .logical else .physical_storage_buffer64, - .opencl => if (target.cpu.arch == .spirv32) .physical32 else .physical64, - .amdhsa => .physical64, - else => unreachable, - }; - try module.sections.memory_model.emit(module.gpa, .OpMemoryModel, .{ - .addressing_model = addressing_model, - .memory_model = switch (target.os.tag) { - .opencl => .open_cl, - .vulkan, .opengl => .glsl450, - else => unreachable, - }, - }); - - var entry_points = try module.entryPoints(); - defer entry_points.deinit(module.gpa); - - const version: spec.Version = .{ - .major = 1, - .minor = blk: { - // Prefer higher versions - if (target.cpu.has(.spirv, .v1_6)) break :blk 6; - if (target.cpu.has(.spirv, .v1_5)) break :blk 5; - if (target.cpu.has(.spirv, .v1_4)) break :blk 4; - if (target.cpu.has(.spirv, .v1_3)) break :blk 3; - if (target.cpu.has(.spirv, .v1_2)) break :blk 2; - if (target.cpu.has(.spirv, .v1_1)) break :blk 1; - break :blk 0; - }, - }; - - const zig_version = @import("builtin").zig_version; - const zig_spirv_compiler_version = comptime (zig_version.major << 12) | (zig_version.minor << 7) | zig_version.patch; - - // A SPIR-V Generator Magic Number is a 32 bit word: The high order 16 - // bits are a tool ID, which should be unique across all SPIR-V - // generators. The low order 16 bits are reserved for use as a tool - // version number, or any other purpose the tool supplier chooses. - // Only the tool IDs are reserved with Khronos. - // See https://github.com/KhronosGroup/SPIRV-Headers/blob/f2e4bd213104fe323a01e935df56557328d37ac8/include/spirv/spir-v.xml#L17C5-L21C54 - const generator_id: u32 = (spec.zig_generator_id << 16) | zig_spirv_compiler_version; - - const header = [_]Word{ - spec.magic_number, - version.toWord(), - generator_id, - module.idBound(), - 0, // Schema (currently reserved for future use) - }; - - var source = Section{}; - defer source.deinit(module.gpa); - try module.sections.debug_strings.emit(module.gpa, .OpSource, .{ - .source_language = .zig, - .version = zig_spirv_compiler_version, - // We cannot emit these because the Khronos translator does not parse this instruction - // correctly. - // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/2188 - .file = null, - .source = null, - }); - - // Note: needs to be kept in order according to section 2.3! - const buffers = &[_][]const Word{ - &header, - module.sections.capabilities.toWords(), - module.sections.extensions.toWords(), - module.sections.extended_instruction_set.toWords(), - module.sections.memory_model.toWords(), - entry_points.toWords(), - module.sections.execution_modes.toWords(), - source.toWords(), - module.sections.debug_strings.toWords(), - module.sections.debug_names.toWords(), - module.sections.annotations.toWords(), - module.sections.globals.toWords(), - module.sections.functions.toWords(), - }; - - var total_result_size: usize = 0; - for (buffers) |buffer| { - total_result_size += buffer.len; - } - const result = try gpa.alloc(Word, total_result_size); - errdefer comptime unreachable; - - var offset: usize = 0; - for (buffers) |buffer| { - @memcpy(result[offset..][0..buffer.len], buffer); - offset += buffer.len; - } - - return result; -} - -pub fn addCapability(module: *Module, cap: spec.Capability) !void { - const entry = try module.cache.capabilities.getOrPut(module.gpa, cap); - if (entry.found_existing) return; - try module.sections.capabilities.emit(module.gpa, .OpCapability, .{ .capability = cap }); -} - -pub fn addExtension(module: *Module, ext: []const u8) !void { - const entry = try module.cache.extensions.getOrPut(module.gpa, ext); - if (entry.found_existing) return; - try module.sections.extensions.emit(module.gpa, .OpExtension, .{ .name = ext }); -} - -/// Imports or returns the existing id of an extended instruction set -pub fn importInstructionSet(module: *Module, set: spec.InstructionSet) !Id { - assert(set != .core); - - const gop = try module.cache.extended_instruction_set.getOrPut(module.gpa, set); - if (gop.found_existing) return gop.value_ptr.*; - - const result_id = module.allocId(); - try module.sections.extended_instruction_set.emit(module.gpa, .OpExtInstImport, .{ - .id_result = result_id, - .name = @tagName(set), - }); - gop.value_ptr.* = result_id; - - return result_id; -} - -pub fn boolType(module: *Module) !Id { - if (module.cache.bool_type) |id| return id; - - const result_id = module.allocId(); - try module.sections.globals.emit(module.gpa, .OpTypeBool, .{ - .id_result = result_id, - }); - module.cache.bool_type = result_id; - return result_id; -} - -pub fn voidType(module: *Module) !Id { - if (module.cache.void_type) |id| return id; - - const result_id = module.allocId(); - try module.sections.globals.emit(module.gpa, .OpTypeVoid, .{ - .id_result = result_id, - }); - module.cache.void_type = result_id; - try module.debugName(result_id, "void"); - return result_id; -} - -pub fn opaqueType(module: *Module, name: []const u8) !Id { - if (module.cache.opaque_types.get(name)) |id| return id; - const result_id = module.allocId(); - const name_dup = try module.arena.dupe(u8, name); - try module.sections.globals.emit(module.gpa, .OpTypeOpaque, .{ - .id_result = result_id, - .literal_string = name_dup, - }); - try module.debugName(result_id, name_dup); - try module.cache.opaque_types.put(module.gpa, name_dup, result_id); - return result_id; -} - -pub fn backingIntBits(module: *Module, bits: u16) struct { u16, bool } { - assert(bits != 0); - const target = module.zcu.getTarget(); - - if (target.cpu.has(.spirv, .arbitrary_precision_integers) and bits <= 32) { - return .{ bits, false }; - } - - // We require Int8 and Int16 capabilities and benefit Int64 when available. - // 32-bit integers are always supported (see spec, 2.16.1, Data rules). - const ints = [_]struct { bits: u16, enabled: bool }{ - .{ .bits = 8, .enabled = true }, - .{ .bits = 16, .enabled = true }, - .{ .bits = 32, .enabled = true }, - .{ - .bits = 64, - .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64, - }, - }; - - for (ints) |int| { - if (bits <= int.bits and int.enabled) return .{ int.bits, false }; - } - - // Big int - return .{ std.mem.alignForward(u16, bits, big_int_bits), true }; -} - -pub fn intType(module: *Module, signedness: std.lang.Signedness, bits: u16) !Id { - assert(bits > 0); - - const target = module.zcu.getTarget(); - const actual_signedness = switch (target.os.tag) { - // Kernel only supports unsigned ints. - .opencl, .amdhsa => .unsigned, - else => signedness, - }; - const backing_bits, const big_int = module.backingIntBits(bits); - if (big_int) { - // TODO: support composite integers larger than 64 bit - assert(backing_bits <= 64); - const u32_ty = try module.intType(.unsigned, 32); - const len_id = try module.constant(u32_ty, .{ .uint32 = backing_bits / big_int_bits }); - return module.arrayType(len_id, u32_ty); - } - - const entry = try module.cache.int_types.getOrPut(module.gpa, .{ .signedness = actual_signedness, .bits = backing_bits }); - if (!entry.found_existing) { - const result_id = module.allocId(); - entry.value_ptr.* = result_id; - try module.sections.globals.emit(module.gpa, .OpTypeInt, .{ - .id_result = result_id, - .width = backing_bits, - .signedness = switch (actual_signedness) { - .signed => 1, - .unsigned => 0, - }, - }); - - switch (actual_signedness) { - .signed => try module.debugNameFmt(result_id, "i{}", .{backing_bits}), - .unsigned => try module.debugNameFmt(result_id, "u{}", .{backing_bits}), - } - } - return entry.value_ptr.*; -} - -pub fn floatType(module: *Module, bits: u16) !Id { - assert(bits > 0); - const entry = try module.cache.float_types.getOrPut(module.gpa, .{ .bits = bits }); - if (!entry.found_existing) { - const result_id = module.allocId(); - entry.value_ptr.* = result_id; - try module.sections.globals.emit(module.gpa, .OpTypeFloat, .{ - .id_result = result_id, - .width = bits, - }); - try module.debugNameFmt(result_id, "f{}", .{bits}); - } - return entry.value_ptr.*; -} - -pub fn vectorType(module: *Module, len: u32, child_ty_id: Id) !Id { - const entry = try module.cache.vector_types.getOrPut(module.gpa, .{ child_ty_id, len }); - if (!entry.found_existing) { - const result_id = module.allocId(); - entry.value_ptr.* = result_id; - try module.sections.globals.emit(module.gpa, .OpTypeVector, .{ - .id_result = result_id, - .component_type = child_ty_id, - .component_count = len, - }); - } - return entry.value_ptr.*; -} - -pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id { - const entry = try module.cache.array_types.getOrPut(module.gpa, .{ child_ty_id, len_id }); - if (!entry.found_existing) { - const result_id = module.allocId(); - entry.value_ptr.* = result_id; - try module.sections.globals.emit(module.gpa, .OpTypeArray, .{ - .id_result = result_id, - .element_type = child_ty_id, - .length = len_id, - }); - } - return entry.value_ptr.*; -} - -pub fn ptrType(module: *Module, child_ty_id: Id, storage_class: spec.StorageClass) !Id { - const key = .{ child_ty_id, storage_class }; - const gop = try module.ptr_types.getOrPut(module.gpa, key); - if (!gop.found_existing) { - gop.value_ptr.* = module.allocId(); - try module.sections.globals.emit(module.gpa, .OpTypePointer, .{ - .id_result = gop.value_ptr.*, - .storage_class = storage_class, - .type = child_ty_id, - }); - return gop.value_ptr.*; - } - return gop.value_ptr.*; -} - -pub fn structType( - module: *Module, - types: []const Id, - maybe_names: ?[]const []const u8, - maybe_offsets: ?[]const u32, - ip_index: InternPool.Index, -) !Id { - const target = module.zcu.getTarget(); - const actual_ip_index = if (module.zcu.comp.config.root_strip) .none else ip_index; - - if (module.cache.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id; - const result_id = module.allocId(); - const types_dup = try module.arena.dupe(Id, types); - try module.sections.globals.emit(module.gpa, .OpTypeStruct, .{ - .id_result = result_id, - .id_ref = types_dup, - }); - - if (maybe_names) |names| { - assert(names.len == types.len); - for (names, 0..) |name, i| { - try module.memberDebugName(result_id, @intCast(i), name); - } - } - - switch (target.os.tag) { - .vulkan, .opengl => { - if (maybe_offsets) |offsets| { - assert(offsets.len == types.len); - for (offsets, 0..) |offset, i| { - try module.decorateMember( - result_id, - @intCast(i), - .{ .offset = .{ .byte_offset = offset } }, - ); - } - } - }, - else => {}, - } - - try module.cache.struct_types.put( - module.gpa, - .{ .fields = types_dup, .ip_index = actual_ip_index }, - result_id, - ); - return result_id; -} - -pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const Id) !Id { - if (module.cache.fn_types.get(.{ - .return_ty = return_ty_id, - .params = param_type_ids, - })) |id| return id; - const result_id = module.allocId(); - const params_dup = try module.arena.dupe(Id, param_type_ids); - try module.sections.globals.emit(module.gpa, .OpTypeFunction, .{ - .id_result = result_id, - .return_type = return_ty_id, - .id_ref_2 = params_dup, - }); - try module.cache.fn_types.put(module.gpa, .{ - .return_ty = return_ty_id, - .params = params_dup, - }, result_id); - return result_id; -} - -pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id { - const gop = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value }); - if (!gop.found_existing) { - gop.value_ptr.* = module.allocId(); - try module.sections.globals.emit(module.gpa, .OpConstant, .{ - .id_result_type = ty_id, - .id_result = gop.value_ptr.*, - .value = value, - }); - } - return gop.value_ptr.*; -} - -pub fn constBool(module: *Module, value: bool) !Id { - if (module.cache.bool_const[@intFromBool(value)]) |b| return b; - - const result_ty_id = try module.boolType(); - const result_id = module.allocId(); - module.cache.bool_const[@intFromBool(value)] = result_id; - - switch (value) { - inline else => |value_ct| try module.sections.globals.emit( - module.gpa, - if (value_ct) .OpConstantTrue else .OpConstantFalse, - .{ - .id_result_type = result_ty_id, - .id_result = result_id, - }, - ), - } - - return result_id; -} - -pub fn builtin( - module: *Module, - result_ty_id: Id, - spirv_builtin: spec.BuiltIn, - storage_class: spec.StorageClass, -) !Decl.Index { - const gop = try module.cache.builtins.getOrPut(module.gpa, .{ spirv_builtin, storage_class }); - if (!gop.found_existing) { - const decl_index = try module.allocDecl(.global); - const decl = module.declPtr(decl_index); - - gop.value_ptr.* = decl_index; - try module.sections.globals.emit(module.gpa, .OpVariable, .{ - .id_result_type = result_ty_id, - .id_result = decl.result_id, - .storage_class = storage_class, - }); - try module.decorate(decl.result_id, .{ .built_in = .{ .built_in = spirv_builtin } }); - } - return gop.value_ptr.*; -} - -pub fn constUndef(module: *Module, ty_id: Id) !Id { - const result_id = module.allocId(); - try module.sections.globals.emit(module.gpa, .OpUndef, .{ - .id_result_type = ty_id, - .id_result = result_id, - }); - return result_id; -} - -pub fn constNull(module: *Module, ty_id: Id) !Id { - const result_id = module.allocId(); - try module.sections.globals.emit(module.gpa, .OpConstantNull, .{ - .id_result_type = ty_id, - .id_result = result_id, - }); - return result_id; -} - -/// Decorate a result-id. -pub fn decorate( - module: *Module, - target: Id, - decoration: spec.Decoration.Extended, -) !void { - const gop = try module.cache.decorations.getOrPut(module.gpa, .{ target, decoration }); - if (!gop.found_existing) { - try module.sections.annotations.emit(module.gpa, .OpDecorate, .{ - .target = target, - .decoration = decoration, - }); - } -} - -/// Decorate a result-id which is a member of some struct. -/// We really don't have to and shouldn't need to cache this. -pub fn decorateMember( - module: *Module, - structure_type: Id, - member: u32, - decoration: spec.Decoration.Extended, -) !void { - try module.sections.annotations.emit(module.gpa, .OpMemberDecorate, .{ - .structure_type = structure_type, - .member = member, - .decoration = decoration, - }); -} - -pub fn allocDecl(module: *Module, kind: Decl.Kind) !Decl.Index { - try module.decls.append(module.gpa, .{ - .kind = kind, - .result_id = module.allocId(), - }); - - return @as(Decl.Index, @enumFromInt(@as(u32, @intCast(module.decls.items.len - 1)))); -} - -pub fn declPtr(module: *Module, index: Decl.Index) *Decl { - return &module.decls.items[@intFromEnum(index)]; -} - -/// Declare a SPIR-V function as an entry point. This causes an extra wrapper -/// function to be generated, which is then exported as the real entry point. The purpose of this -/// wrapper is to allocate and initialize the structure holding the instance globals. -pub fn declareEntryPoint( - module: *Module, - decl_index: Decl.Index, - name: []const u8, - exec_model: spec.ExecutionModel, - exec_mode: ?spec.ExecutionMode, -) !void { - const gop = try module.entry_points.getOrPut(module.gpa, module.declPtr(decl_index).result_id); - gop.value_ptr.decl_index = decl_index; - gop.value_ptr.name = name; - gop.value_ptr.exec_model = exec_model; - // Might've been set by assembler - if (!gop.found_existing) gop.value_ptr.exec_mode = exec_mode; -} - -pub fn debugName(module: *Module, target: Id, name: []const u8) !void { - if (module.zcu.comp.config.root_strip) return; - try module.sections.debug_names.emit(module.gpa, .OpName, .{ - .target = target, - .name = name, - }); -} - -pub fn debugNameFmt(module: *Module, target: Id, comptime fmt: []const u8, args: anytype) !void { - if (module.zcu.comp.config.root_strip) return; - const name = try std.fmt.allocPrint(module.gpa, fmt, args); - defer module.gpa.free(name); - try module.debugName(target, name); -} - -pub fn memberDebugName(module: *Module, target: Id, member: u32, name: []const u8) !void { - if (module.zcu.comp.config.root_strip) return; - try module.sections.debug_names.emit(module.gpa, .OpMemberName, .{ - .type = target, - .member = member, - .name = name, - }); -} - -pub fn debugString(module: *Module, string: []const u8) !Id { - const entry = try module.cache.strings.getOrPut(module.gpa, string); - if (!entry.found_existing) { - entry.value_ptr.* = module.allocId(); - try module.sections.debug_strings.emit(module.gpa, .OpString, .{ - .id_result = entry.value_ptr.*, - .string = string, - }); - } - return entry.value_ptr.*; -} - -pub fn storageClass(module: *Module, as: std.lang.AddressSpace) spec.StorageClass { - const target = module.zcu.getTarget(); - return switch (as) { - .generic => .function, - .global => switch (target.os.tag) { - .opencl, .amdhsa => .cross_workgroup, - else => .storage_buffer, - }, - .push_constant => .push_constant, - .output => .output, - .uniform => .uniform, - .storage_buffer => .storage_buffer, - .physical_storage_buffer => .physical_storage_buffer, - .constant => .uniform_constant, - .shared => .workgroup, - .local => .function, - .input => .input, - .gs, - .fs, - .ss, - .far, - .param, - .flash, - .flash1, - .flash2, - .flash3, - .flash4, - .flash5, - .cog, - .lut, - .hub, - => unreachable, - }; -} diff --git a/src/codegen/spirv/spec.zig b/src/codegen/spirv/spec.zig index df5292e3e2da826e0e816ef5421ccabc4432d2bf..415a2ae706c2ab2fecdb92b132930a92271961d3 100644 --- a/src/codegen/spirv/spec.zig +++ b/src/codegen/spirv/spec.zig @@ -313,16 +313,16 @@ pub const OperandKind = enum { .{ .name = "IterationMultiple", .value = 0x0040, .parameters = &.{.literal_integer} }, .{ .name = "PeelCount", .value = 0x0080, .parameters = &.{.literal_integer} }, .{ .name = "PartialCount", .value = 0x0100, .parameters = &.{.literal_integer} }, - .{ .name = "InitiationIntervalINTEL", .value = 0x10000, .parameters = &.{.literal_integer} }, - .{ .name = "MaxConcurrencyINTEL", .value = 0x20000, .parameters = &.{.literal_integer} }, - .{ .name = "DependencyArrayINTEL", .value = 0x40000, .parameters = &.{.literal_integer} }, - .{ .name = "PipelineEnableINTEL", .value = 0x80000, .parameters = &.{.literal_integer} }, - .{ .name = "LoopCoalesceINTEL", .value = 0x100000, .parameters = &.{.literal_integer} }, - .{ .name = "MaxInterleavingINTEL", .value = 0x200000, .parameters = &.{.literal_integer} }, - .{ .name = "SpeculatedIterationsINTEL", .value = 0x400000, .parameters = &.{.literal_integer} }, - .{ .name = "NoFusionINTEL", .value = 0x800000, .parameters = &.{} }, - .{ .name = "LoopCountINTEL", .value = 0x1000000, .parameters = &.{.literal_integer} }, - .{ .name = "MaxReinvocationDelayINTEL", .value = 0x2000000, .parameters = &.{.literal_integer} }, + .{ .name = "InitiationIntervalALTERA", .value = 0x10000, .parameters = &.{.literal_integer} }, + .{ .name = "MaxConcurrencyALTERA", .value = 0x20000, .parameters = &.{.literal_integer} }, + .{ .name = "DependencyArrayALTERA", .value = 0x40000, .parameters = &.{.literal_integer} }, + .{ .name = "PipelineEnableALTERA", .value = 0x80000, .parameters = &.{.literal_integer} }, + .{ .name = "LoopCoalesceALTERA", .value = 0x100000, .parameters = &.{.literal_integer} }, + .{ .name = "MaxInterleavingALTERA", .value = 0x200000, .parameters = &.{.literal_integer} }, + .{ .name = "SpeculatedIterationsALTERA", .value = 0x400000, .parameters = &.{.literal_integer} }, + .{ .name = "NoFusionALTERA", .value = 0x800000, .parameters = &.{} }, + .{ .name = "LoopCountALTERA", .value = 0x1000000, .parameters = &.{.literal_integer} }, + .{ .name = "MaxReinvocationDelayALTERA", .value = 0x2000000, .parameters = &.{.literal_integer} }, }, .function_control => &.{ .{ .name = "Inline", .value = 0x0001, .parameters = &.{} }, @@ -500,6 +500,7 @@ pub const OperandKind = enum { .{ .name = "QuadDerivativesKHR", .value = 5088, .parameters = &.{} }, .{ .name = "RequireFullQuadsKHR", .value = 5089, .parameters = &.{} }, .{ .name = "SharesInputWithAMDX", .value = 5102, .parameters = &.{ .id_ref, .id_ref } }, + .{ .name = "ArithmeticPoisonKHR", .value = 5157, .parameters = &.{} }, .{ .name = "OutputLinesEXT", .value = 5269, .parameters = &.{} }, .{ .name = "OutputPrimitivesEXT", .value = 5270, .parameters = &.{.literal_integer} }, .{ .name = "DerivativeGroupQuadsKHR", .value = 5289, .parameters = &.{} }, @@ -511,6 +512,7 @@ pub const OperandKind = enum { .{ .name = "SampleInterlockUnorderedEXT", .value = 5369, .parameters = &.{} }, .{ .name = "ShadingRateInterlockOrderedEXT", .value = 5370, .parameters = &.{} }, .{ .name = "ShadingRateInterlockUnorderedEXT", .value = 5371, .parameters = &.{} }, + .{ .name = "Shader64BitIndexingEXT", .value = 5427, .parameters = &.{} }, .{ .name = "SharedLocalMemorySizeINTEL", .value = 5618, .parameters = &.{.literal_integer} }, .{ .name = "RoundingModeRTPINTEL", .value = 5620, .parameters = &.{.literal_integer} }, .{ .name = "RoundingModeRTNINTEL", .value = 5621, .parameters = &.{.literal_integer} }, @@ -556,9 +558,10 @@ pub const OperandKind = enum { .{ .name = "PhysicalStorageBuffer", .value = 5349, .parameters = &.{} }, .{ .name = "HitObjectAttributeNV", .value = 5385, .parameters = &.{} }, .{ .name = "TaskPayloadWorkgroupEXT", .value = 5402, .parameters = &.{} }, + .{ .name = "HitObjectAttributeEXT", .value = 5411, .parameters = &.{} }, .{ .name = "CodeSectionINTEL", .value = 5605, .parameters = &.{} }, - .{ .name = "DeviceOnlyINTEL", .value = 5936, .parameters = &.{} }, - .{ .name = "HostOnlyINTEL", .value = 5937, .parameters = &.{} }, + .{ .name = "DeviceOnlyALTERA", .value = 5936, .parameters = &.{} }, + .{ .name = "HostOnlyALTERA", .value = 5937, .parameters = &.{} }, }, .dim => &.{ .{ .name = "1D", .value = 0, .parameters = &.{} }, @@ -730,7 +733,7 @@ pub const OperandKind = enum { .{ .name = "NoCapture", .value = 5, .parameters = &.{} }, .{ .name = "NoWrite", .value = 6, .parameters = &.{} }, .{ .name = "NoReadWrite", .value = 7, .parameters = &.{} }, - .{ .name = "RuntimeAlignedINTEL", .value = 5940, .parameters = &.{} }, + .{ .name = "RuntimeAlignedALTERA", .value = 5940, .parameters = &.{} }, }, .decoration => &.{ .{ .name = "RelaxedPrecision", .value = 0, .parameters = &.{} }, @@ -795,6 +798,9 @@ pub const OperandKind = enum { .{ .name = "PayloadNodeSparseArrayAMDX", .value = 5099, .parameters = &.{} }, .{ .name = "PayloadNodeArraySizeAMDX", .value = 5100, .parameters = &.{.id_ref} }, .{ .name = "PayloadDispatchIndirectAMDX", .value = 5105, .parameters = &.{} }, + .{ .name = "ArrayStrideIdEXT", .value = 5124, .parameters = &.{.id_ref} }, + .{ .name = "OffsetIdEXT", .value = 5125, .parameters = &.{.id_ref} }, + .{ .name = "UTFEncodedKHR", .value = 5145, .parameters = &.{} }, .{ .name = "OverrideCoverageNV", .value = 5248, .parameters = &.{} }, .{ .name = "PassthroughNV", .value = 5250, .parameters = &.{} }, .{ .name = "ViewportRelativeNV", .value = 5252, .parameters = &.{} }, @@ -806,7 +812,10 @@ pub const OperandKind = enum { .{ .name = "NonUniform", .value = 5300, .parameters = &.{} }, .{ .name = "RestrictPointer", .value = 5355, .parameters = &.{} }, .{ .name = "AliasedPointer", .value = 5356, .parameters = &.{} }, + .{ .name = "MemberOffsetNV", .value = 5358, .parameters = &.{.literal_integer} }, .{ .name = "HitObjectShaderRecordBufferNV", .value = 5386, .parameters = &.{} }, + .{ .name = "HitObjectShaderRecordBufferEXT", .value = 5389, .parameters = &.{} }, + .{ .name = "BankNV", .value = 5397, .parameters = &.{.literal_integer} }, .{ .name = "BindlessSamplerNV", .value = 5398, .parameters = &.{} }, .{ .name = "BindlessImageNV", .value = 5399, .parameters = &.{} }, .{ .name = "BoundSamplerNV", .value = 5400, .parameters = &.{} }, @@ -825,55 +834,56 @@ pub const OperandKind = enum { .{ .name = "UserTypeGOOGLE", .value = 5636, .parameters = &.{.literal_string} }, .{ .name = "FunctionRoundingModeINTEL", .value = 5822, .parameters = &.{ .literal_integer, .fp_rounding_mode } }, .{ .name = "FunctionDenormModeINTEL", .value = 5823, .parameters = &.{ .literal_integer, .fp_denorm_mode } }, - .{ .name = "RegisterINTEL", .value = 5825, .parameters = &.{} }, - .{ .name = "MemoryINTEL", .value = 5826, .parameters = &.{.literal_string} }, - .{ .name = "NumbanksINTEL", .value = 5827, .parameters = &.{.literal_integer} }, - .{ .name = "BankwidthINTEL", .value = 5828, .parameters = &.{.literal_integer} }, - .{ .name = "MaxPrivateCopiesINTEL", .value = 5829, .parameters = &.{.literal_integer} }, - .{ .name = "SinglepumpINTEL", .value = 5830, .parameters = &.{} }, - .{ .name = "DoublepumpINTEL", .value = 5831, .parameters = &.{} }, - .{ .name = "MaxReplicatesINTEL", .value = 5832, .parameters = &.{.literal_integer} }, - .{ .name = "SimpleDualPortINTEL", .value = 5833, .parameters = &.{} }, - .{ .name = "MergeINTEL", .value = 5834, .parameters = &.{ .literal_string, .literal_string } }, - .{ .name = "BankBitsINTEL", .value = 5835, .parameters = &.{.literal_integer} }, - .{ .name = "ForcePow2DepthINTEL", .value = 5836, .parameters = &.{.literal_integer} }, - .{ .name = "StridesizeINTEL", .value = 5883, .parameters = &.{.literal_integer} }, - .{ .name = "WordsizeINTEL", .value = 5884, .parameters = &.{.literal_integer} }, - .{ .name = "TrueDualPortINTEL", .value = 5885, .parameters = &.{} }, - .{ .name = "BurstCoalesceINTEL", .value = 5899, .parameters = &.{} }, - .{ .name = "CacheSizeINTEL", .value = 5900, .parameters = &.{.literal_integer} }, - .{ .name = "DontStaticallyCoalesceINTEL", .value = 5901, .parameters = &.{} }, - .{ .name = "PrefetchINTEL", .value = 5902, .parameters = &.{.literal_integer} }, - .{ .name = "StallEnableINTEL", .value = 5905, .parameters = &.{} }, - .{ .name = "FuseLoopsInFunctionINTEL", .value = 5907, .parameters = &.{} }, - .{ .name = "MathOpDSPModeINTEL", .value = 5909, .parameters = &.{ .literal_integer, .literal_integer } }, + .{ .name = "RegisterALTERA", .value = 5825, .parameters = &.{} }, + .{ .name = "MemoryALTERA", .value = 5826, .parameters = &.{.literal_string} }, + .{ .name = "NumbanksALTERA", .value = 5827, .parameters = &.{.literal_integer} }, + .{ .name = "BankwidthALTERA", .value = 5828, .parameters = &.{.literal_integer} }, + .{ .name = "MaxPrivateCopiesALTERA", .value = 5829, .parameters = &.{.literal_integer} }, + .{ .name = "SinglepumpALTERA", .value = 5830, .parameters = &.{} }, + .{ .name = "DoublepumpALTERA", .value = 5831, .parameters = &.{} }, + .{ .name = "MaxReplicatesALTERA", .value = 5832, .parameters = &.{.literal_integer} }, + .{ .name = "SimpleDualPortALTERA", .value = 5833, .parameters = &.{} }, + .{ .name = "MergeALTERA", .value = 5834, .parameters = &.{ .literal_string, .literal_string } }, + .{ .name = "BankBitsALTERA", .value = 5835, .parameters = &.{.literal_integer} }, + .{ .name = "ForcePow2DepthALTERA", .value = 5836, .parameters = &.{.literal_integer} }, + .{ .name = "StridesizeALTERA", .value = 5883, .parameters = &.{.literal_integer} }, + .{ .name = "WordsizeALTERA", .value = 5884, .parameters = &.{.literal_integer} }, + .{ .name = "TrueDualPortALTERA", .value = 5885, .parameters = &.{} }, + .{ .name = "BurstCoalesceALTERA", .value = 5899, .parameters = &.{} }, + .{ .name = "CacheSizeALTERA", .value = 5900, .parameters = &.{.literal_integer} }, + .{ .name = "DontStaticallyCoalesceALTERA", .value = 5901, .parameters = &.{} }, + .{ .name = "PrefetchALTERA", .value = 5902, .parameters = &.{.literal_integer} }, + .{ .name = "StallEnableALTERA", .value = 5905, .parameters = &.{} }, + .{ .name = "FuseLoopsInFunctionALTERA", .value = 5907, .parameters = &.{} }, + .{ .name = "MathOpDSPModeALTERA", .value = 5909, .parameters = &.{ .literal_integer, .literal_integer } }, .{ .name = "AliasScopeINTEL", .value = 5914, .parameters = &.{.id_ref} }, .{ .name = "NoAliasINTEL", .value = 5915, .parameters = &.{.id_ref} }, - .{ .name = "InitiationIntervalINTEL", .value = 5917, .parameters = &.{.literal_integer} }, - .{ .name = "MaxConcurrencyINTEL", .value = 5918, .parameters = &.{.literal_integer} }, - .{ .name = "PipelineEnableINTEL", .value = 5919, .parameters = &.{.literal_integer} }, - .{ .name = "BufferLocationINTEL", .value = 5921, .parameters = &.{.literal_integer} }, - .{ .name = "IOPipeStorageINTEL", .value = 5944, .parameters = &.{.literal_integer} }, + .{ .name = "InitiationIntervalALTERA", .value = 5917, .parameters = &.{.literal_integer} }, + .{ .name = "MaxConcurrencyALTERA", .value = 5918, .parameters = &.{.literal_integer} }, + .{ .name = "PipelineEnableALTERA", .value = 5919, .parameters = &.{.literal_integer} }, + .{ .name = "BufferLocationALTERA", .value = 5921, .parameters = &.{.literal_integer} }, + .{ .name = "IOPipeStorageALTERA", .value = 5944, .parameters = &.{.literal_integer} }, .{ .name = "FunctionFloatingPointModeINTEL", .value = 6080, .parameters = &.{ .literal_integer, .fp_operation_mode } }, .{ .name = "SingleElementVectorINTEL", .value = 6085, .parameters = &.{} }, .{ .name = "VectorComputeCallableFunctionINTEL", .value = 6087, .parameters = &.{} }, .{ .name = "MediaBlockIOINTEL", .value = 6140, .parameters = &.{} }, - .{ .name = "StallFreeINTEL", .value = 6151, .parameters = &.{} }, + .{ .name = "StallFreeALTERA", .value = 6151, .parameters = &.{} }, .{ .name = "FPMaxErrorDecorationINTEL", .value = 6170, .parameters = &.{.literal_float} }, - .{ .name = "LatencyControlLabelINTEL", .value = 6172, .parameters = &.{.literal_integer} }, - .{ .name = "LatencyControlConstraintINTEL", .value = 6173, .parameters = &.{ .literal_integer, .literal_integer, .literal_integer } }, - .{ .name = "ConduitKernelArgumentINTEL", .value = 6175, .parameters = &.{} }, - .{ .name = "RegisterMapKernelArgumentINTEL", .value = 6176, .parameters = &.{} }, - .{ .name = "MMHostInterfaceAddressWidthINTEL", .value = 6177, .parameters = &.{.literal_integer} }, - .{ .name = "MMHostInterfaceDataWidthINTEL", .value = 6178, .parameters = &.{.literal_integer} }, - .{ .name = "MMHostInterfaceLatencyINTEL", .value = 6179, .parameters = &.{.literal_integer} }, - .{ .name = "MMHostInterfaceReadWriteModeINTEL", .value = 6180, .parameters = &.{.access_qualifier} }, - .{ .name = "MMHostInterfaceMaxBurstINTEL", .value = 6181, .parameters = &.{.literal_integer} }, - .{ .name = "MMHostInterfaceWaitRequestINTEL", .value = 6182, .parameters = &.{.literal_integer} }, - .{ .name = "StableKernelArgumentINTEL", .value = 6183, .parameters = &.{} }, + .{ .name = "LatencyControlLabelALTERA", .value = 6172, .parameters = &.{.literal_integer} }, + .{ .name = "LatencyControlConstraintALTERA", .value = 6173, .parameters = &.{ .literal_integer, .literal_integer, .literal_integer } }, + .{ .name = "ConduitKernelArgumentALTERA", .value = 6175, .parameters = &.{} }, + .{ .name = "RegisterMapKernelArgumentALTERA", .value = 6176, .parameters = &.{} }, + .{ .name = "MMHostInterfaceAddressWidthALTERA", .value = 6177, .parameters = &.{.literal_integer} }, + .{ .name = "MMHostInterfaceDataWidthALTERA", .value = 6178, .parameters = &.{.literal_integer} }, + .{ .name = "MMHostInterfaceLatencyALTERA", .value = 6179, .parameters = &.{.literal_integer} }, + .{ .name = "MMHostInterfaceReadWriteModeALTERA", .value = 6180, .parameters = &.{.access_qualifier} }, + .{ .name = "MMHostInterfaceMaxBurstALTERA", .value = 6181, .parameters = &.{.literal_integer} }, + .{ .name = "MMHostInterfaceWaitRequestALTERA", .value = 6182, .parameters = &.{.literal_integer} }, + .{ .name = "StableKernelArgumentALTERA", .value = 6183, .parameters = &.{} }, .{ .name = "HostAccessINTEL", .value = 6188, .parameters = &.{ .host_access_qualifier, .literal_string } }, - .{ .name = "InitModeINTEL", .value = 6190, .parameters = &.{.initialization_mode_qualifier} }, - .{ .name = "ImplementInRegisterMapINTEL", .value = 6191, .parameters = &.{.literal_integer} }, + .{ .name = "InitModeALTERA", .value = 6190, .parameters = &.{.initialization_mode_qualifier} }, + .{ .name = "ImplementInRegisterMapALTERA", .value = 6191, .parameters = &.{.literal_integer} }, + .{ .name = "ConditionalINTEL", .value = 6247, .parameters = &.{.id_ref} }, .{ .name = "CacheControlLoadINTEL", .value = 6442, .parameters = &.{ .literal_integer, .load_cache_control } }, .{ .name = "CacheControlStoreINTEL", .value = 6443, .parameters = &.{ .literal_integer, .store_cache_control } }, }, @@ -949,6 +959,8 @@ pub const OperandKind = enum { .{ .name = "FragStencilRefEXT", .value = 5014, .parameters = &.{} }, .{ .name = "RemainingRecursionLevelsAMDX", .value = 5021, .parameters = &.{} }, .{ .name = "ShaderIndexAMDX", .value = 5073, .parameters = &.{} }, + .{ .name = "SamplerHeapEXT", .value = 5122, .parameters = &.{} }, + .{ .name = "ResourceHeapEXT", .value = 5123, .parameters = &.{} }, .{ .name = "ViewportMaskNV", .value = 5253, .parameters = &.{} }, .{ .name = "SecondaryPositionNV", .value = 5257, .parameters = &.{} }, .{ .name = "SecondaryViewportMaskNV", .value = 5258, .parameters = &.{} }, @@ -1019,9 +1031,9 @@ pub const OperandKind = enum { .{ .name = "InclusiveScan", .value = 1, .parameters = &.{} }, .{ .name = "ExclusiveScan", .value = 2, .parameters = &.{} }, .{ .name = "ClusteredReduce", .value = 3, .parameters = &.{} }, - .{ .name = "PartitionedReduceNV", .value = 6, .parameters = &.{} }, - .{ .name = "PartitionedInclusiveScanNV", .value = 7, .parameters = &.{} }, - .{ .name = "PartitionedExclusiveScanNV", .value = 8, .parameters = &.{} }, + .{ .name = "PartitionedReduceEXT", .value = 6, .parameters = &.{} }, + .{ .name = "PartitionedInclusiveScanEXT", .value = 7, .parameters = &.{} }, + .{ .name = "PartitionedExclusiveScanEXT", .value = 8, .parameters = &.{} }, }, .kernel_enqueue_flags => &.{ .{ .name = "NoWait", .value = 0, .parameters = &.{} }, @@ -1144,6 +1156,7 @@ pub const OperandKind = enum { .{ .name = "TextureBoxFilterQCOM", .value = 4485, .parameters = &.{} }, .{ .name = "TextureBlockMatchQCOM", .value = 4486, .parameters = &.{} }, .{ .name = "TileShadingQCOM", .value = 4495, .parameters = &.{} }, + .{ .name = "CooperativeMatrixConversionQCOM", .value = 4496, .parameters = &.{} }, .{ .name = "TextureBlockMatch2QCOM", .value = 4498, .parameters = &.{} }, .{ .name = "Float16ImageAMD", .value = 5008, .parameters = &.{} }, .{ .name = "ImageGatherBiasLodAMD", .value = 5009, .parameters = &.{} }, @@ -1159,6 +1172,10 @@ pub const OperandKind = enum { .{ .name = "BFloat16TypeKHR", .value = 5116, .parameters = &.{} }, .{ .name = "BFloat16DotProductKHR", .value = 5117, .parameters = &.{} }, .{ .name = "BFloat16CooperativeMatrixKHR", .value = 5118, .parameters = &.{} }, + .{ .name = "AbortKHR", .value = 5120, .parameters = &.{} }, + .{ .name = "DescriptorHeapEXT", .value = 5128, .parameters = &.{} }, + .{ .name = "ConstantDataKHR", .value = 5146, .parameters = &.{} }, + .{ .name = "PoisonFreezeKHR", .value = 5156, .parameters = &.{} }, .{ .name = "SampleMaskOverrideCoverageNV", .value = 5249, .parameters = &.{} }, .{ .name = "GeometryShaderPassthroughNV", .value = 5251, .parameters = &.{} }, .{ .name = "ShaderViewportIndexLayerEXT", .value = 5254, .parameters = &.{} }, @@ -1172,7 +1189,7 @@ pub const OperandKind = enum { .{ .name = "FragmentBarycentricKHR", .value = 5284, .parameters = &.{} }, .{ .name = "ComputeDerivativeGroupQuadsKHR", .value = 5288, .parameters = &.{} }, .{ .name = "FragmentDensityEXT", .value = 5291, .parameters = &.{} }, - .{ .name = "GroupNonUniformPartitionedNV", .value = 5297, .parameters = &.{} }, + .{ .name = "GroupNonUniformPartitionedEXT", .value = 5297, .parameters = &.{} }, .{ .name = "ShaderNonUniform", .value = 5301, .parameters = &.{} }, .{ .name = "RuntimeDescriptorArray", .value = 5302, .parameters = &.{} }, .{ .name = "InputAttachmentArrayDynamicIndexing", .value = 5303, .parameters = &.{} }, @@ -1202,6 +1219,7 @@ pub const OperandKind = enum { .{ .name = "DisplacementMicromapNV", .value = 5380, .parameters = &.{} }, .{ .name = "RayTracingOpacityMicromapEXT", .value = 5381, .parameters = &.{} }, .{ .name = "ShaderInvocationReorderNV", .value = 5383, .parameters = &.{} }, + .{ .name = "ShaderInvocationReorderEXT", .value = 5388, .parameters = &.{} }, .{ .name = "BindlessTextureNV", .value = 5390, .parameters = &.{} }, .{ .name = "RayQueryPositionFetchKHR", .value = 5391, .parameters = &.{} }, .{ .name = "CooperativeVectorNV", .value = 5394, .parameters = &.{} }, @@ -1210,6 +1228,9 @@ pub const OperandKind = enum { .{ .name = "RawAccessChainsNV", .value = 5414, .parameters = &.{} }, .{ .name = "RayTracingSpheresGeometryNV", .value = 5418, .parameters = &.{} }, .{ .name = "RayTracingLinearSweptSpheresGeometryNV", .value = 5419, .parameters = &.{} }, + .{ .name = "PushConstantBanksNV", .value = 5423, .parameters = &.{} }, + .{ .name = "LongVectorEXT", .value = 5425, .parameters = &.{} }, + .{ .name = "Shader64BitIndexingEXT", .value = 5426, .parameters = &.{} }, .{ .name = "CooperativeMatrixReductionsNV", .value = 5430, .parameters = &.{} }, .{ .name = "CooperativeMatrixConversionsNV", .value = 5431, .parameters = &.{} }, .{ .name = "CooperativeMatrixPerElementOperationsNV", .value = 5432, .parameters = &.{} }, @@ -1239,27 +1260,27 @@ pub const OperandKind = enum { .{ .name = "SubgroupAvcMotionEstimationChromaINTEL", .value = 5698, .parameters = &.{} }, .{ .name = "VariableLengthArrayINTEL", .value = 5817, .parameters = &.{} }, .{ .name = "FunctionFloatControlINTEL", .value = 5821, .parameters = &.{} }, - .{ .name = "FPGAMemoryAttributesINTEL", .value = 5824, .parameters = &.{} }, + .{ .name = "FPGAMemoryAttributesALTERA", .value = 5824, .parameters = &.{} }, .{ .name = "FPFastMathModeINTEL", .value = 5837, .parameters = &.{} }, - .{ .name = "ArbitraryPrecisionIntegersINTEL", .value = 5844, .parameters = &.{} }, - .{ .name = "ArbitraryPrecisionFloatingPointINTEL", .value = 5845, .parameters = &.{} }, + .{ .name = "ArbitraryPrecisionIntegersALTERA", .value = 5844, .parameters = &.{} }, + .{ .name = "ArbitraryPrecisionFloatingPointALTERA", .value = 5845, .parameters = &.{} }, .{ .name = "UnstructuredLoopControlsINTEL", .value = 5886, .parameters = &.{} }, - .{ .name = "FPGALoopControlsINTEL", .value = 5888, .parameters = &.{} }, + .{ .name = "FPGALoopControlsALTERA", .value = 5888, .parameters = &.{} }, .{ .name = "KernelAttributesINTEL", .value = 5892, .parameters = &.{} }, .{ .name = "FPGAKernelAttributesINTEL", .value = 5897, .parameters = &.{} }, - .{ .name = "FPGAMemoryAccessesINTEL", .value = 5898, .parameters = &.{} }, - .{ .name = "FPGAClusterAttributesINTEL", .value = 5904, .parameters = &.{} }, - .{ .name = "LoopFuseINTEL", .value = 5906, .parameters = &.{} }, - .{ .name = "FPGADSPControlINTEL", .value = 5908, .parameters = &.{} }, + .{ .name = "FPGAMemoryAccessesALTERA", .value = 5898, .parameters = &.{} }, + .{ .name = "FPGAClusterAttributesALTERA", .value = 5904, .parameters = &.{} }, + .{ .name = "LoopFuseALTERA", .value = 5906, .parameters = &.{} }, + .{ .name = "FPGADSPControlALTERA", .value = 5908, .parameters = &.{} }, .{ .name = "MemoryAccessAliasingINTEL", .value = 5910, .parameters = &.{} }, - .{ .name = "FPGAInvocationPipeliningAttributesINTEL", .value = 5916, .parameters = &.{} }, - .{ .name = "FPGABufferLocationINTEL", .value = 5920, .parameters = &.{} }, - .{ .name = "ArbitraryPrecisionFixedPointINTEL", .value = 5922, .parameters = &.{} }, - .{ .name = "USMStorageClassesINTEL", .value = 5935, .parameters = &.{} }, - .{ .name = "RuntimeAlignedAttributeINTEL", .value = 5939, .parameters = &.{} }, - .{ .name = "IOPipesINTEL", .value = 5943, .parameters = &.{} }, - .{ .name = "BlockingPipesINTEL", .value = 5945, .parameters = &.{} }, - .{ .name = "FPGARegINTEL", .value = 5948, .parameters = &.{} }, + .{ .name = "FPGAInvocationPipeliningAttributesALTERA", .value = 5916, .parameters = &.{} }, + .{ .name = "FPGABufferLocationALTERA", .value = 5920, .parameters = &.{} }, + .{ .name = "ArbitraryPrecisionFixedPointALTERA", .value = 5922, .parameters = &.{} }, + .{ .name = "USMStorageClassesALTERA", .value = 5935, .parameters = &.{} }, + .{ .name = "RuntimeAlignedAttributeALTERA", .value = 5939, .parameters = &.{} }, + .{ .name = "IOPipesALTERA", .value = 5943, .parameters = &.{} }, + .{ .name = "BlockingPipesALTERA", .value = 5945, .parameters = &.{} }, + .{ .name = "FPGARegALTERA", .value = 5948, .parameters = &.{} }, .{ .name = "DotProductInputAll", .value = 6016, .parameters = &.{} }, .{ .name = "DotProductInput4x8Bit", .value = 6017, .parameters = &.{} }, .{ .name = "DotProductInput4x8BitPacked", .value = 6018, .parameters = &.{} }, @@ -1270,6 +1291,7 @@ pub const OperandKind = enum { .{ .name = "BitInstructions", .value = 6025, .parameters = &.{} }, .{ .name = "GroupNonUniformRotateKHR", .value = 6026, .parameters = &.{} }, .{ .name = "FloatControls2", .value = 6029, .parameters = &.{} }, + .{ .name = "FMAKHR", .value = 6030, .parameters = &.{} }, .{ .name = "AtomicFloat32AddEXT", .value = 6033, .parameters = &.{} }, .{ .name = "AtomicFloat64AddEXT", .value = 6034, .parameters = &.{} }, .{ .name = "LongCompositesINTEL", .value = 6089, .parameters = &.{} }, @@ -1279,26 +1301,33 @@ pub const OperandKind = enum { .{ .name = "BFloat16ConversionINTEL", .value = 6115, .parameters = &.{} }, .{ .name = "SplitBarrierINTEL", .value = 6141, .parameters = &.{} }, .{ .name = "ArithmeticFenceEXT", .value = 6144, .parameters = &.{} }, - .{ .name = "FPGAClusterAttributesV2INTEL", .value = 6150, .parameters = &.{} }, + .{ .name = "FPGAClusterAttributesV2ALTERA", .value = 6150, .parameters = &.{} }, .{ .name = "FPGAKernelAttributesv2INTEL", .value = 6161, .parameters = &.{} }, - .{ .name = "TaskSequenceINTEL", .value = 6162, .parameters = &.{} }, + .{ .name = "TaskSequenceALTERA", .value = 6162, .parameters = &.{} }, .{ .name = "FPMaxErrorINTEL", .value = 6169, .parameters = &.{} }, - .{ .name = "FPGALatencyControlINTEL", .value = 6171, .parameters = &.{} }, - .{ .name = "FPGAArgumentInterfacesINTEL", .value = 6174, .parameters = &.{} }, + .{ .name = "FPGALatencyControlALTERA", .value = 6171, .parameters = &.{} }, + .{ .name = "FPGAArgumentInterfacesALTERA", .value = 6174, .parameters = &.{} }, .{ .name = "GlobalVariableHostAccessINTEL", .value = 6187, .parameters = &.{} }, - .{ .name = "GlobalVariableFPGADecorationsINTEL", .value = 6189, .parameters = &.{} }, + .{ .name = "GlobalVariableFPGADecorationsALTERA", .value = 6189, .parameters = &.{} }, .{ .name = "SubgroupBufferPrefetchINTEL", .value = 6220, .parameters = &.{} }, .{ .name = "Subgroup2DBlockIOINTEL", .value = 6228, .parameters = &.{} }, .{ .name = "Subgroup2DBlockTransformINTEL", .value = 6229, .parameters = &.{} }, .{ .name = "Subgroup2DBlockTransposeINTEL", .value = 6230, .parameters = &.{} }, .{ .name = "SubgroupMatrixMultiplyAccumulateINTEL", .value = 6236, .parameters = &.{} }, .{ .name = "TernaryBitwiseFunctionINTEL", .value = 6241, .parameters = &.{} }, + .{ .name = "UntypedVariableLengthArrayINTEL", .value = 6243, .parameters = &.{} }, + .{ .name = "SpecConditionalINTEL", .value = 6245, .parameters = &.{} }, + .{ .name = "FunctionVariantsINTEL", .value = 6246, .parameters = &.{} }, .{ .name = "GroupUniformArithmeticKHR", .value = 6400, .parameters = &.{} }, .{ .name = "TensorFloat32RoundingINTEL", .value = 6425, .parameters = &.{} }, .{ .name = "MaskedGatherScatterINTEL", .value = 6427, .parameters = &.{} }, .{ .name = "CacheControlsINTEL", .value = 6441, .parameters = &.{} }, .{ .name = "RegisterLimitsINTEL", .value = 6460, .parameters = &.{} }, .{ .name = "BindlessImagesINTEL", .value = 6528, .parameters = &.{} }, + .{ .name = "DotProductFloat16AccFloat32VALVE", .value = 6912, .parameters = &.{} }, + .{ .name = "DotProductFloat16AccFloat16VALVE", .value = 6913, .parameters = &.{} }, + .{ .name = "DotProductBFloat16AccVALVE", .value = 6914, .parameters = &.{} }, + .{ .name = "DotProductFloat8AccFloat32VALVE", .value = 6915, .parameters = &.{} }, }, .ray_query_intersection => &.{ .{ .name = "RayQueryCandidateIntersectionKHR", .value = 0, .parameters = &.{} }, @@ -1352,8 +1381,8 @@ pub const OperandKind = enum { .{ .name = "DecodeFunc", .value = 0x0002, .parameters = &.{.id_ref} }, }, .initialization_mode_qualifier => &.{ - .{ .name = "InitOnDeviceReprogramINTEL", .value = 0, .parameters = &.{} }, - .{ .name = "InitOnDeviceResetINTEL", .value = 1, .parameters = &.{} }, + .{ .name = "InitOnDeviceReprogramALTERA", .value = 0, .parameters = &.{} }, + .{ .name = "InitOnDeviceResetALTERA", .value = 1, .parameters = &.{} }, }, .load_cache_control => &.{ .{ .name = "UncachedINTEL", .value = 0, .parameters = &.{} }, @@ -1811,12 +1840,14 @@ pub const Opcode = enum(u16) { OpUntypedInBoundsPtrAccessChainKHR = 4424, OpUntypedArrayLengthKHR = 4425, OpUntypedPrefetchKHR = 4426, + OpFmaKHR = 4427, OpSubgroupAllKHR = 4428, OpSubgroupAnyKHR = 4429, OpSubgroupAllEqualKHR = 4430, OpGroupNonUniformRotateKHR = 4431, OpSubgroupReadInvocationKHR = 4432, OpExtInstWithForwardRefsKHR = 4433, + OpUntypedGroupAsyncCopyKHR = 4434, OpTraceRayKHR = 4445, OpExecuteCallableKHR = 4446, OpConvertUToAccelerationStructureKHR = 4447, @@ -1847,10 +1878,14 @@ pub const Opcode = enum(u16) { OpImageBoxFilterQCOM = 4481, OpImageBlockMatchSSDQCOM = 4482, OpImageBlockMatchSADQCOM = 4483, + OpBitCastArrayQCOM = 4497, OpImageBlockMatchWindowSSDQCOM = 4500, OpImageBlockMatchWindowSADQCOM = 4501, OpImageBlockMatchGatherSSDQCOM = 4502, OpImageBlockMatchGatherSADQCOM = 4503, + OpCompositeConstructCoopMatQCOM = 4540, + OpCompositeExtractCoopMatQCOM = 4541, + OpExtractSubArrayQCOM = 4542, OpGroupIAddNonUniformAMD = 5000, OpGroupFAddNonUniformAMD = 5001, OpGroupFMinNonUniformAMD = 5002, @@ -1872,6 +1907,16 @@ pub const Opcode = enum(u16) { OpSpecConstantStringAMDX = 5104, OpGroupNonUniformQuadAllKHR = 5110, OpGroupNonUniformQuadAnyKHR = 5111, + OpTypeBufferEXT = 5115, + OpBufferPointerEXT = 5119, + OpAbortKHR = 5121, + OpUntypedImageTexelPointerEXT = 5126, + OpMemberDecorateIdEXT = 5127, + OpConstantSizeOfEXT = 5129, + OpConstantDataKHR = 5147, + OpSpecConstantDataKHR = 5148, + OpPoisonKHR = 5158, + OpFreezeKHR = 5159, OpHitObjectRecordHitMotionNV = 5249, OpHitObjectRecordHitWithIndexMotionNV = 5250, OpHitObjectRecordMissMotionNV = 5251, @@ -1906,7 +1951,7 @@ pub const Opcode = enum(u16) { OpReorderThreadWithHintNV = 5280, OpTypeHitObjectNV = 5281, OpImageSampleFootprintNV = 5283, - OpTypeCooperativeVectorNV = 5288, + OpTypeVectorIdEXT = 5288, OpCooperativeVectorMatrixMulNV = 5289, OpCooperativeVectorOuterProductAccumulateNV = 5290, OpCooperativeVectorReduceSumAccumulateNV = 5291, @@ -1914,12 +1959,42 @@ pub const Opcode = enum(u16) { OpCooperativeMatrixConvertNV = 5293, OpEmitMeshTasksEXT = 5294, OpSetMeshOutputsEXT = 5295, - OpGroupNonUniformPartitionNV = 5296, + OpGroupNonUniformPartitionEXT = 5296, OpWritePackedPrimitiveIndices4x8NV = 5299, OpFetchMicroTriangleVertexPositionNV = 5300, OpFetchMicroTriangleVertexBarycentricNV = 5301, OpCooperativeVectorLoadNV = 5302, OpCooperativeVectorStoreNV = 5303, + OpHitObjectRecordFromQueryEXT = 5304, + OpHitObjectRecordMissEXT = 5305, + OpHitObjectRecordMissMotionEXT = 5306, + OpHitObjectGetIntersectionTriangleVertexPositionsEXT = 5307, + OpHitObjectGetRayFlagsEXT = 5308, + OpHitObjectSetShaderBindingTableRecordIndexEXT = 5309, + OpHitObjectReorderExecuteShaderEXT = 5310, + OpHitObjectTraceReorderExecuteEXT = 5311, + OpHitObjectTraceMotionReorderExecuteEXT = 5312, + OpTypeHitObjectEXT = 5313, + OpReorderThreadWithHintEXT = 5314, + OpReorderThreadWithHitObjectEXT = 5315, + OpHitObjectTraceRayEXT = 5316, + OpHitObjectTraceRayMotionEXT = 5317, + OpHitObjectRecordEmptyEXT = 5318, + OpHitObjectExecuteShaderEXT = 5319, + OpHitObjectGetCurrentTimeEXT = 5320, + OpHitObjectGetAttributesEXT = 5321, + OpHitObjectGetHitKindEXT = 5322, + OpHitObjectGetPrimitiveIndexEXT = 5323, + OpHitObjectGetGeometryIndexEXT = 5324, + OpHitObjectGetInstanceIdEXT = 5325, + OpHitObjectGetInstanceCustomIndexEXT = 5326, + OpHitObjectGetObjectRayOriginEXT = 5327, + OpHitObjectGetObjectRayDirectionEXT = 5328, + OpHitObjectGetWorldRayDirectionEXT = 5329, + OpHitObjectGetWorldRayOriginEXT = 5330, + OpHitObjectGetObjectToWorldEXT = 5331, + OpHitObjectGetWorldToObjectEXT = 5332, + OpHitObjectGetRayTMaxEXT = 5333, OpReportIntersectionKHR = 5334, OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, @@ -1929,8 +2004,14 @@ pub const Opcode = enum(u16) { OpRayQueryGetIntersectionTriangleVertexPositionsKHR = 5340, OpTypeAccelerationStructureKHR = 5341, OpExecuteCallableNV = 5344, - OpRayQueryGetClusterIdNV = 5345, + OpRayQueryGetIntersectionClusterIdNV = 5345, OpHitObjectGetClusterIdNV = 5346, + OpHitObjectGetRayTMinEXT = 5347, + OpHitObjectGetShaderBindingTableRecordIndexEXT = 5348, + OpHitObjectGetShaderRecordBufferHandleEXT = 5349, + OpHitObjectIsEmptyEXT = 5350, + OpHitObjectIsHitEXT = 5351, + OpHitObjectIsMissEXT = 5352, OpTypeCooperativeMatrixNV = 5358, OpCooperativeMatrixLoadNV = 5359, OpCooperativeMatrixStoreNV = 5360, @@ -2008,10 +2089,10 @@ pub const Opcode = enum(u16) { OpExpectKHR = 5631, OpDecorateString = 5632, OpMemberDecorateString = 5633, + OpVariableLengthArrayINTEL = 5818, + OpSaveMemoryINTEL = 5819, + OpRestoreMemoryINTEL = 5820, OpLoopControlINTEL = 5887, - OpReadPipeBlockingINTEL = 5946, - OpWritePipeBlockingINTEL = 5947, - OpFPGARegINTEL = 5949, OpRayQueryGetRayTMinKHR = 6016, OpRayQueryGetRayFlagsKHR = 6017, OpRayQueryGetIntersectionTKHR = 6018, @@ -2040,11 +2121,6 @@ pub const Opcode = enum(u16) { OpControlBarrierArriveINTEL = 6142, OpControlBarrierWaitINTEL = 6143, OpArithmeticFenceEXT = 6145, - OpTaskSequenceCreateINTEL = 6163, - OpTaskSequenceAsyncINTEL = 6164, - OpTaskSequenceGetINTEL = 6165, - OpTaskSequenceReleaseINTEL = 6166, - OpTypeTaskSequenceINTEL = 6199, OpSubgroupBlockPrefetchINTEL = 6221, OpSubgroup2DBlockLoadINTEL = 6231, OpSubgroup2DBlockLoadTransformINTEL = 6232, @@ -2053,6 +2129,14 @@ pub const Opcode = enum(u16) { OpSubgroup2DBlockStoreINTEL = 6235, OpSubgroupMatrixMultiplyAccumulateINTEL = 6237, OpBitwiseFunctionINTEL = 6242, + OpUntypedVariableLengthArrayINTEL = 6244, + OpConditionalExtensionINTEL = 6248, + OpConditionalEntryPointINTEL = 6249, + OpConditionalCapabilityINTEL = 6250, + OpSpecConstantTargetINTEL = 6251, + OpSpecConstantArchitectureINTEL = 6252, + OpSpecConstantCapabilitiesINTEL = 6253, + OpConditionalCopyObjectINTEL = 6254, OpGroupIMulKHR = 6401, OpGroupFMulKHR = 6402, OpGroupBitwiseAndKHR = 6403, @@ -2067,6 +2151,9 @@ pub const Opcode = enum(u16) { OpConvertHandleToImageINTEL = 6529, OpConvertHandleToSamplerINTEL = 6530, OpConvertHandleToSampledImageINTEL = 6531, + OpFDot2MixAcc32VALVE = 6916, + OpFDot2MixAcc16VALVE = 6917, + OpFDot4MixAcc32VALVE = 6918, pub fn Operands(comptime self: Opcode) type { return switch (self) { @@ -2380,7 +2467,7 @@ pub const Opcode = enum(u16) { .OpGroupNonUniformAll => struct { id_result_type: Id, id_result: Id, execution: Id, predicate: Id }, .OpGroupNonUniformAny => struct { id_result_type: Id, id_result: Id, execution: Id, predicate: Id }, .OpGroupNonUniformAllEqual => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id }, - .OpGroupNonUniformBroadcast => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, id: Id }, + .OpGroupNonUniformBroadcast => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, invocation_id: Id }, .OpGroupNonUniformBroadcastFirst => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id }, .OpGroupNonUniformBallot => struct { id_result_type: Id, id_result: Id, execution: Id, predicate: Id }, .OpGroupNonUniformInverseBallot => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id }, @@ -2388,7 +2475,7 @@ pub const Opcode = enum(u16) { .OpGroupNonUniformBallotBitCount => struct { id_result_type: Id, id_result: Id, execution: Id, operation: GroupOperation, value: Id }, .OpGroupNonUniformBallotFindLSB => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id }, .OpGroupNonUniformBallotFindMSB => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id }, - .OpGroupNonUniformShuffle => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, id: Id }, + .OpGroupNonUniformShuffle => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, invocation_id: Id }, .OpGroupNonUniformShuffleXor => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, mask: Id }, .OpGroupNonUniformShuffleUp => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, delta: Id }, .OpGroupNonUniformShuffleDown => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, delta: Id }, @@ -2439,12 +2526,14 @@ pub const Opcode = enum(u16) { .OpUntypedInBoundsPtrAccessChainKHR => struct { id_result_type: Id, id_result: Id, base_type: Id, base: Id, element: Id, indexes: []const Id = &.{} }, .OpUntypedArrayLengthKHR => struct { id_result_type: Id, id_result: Id, structure: Id, pointer: Id, array_member: LiteralInteger }, .OpUntypedPrefetchKHR => struct { pointer_type: Id, num_bytes: Id, rw: ?Id = null, locality: ?Id = null, cache_type: ?Id = null }, + .OpFmaKHR => struct { id_result_type: Id, id_result: Id, operand_1: Id, operand_2: Id, operand_3: Id }, .OpSubgroupAllKHR => struct { id_result_type: Id, id_result: Id, predicate: Id }, .OpSubgroupAnyKHR => struct { id_result_type: Id, id_result: Id, predicate: Id }, .OpSubgroupAllEqualKHR => struct { id_result_type: Id, id_result: Id, predicate: Id }, .OpGroupNonUniformRotateKHR => struct { id_result_type: Id, id_result: Id, execution: Id, value: Id, delta: Id, cluster_size: ?Id = null }, .OpSubgroupReadInvocationKHR => struct { id_result_type: Id, id_result: Id, value: Id, index: Id }, .OpExtInstWithForwardRefsKHR => struct { id_result_type: Id, id_result: Id, set: Id, instruction: LiteralExtInstInteger, id_ref_4: []const Id = &.{} }, + .OpUntypedGroupAsyncCopyKHR => struct { id_result_type: Id, id_result: Id, execution: Id, destination: Id, source: Id, element_num_bytes: Id, num_elements: Id, stride: Id, event: Id, destination_memory_operands: ?MemoryAccess.Extended = null, source_memory_operands: ?MemoryAccess.Extended = null }, .OpTraceRayKHR => struct { accel: Id, ray_flags: Id, cull_mask: Id, sbt_offset: Id, sbt_stride: Id, miss_index: Id, ray_origin: Id, ray_tmin: Id, ray_direction: Id, ray_tmax: Id, payload: Id }, .OpExecuteCallableKHR => struct { sbt_index: Id, callable_data: Id }, .OpConvertUToAccelerationStructureKHR => struct { id_result_type: Id, id_result: Id, accel: Id }, @@ -2475,10 +2564,14 @@ pub const Opcode = enum(u16) { .OpImageBoxFilterQCOM => struct { id_result_type: Id, id_result: Id, texture: Id, coordinates: Id, box_size: Id }, .OpImageBlockMatchSSDQCOM => struct { id_result_type: Id, id_result: Id, target: Id, target_coordinates: Id, reference: Id, reference_coordinates: Id, block_size: Id }, .OpImageBlockMatchSADQCOM => struct { id_result_type: Id, id_result: Id, target: Id, target_coordinates: Id, reference: Id, reference_coordinates: Id, block_size: Id }, + .OpBitCastArrayQCOM => struct { id_result_type: Id, id_result: Id, source_array: Id }, .OpImageBlockMatchWindowSSDQCOM => struct { id_result_type: Id, id_result: Id, target_sampled_image: Id, target_coordinates: Id, reference_sampled_image: Id, reference_coordinates: Id, block_size: Id }, .OpImageBlockMatchWindowSADQCOM => struct { id_result_type: Id, id_result: Id, target_sampled_image: Id, target_coordinates: Id, reference_sampled_image: Id, reference_coordinates: Id, block_size: Id }, .OpImageBlockMatchGatherSSDQCOM => struct { id_result_type: Id, id_result: Id, target_sampled_image: Id, target_coordinates: Id, reference_sampled_image: Id, reference_coordinates: Id, block_size: Id }, .OpImageBlockMatchGatherSADQCOM => struct { id_result_type: Id, id_result: Id, target_sampled_image: Id, target_coordinates: Id, reference_sampled_image: Id, reference_coordinates: Id, block_size: Id }, + .OpCompositeConstructCoopMatQCOM => struct { id_result_type: Id, id_result: Id, source_array: Id }, + .OpCompositeExtractCoopMatQCOM => struct { id_result_type: Id, id_result: Id, source_cooperative_matrix: Id }, + .OpExtractSubArrayQCOM => struct { id_result_type: Id, id_result: Id, source_array: Id, index: Id }, .OpGroupIAddNonUniformAMD => struct { id_result_type: Id, id_result: Id, execution: Id, operation: GroupOperation, x: Id }, .OpGroupFAddNonUniformAMD => struct { id_result_type: Id, id_result: Id, execution: Id, operation: GroupOperation, x: Id }, .OpGroupFMinNonUniformAMD => struct { id_result_type: Id, id_result: Id, execution: Id, operation: GroupOperation, x: Id }, @@ -2500,6 +2593,16 @@ pub const Opcode = enum(u16) { .OpSpecConstantStringAMDX => struct { id_result: Id, literal_string: LiteralString }, .OpGroupNonUniformQuadAllKHR => struct { id_result_type: Id, id_result: Id, predicate: Id }, .OpGroupNonUniformQuadAnyKHR => struct { id_result_type: Id, id_result: Id, predicate: Id }, + .OpTypeBufferEXT => struct { id_result: Id, storage_class: StorageClass }, + .OpBufferPointerEXT => struct { id_result_type: Id, id_result: Id, buffer: Id }, + .OpAbortKHR => struct { message_type: Id, message: Id }, + .OpUntypedImageTexelPointerEXT => struct { id_result_type: Id, id_result: Id, image_type: Id, image: Id, coordinate: Id, sample: Id }, + .OpMemberDecorateIdEXT => struct { structure_type: Id, member: LiteralInteger, decoration: Decoration.Extended }, + .OpConstantSizeOfEXT => struct { id_result_type: Id, id_result: Id, type: Id }, + .OpConstantDataKHR => struct { id_result_type: Id, id_result: Id, data: []const LiteralInteger = &.{} }, + .OpSpecConstantDataKHR => struct { id_result_type: Id, id_result: Id, data: []const LiteralInteger = &.{} }, + .OpPoisonKHR => struct { id_result_type: Id, id_result: Id }, + .OpFreezeKHR => struct { id_result_type: Id, id_result: Id, value: Id }, .OpHitObjectRecordHitMotionNV => struct { hit_object: Id, acceleration_structure: Id, instance_id: Id, primitive_id: Id, geometry_index: Id, hit_kind: Id, sbt_record_offset: Id, sbt_record_stride: Id, origin: Id, t_min: Id, direction: Id, t_max: Id, current_time: Id, hit_object_attributes: Id }, .OpHitObjectRecordHitWithIndexMotionNV => struct { hit_object: Id, acceleration_structure: Id, instance_id: Id, primitive_id: Id, geometry_index: Id, hit_kind: Id, sbt_record_index: Id, origin: Id, t_min: Id, direction: Id, t_max: Id, current_time: Id, hit_object_attributes: Id }, .OpHitObjectRecordMissMotionNV => struct { hit_object: Id, sbt_index: Id, origin: Id, t_min: Id, direction: Id, t_max: Id, current_time: Id }, @@ -2534,7 +2637,7 @@ pub const Opcode = enum(u16) { .OpReorderThreadWithHintNV => struct { hint: Id, bits: Id }, .OpTypeHitObjectNV => struct { id_result: Id }, .OpImageSampleFootprintNV => struct { id_result_type: Id, id_result: Id, sampled_image: Id, coordinate: Id, granularity: Id, coarse: Id, image_operands: ?ImageOperands.Extended = null }, - .OpTypeCooperativeVectorNV => struct { id_result: Id, component_type: Id, component_count: Id }, + .OpTypeVectorIdEXT => struct { id_result: Id, component_type: Id, component_count: Id }, .OpCooperativeVectorMatrixMulNV => struct { id_result_type: Id, id_result: Id, input: Id, input_interpretation: Id, matrix: Id, matrix_offset: Id, matrix_interpretation: Id, m: Id, k: Id, memory_layout: Id, transpose: Id, matrix_stride: ?Id = null, cooperative_matrix_operands: ?CooperativeMatrixOperands = null }, .OpCooperativeVectorOuterProductAccumulateNV => struct { pointer: Id, offset: Id, a: Id, b: Id, memory_layout: Id, matrix_interpretation: Id, matrix_stride: ?Id = null }, .OpCooperativeVectorReduceSumAccumulateNV => struct { pointer: Id, offset: Id, v: Id }, @@ -2542,12 +2645,42 @@ pub const Opcode = enum(u16) { .OpCooperativeMatrixConvertNV => struct { id_result_type: Id, id_result: Id, matrix: Id }, .OpEmitMeshTasksEXT => struct { group_count_x: Id, group_count_y: Id, group_count_z: Id, payload: ?Id = null }, .OpSetMeshOutputsEXT => struct { vertex_count: Id, primitive_count: Id }, - .OpGroupNonUniformPartitionNV => struct { id_result_type: Id, id_result: Id, value: Id }, + .OpGroupNonUniformPartitionEXT => struct { id_result_type: Id, id_result: Id, value: Id }, .OpWritePackedPrimitiveIndices4x8NV => struct { index_offset: Id, packed_indices: Id }, .OpFetchMicroTriangleVertexPositionNV => struct { id_result_type: Id, id_result: Id, accel: Id, instance_id: Id, geometry_index: Id, primitive_index: Id, barycentric: Id }, .OpFetchMicroTriangleVertexBarycentricNV => struct { id_result_type: Id, id_result: Id, accel: Id, instance_id: Id, geometry_index: Id, primitive_index: Id, barycentric: Id }, .OpCooperativeVectorLoadNV => struct { id_result_type: Id, id_result: Id, pointer: Id, offset: Id, memory_access: ?MemoryAccess.Extended = null }, .OpCooperativeVectorStoreNV => struct { pointer: Id, offset: Id, object: Id, memory_access: ?MemoryAccess.Extended = null }, + .OpHitObjectRecordFromQueryEXT => struct { hit_object: Id, ray_query: Id, sbt_record_index: Id, hit_object_attributes: Id }, + .OpHitObjectRecordMissEXT => struct { hit_object: Id, ray_flags: Id, miss_index: Id, ray_origin: Id, ray_tmin: Id, ray_direction: Id, ray_tmax: Id }, + .OpHitObjectRecordMissMotionEXT => struct { hit_object: Id, ray_flags: Id, miss_index: Id, ray_origin: Id, ray_tmin: Id, ray_direction: Id, ray_tmax: Id, current_time: Id }, + .OpHitObjectGetIntersectionTriangleVertexPositionsEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetRayFlagsEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectSetShaderBindingTableRecordIndexEXT => struct { hit_object: Id, sbt_record_index: Id }, + .OpHitObjectReorderExecuteShaderEXT => struct { hit_object: Id, payload: Id, hint: ?Id = null, bits: ?Id = null }, + .OpHitObjectTraceReorderExecuteEXT => struct { hit_object: Id, acceleration_structure: Id, ray_flags: Id, cull_mask: Id, sbt_offset: Id, sbt_stride: Id, miss_index: Id, ray_origin: Id, ray_tmin: Id, ray_direction: Id, ray_tmax: Id, payload: Id, hint: ?Id = null, bits: ?Id = null }, + .OpHitObjectTraceMotionReorderExecuteEXT => struct { hit_object: Id, acceleration_structure: Id, ray_flags: Id, cull_mask: Id, sbt_offset: Id, sbt_stride: Id, miss_index: Id, ray_origin: Id, ray_tmin: Id, ray_direction: Id, ray_tmax: Id, current_time: Id, payload: Id, hint: ?Id = null, bits: ?Id = null }, + .OpTypeHitObjectEXT => struct { id_result: Id }, + .OpReorderThreadWithHintEXT => struct { hint: Id, bits: Id }, + .OpReorderThreadWithHitObjectEXT => struct { hit_object: Id, hint: ?Id = null, bits: ?Id = null }, + .OpHitObjectTraceRayEXT => struct { hit_object: Id, acceleration_structure: Id, ray_flags: Id, cull_mask: Id, sbt_offset: Id, sbt_stride: Id, miss_index: Id, ray_origin: Id, ray_tmin: Id, ray_direction: Id, ray_tmax: Id, payload: Id }, + .OpHitObjectTraceRayMotionEXT => struct { hit_object: Id, acceleration_structure: Id, ray_flags: Id, cull_mask: Id, sbt_offset: Id, sbt_stride: Id, miss_index: Id, ray_origin: Id, ray_tmin: Id, ray_direction: Id, ray_tmax: Id, current_time: Id, payload: Id }, + .OpHitObjectRecordEmptyEXT => struct { hit_object: Id }, + .OpHitObjectExecuteShaderEXT => struct { hit_object: Id, payload: Id }, + .OpHitObjectGetCurrentTimeEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetAttributesEXT => struct { hit_object: Id, hit_object_attribute: Id }, + .OpHitObjectGetHitKindEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetPrimitiveIndexEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetGeometryIndexEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetInstanceIdEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetInstanceCustomIndexEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetObjectRayOriginEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetObjectRayDirectionEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetWorldRayDirectionEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetWorldRayOriginEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetObjectToWorldEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetWorldToObjectEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetRayTMaxEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, .OpReportIntersectionKHR => struct { id_result_type: Id, id_result: Id, hit: Id, hit_kind: Id }, .OpIgnoreIntersectionNV => void, .OpTerminateRayNV => void, @@ -2557,8 +2690,14 @@ pub const Opcode = enum(u16) { .OpRayQueryGetIntersectionTriangleVertexPositionsKHR => struct { id_result_type: Id, id_result: Id, ray_query: Id, intersection: Id }, .OpTypeAccelerationStructureKHR => struct { id_result: Id }, .OpExecuteCallableNV => struct { sbt_index: Id, callable_data_id: Id }, - .OpRayQueryGetClusterIdNV => struct { id_result_type: Id, id_result: Id, ray_query: Id, intersection: Id }, + .OpRayQueryGetIntersectionClusterIdNV => struct { id_result_type: Id, id_result: Id, ray_query: Id, intersection: Id }, .OpHitObjectGetClusterIdNV => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetRayTMinEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetShaderBindingTableRecordIndexEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectGetShaderRecordBufferHandleEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectIsEmptyEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectIsHitEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, + .OpHitObjectIsMissEXT => struct { id_result_type: Id, id_result: Id, hit_object: Id }, .OpTypeCooperativeMatrixNV => struct { id_result: Id, component_type: Id, execution: Id, rows: Id, columns: Id }, .OpCooperativeMatrixLoadNV => struct { id_result_type: Id, id_result: Id, pointer: Id, stride: Id, column_major: Id, memory_access: ?MemoryAccess.Extended = null }, .OpCooperativeMatrixStoreNV => struct { pointer: Id, object: Id, stride: Id, column_major: Id, memory_access: ?MemoryAccess.Extended = null }, @@ -2636,10 +2775,10 @@ pub const Opcode = enum(u16) { .OpExpectKHR => struct { id_result_type: Id, id_result: Id, value: Id, expected_value: Id }, .OpDecorateString => struct { target: Id, decoration: Decoration.Extended }, .OpMemberDecorateString => struct { struct_type: Id, member: LiteralInteger, decoration: Decoration.Extended }, + .OpVariableLengthArrayINTEL => struct { id_result_type: Id, id_result: Id, length: Id }, + .OpSaveMemoryINTEL => struct { id_result_type: Id, id_result: Id }, + .OpRestoreMemoryINTEL => struct { ptr: Id }, .OpLoopControlINTEL => struct { loop_control_parameters: []const LiteralInteger = &.{} }, - .OpReadPipeBlockingINTEL => struct { id_result_type: Id, id_result: Id, packet_size: Id, packet_alignment: Id }, - .OpWritePipeBlockingINTEL => struct { id_result_type: Id, id_result: Id, packet_size: Id, packet_alignment: Id }, - .OpFPGARegINTEL => struct { id_result_type: Id, id_result: Id, input: Id }, .OpRayQueryGetRayTMinKHR => struct { id_result_type: Id, id_result: Id, ray_query: Id }, .OpRayQueryGetRayFlagsKHR => struct { id_result_type: Id, id_result: Id, ray_query: Id }, .OpRayQueryGetIntersectionTKHR => struct { id_result_type: Id, id_result: Id, ray_query: Id, intersection: Id }, @@ -2668,11 +2807,6 @@ pub const Opcode = enum(u16) { .OpControlBarrierArriveINTEL => struct { execution: Id, memory: Id, semantics: Id }, .OpControlBarrierWaitINTEL => struct { execution: Id, memory: Id, semantics: Id }, .OpArithmeticFenceEXT => struct { id_result_type: Id, id_result: Id, target: Id }, - .OpTaskSequenceCreateINTEL => struct { id_result_type: Id, id_result: Id, function: Id, pipelined: LiteralInteger, use_stall_enable_clusters: LiteralInteger, get_capacity: LiteralInteger, async_capacity: LiteralInteger }, - .OpTaskSequenceAsyncINTEL => struct { sequence: Id, arguments: []const Id = &.{} }, - .OpTaskSequenceGetINTEL => struct { id_result_type: Id, id_result: Id, sequence: Id }, - .OpTaskSequenceReleaseINTEL => struct { sequence: Id }, - .OpTypeTaskSequenceINTEL => struct { id_result: Id }, .OpSubgroupBlockPrefetchINTEL => struct { ptr: Id, num_bytes: Id, memory_access: ?MemoryAccess.Extended = null }, .OpSubgroup2DBlockLoadINTEL => struct { element_size: Id, block_width: Id, block_height: Id, block_count: Id, src_base_pointer: Id, memory_width: Id, memory_height: Id, memory_pitch: Id, coordinate: Id, dst_pointer: Id }, .OpSubgroup2DBlockLoadTransformINTEL => struct { element_size: Id, block_width: Id, block_height: Id, block_count: Id, src_base_pointer: Id, memory_width: Id, memory_height: Id, memory_pitch: Id, coordinate: Id, dst_pointer: Id }, @@ -2681,6 +2815,14 @@ pub const Opcode = enum(u16) { .OpSubgroup2DBlockStoreINTEL => struct { element_size: Id, block_width: Id, block_height: Id, block_count: Id, src_pointer: Id, dst_base_pointer: Id, memory_width: Id, memory_height: Id, memory_pitch: Id, coordinate: Id }, .OpSubgroupMatrixMultiplyAccumulateINTEL => struct { id_result_type: Id, id_result: Id, k_dim: Id, matrix_a: Id, matrix_b: Id, matrix_c: Id, matrix_multiply_accumulate_operands: ?MatrixMultiplyAccumulateOperands = null }, .OpBitwiseFunctionINTEL => struct { id_result_type: Id, id_result: Id, a: Id, b: Id, c: Id, lut_index: Id }, + .OpUntypedVariableLengthArrayINTEL => struct { id_result_type: Id, id_result: Id, element_type: Id, length: Id }, + .OpConditionalExtensionINTEL => struct { condition: Id, name: LiteralString }, + .OpConditionalEntryPointINTEL => struct { condition: Id, execution_model: ExecutionModel, entry_point: Id, name: LiteralString, interface: []const Id = &.{} }, + .OpConditionalCapabilityINTEL => struct { condition: Id, capability: Capability }, + .OpSpecConstantTargetINTEL => struct { id_result_type: Id, id_result: Id, target: LiteralInteger, features: []const LiteralInteger = &.{} }, + .OpSpecConstantArchitectureINTEL => struct { id_result_type: Id, id_result: Id, category: LiteralInteger, family: LiteralInteger, opcode: LiteralInteger, architecture: LiteralInteger }, + .OpSpecConstantCapabilitiesINTEL => struct { id_result_type: Id, id_result: Id, capabilities: []const Capability = &.{} }, + .OpConditionalCopyObjectINTEL => struct { id_result_type: Id, id_result: Id, id_ref: []const Id = &.{} }, .OpGroupIMulKHR => struct { id_result_type: Id, id_result: Id, execution: Id, operation: GroupOperation, x: Id }, .OpGroupFMulKHR => struct { id_result_type: Id, id_result: Id, execution: Id, operation: GroupOperation, x: Id }, .OpGroupBitwiseAndKHR => struct { id_result_type: Id, id_result: Id, execution: Id, operation: GroupOperation, x: Id }, @@ -2695,6 +2837,9 @@ pub const Opcode = enum(u16) { .OpConvertHandleToImageINTEL => struct { id_result_type: Id, id_result: Id, operand: Id }, .OpConvertHandleToSamplerINTEL => struct { id_result_type: Id, id_result: Id, operand: Id }, .OpConvertHandleToSampledImageINTEL => struct { id_result_type: Id, id_result: Id, operand: Id }, + .OpFDot2MixAcc32VALVE => struct { id_result_type: Id, id_result: Id, vector_1: Id, vector_2: Id, accumulator: Id }, + .OpFDot2MixAcc16VALVE => struct { id_result_type: Id, id_result: Id, vector_1: Id, vector_2: Id, accumulator: Id }, + .OpFDot4MixAcc32VALVE => struct { id_result_type: Id, id_result: Id, vector_1: Id, vector_2: Id, accumulator: Id }, }; } pub fn class(self: Opcode) Class { @@ -3068,12 +3213,14 @@ pub const Opcode = enum(u16) { .OpUntypedInBoundsPtrAccessChainKHR => .memory, .OpUntypedArrayLengthKHR => .memory, .OpUntypedPrefetchKHR => .memory, + .OpFmaKHR => .arithmetic, .OpSubgroupAllKHR => .group, .OpSubgroupAnyKHR => .group, .OpSubgroupAllEqualKHR => .group, .OpGroupNonUniformRotateKHR => .group, .OpSubgroupReadInvocationKHR => .group, .OpExtInstWithForwardRefsKHR => .extension, + .OpUntypedGroupAsyncCopyKHR => .group, .OpTraceRayKHR => .reserved, .OpExecuteCallableKHR => .reserved, .OpConvertUToAccelerationStructureKHR => .reserved, @@ -3104,10 +3251,14 @@ pub const Opcode = enum(u16) { .OpImageBoxFilterQCOM => .image, .OpImageBlockMatchSSDQCOM => .image, .OpImageBlockMatchSADQCOM => .image, + .OpBitCastArrayQCOM => .conversion, .OpImageBlockMatchWindowSSDQCOM => .image, .OpImageBlockMatchWindowSADQCOM => .image, .OpImageBlockMatchGatherSSDQCOM => .image, .OpImageBlockMatchGatherSADQCOM => .image, + .OpCompositeConstructCoopMatQCOM => .composite, + .OpCompositeExtractCoopMatQCOM => .composite, + .OpExtractSubArrayQCOM => .composite, .OpGroupIAddNonUniformAMD => .group, .OpGroupFAddNonUniformAMD => .group, .OpGroupFMinNonUniformAMD => .group, @@ -3129,6 +3280,16 @@ pub const Opcode = enum(u16) { .OpSpecConstantStringAMDX => .reserved, .OpGroupNonUniformQuadAllKHR => .non_uniform, .OpGroupNonUniformQuadAnyKHR => .non_uniform, + .OpTypeBufferEXT => .type_declaration, + .OpBufferPointerEXT => .memory, + .OpAbortKHR => .control_flow, + .OpUntypedImageTexelPointerEXT => .memory, + .OpMemberDecorateIdEXT => .annotation, + .OpConstantSizeOfEXT => .constant_creation, + .OpConstantDataKHR => .constant_creation, + .OpSpecConstantDataKHR => .constant_creation, + .OpPoisonKHR => .miscellaneous, + .OpFreezeKHR => .miscellaneous, .OpHitObjectRecordHitMotionNV => .reserved, .OpHitObjectRecordHitWithIndexMotionNV => .reserved, .OpHitObjectRecordMissMotionNV => .reserved, @@ -3163,7 +3324,7 @@ pub const Opcode = enum(u16) { .OpReorderThreadWithHintNV => .reserved, .OpTypeHitObjectNV => .type_declaration, .OpImageSampleFootprintNV => .image, - .OpTypeCooperativeVectorNV => .type_declaration, + .OpTypeVectorIdEXT => .type_declaration, .OpCooperativeVectorMatrixMulNV => .reserved, .OpCooperativeVectorOuterProductAccumulateNV => .reserved, .OpCooperativeVectorReduceSumAccumulateNV => .reserved, @@ -3171,12 +3332,42 @@ pub const Opcode = enum(u16) { .OpCooperativeMatrixConvertNV => .conversion, .OpEmitMeshTasksEXT => .reserved, .OpSetMeshOutputsEXT => .reserved, - .OpGroupNonUniformPartitionNV => .non_uniform, + .OpGroupNonUniformPartitionEXT => .non_uniform, .OpWritePackedPrimitiveIndices4x8NV => .reserved, .OpFetchMicroTriangleVertexPositionNV => .reserved, .OpFetchMicroTriangleVertexBarycentricNV => .reserved, .OpCooperativeVectorLoadNV => .memory, .OpCooperativeVectorStoreNV => .memory, + .OpHitObjectRecordFromQueryEXT => .reserved, + .OpHitObjectRecordMissEXT => .reserved, + .OpHitObjectRecordMissMotionEXT => .reserved, + .OpHitObjectGetIntersectionTriangleVertexPositionsEXT => .reserved, + .OpHitObjectGetRayFlagsEXT => .reserved, + .OpHitObjectSetShaderBindingTableRecordIndexEXT => .reserved, + .OpHitObjectReorderExecuteShaderEXT => .reserved, + .OpHitObjectTraceReorderExecuteEXT => .reserved, + .OpHitObjectTraceMotionReorderExecuteEXT => .reserved, + .OpTypeHitObjectEXT => .type_declaration, + .OpReorderThreadWithHintEXT => .reserved, + .OpReorderThreadWithHitObjectEXT => .reserved, + .OpHitObjectTraceRayEXT => .reserved, + .OpHitObjectTraceRayMotionEXT => .reserved, + .OpHitObjectRecordEmptyEXT => .reserved, + .OpHitObjectExecuteShaderEXT => .reserved, + .OpHitObjectGetCurrentTimeEXT => .reserved, + .OpHitObjectGetAttributesEXT => .reserved, + .OpHitObjectGetHitKindEXT => .reserved, + .OpHitObjectGetPrimitiveIndexEXT => .reserved, + .OpHitObjectGetGeometryIndexEXT => .reserved, + .OpHitObjectGetInstanceIdEXT => .reserved, + .OpHitObjectGetInstanceCustomIndexEXT => .reserved, + .OpHitObjectGetObjectRayOriginEXT => .reserved, + .OpHitObjectGetObjectRayDirectionEXT => .reserved, + .OpHitObjectGetWorldRayDirectionEXT => .reserved, + .OpHitObjectGetWorldRayOriginEXT => .reserved, + .OpHitObjectGetObjectToWorldEXT => .reserved, + .OpHitObjectGetWorldToObjectEXT => .reserved, + .OpHitObjectGetRayTMaxEXT => .reserved, .OpReportIntersectionKHR => .reserved, .OpIgnoreIntersectionNV => .reserved, .OpTerminateRayNV => .reserved, @@ -3186,8 +3377,14 @@ pub const Opcode = enum(u16) { .OpRayQueryGetIntersectionTriangleVertexPositionsKHR => .reserved, .OpTypeAccelerationStructureKHR => .type_declaration, .OpExecuteCallableNV => .reserved, - .OpRayQueryGetClusterIdNV => .reserved, + .OpRayQueryGetIntersectionClusterIdNV => .reserved, .OpHitObjectGetClusterIdNV => .reserved, + .OpHitObjectGetRayTMinEXT => .reserved, + .OpHitObjectGetShaderBindingTableRecordIndexEXT => .reserved, + .OpHitObjectGetShaderRecordBufferHandleEXT => .reserved, + .OpHitObjectIsEmptyEXT => .reserved, + .OpHitObjectIsHitEXT => .reserved, + .OpHitObjectIsMissEXT => .reserved, .OpTypeCooperativeMatrixNV => .type_declaration, .OpCooperativeMatrixLoadNV => .reserved, .OpCooperativeMatrixStoreNV => .reserved, @@ -3265,10 +3462,10 @@ pub const Opcode = enum(u16) { .OpExpectKHR => .miscellaneous, .OpDecorateString => .annotation, .OpMemberDecorateString => .annotation, + .OpVariableLengthArrayINTEL => .memory, + .OpSaveMemoryINTEL => .memory, + .OpRestoreMemoryINTEL => .memory, .OpLoopControlINTEL => .reserved, - .OpReadPipeBlockingINTEL => .pipe, - .OpWritePipeBlockingINTEL => .pipe, - .OpFPGARegINTEL => .reserved, .OpRayQueryGetRayTMinKHR => .reserved, .OpRayQueryGetRayFlagsKHR => .reserved, .OpRayQueryGetIntersectionTKHR => .reserved, @@ -3297,11 +3494,6 @@ pub const Opcode = enum(u16) { .OpControlBarrierArriveINTEL => .barrier, .OpControlBarrierWaitINTEL => .barrier, .OpArithmeticFenceEXT => .miscellaneous, - .OpTaskSequenceCreateINTEL => .reserved, - .OpTaskSequenceAsyncINTEL => .reserved, - .OpTaskSequenceGetINTEL => .reserved, - .OpTaskSequenceReleaseINTEL => .reserved, - .OpTypeTaskSequenceINTEL => .type_declaration, .OpSubgroupBlockPrefetchINTEL => .group, .OpSubgroup2DBlockLoadINTEL => .group, .OpSubgroup2DBlockLoadTransformINTEL => .group, @@ -3310,6 +3502,14 @@ pub const Opcode = enum(u16) { .OpSubgroup2DBlockStoreINTEL => .group, .OpSubgroupMatrixMultiplyAccumulateINTEL => .group, .OpBitwiseFunctionINTEL => .bit, + .OpUntypedVariableLengthArrayINTEL => .memory, + .OpConditionalExtensionINTEL => .extension, + .OpConditionalEntryPointINTEL => .mode_setting, + .OpConditionalCapabilityINTEL => .mode_setting, + .OpSpecConstantTargetINTEL => .constant_creation, + .OpSpecConstantArchitectureINTEL => .constant_creation, + .OpSpecConstantCapabilitiesINTEL => .constant_creation, + .OpConditionalCopyObjectINTEL => .composite, .OpGroupIMulKHR => .group, .OpGroupFMulKHR => .group, .OpGroupBitwiseAndKHR => .group, @@ -3324,94 +3524,13 @@ pub const Opcode = enum(u16) { .OpConvertHandleToImageINTEL => .image, .OpConvertHandleToSamplerINTEL => .image, .OpConvertHandleToSampledImageINTEL => .image, + .OpFDot2MixAcc32VALVE => .reserved, + .OpFDot2MixAcc16VALVE => .reserved, + .OpFDot4MixAcc32VALVE => .reserved, }; } }; -pub const GlslOpcode = enum(u16) { - Round = 1, - RoundEven = 2, - Trunc = 3, - FAbs = 4, - SAbs = 5, - FSign = 6, - SSign = 7, - Floor = 8, - Ceil = 9, - Fract = 10, - Radians = 11, - Degrees = 12, - Sin = 13, - Cos = 14, - Tan = 15, - Asin = 16, - Acos = 17, - Atan = 18, - Sinh = 19, - Cosh = 20, - Tanh = 21, - Asinh = 22, - Acosh = 23, - Atanh = 24, - Atan2 = 25, - Pow = 26, - Exp = 27, - Log = 28, - Exp2 = 29, - Log2 = 30, - Sqrt = 31, - InverseSqrt = 32, - Determinant = 33, - MatrixInverse = 34, - Modf = 35, - ModfStruct = 36, - FMin = 37, - UMin = 38, - SMin = 39, - FMax = 40, - UMax = 41, - SMax = 42, - FClamp = 43, - UClamp = 44, - SClamp = 45, - FMix = 46, - IMix = 47, - Step = 48, - SmoothStep = 49, - Fma = 50, - Frexp = 51, - FrexpStruct = 52, - Ldexp = 53, - PackSnorm4x8 = 54, - PackUnorm4x8 = 55, - PackSnorm2x16 = 56, - PackUnorm2x16 = 57, - PackHalf2x16 = 58, - PackDouble2x32 = 59, - UnpackSnorm2x16 = 60, - UnpackUnorm2x16 = 61, - UnpackHalf2x16 = 62, - UnpackSnorm4x8 = 63, - UnpackUnorm4x8 = 64, - UnpackDouble2x32 = 65, - Length = 66, - Distance = 67, - Cross = 68, - Normalize = 69, - FaceForward = 70, - Reflect = 71, - Refract = 72, - FindILsb = 73, - FindSMsb = 74, - FindUMsb = 75, - InterpolateAtCentroid = 76, - InterpolateAtSample = 77, - InterpolateAtOffset = 78, - NMin = 79, - NMax = 80, - NClamp = 81, -}; - pub const OpenClOpcode = enum(u16) { acos = 0, acosh = 1, @@ -3577,6 +3696,90 @@ pub const OpenClOpcode = enum(u16) { u_mad_hi = 204, }; +pub const GlslOpcode = enum(u16) { + Round = 1, + RoundEven = 2, + Trunc = 3, + FAbs = 4, + SAbs = 5, + FSign = 6, + SSign = 7, + Floor = 8, + Ceil = 9, + Fract = 10, + Radians = 11, + Degrees = 12, + Sin = 13, + Cos = 14, + Tan = 15, + Asin = 16, + Acos = 17, + Atan = 18, + Sinh = 19, + Cosh = 20, + Tanh = 21, + Asinh = 22, + Acosh = 23, + Atanh = 24, + Atan2 = 25, + Pow = 26, + Exp = 27, + Log = 28, + Exp2 = 29, + Log2 = 30, + Sqrt = 31, + InverseSqrt = 32, + Determinant = 33, + MatrixInverse = 34, + Modf = 35, + ModfStruct = 36, + FMin = 37, + UMin = 38, + SMin = 39, + FMax = 40, + UMax = 41, + SMax = 42, + FClamp = 43, + UClamp = 44, + SClamp = 45, + FMix = 46, + IMix = 47, + Step = 48, + SmoothStep = 49, + Fma = 50, + Frexp = 51, + FrexpStruct = 52, + Ldexp = 53, + PackSnorm4x8 = 54, + PackUnorm4x8 = 55, + PackSnorm2x16 = 56, + PackUnorm2x16 = 57, + PackHalf2x16 = 58, + PackDouble2x32 = 59, + UnpackSnorm2x16 = 60, + UnpackUnorm2x16 = 61, + UnpackHalf2x16 = 62, + UnpackSnorm4x8 = 63, + UnpackUnorm4x8 = 64, + UnpackDouble2x32 = 65, + Length = 66, + Distance = 67, + Cross = 68, + Normalize = 69, + FaceForward = 70, + Reflect = 71, + Refract = 72, + FindILsb = 73, + FindSMsb = 74, + FindUMsb = 75, + InterpolateAtCentroid = 76, + InterpolateAtSample = 77, + InterpolateAtOffset = 78, + NMin = 79, + NMax = 80, + NClamp = 81, +}; + pub const Zig = enum(u16) { InvocationGlobal = 0, }; @@ -3734,16 +3937,16 @@ pub const LoopControl = packed struct { _reserved_bit_13: bool = false, _reserved_bit_14: bool = false, _reserved_bit_15: bool = false, - initiation_interval_intel: bool = false, - max_concurrency_intel: bool = false, - dependency_array_intel: bool = false, - pipeline_enable_intel: bool = false, - loop_coalesce_intel: bool = false, - max_interleaving_intel: bool = false, - speculated_iterations_intel: bool = false, - no_fusion_intel: bool = false, - loop_count_intel: bool = false, - max_reinvocation_delay_intel: bool = false, + initiation_interval_altera: bool = false, + max_concurrency_altera: bool = false, + dependency_array_altera: bool = false, + pipeline_enable_altera: bool = false, + loop_coalesce_altera: bool = false, + max_interleaving_altera: bool = false, + speculated_iterations_altera: bool = false, + no_fusion_altera: bool = false, + loop_count_altera: bool = false, + max_reinvocation_delay_altera: bool = false, _reserved_bit_26: bool = false, _reserved_bit_27: bool = false, _reserved_bit_28: bool = false, @@ -3768,16 +3971,16 @@ pub const LoopControl = packed struct { _reserved_bit_13: bool = false, _reserved_bit_14: bool = false, _reserved_bit_15: bool = false, - initiation_interval_intel: ?struct { literal_integer: LiteralInteger } = null, - max_concurrency_intel: ?struct { literal_integer: LiteralInteger } = null, - dependency_array_intel: ?struct { literal_integer: LiteralInteger } = null, - pipeline_enable_intel: ?struct { literal_integer: LiteralInteger } = null, - loop_coalesce_intel: ?struct { literal_integer: LiteralInteger } = null, - max_interleaving_intel: ?struct { literal_integer: LiteralInteger } = null, - speculated_iterations_intel: ?struct { literal_integer: LiteralInteger } = null, - no_fusion_intel: bool = false, - loop_count_intel: ?struct { literal_integer: LiteralInteger } = null, - max_reinvocation_delay_intel: ?struct { literal_integer: LiteralInteger } = null, + initiation_interval_altera: ?struct { literal_integer: LiteralInteger } = null, + max_concurrency_altera: ?struct { literal_integer: LiteralInteger } = null, + dependency_array_altera: ?struct { literal_integer: LiteralInteger } = null, + pipeline_enable_altera: ?struct { literal_integer: LiteralInteger } = null, + loop_coalesce_altera: ?struct { literal_integer: LiteralInteger } = null, + max_interleaving_altera: ?struct { literal_integer: LiteralInteger } = null, + speculated_iterations_altera: ?struct { literal_integer: LiteralInteger } = null, + no_fusion_altera: bool = false, + loop_count_altera: ?struct { literal_integer: LiteralInteger } = null, + max_reinvocation_delay_altera: ?struct { literal_integer: LiteralInteger } = null, _reserved_bit_26: bool = false, _reserved_bit_27: bool = false, _reserved_bit_28: bool = false, @@ -4174,6 +4377,7 @@ pub const ExecutionMode = enum(u32) { quad_derivatives_khr = 5088, require_full_quads_khr = 5089, shares_input_with_amdx = 5102, + arithmetic_poison_khr = 5157, output_lines_ext = 5269, output_primitives_ext = 5270, derivative_group_quads_khr = 5289, @@ -4185,6 +4389,7 @@ pub const ExecutionMode = enum(u32) { sample_interlock_unordered_ext = 5369, shading_rate_interlock_ordered_ext = 5370, shading_rate_interlock_unordered_ext = 5371, + shader64bit_indexing_ext = 5427, shared_local_memory_size_intel = 5618, rounding_mode_rtpintel = 5620, rounding_mode_rtnintel = 5621, @@ -4272,6 +4477,7 @@ pub const ExecutionMode = enum(u32) { quad_derivatives_khr, require_full_quads_khr, shares_input_with_amdx: struct { node_name: Id, shader_index: Id }, + arithmetic_poison_khr, output_lines_ext, output_primitives_ext: struct { primitive_count: LiteralInteger }, derivative_group_quads_khr, @@ -4283,6 +4489,7 @@ pub const ExecutionMode = enum(u32) { sample_interlock_unordered_ext, shading_rate_interlock_ordered_ext, shading_rate_interlock_unordered_ext, + shader64bit_indexing_ext, shared_local_memory_size_intel: struct { size: LiteralInteger }, rounding_mode_rtpintel: struct { target_width: LiteralInteger }, rounding_mode_rtnintel: struct { target_width: LiteralInteger }, @@ -4329,9 +4536,10 @@ pub const StorageClass = enum(u32) { physical_storage_buffer = 5349, hit_object_attribute_nv = 5385, task_payload_workgroup_ext = 5402, + hit_object_attribute_ext = 5411, code_section_intel = 5605, - device_only_intel = 5936, - host_only_intel = 5937, + device_only_altera = 5936, + host_only_altera = 5937, }; pub const Dim = enum(u32) { @"1d" = 0, @@ -4503,7 +4711,7 @@ pub const FunctionParameterAttribute = enum(u32) { no_capture = 5, no_write = 6, no_read_write = 7, - runtime_aligned_intel = 5940, + runtime_aligned_altera = 5940, }; pub const Decoration = enum(u32) { relaxed_precision = 0, @@ -4568,6 +4776,9 @@ pub const Decoration = enum(u32) { payload_node_sparse_array_amdx = 5099, payload_node_array_size_amdx = 5100, payload_dispatch_indirect_amdx = 5105, + array_stride_id_ext = 5124, + offset_id_ext = 5125, + utf_encoded_khr = 5145, override_coverage_nv = 5248, passthrough_nv = 5250, viewport_relative_nv = 5252, @@ -4579,7 +4790,10 @@ pub const Decoration = enum(u32) { non_uniform = 5300, restrict_pointer = 5355, aliased_pointer = 5356, + member_offset_nv = 5358, hit_object_shader_record_buffer_nv = 5386, + hit_object_shader_record_buffer_ext = 5389, + bank_nv = 5397, bindless_sampler_nv = 5398, bindless_image_nv = 5399, bound_sampler_nv = 5400, @@ -4598,55 +4812,56 @@ pub const Decoration = enum(u32) { user_type_google = 5636, function_rounding_mode_intel = 5822, function_denorm_mode_intel = 5823, - register_intel = 5825, - memory_intel = 5826, - numbanks_intel = 5827, - bankwidth_intel = 5828, - max_private_copies_intel = 5829, - singlepump_intel = 5830, - doublepump_intel = 5831, - max_replicates_intel = 5832, - simple_dual_port_intel = 5833, - merge_intel = 5834, - bank_bits_intel = 5835, - force_pow2depth_intel = 5836, - stridesize_intel = 5883, - wordsize_intel = 5884, - true_dual_port_intel = 5885, - burst_coalesce_intel = 5899, - cache_size_intel = 5900, - dont_statically_coalesce_intel = 5901, - prefetch_intel = 5902, - stall_enable_intel = 5905, - fuse_loops_in_function_intel = 5907, - math_op_dsp_mode_intel = 5909, + register_altera = 5825, + memory_altera = 5826, + numbanks_altera = 5827, + bankwidth_altera = 5828, + max_private_copies_altera = 5829, + singlepump_altera = 5830, + doublepump_altera = 5831, + max_replicates_altera = 5832, + simple_dual_port_altera = 5833, + merge_altera = 5834, + bank_bits_altera = 5835, + force_pow2depth_altera = 5836, + stridesize_altera = 5883, + wordsize_altera = 5884, + true_dual_port_altera = 5885, + burst_coalesce_altera = 5899, + cache_size_altera = 5900, + dont_statically_coalesce_altera = 5901, + prefetch_altera = 5902, + stall_enable_altera = 5905, + fuse_loops_in_function_altera = 5907, + math_op_dsp_mode_altera = 5909, alias_scope_intel = 5914, no_alias_intel = 5915, - initiation_interval_intel = 5917, - max_concurrency_intel = 5918, - pipeline_enable_intel = 5919, - buffer_location_intel = 5921, - io_pipe_storage_intel = 5944, + initiation_interval_altera = 5917, + max_concurrency_altera = 5918, + pipeline_enable_altera = 5919, + buffer_location_altera = 5921, + io_pipe_storage_altera = 5944, function_floating_point_mode_intel = 6080, single_element_vector_intel = 6085, vector_compute_callable_function_intel = 6087, media_block_iointel = 6140, - stall_free_intel = 6151, + stall_free_altera = 6151, fp_max_error_decoration_intel = 6170, - latency_control_label_intel = 6172, - latency_control_constraint_intel = 6173, - conduit_kernel_argument_intel = 6175, - register_map_kernel_argument_intel = 6176, - mm_host_interface_address_width_intel = 6177, - mm_host_interface_data_width_intel = 6178, - mm_host_interface_latency_intel = 6179, - mm_host_interface_read_write_mode_intel = 6180, - mm_host_interface_max_burst_intel = 6181, - mm_host_interface_wait_request_intel = 6182, - stable_kernel_argument_intel = 6183, + latency_control_label_altera = 6172, + latency_control_constraint_altera = 6173, + conduit_kernel_argument_altera = 6175, + register_map_kernel_argument_altera = 6176, + mm_host_interface_address_width_altera = 6177, + mm_host_interface_data_width_altera = 6178, + mm_host_interface_latency_altera = 6179, + mm_host_interface_read_write_mode_altera = 6180, + mm_host_interface_max_burst_altera = 6181, + mm_host_interface_wait_request_altera = 6182, + stable_kernel_argument_altera = 6183, host_access_intel = 6188, - init_mode_intel = 6190, - implement_in_register_map_intel = 6191, + init_mode_altera = 6190, + implement_in_register_map_altera = 6191, + conditional_intel = 6247, cache_control_load_intel = 6442, cache_control_store_intel = 6443, @@ -4713,6 +4928,9 @@ pub const Decoration = enum(u32) { payload_node_sparse_array_amdx, payload_node_array_size_amdx: struct { array_size: Id }, payload_dispatch_indirect_amdx, + array_stride_id_ext: struct { array_stride: Id }, + offset_id_ext: struct { byte_offset: Id }, + utf_encoded_khr, override_coverage_nv, passthrough_nv, viewport_relative_nv, @@ -4724,7 +4942,10 @@ pub const Decoration = enum(u32) { non_uniform, restrict_pointer, aliased_pointer, + member_offset_nv: struct { member_offset: LiteralInteger }, hit_object_shader_record_buffer_nv, + hit_object_shader_record_buffer_ext, + bank_nv: struct { bank: LiteralInteger }, bindless_sampler_nv, bindless_image_nv, bound_sampler_nv, @@ -4743,55 +4964,56 @@ pub const Decoration = enum(u32) { user_type_google: struct { user_type: LiteralString }, function_rounding_mode_intel: struct { target_width: LiteralInteger, fp_rounding_mode: FPRoundingMode }, function_denorm_mode_intel: struct { target_width: LiteralInteger, fp_denorm_mode: FPDenormMode }, - register_intel, - memory_intel: struct { memory_type: LiteralString }, - numbanks_intel: struct { banks: LiteralInteger }, - bankwidth_intel: struct { bank_width: LiteralInteger }, - max_private_copies_intel: struct { maximum_copies: LiteralInteger }, - singlepump_intel, - doublepump_intel, - max_replicates_intel: struct { maximum_replicates: LiteralInteger }, - simple_dual_port_intel, - merge_intel: struct { merge_key: LiteralString, merge_type: LiteralString }, - bank_bits_intel: struct { bank_bits: []const LiteralInteger = &.{} }, - force_pow2depth_intel: struct { force_key: LiteralInteger }, - stridesize_intel: struct { stride_size: LiteralInteger }, - wordsize_intel: struct { word_size: LiteralInteger }, - true_dual_port_intel, - burst_coalesce_intel, - cache_size_intel: struct { cache_size_in_bytes: LiteralInteger }, - dont_statically_coalesce_intel, - prefetch_intel: struct { prefetcher_size_in_bytes: LiteralInteger }, - stall_enable_intel, - fuse_loops_in_function_intel, - math_op_dsp_mode_intel: struct { mode: LiteralInteger, propagate: LiteralInteger }, + register_altera, + memory_altera: struct { memory_type: LiteralString }, + numbanks_altera: struct { banks: LiteralInteger }, + bankwidth_altera: struct { bank_width: LiteralInteger }, + max_private_copies_altera: struct { maximum_copies: LiteralInteger }, + singlepump_altera, + doublepump_altera, + max_replicates_altera: struct { maximum_replicates: LiteralInteger }, + simple_dual_port_altera, + merge_altera: struct { merge_key: LiteralString, merge_type: LiteralString }, + bank_bits_altera: struct { bank_bits: []const LiteralInteger = &.{} }, + force_pow2depth_altera: struct { force_key: LiteralInteger }, + stridesize_altera: struct { stride_size: LiteralInteger }, + wordsize_altera: struct { word_size: LiteralInteger }, + true_dual_port_altera, + burst_coalesce_altera, + cache_size_altera: struct { cache_size_in_bytes: LiteralInteger }, + dont_statically_coalesce_altera, + prefetch_altera: struct { prefetcher_size_in_bytes: LiteralInteger }, + stall_enable_altera, + fuse_loops_in_function_altera, + math_op_dsp_mode_altera: struct { mode: LiteralInteger, propagate: LiteralInteger }, alias_scope_intel: struct { aliasing_scopes_list: Id }, no_alias_intel: struct { aliasing_scopes_list: Id }, - initiation_interval_intel: struct { cycles: LiteralInteger }, - max_concurrency_intel: struct { invocations: LiteralInteger }, - pipeline_enable_intel: struct { enable: LiteralInteger }, - buffer_location_intel: struct { buffer_location_id: LiteralInteger }, - io_pipe_storage_intel: struct { io_pipe_id: LiteralInteger }, + initiation_interval_altera: struct { cycles: LiteralInteger }, + max_concurrency_altera: struct { invocations: LiteralInteger }, + pipeline_enable_altera: struct { enable: LiteralInteger }, + buffer_location_altera: struct { buffer_location_id: LiteralInteger }, + io_pipe_storage_altera: struct { io_pipe_id: LiteralInteger }, function_floating_point_mode_intel: struct { target_width: LiteralInteger, fp_operation_mode: FPOperationMode }, single_element_vector_intel, vector_compute_callable_function_intel, media_block_iointel, - stall_free_intel, + stall_free_altera, fp_max_error_decoration_intel: struct { max_error: LiteralFloat }, - latency_control_label_intel: struct { latency_label: LiteralInteger }, - latency_control_constraint_intel: struct { relative_to: LiteralInteger, control_type: LiteralInteger, relative_cycle: LiteralInteger }, - conduit_kernel_argument_intel, - register_map_kernel_argument_intel, - mm_host_interface_address_width_intel: struct { address_width: LiteralInteger }, - mm_host_interface_data_width_intel: struct { data_width: LiteralInteger }, - mm_host_interface_latency_intel: struct { latency: LiteralInteger }, - mm_host_interface_read_write_mode_intel: struct { read_write_mode: AccessQualifier }, - mm_host_interface_max_burst_intel: struct { max_burst_count: LiteralInteger }, - mm_host_interface_wait_request_intel: struct { waitrequest: LiteralInteger }, - stable_kernel_argument_intel, + latency_control_label_altera: struct { latency_label: LiteralInteger }, + latency_control_constraint_altera: struct { relative_to: LiteralInteger, control_type: LiteralInteger, relative_cycle: LiteralInteger }, + conduit_kernel_argument_altera, + register_map_kernel_argument_altera, + mm_host_interface_address_width_altera: struct { address_width: LiteralInteger }, + mm_host_interface_data_width_altera: struct { data_width: LiteralInteger }, + mm_host_interface_latency_altera: struct { latency: LiteralInteger }, + mm_host_interface_read_write_mode_altera: struct { read_write_mode: AccessQualifier }, + mm_host_interface_max_burst_altera: struct { max_burst_count: LiteralInteger }, + mm_host_interface_wait_request_altera: struct { waitrequest: LiteralInteger }, + stable_kernel_argument_altera, host_access_intel: struct { access: HostAccessQualifier, name: LiteralString }, - init_mode_intel: struct { trigger: InitializationModeQualifier }, - implement_in_register_map_intel: struct { value: LiteralInteger }, + init_mode_altera: struct { trigger: InitializationModeQualifier }, + implement_in_register_map_altera: struct { value: LiteralInteger }, + conditional_intel: struct { condition: Id }, cache_control_load_intel: struct { cache_level: LiteralInteger, cache_control: LoadCacheControl }, cache_control_store_intel: struct { cache_level: LiteralInteger, cache_control: StoreCacheControl }, }; @@ -4868,6 +5090,8 @@ pub const BuiltIn = enum(u32) { frag_stencil_ref_ext = 5014, remaining_recursion_levels_amdx = 5021, shader_index_amdx = 5073, + sampler_heap_ext = 5122, + resource_heap_ext = 5123, viewport_mask_nv = 5253, secondary_position_nv = 5257, secondary_viewport_mask_nv = 5258, @@ -4938,9 +5162,9 @@ pub const GroupOperation = enum(u32) { inclusive_scan = 1, exclusive_scan = 2, clustered_reduce = 3, - partitioned_reduce_nv = 6, - partitioned_inclusive_scan_nv = 7, - partitioned_exclusive_scan_nv = 8, + partitioned_reduce_ext = 6, + partitioned_inclusive_scan_ext = 7, + partitioned_exclusive_scan_ext = 8, }; pub const KernelEnqueueFlags = enum(u32) { no_wait = 0, @@ -4989,8 +5213,6 @@ pub const Capability = enum(u32) { input_attachment = 40, sparse_residency = 41, min_lod = 42, - sampled1d = 43, - image1d = 44, sampled_cube_array = 45, sampled_buffer = 46, image_buffer = 47, @@ -5018,15 +5240,9 @@ pub const Capability = enum(u32) { shader_layer = 69, shader_viewport_index = 70, uniform_decoration = 71, - core_builtins_arm = 4165, tile_image_color_read_access_ext = 4166, tile_image_depth_read_access_ext = 4167, tile_image_stencil_read_access_ext = 4168, - tensors_arm = 4174, - storage_tensor_array_dynamic_indexing_arm = 4175, - storage_tensor_array_non_uniform_indexing_arm = 4176, - graph_arm = 4191, - cooperative_matrix_layouts_arm = 4201, float8ext = 4212, float8cooperative_matrix_ext = 4213, fragment_shading_rate_khr = 4422, @@ -5052,46 +5268,29 @@ pub const Capability = enum(u32) { denorm_preserve = 4464, denorm_flush_to_zero = 4465, signed_zero_inf_nan_preserve = 4466, - rounding_mode_rte = 4467, - rounding_mode_rtz = 4468, ray_query_provisional_khr = 4471, ray_query_khr = 4472, untyped_pointers_khr = 4473, ray_traversal_primitive_culling_khr = 4478, ray_tracing_khr = 4479, - texture_sample_weighted_qcom = 4484, - texture_box_filter_qcom = 4485, - texture_block_match_qcom = 4486, - tile_shading_qcom = 4495, - texture_block_match2qcom = 4498, - float16image_amd = 5008, - image_gather_bias_lod_amd = 5009, - fragment_mask_amd = 5010, stencil_export_ext = 5013, - image_read_write_lod_amd = 5015, int64image_ext = 5016, shader_clock_khr = 5055, - shader_enqueue_amdx = 5067, quad_control_khr = 5087, - int4type_intel = 5112, - int4cooperative_matrix_intel = 5114, b_float16type_khr = 5116, b_float16dot_product_khr = 5117, b_float16cooperative_matrix_khr = 5118, - sample_mask_override_coverage_nv = 5249, - geometry_shader_passthrough_nv = 5251, + abort_khr = 5120, + descriptor_heap_ext = 5128, + constant_data_khr = 5146, + poison_freeze_khr = 5156, shader_viewport_index_layer_ext = 5254, - shader_viewport_mask_nv = 5255, - shader_stereo_view_nv = 5259, - per_view_attributes_nv = 5260, fragment_fully_covered_ext = 5265, - mesh_shading_nv = 5266, - image_footprint_nv = 5282, mesh_shading_ext = 5283, fragment_barycentric_khr = 5284, compute_derivative_group_quads_khr = 5288, fragment_density_ext = 5291, - group_non_uniform_partitioned_nv = 5297, + group_non_uniform_partitioned_ext = 5297, shader_non_uniform = 5301, runtime_descriptor_array = 5302, input_attachment_array_dynamic_indexing = 5303, @@ -5105,80 +5304,24 @@ pub const Capability = enum(u32) { uniform_texel_buffer_array_non_uniform_indexing = 5311, storage_texel_buffer_array_non_uniform_indexing = 5312, ray_tracing_position_fetch_khr = 5336, - ray_tracing_nv = 5340, - ray_tracing_motion_blur_nv = 5341, vulkan_memory_model = 5345, vulkan_memory_model_device_scope = 5346, physical_storage_buffer_addresses = 5347, compute_derivative_group_linear_khr = 5350, ray_tracing_provisional_khr = 5353, - cooperative_matrix_nv = 5357, fragment_shader_sample_interlock_ext = 5363, fragment_shader_shading_rate_interlock_ext = 5372, - shader_sm_builtins_nv = 5373, fragment_shader_pixel_interlock_ext = 5378, demote_to_helper_invocation = 5379, - displacement_micromap_nv = 5380, ray_tracing_opacity_micromap_ext = 5381, - shader_invocation_reorder_nv = 5383, - bindless_texture_nv = 5390, + shader_invocation_reorder_ext = 5388, ray_query_position_fetch_khr = 5391, - cooperative_vector_nv = 5394, - atomic_float16vector_nv = 5404, - ray_tracing_displacement_micromap_nv = 5409, - raw_access_chains_nv = 5414, - ray_tracing_spheres_geometry_nv = 5418, - ray_tracing_linear_swept_spheres_geometry_nv = 5419, - cooperative_matrix_reductions_nv = 5430, - cooperative_matrix_conversions_nv = 5431, - cooperative_matrix_per_element_operations_nv = 5432, - cooperative_matrix_tensor_addressing_nv = 5433, - cooperative_matrix_block_loads_nv = 5434, - cooperative_vector_training_nv = 5435, - ray_tracing_cluster_acceleration_structure_nv = 5437, - tensor_addressing_nv = 5439, - subgroup_shuffle_intel = 5568, - subgroup_buffer_block_iointel = 5569, - subgroup_image_block_iointel = 5570, - subgroup_image_media_block_iointel = 5579, - round_to_infinity_intel = 5582, - floating_point_mode_intel = 5583, - integer_functions2intel = 5584, - function_pointers_intel = 5603, - indirect_references_intel = 5604, - asm_intel = 5606, + long_vector_ext = 5425, + shader64bit_indexing_ext = 5426, atomic_float32min_max_ext = 5612, atomic_float64min_max_ext = 5613, atomic_float16min_max_ext = 5616, - vector_compute_intel = 5617, - vector_any_intel = 5619, expect_assume_khr = 5629, - subgroup_avc_motion_estimation_intel = 5696, - subgroup_avc_motion_estimation_intra_intel = 5697, - subgroup_avc_motion_estimation_chroma_intel = 5698, - variable_length_array_intel = 5817, - function_float_control_intel = 5821, - fpga_memory_attributes_intel = 5824, - fp_fast_math_mode_intel = 5837, - arbitrary_precision_integers_intel = 5844, - arbitrary_precision_floating_point_intel = 5845, - unstructured_loop_controls_intel = 5886, - fpga_loop_controls_intel = 5888, - kernel_attributes_intel = 5892, - fpga_kernel_attributes_intel = 5897, - fpga_memory_accesses_intel = 5898, - fpga_cluster_attributes_intel = 5904, - loop_fuse_intel = 5906, - fpgadsp_control_intel = 5908, - memory_access_aliasing_intel = 5910, - fpga_invocation_pipelining_attributes_intel = 5916, - fpga_buffer_location_intel = 5920, - arbitrary_precision_fixed_point_intel = 5922, - usm_storage_classes_intel = 5935, - runtime_aligned_attribute_intel = 5939, - io_pipes_intel = 5943, - blocking_pipes_intel = 5945, - fpga_reg_intel = 5948, dot_product_input_all = 6016, dot_product_input4x8bit = 6017, dot_product_input4x8bit_packed = 6018, @@ -5189,35 +5332,620 @@ pub const Capability = enum(u32) { bit_instructions = 6025, group_non_uniform_rotate_khr = 6026, float_controls2 = 6029, + fmakhr = 6030, atomic_float32add_ext = 6033, atomic_float64add_ext = 6034, - long_composites_intel = 6089, opt_none_ext = 6094, atomic_float16add_ext = 6095, - debug_info_module_intel = 6114, - b_float16conversion_intel = 6115, - split_barrier_intel = 6141, arithmetic_fence_ext = 6144, - fpga_cluster_attributes_v2intel = 6150, - fpga_kernel_attributesv2intel = 6161, - task_sequence_intel = 6162, - fp_max_error_intel = 6169, - fpga_latency_control_intel = 6171, - fpga_argument_interfaces_intel = 6174, - global_variable_host_access_intel = 6187, - global_variable_fpga_decorations_intel = 6189, - subgroup_buffer_prefetch_intel = 6220, - subgroup2d_block_iointel = 6228, - subgroup2d_block_transform_intel = 6229, - subgroup2d_block_transpose_intel = 6230, - subgroup_matrix_multiply_accumulate_intel = 6236, - ternary_bitwise_function_intel = 6241, group_uniform_arithmetic_khr = 6400, - tensor_float32rounding_intel = 6425, - masked_gather_scatter_intel = 6427, - cache_controls_intel = 6441, - register_limits_intel = 6460, - bindless_images_intel = 6528, + + pub fn dependencies(self: Capability) []const Extension { + return switch (self) { + .matrix => &.{ + .v1_0, + }, + .shader => &.{ + .v1_0, + }, + .geometry => &.{ + .v1_0, + }, + .tessellation => &.{ + .v1_0, + }, + .addresses => &.{ + .v1_0, + }, + .linkage => &.{ + .v1_0, + }, + .kernel => &.{ + .v1_0, + }, + .vector16 => &.{ + .v1_0, + }, + .float16buffer => &.{ + .v1_0, + }, + .float16 => &.{ + .v1_0, + }, + .float64 => &.{ + .v1_0, + }, + .int64 => &.{ + .v1_0, + }, + .int64atomics => &.{ + .v1_0, + }, + .image_basic => &.{ + .v1_0, + }, + .image_read_write => &.{ + .v1_0, + }, + .image_mipmap => &.{ + .v1_0, + }, + .pipes => &.{ + .v1_0, + }, + .groups => &.{ + .v1_0, + }, + .device_enqueue => &.{ + .v1_0, + }, + .literal_sampler => &.{ + .v1_0, + }, + .atomic_storage => &.{ + .v1_0, + }, + .int16 => &.{ + .v1_0, + }, + .tessellation_point_size => &.{ + .v1_0, + }, + .geometry_point_size => &.{ + .v1_0, + }, + .image_gather_extended => &.{ + .v1_0, + }, + .storage_image_multisample => &.{ + .v1_0, + }, + .uniform_buffer_array_dynamic_indexing => &.{ + .v1_0, + }, + .sampled_image_array_dynamic_indexing => &.{ + .v1_0, + }, + .storage_buffer_array_dynamic_indexing => &.{ + .v1_0, + }, + .storage_image_array_dynamic_indexing => &.{ + .v1_0, + }, + .clip_distance => &.{ + .v1_0, + }, + .cull_distance => &.{ + .v1_0, + }, + .image_cube_array => &.{ + .v1_0, + }, + .sample_rate_shading => &.{ + .v1_0, + }, + .image_rect => &.{ + .v1_0, + }, + .sampled_rect => &.{ + .v1_0, + }, + .generic_pointer => &.{ + .v1_0, + }, + .int8 => &.{ + .v1_0, + }, + .input_attachment => &.{ + .v1_0, + }, + .sparse_residency => &.{ + .v1_0, + }, + .min_lod => &.{ + .v1_0, + }, + .sampled_cube_array => &.{ + .v1_0, + }, + .sampled_buffer => &.{ + .v1_0, + }, + .image_buffer => &.{ + .v1_0, + }, + .image_ms_array => &.{ + .v1_0, + }, + .storage_image_extended_formats => &.{ + .v1_0, + }, + .image_query => &.{ + .v1_0, + }, + .derivative_control => &.{ + .v1_0, + }, + .interpolation_function => &.{ + .v1_0, + }, + .transform_feedback => &.{ + .v1_0, + }, + .geometry_streams => &.{ + .v1_0, + }, + .storage_image_read_without_format => &.{ + .v1_0, + }, + .storage_image_write_without_format => &.{ + .v1_0, + }, + .multi_viewport => &.{ + .v1_0, + }, + .subgroup_dispatch => &.{ + .v1_1, + }, + .named_barrier => &.{ + .v1_1, + }, + .pipe_storage => &.{ + .v1_1, + }, + .group_non_uniform => &.{ + .v1_3, + }, + .group_non_uniform_vote => &.{ + .v1_3, + }, + .group_non_uniform_arithmetic => &.{ + .v1_3, + }, + .group_non_uniform_ballot => &.{ + .v1_3, + }, + .group_non_uniform_shuffle => &.{ + .v1_3, + }, + .group_non_uniform_shuffle_relative => &.{ + .v1_3, + }, + .group_non_uniform_clustered => &.{ + .v1_3, + }, + .group_non_uniform_quad => &.{ + .v1_3, + }, + .shader_layer => &.{ + .v1_5, + }, + .shader_viewport_index => &.{ + .v1_5, + }, + .uniform_decoration => &.{ + .v1_6, + }, + .tile_image_color_read_access_ext => &.{ + .v1_0, + .SPV_EXT_shader_tile_image, + }, + .tile_image_depth_read_access_ext => &.{ + .v1_0, + .SPV_EXT_shader_tile_image, + }, + .tile_image_stencil_read_access_ext => &.{ + .v1_0, + .SPV_EXT_shader_tile_image, + }, + .float8ext => &.{ + .v1_0, + .SPV_EXT_float8, + }, + .float8cooperative_matrix_ext => &.{ + .v1_0, + .SPV_EXT_float8, + }, + .fragment_shading_rate_khr => &.{ + .v1_0, + .SPV_KHR_fragment_shading_rate, + }, + .subgroup_ballot_khr => &.{ + .v1_0, + .SPV_KHR_shader_ballot, + }, + .draw_parameters => &.{ + .v1_3, + .SPV_KHR_shader_draw_parameters, + }, + .workgroup_memory_explicit_layout_khr => &.{ + .v1_0, + .SPV_KHR_workgroup_memory_explicit_layout, + }, + .workgroup_memory_explicit_layout8bit_access_khr => &.{ + .v1_0, + .SPV_KHR_workgroup_memory_explicit_layout, + }, + .workgroup_memory_explicit_layout16bit_access_khr => &.{ + .v1_0, + .SPV_KHR_workgroup_memory_explicit_layout, + }, + .subgroup_vote_khr => &.{ + .v1_0, + .SPV_KHR_subgroup_vote, + }, + .storage_buffer16bit_access => &.{ + .v1_3, + .SPV_KHR_16bit_storage, + }, + .uniform_and_storage_buffer16bit_access => &.{ + .v1_3, + .SPV_KHR_16bit_storage, + }, + .storage_push_constant16 => &.{ + .v1_3, + .SPV_KHR_16bit_storage, + }, + .storage_input_output16 => &.{ + .v1_3, + .SPV_KHR_16bit_storage, + }, + .device_group => &.{ + .v1_3, + .SPV_KHR_device_group, + }, + .multi_view => &.{ + .v1_3, + .SPV_KHR_multiview, + }, + .variable_pointers_storage_buffer => &.{ + .v1_3, + .SPV_KHR_variable_pointers, + }, + .variable_pointers => &.{ + .v1_3, + .SPV_KHR_variable_pointers, + }, + .atomic_storage_ops => &.{ + .v1_0, + .SPV_KHR_shader_atomic_counter_ops, + }, + .sample_mask_post_depth_coverage => &.{ + .v1_0, + .SPV_KHR_post_depth_coverage, + }, + .storage_buffer8bit_access => &.{ + .v1_5, + .SPV_KHR_8bit_storage, + }, + .uniform_and_storage_buffer8bit_access => &.{ + .v1_5, + .SPV_KHR_8bit_storage, + }, + .storage_push_constant8 => &.{ + .v1_5, + .SPV_KHR_8bit_storage, + }, + .denorm_preserve => &.{ + .v1_4, + .SPV_KHR_float_controls, + }, + .denorm_flush_to_zero => &.{ + .v1_4, + .SPV_KHR_float_controls, + }, + .signed_zero_inf_nan_preserve => &.{ + .v1_4, + .SPV_KHR_float_controls, + }, + .ray_query_provisional_khr => &.{ + .v1_0, + .SPV_KHR_ray_query, + }, + .ray_query_khr => &.{ + .v1_0, + .SPV_KHR_ray_query, + }, + .untyped_pointers_khr => &.{ + .v1_0, + .SPV_KHR_untyped_pointers, + }, + .ray_traversal_primitive_culling_khr => &.{ + .v1_0, + .SPV_KHR_ray_query, + .SPV_KHR_ray_tracing, + }, + .ray_tracing_khr => &.{ + .v1_0, + .SPV_KHR_ray_tracing, + }, + .stencil_export_ext => &.{ + .v1_0, + .SPV_EXT_shader_stencil_export, + }, + .int64image_ext => &.{ + .v1_0, + .SPV_EXT_shader_image_int64, + }, + .shader_clock_khr => &.{ + .v1_0, + .SPV_KHR_shader_clock, + }, + .quad_control_khr => &.{ + .v1_0, + .SPV_KHR_quad_control, + }, + .b_float16type_khr => &.{ + .v1_0, + .SPV_KHR_bfloat16, + }, + .b_float16dot_product_khr => &.{ + .v1_0, + .SPV_KHR_bfloat16, + }, + .b_float16cooperative_matrix_khr => &.{ + .v1_0, + .SPV_KHR_bfloat16, + }, + .abort_khr => &.{ + .v1_0, + .SPV_KHR_abort, + }, + .descriptor_heap_ext => &.{ + .v1_0, + .SPV_EXT_descriptor_heap, + }, + .constant_data_khr => &.{ + .v1_0, + .SPV_KHR_constant_data, + }, + .poison_freeze_khr => &.{ + .v1_0, + .SPV_KHR_poison_freeze, + }, + .shader_viewport_index_layer_ext => &.{ + .v1_0, + .SPV_EXT_shader_viewport_index_layer, + }, + .fragment_fully_covered_ext => &.{ + .v1_0, + .SPV_EXT_fragment_fully_covered, + }, + .mesh_shading_ext => &.{ + .v1_0, + .SPV_EXT_mesh_shader, + }, + .fragment_barycentric_khr => &.{ + .v1_0, + .SPV_KHR_fragment_shader_barycentric, + }, + .compute_derivative_group_quads_khr => &.{ + .v1_0, + .SPV_KHR_compute_shader_derivatives, + }, + .fragment_density_ext => &.{ + .v1_0, + .SPV_EXT_fragment_invocation_density, + }, + .group_non_uniform_partitioned_ext => &.{ + .v1_0, + .SPV_EXT_shader_subgroup_partitioned, + }, + .shader_non_uniform => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .runtime_descriptor_array => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .input_attachment_array_dynamic_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .uniform_texel_buffer_array_dynamic_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .storage_texel_buffer_array_dynamic_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .uniform_buffer_array_non_uniform_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .sampled_image_array_non_uniform_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .storage_buffer_array_non_uniform_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .storage_image_array_non_uniform_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .input_attachment_array_non_uniform_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .uniform_texel_buffer_array_non_uniform_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .storage_texel_buffer_array_non_uniform_indexing => &.{ + .v1_5, + .SPV_EXT_descriptor_indexing, + }, + .ray_tracing_position_fetch_khr => &.{ + .v1_0, + .SPV_KHR_ray_tracing_position_fetch, + }, + .vulkan_memory_model => &.{ + .v1_5, + .SPV_KHR_vulkan_memory_model, + }, + .vulkan_memory_model_device_scope => &.{ + .v1_5, + .SPV_KHR_vulkan_memory_model, + }, + .physical_storage_buffer_addresses => &.{ + .v1_5, + .SPV_EXT_physical_storage_buffer, + .SPV_KHR_physical_storage_buffer, + }, + .compute_derivative_group_linear_khr => &.{ + .v1_0, + .SPV_KHR_compute_shader_derivatives, + }, + .ray_tracing_provisional_khr => &.{ + .v1_0, + .SPV_KHR_ray_tracing, + }, + .fragment_shader_sample_interlock_ext => &.{ + .v1_0, + .SPV_EXT_fragment_shader_interlock, + }, + .fragment_shader_shading_rate_interlock_ext => &.{ + .v1_0, + .SPV_EXT_fragment_shader_interlock, + }, + .fragment_shader_pixel_interlock_ext => &.{ + .v1_0, + .SPV_EXT_fragment_shader_interlock, + }, + .demote_to_helper_invocation => &.{ + .v1_6, + .SPV_EXT_demote_to_helper_invocation, + }, + .ray_tracing_opacity_micromap_ext => &.{ + .v1_0, + .SPV_EXT_opacity_micromap, + }, + .shader_invocation_reorder_ext => &.{ + .v1_0, + .SPV_EXT_shader_invocation_reorder, + }, + .ray_query_position_fetch_khr => &.{ + .v1_0, + .SPV_KHR_ray_tracing_position_fetch, + }, + .long_vector_ext => &.{ + .v1_0, + .SPV_EXT_long_vector, + }, + .shader64bit_indexing_ext => &.{ + .v1_0, + .SPV_EXT_shader_64bit_indexing, + }, + .atomic_float32min_max_ext => &.{ + .v1_0, + .SPV_EXT_shader_atomic_float_min_max, + }, + .atomic_float64min_max_ext => &.{ + .v1_0, + .SPV_EXT_shader_atomic_float_min_max, + }, + .atomic_float16min_max_ext => &.{ + .v1_0, + .SPV_EXT_shader_atomic_float_min_max, + }, + .expect_assume_khr => &.{ + .v1_0, + .SPV_KHR_expect_assume, + }, + .dot_product_input_all => &.{ + .v1_6, + .SPV_KHR_integer_dot_product, + }, + .dot_product_input4x8bit => &.{ + .v1_6, + .SPV_KHR_integer_dot_product, + }, + .dot_product_input4x8bit_packed => &.{ + .v1_6, + .SPV_KHR_integer_dot_product, + }, + .dot_product => &.{ + .v1_6, + .SPV_KHR_integer_dot_product, + }, + .ray_cull_mask_khr => &.{ + .v1_0, + .SPV_KHR_ray_cull_mask, + }, + .cooperative_matrix_khr => &.{ + .v1_0, + .SPV_KHR_cooperative_matrix, + }, + .replicated_composites_ext => &.{ + .v1_0, + .SPV_EXT_replicated_composites, + }, + .bit_instructions => &.{ + .v1_0, + .SPV_KHR_bit_instructions, + }, + .group_non_uniform_rotate_khr => &.{ + .v1_0, + .SPV_KHR_subgroup_rotate, + }, + .float_controls2 => &.{ + .v1_0, + .SPV_KHR_float_controls2, + }, + .fmakhr => &.{ + .v1_0, + .SPV_KHR_fma, + }, + .atomic_float32add_ext => &.{ + .v1_0, + .SPV_EXT_shader_atomic_float_add, + }, + .atomic_float64add_ext => &.{ + .v1_0, + .SPV_EXT_shader_atomic_float_add, + }, + .opt_none_ext => &.{ + .v1_0, + .SPV_EXT_optnone, + }, + .atomic_float16add_ext => &.{ + .v1_0, + .SPV_EXT_shader_atomic_float16_add, + }, + .arithmetic_fence_ext => &.{ + .v1_0, + .SPV_EXT_arithmetic_fence, + }, + .group_uniform_arithmetic_khr => &.{ + .v1_0, + .SPV_KHR_uniform_group_instructions, + }, + }; + } }; pub const RayQueryIntersection = enum(u32) { ray_query_candidate_intersection_khr = 0, @@ -5391,8 +6119,8 @@ pub const TensorAddressingOperands = packed struct { }; }; pub const InitializationModeQualifier = enum(u32) { - init_on_device_reprogram_intel = 0, - init_on_device_reset_intel = 1, + init_on_device_reprogram_altera = 0, + init_on_device_reset_altera = 1, }; pub const LoadCacheControl = enum(u32) { uncached_intel = 0, @@ -5543,8 +6271,8 @@ pub const TensorOperands = packed struct { }; pub const InstructionSet = enum { core, - @"GLSL.std.450", @"OpenCL.std", + @"GLSL.std.450", zig, pub fn instructions(self: InstructionSet) []const Instruction { @@ -9178,6 +9906,17 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .optional }, }, }, + .{ + .name = "OpFmaKHR", + .opcode = 4427, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, .{ .name = "OpSubgroupAllKHR", .opcode = 4428, @@ -9238,6 +9977,23 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .variadic }, }, }, + .{ + .name = "OpUntypedGroupAsyncCopyKHR", + .opcode = 4434, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .memory_access, .quantifier = .optional }, + .{ .kind = .memory_access, .quantifier = .optional }, + }, + }, .{ .name = "OpTraceRayKHR", .opcode = 4445, @@ -9544,6 +10300,15 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .required }, }, }, + .{ + .name = "OpBitCastArrayQCOM", + .opcode = 4497, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, .{ .name = "OpImageBlockMatchWindowSSDQCOM", .opcode = 4500, @@ -9596,6 +10361,34 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .required }, }, }, + .{ + .name = "OpCompositeConstructCoopMatQCOM", + .opcode = 4540, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpCompositeExtractCoopMatQCOM", + .opcode = 4541, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpExtractSubArrayQCOM", + .opcode = 4542, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, .{ .name = "OpGroupIAddNonUniformAMD", .opcode = 5000, @@ -9802,6 +10595,96 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .required }, }, }, + .{ + .name = "OpTypeBufferEXT", + .opcode = 5115, + .operands = &.{ + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .storage_class, .quantifier = .required }, + }, + }, + .{ + .name = "OpBufferPointerEXT", + .opcode = 5119, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpAbortKHR", + .opcode = 5121, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpUntypedImageTexelPointerEXT", + .opcode = 5126, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpMemberDecorateIdEXT", + .opcode = 5127, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .required }, + .{ .kind = .decoration, .quantifier = .required }, + }, + }, + .{ + .name = "OpConstantSizeOfEXT", + .opcode = 5129, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpConstantDataKHR", + .opcode = 5147, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .variadic }, + }, + }, + .{ + .name = "OpSpecConstantDataKHR", + .opcode = 5148, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .variadic }, + }, + }, + .{ + .name = "OpPoisonKHR", + .opcode = 5158, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + }, + }, + .{ + .name = "OpFreezeKHR", + .opcode = 5159, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, .{ .name = "OpHitObjectRecordHitMotionNV", .opcode = 5249, @@ -10172,7 +11055,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpTypeCooperativeVectorNV", + .name = "OpTypeVectorIdEXT", .opcode = 5288, .operands = &.{ .{ .kind = .id_result, .quantifier = .required }, @@ -10271,7 +11154,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpGroupNonUniformPartitionNV", + .name = "OpGroupNonUniformPartitionEXT", .opcode = 5296, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -10334,6 +11217,321 @@ pub const InstructionSet = enum { .{ .kind = .memory_access, .quantifier = .optional }, }, }, + .{ + .name = "OpHitObjectRecordFromQueryEXT", + .opcode = 5304, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectRecordMissEXT", + .opcode = 5305, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectRecordMissMotionEXT", + .opcode = 5306, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetIntersectionTriangleVertexPositionsEXT", + .opcode = 5307, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetRayFlagsEXT", + .opcode = 5308, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectSetShaderBindingTableRecordIndexEXT", + .opcode = 5309, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectReorderExecuteShaderEXT", + .opcode = 5310, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .optional }, + .{ .kind = .id_ref, .quantifier = .optional }, + }, + }, + .{ + .name = "OpHitObjectTraceReorderExecuteEXT", + .opcode = 5311, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .optional }, + .{ .kind = .id_ref, .quantifier = .optional }, + }, + }, + .{ + .name = "OpHitObjectTraceMotionReorderExecuteEXT", + .opcode = 5312, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .optional }, + .{ .kind = .id_ref, .quantifier = .optional }, + }, + }, + .{ + .name = "OpTypeHitObjectEXT", + .opcode = 5313, + .operands = &.{ + .{ .kind = .id_result, .quantifier = .required }, + }, + }, + .{ + .name = "OpReorderThreadWithHintEXT", + .opcode = 5314, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpReorderThreadWithHitObjectEXT", + .opcode = 5315, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .optional }, + .{ .kind = .id_ref, .quantifier = .optional }, + }, + }, + .{ + .name = "OpHitObjectTraceRayEXT", + .opcode = 5316, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectTraceRayMotionEXT", + .opcode = 5317, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectRecordEmptyEXT", + .opcode = 5318, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectExecuteShaderEXT", + .opcode = 5319, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetCurrentTimeEXT", + .opcode = 5320, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetAttributesEXT", + .opcode = 5321, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetHitKindEXT", + .opcode = 5322, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetPrimitiveIndexEXT", + .opcode = 5323, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetGeometryIndexEXT", + .opcode = 5324, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetInstanceIdEXT", + .opcode = 5325, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetInstanceCustomIndexEXT", + .opcode = 5326, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetObjectRayOriginEXT", + .opcode = 5327, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetObjectRayDirectionEXT", + .opcode = 5328, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetWorldRayDirectionEXT", + .opcode = 5329, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetWorldRayOriginEXT", + .opcode = 5330, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetObjectToWorldEXT", + .opcode = 5331, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetWorldToObjectEXT", + .opcode = 5332, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetRayTMaxEXT", + .opcode = 5333, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, .{ .name = "OpReportIntersectionKHR", .opcode = 5334, @@ -10433,7 +11631,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpRayQueryGetClusterIdNV", + .name = "OpRayQueryGetIntersectionClusterIdNV", .opcode = 5345, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -10451,6 +11649,60 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .required }, }, }, + .{ + .name = "OpHitObjectGetRayTMinEXT", + .opcode = 5347, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetShaderBindingTableRecordIndexEXT", + .opcode = 5348, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectGetShaderRecordBufferHandleEXT", + .opcode = 5349, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectIsEmptyEXT", + .opcode = 5350, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectIsHitEXT", + .opcode = 5351, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpHitObjectIsMissEXT", + .opcode = 5352, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, .{ .name = "OpTypeCooperativeMatrixNV", .opcode = 5358, @@ -12432,7 +13684,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatSinCosPiINTEL", + .name = "OpArbitraryFloatSinCosPiALTERA", .opcode = 5840, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12446,7 +13698,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatCastINTEL", + .name = "OpArbitraryFloatCastALTERA", .opcode = 5841, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12460,7 +13712,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatCastFromIntINTEL", + .name = "OpArbitraryFloatCastFromIntALTERA", .opcode = 5842, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12474,7 +13726,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatCastToIntINTEL", + .name = "OpArbitraryFloatCastToIntALTERA", .opcode = 5843, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12488,7 +13740,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatAddINTEL", + .name = "OpArbitraryFloatAddALTERA", .opcode = 5846, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12504,7 +13756,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatSubINTEL", + .name = "OpArbitraryFloatSubALTERA", .opcode = 5847, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12520,7 +13772,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatMulINTEL", + .name = "OpArbitraryFloatMulALTERA", .opcode = 5848, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12536,7 +13788,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatDivINTEL", + .name = "OpArbitraryFloatDivALTERA", .opcode = 5849, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12552,7 +13804,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatGTINTEL", + .name = "OpArbitraryFloatGTALTERA", .opcode = 5850, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12564,7 +13816,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatGEINTEL", + .name = "OpArbitraryFloatGEALTERA", .opcode = 5851, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12576,7 +13828,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatLTINTEL", + .name = "OpArbitraryFloatLTALTERA", .opcode = 5852, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12588,7 +13840,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatLEINTEL", + .name = "OpArbitraryFloatLEALTERA", .opcode = 5853, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12600,7 +13852,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatEQINTEL", + .name = "OpArbitraryFloatEQALTERA", .opcode = 5854, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12612,7 +13864,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatRecipINTEL", + .name = "OpArbitraryFloatRecipALTERA", .opcode = 5855, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12626,7 +13878,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatRSqrtINTEL", + .name = "OpArbitraryFloatRSqrtALTERA", .opcode = 5856, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12640,7 +13892,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatCbrtINTEL", + .name = "OpArbitraryFloatCbrtALTERA", .opcode = 5857, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12654,7 +13906,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatHypotINTEL", + .name = "OpArbitraryFloatHypotALTERA", .opcode = 5858, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -12670,7 +13922,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpArbitraryFloatSqrtINTEL", + .name = "OpArbitraryFloatSqrtALTERA", .opcode = 5859, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13046,7 +14298,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedSqrtINTEL", + .name = "OpFixedSqrtALTERA", .opcode = 5923, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13060,7 +14312,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedRecipINTEL", + .name = "OpFixedRecipALTERA", .opcode = 5924, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13074,7 +14326,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedRsqrtINTEL", + .name = "OpFixedRsqrtALTERA", .opcode = 5925, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13088,7 +14340,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedSinINTEL", + .name = "OpFixedSinALTERA", .opcode = 5926, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13102,7 +14354,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedCosINTEL", + .name = "OpFixedCosALTERA", .opcode = 5927, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13116,7 +14368,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedSinCosINTEL", + .name = "OpFixedSinCosALTERA", .opcode = 5928, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13130,7 +14382,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedSinPiINTEL", + .name = "OpFixedSinPiALTERA", .opcode = 5929, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13144,7 +14396,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedCosPiINTEL", + .name = "OpFixedCosPiALTERA", .opcode = 5930, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13158,7 +14410,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedSinCosPiINTEL", + .name = "OpFixedSinCosPiALTERA", .opcode = 5931, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13172,7 +14424,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedLogINTEL", + .name = "OpFixedLogALTERA", .opcode = 5932, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13186,7 +14438,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFixedExpINTEL", + .name = "OpFixedExpALTERA", .opcode = 5933, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13200,7 +14452,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpPtrCastToCrossWorkgroupINTEL", + .name = "OpPtrCastToCrossWorkgroupALTERA", .opcode = 5934, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13209,7 +14461,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpCrossWorkgroupCastToPtrINTEL", + .name = "OpCrossWorkgroupCastToPtrALTERA", .opcode = 5938, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13218,7 +14470,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpReadPipeBlockingINTEL", + .name = "OpReadPipeBlockingALTERA", .opcode = 5946, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13228,7 +14480,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpWritePipeBlockingINTEL", + .name = "OpWritePipeBlockingALTERA", .opcode = 5947, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13238,7 +14490,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpFPGARegINTEL", + .name = "OpFPGARegALTERA", .opcode = 5949, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13507,7 +14759,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpTaskSequenceCreateINTEL", + .name = "OpTaskSequenceCreateALTERA", .opcode = 6163, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13520,7 +14772,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpTaskSequenceAsyncINTEL", + .name = "OpTaskSequenceAsyncALTERA", .opcode = 6164, .operands = &.{ .{ .kind = .id_ref, .quantifier = .required }, @@ -13528,7 +14780,7 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpTaskSequenceGetINTEL", + .name = "OpTaskSequenceGetALTERA", .opcode = 6165, .operands = &.{ .{ .kind = .id_result_type, .quantifier = .required }, @@ -13537,14 +14789,14 @@ pub const InstructionSet = enum { }, }, .{ - .name = "OpTaskSequenceReleaseINTEL", + .name = "OpTaskSequenceReleaseALTERA", .opcode = 6166, .operands = &.{ .{ .kind = .id_ref, .quantifier = .required }, }, }, .{ - .name = "OpTypeTaskSequenceINTEL", + .name = "OpTypeTaskSequenceALTERA", .opcode = 6199, .operands = &.{ .{ .kind = .id_result, .quantifier = .required }, @@ -13663,6 +14915,83 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .required }, }, }, + .{ + .name = "OpUntypedVariableLengthArrayINTEL", + .opcode = 6244, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "OpConditionalExtensionINTEL", + .opcode = 6248, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .literal_string, .quantifier = .required }, + }, + }, + .{ + .name = "OpConditionalEntryPointINTEL", + .opcode = 6249, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .execution_model, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .literal_string, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .variadic }, + }, + }, + .{ + .name = "OpConditionalCapabilityINTEL", + .opcode = 6250, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .capability, .quantifier = .required }, + }, + }, + .{ + .name = "OpSpecConstantTargetINTEL", + .opcode = 6251, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .variadic }, + }, + }, + .{ + .name = "OpSpecConstantArchitectureINTEL", + .opcode = 6252, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .required }, + .{ .kind = .literal_integer, .quantifier = .required }, + }, + }, + .{ + .name = "OpSpecConstantCapabilitiesINTEL", + .opcode = 6253, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .capability, .quantifier = .variadic }, + }, + }, + .{ + .name = "OpConditionalCopyObjectINTEL", + .opcode = 6254, + .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .variadic }, + }, + }, .{ .name = "OpGroupIMulKHR", .opcode = 6401, @@ -13809,609 +15138,34 @@ pub const InstructionSet = enum { .{ .kind = .id_ref, .quantifier = .required }, }, }, - }, - .@"GLSL.std.450" => &.{ .{ - .name = "Round", - .opcode = 1, + .name = "OpFDot2MixAcc32VALVE", + .opcode = 6916, .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "RoundEven", - .opcode = 2, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Trunc", - .opcode = 3, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FAbs", - .opcode = 4, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "SAbs", - .opcode = 5, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FSign", - .opcode = 6, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "SSign", - .opcode = 7, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Floor", - .opcode = 8, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Ceil", - .opcode = 9, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Fract", - .opcode = 10, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Radians", - .opcode = 11, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Degrees", - .opcode = 12, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Sin", - .opcode = 13, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Cos", - .opcode = 14, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Tan", - .opcode = 15, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Asin", - .opcode = 16, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Acos", - .opcode = 17, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Atan", - .opcode = 18, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Sinh", - .opcode = 19, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Cosh", - .opcode = 20, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Tanh", - .opcode = 21, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Asinh", - .opcode = 22, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Acosh", - .opcode = 23, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Atanh", - .opcode = 24, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Atan2", - .opcode = 25, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Pow", - .opcode = 26, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Exp", - .opcode = 27, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Log", - .opcode = 28, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Exp2", - .opcode = 29, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Log2", - .opcode = 30, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Sqrt", - .opcode = 31, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "InverseSqrt", - .opcode = 32, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Determinant", - .opcode = 33, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "MatrixInverse", - .opcode = 34, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Modf", - .opcode = 35, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "ModfStruct", - .opcode = 36, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FMin", - .opcode = 37, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UMin", - .opcode = 38, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "SMin", - .opcode = 39, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FMax", - .opcode = 40, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UMax", - .opcode = 41, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "SMax", - .opcode = 42, - .operands = &.{ .{ .kind = .id_ref, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, }, }, .{ - .name = "FClamp", - .opcode = 43, + .name = "OpFDot2MixAcc16VALVE", + .opcode = 6917, .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, }, }, .{ - .name = "UClamp", - .opcode = 44, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "SClamp", - .opcode = 45, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FMix", - .opcode = 46, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "IMix", - .opcode = 47, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Step", - .opcode = 48, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "SmoothStep", - .opcode = 49, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Fma", - .opcode = 50, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Frexp", - .opcode = 51, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FrexpStruct", - .opcode = 52, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Ldexp", - .opcode = 53, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "PackSnorm4x8", - .opcode = 54, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "PackUnorm4x8", - .opcode = 55, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "PackSnorm2x16", - .opcode = 56, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "PackUnorm2x16", - .opcode = 57, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "PackHalf2x16", - .opcode = 58, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "PackDouble2x32", - .opcode = 59, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UnpackSnorm2x16", - .opcode = 60, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UnpackUnorm2x16", - .opcode = 61, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UnpackHalf2x16", - .opcode = 62, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UnpackSnorm4x8", - .opcode = 63, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UnpackUnorm4x8", - .opcode = 64, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "UnpackDouble2x32", - .opcode = 65, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Length", - .opcode = 66, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Distance", - .opcode = 67, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Cross", - .opcode = 68, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Normalize", - .opcode = 69, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FaceForward", - .opcode = 70, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Reflect", - .opcode = 71, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "Refract", - .opcode = 72, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FindILsb", - .opcode = 73, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FindSMsb", - .opcode = 74, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "FindUMsb", - .opcode = 75, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "InterpolateAtCentroid", - .opcode = 76, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "InterpolateAtSample", - .opcode = 77, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "InterpolateAtOffset", - .opcode = 78, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "NMin", - .opcode = 79, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "NMax", - .opcode = 80, - .operands = &.{ - .{ .kind = .id_ref, .quantifier = .required }, - .{ .kind = .id_ref, .quantifier = .required }, - }, - }, - .{ - .name = "NClamp", - .opcode = 81, + .name = "OpFDot4MixAcc32VALVE", + .opcode = 6918, .operands = &.{ + .{ .kind = .id_result_type, .quantifier = .required }, + .{ .kind = .id_result, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, .{ .kind = .id_ref, .quantifier = .required }, @@ -15668,6 +16422,614 @@ pub const InstructionSet = enum { }, }, }, + .@"GLSL.std.450" => &.{ + .{ + .name = "Round", + .opcode = 1, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "RoundEven", + .opcode = 2, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Trunc", + .opcode = 3, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FAbs", + .opcode = 4, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "SAbs", + .opcode = 5, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FSign", + .opcode = 6, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "SSign", + .opcode = 7, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Floor", + .opcode = 8, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Ceil", + .opcode = 9, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Fract", + .opcode = 10, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Radians", + .opcode = 11, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Degrees", + .opcode = 12, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Sin", + .opcode = 13, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Cos", + .opcode = 14, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Tan", + .opcode = 15, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Asin", + .opcode = 16, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Acos", + .opcode = 17, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Atan", + .opcode = 18, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Sinh", + .opcode = 19, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Cosh", + .opcode = 20, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Tanh", + .opcode = 21, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Asinh", + .opcode = 22, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Acosh", + .opcode = 23, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Atanh", + .opcode = 24, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Atan2", + .opcode = 25, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Pow", + .opcode = 26, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Exp", + .opcode = 27, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Log", + .opcode = 28, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Exp2", + .opcode = 29, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Log2", + .opcode = 30, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Sqrt", + .opcode = 31, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "InverseSqrt", + .opcode = 32, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Determinant", + .opcode = 33, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "MatrixInverse", + .opcode = 34, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Modf", + .opcode = 35, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "ModfStruct", + .opcode = 36, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FMin", + .opcode = 37, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UMin", + .opcode = 38, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "SMin", + .opcode = 39, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FMax", + .opcode = 40, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UMax", + .opcode = 41, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "SMax", + .opcode = 42, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FClamp", + .opcode = 43, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UClamp", + .opcode = 44, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "SClamp", + .opcode = 45, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FMix", + .opcode = 46, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "IMix", + .opcode = 47, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Step", + .opcode = 48, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "SmoothStep", + .opcode = 49, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Fma", + .opcode = 50, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Frexp", + .opcode = 51, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FrexpStruct", + .opcode = 52, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Ldexp", + .opcode = 53, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "PackSnorm4x8", + .opcode = 54, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "PackUnorm4x8", + .opcode = 55, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "PackSnorm2x16", + .opcode = 56, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "PackUnorm2x16", + .opcode = 57, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "PackHalf2x16", + .opcode = 58, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "PackDouble2x32", + .opcode = 59, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UnpackSnorm2x16", + .opcode = 60, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UnpackUnorm2x16", + .opcode = 61, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UnpackHalf2x16", + .opcode = 62, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UnpackSnorm4x8", + .opcode = 63, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UnpackUnorm4x8", + .opcode = 64, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "UnpackDouble2x32", + .opcode = 65, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Length", + .opcode = 66, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Distance", + .opcode = 67, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Cross", + .opcode = 68, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Normalize", + .opcode = 69, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FaceForward", + .opcode = 70, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Reflect", + .opcode = 71, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "Refract", + .opcode = 72, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FindILsb", + .opcode = 73, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FindSMsb", + .opcode = 74, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "FindUMsb", + .opcode = 75, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "InterpolateAtCentroid", + .opcode = 76, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "InterpolateAtSample", + .opcode = 77, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "InterpolateAtOffset", + .opcode = 78, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "NMin", + .opcode = 79, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "NMax", + .opcode = 80, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + .{ + .name = "NClamp", + .opcode = 81, + .operands = &.{ + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + .{ .kind = .id_ref, .quantifier = .required }, + }, + }, + }, .zig => &.{ .{ .name = "InvocationGlobal", @@ -15680,3 +17042,72 @@ pub const InstructionSet = enum { }; } }; +pub const Extension = enum { + v1_0, + v1_1, + v1_2, + v1_3, + v1_4, + v1_5, + v1_6, + SPV_EXT_shader_tile_image, + SPV_EXT_float8, + SPV_KHR_fragment_shading_rate, + SPV_KHR_shader_ballot, + SPV_KHR_shader_draw_parameters, + SPV_KHR_workgroup_memory_explicit_layout, + SPV_KHR_subgroup_vote, + SPV_KHR_16bit_storage, + SPV_KHR_device_group, + SPV_KHR_multiview, + SPV_KHR_variable_pointers, + SPV_KHR_shader_atomic_counter_ops, + SPV_KHR_post_depth_coverage, + SPV_KHR_8bit_storage, + SPV_KHR_float_controls, + SPV_KHR_ray_query, + SPV_KHR_untyped_pointers, + SPV_KHR_ray_tracing, + SPV_EXT_shader_stencil_export, + SPV_EXT_shader_image_int64, + SPV_KHR_shader_clock, + SPV_KHR_quad_control, + SPV_KHR_bfloat16, + SPV_KHR_abort, + SPV_EXT_descriptor_heap, + SPV_KHR_constant_data, + SPV_KHR_poison_freeze, + SPV_EXT_shader_viewport_index_layer, + SPV_EXT_fragment_fully_covered, + SPV_EXT_mesh_shader, + SPV_KHR_fragment_shader_barycentric, + SPV_KHR_compute_shader_derivatives, + SPV_EXT_fragment_invocation_density, + SPV_EXT_shader_subgroup_partitioned, + SPV_EXT_descriptor_indexing, + SPV_KHR_ray_tracing_position_fetch, + SPV_KHR_vulkan_memory_model, + SPV_EXT_physical_storage_buffer, + SPV_KHR_physical_storage_buffer, + SPV_EXT_fragment_shader_interlock, + SPV_EXT_demote_to_helper_invocation, + SPV_EXT_opacity_micromap, + SPV_EXT_shader_invocation_reorder, + SPV_EXT_long_vector, + SPV_EXT_shader_64bit_indexing, + SPV_EXT_shader_atomic_float_min_max, + SPV_KHR_expect_assume, + SPV_KHR_integer_dot_product, + SPV_KHR_ray_cull_mask, + SPV_KHR_cooperative_matrix, + SPV_EXT_replicated_composites, + SPV_KHR_bit_instructions, + SPV_KHR_subgroup_rotate, + SPV_KHR_float_controls2, + SPV_KHR_fma, + SPV_EXT_shader_atomic_float_add, + SPV_EXT_optnone, + SPV_EXT_shader_atomic_float16_add, + SPV_EXT_arithmetic_fence, + SPV_KHR_uniform_group_instructions, +}; diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index 11eed60c75e3d375f7008d5e6f3c81f4cb60b949..08e1f4ab30210f52fc5de80d0042ab0ae1887859 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -32,7 +32,7 @@ const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev; pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { return comptime &.initMany(&.{ - .expand_intcast_safe, + .expand_int_cast_safe, .expand_int_from_float_safe, .expand_int_from_float_optimized_safe, .expand_add_safe, @@ -83,7 +83,6 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { .scalarize_shl_sat, .scalarize_xor, .scalarize_not, - .scalarize_bitcast, .scalarize_clz, .scalarize_ctz, .scalarize_popcount, @@ -109,7 +108,10 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { .scalarize_cmp_vector_optimized, .scalarize_fptrunc, .scalarize_fpext, - .scalarize_intcast, + .scalarize_int_cast, + .scalarize_ptr_cast, + .scalarize_ptr_from_int, + .scalarize_int_from_ptr, .scalarize_trunc, .scalarize_int_from_float, .scalarize_int_from_float_optimized, @@ -120,6 +122,8 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { .scalarize_shuffle_two, .scalarize_select, .scalarize_mul_add, + + .scalarize_bit_cast_padded_elems, }); } @@ -141,7 +145,7 @@ branches: std.ArrayList(Branch) = .empty, /// Table to save `WValue`'s generated by an `Air.Inst` // values: ValueTable, /// Mapping from Air.Inst.Index to block ids -blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, struct { +blocks: std.array_hash_map.Auto(Air.Inst.Index, struct { label: u32, value: WValue, }) = .{}, @@ -171,12 +175,12 @@ mir_extra: std.ArrayList(u32), mir_locals: std.ArrayList(std.wasm.Valtype), /// Set of all UAVs referenced by this function. Key is the UAV value, value is the alignment. /// `.none` means naturally aligned. An explicit alignment is never less than the natural alignment. -mir_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), +mir_uavs: std.array_hash_map.Auto(InternPool.Index, Alignment), /// Set of all functions whose address this function has taken and which therefore might be called /// via a `call_indirect` function. -mir_indirect_function_set: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), +mir_indirect_function_set: std.array_hash_map.Auto(InternPool.Nav.Index, void), /// Set of all function types used by this function. These must be interned by the linker. -mir_func_tys: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), +mir_func_tys: std.array_hash_map.Auto(InternPool.Index, void), /// The number of `error_name_table_ref` instructions emitted. error_name_table_ref_count: u32, /// When a function is executing, we store the the current stack pointer's value within this local. @@ -322,7 +326,7 @@ const WValue = union(enum) { }; /// Hashmap to store generated `WValue` for each `Air.Inst.Ref` -const ValueTable = std.AutoArrayHashMapUnmanaged(Air.Inst.Ref, WValue); +const ValueTable = std.array_hash_map.Auto(Air.Inst.Ref, WValue); const bookkeeping_init = if (std.debug.runtime_safety) @as(usize, 0) else {}; @@ -1195,6 +1199,7 @@ fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool { .undefined, .null, .@"opaque", + .spirv, => unreachable, .noreturn, @@ -1549,9 +1554,17 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { try cg.finishAir(inst, result, &.{ty_op.operand}); }, - .bitcast => cg.airBitcast(inst), + .ptr_cast => cg.airNopCast(inst), + .error_cast => cg.airNopCast(inst), + .error_from_int => cg.airNopCast(inst), + .int_from_error => cg.airNopCast(inst), + .ptr_from_int => cg.airNopCast(inst), + .int_from_ptr => cg.airIntFromPtr(inst), - .intcast => { + .bit_cast => cg.airBitcast(inst), + .union_from_enum => cg.airBitcast(inst), + + .int_cast => { const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const dest_ty = ty_op.ty.toType(); @@ -1559,7 +1572,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const src_ty = cg.typeOf(ty_op.operand); if (dest_ty.zigTypeTag(zcu) == .vector) { - return cg.fail("TODO: implement AIR op: intcast for vectors", .{}); + return cg.fail("TODO: implement AIR op: int_cast for vectors", .{}); } const src_int_ty: IntType = .fromType(cg, src_ty); @@ -1874,7 +1887,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .add_safe, .sub_safe, .mul_safe, - .intcast_safe, + .int_cast_safe, .int_from_float_safe, .int_from_float_optimized_safe, => return cg.fail("TODO implement safety_checked_instructions", .{}), @@ -1882,6 +1895,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { .work_item_id, .work_group_size, .work_group_id, + .spirv_runtime_array_len, => unreachable, }; } @@ -2097,16 +2111,20 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { const rhs = try cg.resolveInst(bin_op.rhs); const ptr_ty = cg.typeOf(bin_op.lhs); const ptr_info = ptr_ty.ptrInfo(zcu); - const ty = ptr_ty.childType(zcu); + const elem_ty = ptr_ty.childType(zcu); if (!safety and bin_op.rhs == .undef) { return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); } - assert(!(ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none)); // legalize .expand_packed_store - - try cg.store(lhs, rhs, ty, 0); - + const offset: u32 = switch (ptr_info.flags.vector_index) { + .none => offset: { + assert(ptr_info.packed_offset.host_size == 0); // legalize .expand_packed_store + break :offset 0; + }, + else => |index| @intCast(@intFromEnum(index) * elem_ty.abiSize(zcu)), + }; + try cg.store(lhs, rhs, elem_ty, offset); return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); } @@ -2119,7 +2137,16 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr if (!ty.hasRuntimeBits(zcu)) return; if (isByRef(ty, zcu, cg.target)) { - return cg.memcpy(lhs, rhs, .{ .imm32 = @intCast(abi_size) }); + const offset_ptr: WValue = switch (offset + lhs.offset()) { + 0 => lhs, + else => |total_offset| ptr: { + try cg.emitWValue(lhs); + try cg.addImm32(total_offset); + try cg.addTag(.i32_add); + break :ptr .stack; + }, + }; + return cg.memcpy(offset_ptr, rhs, .{ .imm32 = @intCast(abi_size) }); } if (ty.zigTypeTag(zcu) == .vector) { @@ -2131,7 +2158,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErr try cg.mir_extra.appendSlice(cg.gpa, &[_]u32{ @intFromEnum(std.wasm.SimdOpcode.v128_store), offset + lhs.offset(), - @intCast(ty.abiAlignment(zcu).toByteUnits() orelse 0), + @intCast(ty.abiAlignment(zcu).toByteUnits().?), }); return cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); } @@ -2172,15 +2199,20 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const zcu = pt.zcu; const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); - const ty = ty_op.ty.toType(); + const elem_ty = ty_op.ty.toType(); const ptr_ty = cg.typeOf(ty_op.operand); const ptr_info = ptr_ty.ptrInfo(zcu); - if (!ty.hasRuntimeBits(zcu)) return cg.finishAir(inst, .none, &.{ty_op.operand}); + assert(elem_ty.hasRuntimeBits(zcu)); - assert(!(ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none)); // legalize .expand_packed_load - - const result = try cg.load(operand, ty, 0); + const offset: u32 = switch (ptr_info.flags.vector_index) { + .none => offset: { + assert(ptr_info.packed_offset.host_size == 0); // legalize .expand_packed_load + break :offset 0; + }, + else => |index| @intCast(@intFromEnum(index) * elem_ty.abiSize(zcu)), + }; + const result = try cg.load(operand, elem_ty, offset); return cg.finishAir(inst, result, &.{ty_op.operand}); } @@ -2189,9 +2221,19 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { fn load(cg: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue { const zcu = cg.pt.zcu; if (isByRef(ty, zcu, cg.target)) { - const val = try cg.allocStack(ty); - try cg.store(val, try operand.toLocal(cg, .usize), ty, 0); - return val; + const src_ptr_maybe_stack: WValue = switch (offset + operand.offset()) { + 0 => operand, + else => |total_offset| ptr: { + try cg.emitWValue(operand); + try cg.addImm32(total_offset); + try cg.addTag(.i32_add); + break :ptr .stack; + }, + }; + const src_ptr = try src_ptr_maybe_stack.toLocal(cg, .usize); + const new_ptr = try cg.allocStack(ty); + try cg.store(new_ptr, src_ptr, ty, 0); + return new_ptr; } // load local's value from memory by its stack position @@ -4698,6 +4740,7 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { .tuple_type, .union_type, .opaque_type, + .spirv_type, .enum_type, .func_type, .error_set_type, @@ -5232,6 +5275,39 @@ fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { return cg.finishAir(inst, .none, &.{}); } +fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { + const zcu = cg.pt.zcu; + const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + + const operand_ty = cg.typeOf(ty_op.operand); + const dest_ty = cg.typeOfIndex(inst); + assert(isByRef(operand_ty, zcu, cg.target) == isByRef(dest_ty, zcu, cg.target)); + assert(operand_ty.abiSize(zcu) == dest_ty.abiSize(zcu)); + assert(operand_ty.abiAlignment(zcu) == dest_ty.abiAlignment(zcu)); + + const operand = try cg.resolveInst(ty_op.operand); + const result = cg.reuseOperand(ty_op.operand, operand); + return cg.finishAir(inst, result, &.{ty_op.operand}); +} + +fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { + const zcu = cg.pt.zcu; + const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; + + const operand_ty = cg.typeOf(ty_op.operand); + const dest_ty = cg.typeOfIndex(inst); + assert(isByRef(operand_ty, zcu, cg.target) == isByRef(dest_ty, zcu, cg.target)); + assert(operand_ty.abiSize(zcu) == dest_ty.abiSize(zcu)); + assert(operand_ty.abiAlignment(zcu) == dest_ty.abiAlignment(zcu)); + + const operand = try cg.resolveInst(ty_op.operand); + const result = switch (operand) { + .stack_offset => try cg.buildPointerOffset(operand, 0, .new), + else => cg.reuseOperand(ty_op.operand, operand), + }; + return cg.finishAir(inst, result, &.{ty_op.operand}); +} + fn airBitcast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); @@ -6337,12 +6413,11 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } } - const elem_result = if (isByRef(elem_ty, zcu, cg.target)) + const result = if (isByRef(elem_ty, zcu, cg.target)) .stack else try cg.load(.stack, elem_ty, 0); - - return cg.finishAir(inst, elem_result, &.{ bin_op.lhs, bin_op.rhs }); + return cg.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { diff --git a/src/codegen/wasm/Mir.zig b/src/codegen/wasm/Mir.zig index 662e177447cdb966b961731253c0334c53e519aa..f3b96f1c7939b4566630b8c3261cb432206d49ac 100644 --- a/src/codegen/wasm/Mir.zig +++ b/src/codegen/wasm/Mir.zig @@ -26,11 +26,11 @@ prologue: Prologue, /// Not directly used by `Emit`, but the linker needs this to merge it with a global set. /// Value is the explicit alignment if greater than natural alignment, `.none` otherwise. -uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), +uavs: std.array_hash_map.Auto(InternPool.Index, Alignment), /// Not directly used by `Emit`, but the linker needs this to merge it with a global set. -indirect_function_set: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), +indirect_function_set: std.array_hash_map.Auto(InternPool.Nav.Index, void), /// Not directly used by `Emit`, but the linker needs this to ensure these types are interned. -func_tys: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), +func_tys: std.array_hash_map.Auto(InternPool.Index, void), /// Not directly used by `Emit`, but the linker needs this to add it to its own refcount. error_name_table_ref_count: u32, diff --git a/src/codegen/wasm/abi.zig b/src/codegen/wasm/abi.zig index d59047044b302fc86485237e03300efb89d7c151..7a643e8dc7a755937f096f9826e5d770c2394b42 100644 --- a/src/codegen/wasm/abi.zig +++ b/src/codegen/wasm/abi.zig @@ -77,6 +77,7 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class { .null, .@"fn", .@"opaque", + .spirv, .enum_literal, => unreachable, } diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index 821aaf50270149896b83619c82e1989678d98be9..71b7a5bc21fcc3c68d1ef31673306560d8f364ce 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -47,7 +47,6 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { .scalarize_shl, .scalarize_shl_exact, .scalarize_shl_sat, - .scalarize_bitcast, .scalarize_ctz, .scalarize_popcount, .scalarize_byte_swap, @@ -58,11 +57,13 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { .scalarize_shuffle_two, .scalarize_select, + .scalarize_bit_cast_padded_elems, + //.unsplat_shift_rhs, - .reduce_one_elem_to_bitcast, - .splat_one_elem_to_bitcast, + .reduce_one_elem_to_bit_cast, + .splat_one_elem_to_bit_cast, - .expand_intcast_safe, + .expand_int_cast_safe, .expand_int_from_float_safe, .expand_int_from_float_optimized_safe, .expand_add_safe, @@ -140,7 +141,7 @@ register_manager: RegisterManager = .{}, scope_generation: u32 = 0, frame_allocs: std.MultiArrayList(FrameAlloc) = .empty, -free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .empty, +free_frame_indices: std.array_hash_map.Auto(FrameIndex, void) = .empty, frame_locs: std.MultiArrayList(Mir.FrameLoc) = .empty, loops: std.AutoHashMapUnmanaged(Air.Inst.Index, struct { @@ -164,11 +165,16 @@ next_temp_index: Temp.Index = @enumFromInt(0), temp_type: [Temp.Index.max]Type = undefined, const MaskInfo = packed struct { - kind: enum(u1) { sign, all }, + kind: enum(u2) { lsb, msb, zero_extend, sign_extend }, inverted: bool = false, scalar: Memory.Size, }; +const ArgsInfo = struct { + info: packed struct { reg_index: u3, frame_off: i29 }, + frame_index: FrameIndex, +}; + pub const MCValue = union(enum) { /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. /// TODO Look into deleting this tag and using `dead` instead, since every use @@ -199,17 +205,19 @@ pub const MCValue = union(enum) { /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register. register_overflow: struct { reg: Register, eflags: Condition }, /// The value is a bool vector stored in a vector register with a different scalar type. - register_mask: struct { reg: Register, info: MaskInfo }, + register_mask: Mask, /// The value is in memory at a hard-coded address. /// If the type is a pointer, it means the pointer address is stored at this memory location. memory: u64, /// The value is in memory at a constant offset from the address in a register. indirect: bits.RegisterOffset, indirect_load_frame: bits.FrameAddr, - /// The value stored at an offset from a frame index + /// The value is a bool vector stored in memory with a different scalar type at the address in a register. + indirect_mask: Mask, + /// The value stored at an offset from a frame index. /// Payload is a frame address. load_frame: bits.FrameAddr, - /// The address of an offset from a frame index + /// The address of an offset from a frame index. /// Payload is a frame address. lea_frame: bits.FrameAddr, load_nav: InternPool.Nav.Index, @@ -220,14 +228,26 @@ pub const MCValue = union(enum) { lea_lazy_sym: link.File.LazySymbol, load_extern_func: Mir.NullTerminatedString, lea_extern_func: Mir.NullTerminatedString, - /// Supports integer_per_element abi - elementwise_args: packed struct { regs: u3, frame_off: i29, frame_index: FrameIndex }, + /// The value is duplicated in two different registers. + register_tee: [4]Register, + /// Supports `integer_per_element` abi. + elementwise_gpr: ArgsInfo, + /// Supports `sse_per_element` abi. + elementwise_sse: ArgsInfo, + /// Supports `sse_per_xword` abi. + xwordwise_sse: ArgsInfo, + /// Supports `sse_per_yword` abi. + ywordwise_sse: ArgsInfo, + /// Supports `sse_per_zword` abi. + zwordwise_sse: ArgsInfo, /// This indicates that we have already allocated a frame index for this instruction, /// but it has not been spilled there yet in the current control flow. /// Payload is a frame index. reserved_frame: FrameIndex, air_ref: Air.Inst.Ref, + const Mask = struct { reg: Register, info: MaskInfo }; + fn isModifiable(mcv: MCValue) bool { return switch (mcv) { .none, @@ -248,7 +268,12 @@ pub const MCValue = union(enum) { .lea_lazy_sym, .lea_extern_func, .load_extern_func, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => false, @@ -258,6 +283,7 @@ pub const MCValue = union(enum) { .register_quadruple, .memory, .indirect, + .indirect_mask, .load_nav, => true, .load_frame => |frame_addr| !frame_addr.index.isNamed(), @@ -326,9 +352,10 @@ pub const MCValue = union(enum) { .register_quadruple, => |*regs| regs, inline .register_offset, - .indirect, .register_overflow, .register_mask, + .indirect, + .indirect_mask, => |*pl| (&pl.reg)[0..1], else => &.{}, }; @@ -364,12 +391,18 @@ pub const MCValue = union(enum) { .register_offset, .register_overflow, .register_mask, + .indirect_mask, .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym, .lea_extern_func, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, // not in memory @@ -402,11 +435,17 @@ pub const MCValue = union(enum) { .memory, .indirect, .indirect_load_frame, + .indirect_mask, .load_nav, .load_uav, .load_lazy_sym, .load_extern_func, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, // not dereferenceable @@ -428,7 +467,12 @@ pub const MCValue = union(enum) { .unreach, .dead, .undef, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, // not valid @@ -441,6 +485,7 @@ pub const MCValue = union(enum) { .memory, .indirect, .indirect_load_frame, + .indirect_mask, .load_frame, .load_nav, .lea_nav, @@ -482,7 +527,12 @@ pub const MCValue = union(enum) { .register_mask, .indirect_load_frame, .lea_frame, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .lea_nav, .lea_uav, @@ -507,6 +557,10 @@ pub const MCValue = union(enum) { .disp = reg_off.off + mod_rm.disp, } }, }, + .indirect_mask => |reg_mask| .{ + .base = .{ .reg = reg_mask.reg.toSize(.ptr, function.target) }, + .mod = .{ .rm = mod_rm }, + }, .load_frame => |frame_addr| .{ .base = .{ .frame = frame_addr.index }, .mod = .{ .rm = .{ @@ -528,7 +582,6 @@ pub const MCValue = union(enum) { switch (mcv) { .none, .unreach, .dead, .undef => try w.print("({s})", .{@tagName(mcv)}), .immediate => |pl| try w.print("0x{x}", .{pl}), - .memory => |pl| try w.print("[ds:0x{x}]", .{pl}), inline .eflags, .register => |pl| try w.print("{s}", .{@tagName(pl)}), .register_pair => |pl| try w.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), .register_triple => |pl| try w.print("{s}:{s}:{s}", .{ @@ -542,14 +595,21 @@ pub const MCValue = union(enum) { @tagName(pl.eflags), @tagName(pl.reg), }), - .register_mask => |pl| try w.print("mask({s},{f}):{c}{s}", .{ + .register_mask => |pl| try w.print("mask({s},{f}):{s}{s}", .{ @tagName(pl.info.kind), pl.info.scalar, - @as(u8, if (pl.info.inverted) '!' else ' '), + if (pl.info.inverted) "!" else "", @tagName(pl.reg), }), + .memory => |pl| try w.print("[ds:0x{x}]", .{pl}), .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), .indirect_load_frame => |pl| try w.print("[[{f} + 0x{x}]]", .{ pl.index, pl.off }), + .indirect_mask => |pl| try w.print("[mask({s},{f}):{s}{s}]", .{ + @tagName(pl.info.kind), + pl.info.scalar, + if (pl.info.inverted) "!" else "", + @tagName(pl.reg), + }), .load_frame => |pl| try w.print("[{f} + 0x{x}]", .{ pl.index, pl.off }), .lea_frame => |pl| try w.print("{f} + 0x{x}", .{ pl.index, pl.off }), .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}), @@ -560,8 +620,21 @@ pub const MCValue = union(enum) { .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}), .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}), - .elementwise_args => |pl| try w.print("elementwise:{d}:[{f} + 0x{x}]", .{ - pl.regs, pl.frame_index, pl.frame_off, + .register_tee => |pl| try w.print("tee:{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), + .elementwise_gpr => |pl| try w.print("elementwise:gpr{d}:[{f} + 0x{x}]", .{ + pl.info.reg_index, pl.frame_index, pl.info.frame_off, + }), + .elementwise_sse => |pl| try w.print("elementwise:sse{d}:[{f} + 0x{x}]", .{ + pl.info.reg_index, pl.frame_index, pl.info.frame_off, + }), + .xwordwise_sse => |pl| try w.print("xwordwise:sse{d}:[{f} + 0x{x}]", .{ + pl.info.reg_index, pl.frame_index, pl.info.frame_off, + }), + .ywordwise_sse => |pl| try w.print("ywordwise:sse{d}:[{f} + 0x{x}]", .{ + pl.info.reg_index, pl.frame_index, pl.info.frame_off, + }), + .zwordwise_sse => |pl| try w.print("zwordwise:sse{d}:[{f} + 0x{x}]", .{ + pl.info.reg_index, pl.frame_index, pl.info.frame_off, }), .reserved_frame => |pl| try w.print("(dead:{f})", .{pl}), .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}), @@ -569,8 +642,8 @@ pub const MCValue = union(enum) { } }; -const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking); -const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking); +const InstTrackingMap = std.array_hash_map.Auto(Air.Inst.Index, InstTracking); +const ConstTrackingMap = std.array_hash_map.Auto(InternPool.Index, InstTracking); const InstTracking = struct { long: MCValue, short: MCValue, @@ -595,7 +668,12 @@ const InstTracking = struct { .lea_extern_func, => result, .dead, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, @@ -608,6 +686,7 @@ const InstTracking = struct { .register_overflow, .register_mask, .indirect, + .indirect_mask, => .none, }, .short = result }; } @@ -707,7 +786,13 @@ const InstTracking = struct { .register_overflow, .register_mask, .indirect, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .air_ref, => unreachable, } @@ -789,19 +874,24 @@ const InstTracking = struct { // Disable death. var found_reg = false; - var remaining_reg: Register = .none; + var remaining_regs: [4]Register = undefined; + var remaining_regs_len: usize = 0; for (tracking.getRegs()) |tracked_reg| if (tracked_reg.id() == reg.id()) { assert(!found_reg); found_reg = true; } else { - assert(remaining_reg == .none); - remaining_reg = tracked_reg; + remaining_regs[remaining_regs_len] = tracked_reg; + remaining_regs_len += 1; }; assert(found_reg); if (tracking.long == .none) tracking.long = tracking.short; - tracking.short = switch (remaining_reg) { - .none => .{ .dead = function.scope_generation }, - else => .{ .register = remaining_reg }, + tracking.short = switch (remaining_regs_len) { + 0 => .{ .dead = function.scope_generation }, + 1 => .{ .register = remaining_regs[0] }, + 2 => .{ .register_pair = remaining_regs[0..2].* }, + 3 => .{ .register_triple = remaining_regs[0..3].* }, + 4 => .{ .register_quadruple = remaining_regs[0..4].* }, + else => unreachable, }; // Perform side-effects of freeValue manually. @@ -67344,7 +67434,15 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }; try res[0].finish(inst, &.{ty_op.operand}, &ops, cg); }, - .bitcast => try cg.airBitCast(inst), + .bit_cast, + .ptr_cast, + .ptr_from_int, + .int_from_ptr, + .error_cast, + .error_from_int, + .int_from_error, + .union_from_enum, + => try cg.airBitCast(inst), .block => { const block = cg.air.unwrapBlock(inst); if (!cg.mod.strip) try cg.asmPseudo(.pseudo_dbg_enter_block_none); @@ -72449,7 +72547,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -72473,7 +72571,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -72497,7 +72595,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -72525,7 +72623,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -72554,7 +72652,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -72583,7 +72681,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -72650,7 +72748,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -72676,7 +72774,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -72702,7 +72800,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -72732,7 +72830,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -72763,7 +72861,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -72794,7 +72892,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -72864,7 +72962,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -72890,7 +72988,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -72916,7 +73014,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -72946,7 +73044,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -72977,7 +73075,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -73008,7 +73106,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -73078,8 +73176,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73104,8 +73202,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73130,7 +73228,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73156,8 +73254,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word, .smear = 8 } } }, - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -73185,8 +73283,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word, .smear = 8 } } }, - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -73255,8 +73353,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73282,8 +73380,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73309,7 +73407,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73336,8 +73434,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word, .smear = 8 } } }, - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -73367,8 +73465,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word, .smear = 8 } } }, - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -73440,8 +73538,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73467,8 +73565,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73494,7 +73592,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -73522,8 +73620,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word, .smear = 8 } } }, - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, @@ -73553,8 +73651,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .word, .smear = 8 } } }, - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .word, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .unused, .unused, @@ -73626,8 +73724,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73652,8 +73750,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73678,7 +73776,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73705,8 +73803,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_32_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword, .smear = 8 } } }, - .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_32_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, .unused, @@ -73776,8 +73874,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73803,8 +73901,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73830,7 +73928,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73858,8 +73956,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_32_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword, .smear = 8 } } }, - .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_32_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, .unused, @@ -73932,8 +74030,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73959,8 +74057,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -73986,7 +74084,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74014,8 +74112,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_32_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .dword, .smear = 8 } } }, - .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .reverse } }, + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .{ .direction = .reverse } } }, .{ .type = .vector_32_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, .unused, @@ -74088,8 +74186,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .qword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .qword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74114,8 +74212,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .qword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .qword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74140,7 +74238,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .unused, .unused, .unused, @@ -74211,7 +74309,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .unused, .unused, @@ -74239,7 +74337,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .unused, .unused, .unused, @@ -74313,8 +74411,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .qword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .qword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74340,8 +74438,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .qword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .qword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74367,7 +74465,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, .unused, .unused, .unused, @@ -74441,8 +74539,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74467,8 +74565,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74493,8 +74591,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, @@ -74526,8 +74624,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .unused, @@ -74559,8 +74657,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .vector_16_u8, .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } }, .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, @@ -74592,8 +74690,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .u64, .kind = .{ .rc = .general_purpose } }, .unused, @@ -74625,8 +74723,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_32_u8, .kind = .{ .pshufb_bswap_mem = .{ .repeat = 2, .size = .xword } } }, + .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .repeat = 2, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .unused, .unused, @@ -74652,8 +74750,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .none, .none } }, }, .extra_temps = .{ - .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, @@ -74684,8 +74782,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, - .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_32_u8, .kind = .{ .pshufb_bswap_mem = .{ .repeat = 2, .size = .xword } } }, + .{ .type = .vector_32_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .repeat = 2, .size = .xword } } }, .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, @@ -74720,8 +74818,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, .{ .type = .isize, .kind = .{ .rc = .general_purpose } }, - .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .forward } }, - .{ .type = .vector_16_u8, .kind = .{ .pshufb_bswap_mem = .{ .size = .xword } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .reverse, .size = .xword } } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, @@ -81999,7 +82097,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ }, @@ -82039,7 +82137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ }, @@ -82079,7 +82177,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cvtph2, .dst0y, .src0x, ._, ._ }, @@ -82103,7 +82201,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ss, .cmp, .dst0x, .src0x, .src1d, .vp(switch (cc) { @@ -82126,7 +82224,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ss, .cmp, .dst0x, .src0x, .src1d, .vp(switch (cc) { @@ -82148,7 +82246,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._ss, .cmp, .dst0x, .src1d, .sp(switch (cc) { @@ -82170,7 +82268,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) { @@ -82193,7 +82291,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) { @@ -82215,7 +82313,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._ps, .cmp, .dst0x, .src1x, .sp(switch (cc) { @@ -82237,7 +82335,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) { @@ -82260,7 +82358,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) { @@ -82282,7 +82380,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_sd, .cmp, .dst0x, .src0x, .src1q, .vp(switch (cc) { @@ -82305,7 +82403,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_sd, .cmp, .dst0x, .src0x, .src1q, .vp(switch (cc) { @@ -82327,7 +82425,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._sd, .cmp, .dst0x, .src1q, .sp(switch (cc) { @@ -82349,7 +82447,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_pd, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) { @@ -82372,7 +82470,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_pd, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) { @@ -82394,7 +82492,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._pd, .cmp, .dst0x, .src1x, .sp(switch (cc) { @@ -82416,7 +82514,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_pd, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) { @@ -82439,7 +82537,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_pd, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) { @@ -84643,7 +84741,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84667,7 +84765,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84691,7 +84789,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84715,7 +84813,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84739,7 +84837,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84763,7 +84861,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84787,7 +84885,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84811,7 +84909,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84835,7 +84933,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_mmx, .to_mmx, .none } }, }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84859,7 +84957,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_mmx, .to_mmx, .none } }, }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84883,7 +84981,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_mut_mmx, .to_mmx, .none } }, }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84907,7 +85005,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84931,7 +85029,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84955,7 +85053,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -84979,7 +85077,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .{ .src = .{ .to_sse, .to_sse, .none } }, }, .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{ - .kind = .all, + .kind = .sign_extend, .inverted = switch (cc) { else => unreachable, .e => false, @@ -86631,7 +86729,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ }, @@ -86671,7 +86769,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ }, @@ -86711,7 +86809,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cvtph2, .dst0y, .src0x, ._, ._ }, @@ -86737,7 +86835,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ss, .cmp, .dst0x, .src0x, .src1d, .vp(switch (cc) { @@ -86760,7 +86858,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._ss, .cmp, .dst0x, .src1d, .sp(switch (cc) { @@ -86784,7 +86882,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) { @@ -86807,7 +86905,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._ps, .cmp, .dst0x, .src1x, .sp(switch (cc) { @@ -86831,7 +86929,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .dword }, + .info = .{ .kind = .sign_extend, .scalar = .dword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_ps, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) { @@ -86855,7 +86953,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_sd, .cmp, .dst0x, .src0x, .src1q, .vp(switch (cc) { @@ -86878,7 +86976,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._sd, .cmp, .dst0x, .src1q, .sp(switch (cc) { @@ -86902,7 +87000,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_pd, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) { @@ -86925,7 +87023,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }, .dst_temps = .{ .{ .ref_mask = .{ .ref = .src0, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, ._pd, .cmp, .dst0x, .src1x, .sp(switch (cc) { @@ -86949,7 +87047,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_temps = .{ .{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, - .info = .{ .kind = .all, .scalar = .qword }, + .info = .{ .kind = .sign_extend, .scalar = .qword }, } }, .unused }, .each = .{ .once = &.{ .{ ._, .v_pd, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) { @@ -89204,7 +89302,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { var ops = try cg.tempsFromOperands(inst, .{un_op}); while (try ops[0].toBase(false, cg)) {} try cg.asmMemoryImmediate(.{ ._, .cmp }, try ops[0].tracking(cg).short.mem(cg, .{ - .size = cg.memSize(eu_err_ty), + .size = cg.memSize(eu_err_ty, .general_purpose), .disp = eu_err_off, }), .u(0)); const is_err = try cg.tempInit(.bool, .{ .eflags = .ne }); @@ -89220,7 +89318,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { var ops = try cg.tempsFromOperands(inst, .{un_op}); while (try ops[0].toBase(false, cg)) {} try cg.asmMemoryImmediate(.{ ._, .cmp }, try ops[0].tracking(cg).short.mem(cg, .{ - .size = cg.memSize(eu_err_ty), + .size = cg.memSize(eu_err_ty, .general_purpose), .disp = eu_err_off, }), .u(0)); const is_non_err = try cg.tempInit(.bool, .{ .eflags = .e }); @@ -89236,11 +89334,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { var ops = try cg.tempsFromOperands(inst, .{un_op}); try ops[0].toOffset(eu_err_off, cg); while (try ops[0].toLea(cg)) {} - try cg.asmMemoryImmediate( - .{ ._, .cmp }, - try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }), - .u(0), - ); + try cg.asmMemoryImmediate(.{ ._, .cmp }, try ops[0].tracking(cg).short.deref().mem(cg, .{ + .size = cg.memSize(eu_err_ty, .general_purpose), + }), .u(0)); const is_err = try cg.tempInit(.bool, .{ .eflags = .ne }); try is_err.finish(inst, &.{un_op}, &ops, cg); }, @@ -89254,11 +89350,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { var ops = try cg.tempsFromOperands(inst, .{un_op}); try ops[0].toOffset(eu_err_off, cg); while (try ops[0].toLea(cg)) {} - try cg.asmMemoryImmediate( - .{ ._, .cmp }, - try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }), - .u(0), - ); + try cg.asmMemoryImmediate(.{ ._, .cmp }, try ops[0].tracking(cg).short.deref().mem(cg, .{ + .size = cg.memSize(eu_err_ty, .general_purpose), + }), .u(0)); const is_non_err = try cg.tempInit(.bool, .{ .eflags = .e }); try is_non_err.finish(inst, &.{un_op}, &ops, cg); }, @@ -89328,6 +89422,25 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .store, .store_safe => |air_tag| { const bin_op = air_datas[@intFromEnum(inst)].bin_op; var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); + switch (ops[1].tracking(cg).short) { + else => {}, + .register_mask => |src_reg_mask| { + const ty = ops[1].typeOf(cg); + const new_op1 = try cg.tempAllocReg(ty, abi.RegisterClass.gp); + try cg.genSetReg( + new_op1.tracking(cg).short.register, + ty, + .{ .register_mask = src_reg_mask }, + .{ .safety = switch (air_tag) { + else => unreachable, + .store => false, + .store_safe => true, + } }, + ); + try ops[1].die(cg); + ops[1] = new_op1; + }, + } cg.select(&.{}, &.{}, &ops, comptime &.{ .{ .src_constraints = .{ .{ .ptr_bool_vec_elem = .byte }, .bool, .any }, .patterns = &.{ @@ -93270,7 +93383,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }; try res[0].finish(inst, &.{ty_op.operand}, &ops, cg); }, - .intcast => |air_tag| { + .int_cast => |air_tag| { const ty_op = air_datas[@intFromEnum(inst)].ty_op; const dst_ty = ty_op.ty.toType(); const src_ty = cg.typeOf(ty_op.operand); @@ -98028,7 +98141,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }; try res[0].finish(inst, &.{ty_op.operand}, &ops, cg); }, - .intcast_safe => unreachable, + .int_cast_safe => unreachable, .trunc => |air_tag| { const ty_op = air_datas[@intFromEnum(inst)].ty_op; var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); @@ -104246,7 +104359,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); try ops[0].toSlicePtr(cg); const dst_ty = ty_pl.ty.toType(); - if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: { + zero_offset: { const elem_size = dst_ty.childType(zcu).abiSize(zcu); if (hack_around_sema_opv_bugs and elem_size == 0) break :zero_offset; while (true) for (&ops) |*op| { @@ -127103,7 +127216,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword, .is = .inverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend, .is = .inverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .z }, .unused }, .clobbers = .{ .eflags = true }, @@ -127115,7 +127228,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword, .is = .inverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend, .is = .inverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .z }, .unused }, .clobbers = .{ .eflags = true }, @@ -127127,7 +127240,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, @@ -127153,7 +127266,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, @@ -127179,7 +127292,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .msb } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, @@ -127205,7 +127318,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .msb } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, @@ -127231,7 +127344,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword, .is = .inverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend, .is = .inverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .z }, .unused }, .clobbers = .{ .eflags = true }, @@ -127243,7 +127356,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword, .is = .inverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend, .is = .inverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .z }, .unused }, .clobbers = .{ .eflags = true }, @@ -127255,7 +127368,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, @@ -127281,7 +127394,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } }, @@ -127307,7 +127420,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .reg_mask = .{ .size = .yword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .msb } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, @@ -127508,7 +127621,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword, .is = .uninverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend, .is = .uninverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .nz }, .unused }, .clobbers = .{ .eflags = true }, @@ -127520,7 +127633,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword, .is = .uninverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend, .is = .uninverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .nz }, .unused }, .clobbers = .{ .eflags = true }, @@ -127532,7 +127645,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, @@ -127558,7 +127671,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, @@ -127584,7 +127697,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .msb } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, @@ -127610,7 +127723,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .reg_mask = .{ .size = .xword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .msb } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, @@ -127636,7 +127749,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword, .is = .uninverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend, .is = .uninverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .nz }, .unused }, .clobbers = .{ .eflags = true }, @@ -127648,7 +127761,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword, .is = .uninverted } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend, .is = .uninverted } }, .none, .none } }, }, .dst_temps = .{ .{ .cc = .nz }, .unused }, .clobbers = .{ .eflags = true }, @@ -127660,7 +127773,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, @@ -127686,7 +127799,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .all_reg_mask = .{ .size = .yword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .sign_extend } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } }, @@ -127712,7 +127825,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { .dst_constraints = .{ .bool, .any }, .src_constraints = .{ .any_bool_vec, .any, .any }, .patterns = &.{ - .{ .src = .{ .{ .reg_mask = .{ .size = .yword } }, .none, .none } }, + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .msb } }, .none, .none } }, }, .extra_temps = .{ .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, @@ -168986,12 +169099,56 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { }; try res[0].finish(inst, &.{reduce.operand}, &ops, cg); }, - .splat => |air_tag| fallback: { + .splat => |air_tag| { const ty_op = air_datas[@intFromEnum(inst)].ty_op; - if (cg.typeOf(ty_op.operand).toIntern() == .bool_type) break :fallback try cg.airSplat(inst); var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); var res: [1]Temp = undefined; cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{ + .dst_constraints = .{ .{ .bool_vec = .qword }, .any }, + .src_constraints = .{ .bool, .any, .any }, + .patterns = &.{ + .{ .src = .{ .to_gpr, .none, .none } }, + }, + .dst_temps = .{ .{ .rc = .general_purpose }, .unused }, + .clobbers = .{ .eflags = true }, + .each = .{ .once = &.{ + .{ ._, ._, .bt, .src0d, .si(0), ._, ._ }, + .{ ._, ._, .sbb, .dst0q, .dst0q, ._, ._ }, + .{ ._, ._r, .sh, .dst0q, .uia(64, .dst0, .sub_bit_size), ._, ._ }, + } }, + }, .{ + .dst_constraints = .{ .any_bool_vec, .any }, + .src_constraints = .{ .bool, .any, .any }, + .patterns = &.{ + .{ .src = .{ .to_gpr, .none, .none } }, + }, + .dst_temps = .{ .mem, .unused }, + .extra_temps = .{ + .{ .type = .isize, .kind = .{ .reg = .rdi } }, + .{ .type = .u8, .kind = .{ .reg = .rax } }, + .{ .type = .u32, .kind = .{ .reg = .rcx } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .clobbers = .{ .eflags = true }, + .each = .{ .once = &.{ + .{ ._, ._, .bt, .src0d, .si(0), ._, ._ }, + .{ ._, ._, .sbb, .tmp1b, .tmp1b, ._, ._ }, + .{ ._, ._, .lea, .tmp0q, .dst0b, ._, ._ }, + .{ ._, ._, .mov, .tmp2d, .sia(1, .dst0, .add_bit_size_sub_1_div_8_down_1), ._, ._ }, + .{ ._, .@"rep _sb", .sto, ._, ._, ._, ._ }, + .{ ._, ._, .@"and", .memad(.dst0b, .add_bit_size_sub_1_div_8_down_1, 0), .ua(.dst0, .bit_size_last_byte_mask), ._, ._ }, + .{ ._, ._, .mov, .tmp2d, .sa(.dst0, .add_size_sub_bit_size_div_8_down_1_sub_1), ._, ._ }, + .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ }, + .{ ._, .@"rep _sb", .sto, ._, ._, ._, ._ }, + } }, + }, .{ .required_features = .{ .avx2, null, null, null }, .dst_constraints = .{ .{ .scalar_int = .{ .of = .xword, .is = .byte } }, .any }, .src_constraints = .{ .{ .int = .byte }, .any, .any }, @@ -173719,7 +173876,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { // No soft-float `Legalize` features are enabled, so this instruction never appears. .legalize_compiler_rt_call => unreachable, - .work_item_id, .work_group_size, .work_group_id => unreachable, + .work_item_id, .work_group_size, .work_group_id, .spirv_runtime_array_len => unreachable, } try cg.resetTemps(@enumFromInt(0)); cg.checkInvariantsAfterAirInst(); @@ -174212,15 +174369,16 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).array.len]RegisterLock; const bfa_buf_len = if (opts.update_tracking) 0 else 1; var bfa_buf: [bfa_buf_len]ExpectedContents = undefined; - var stack = if (opts.update_tracking) {} else std.heap.BufferFirstAllocator.init(@ptrCast(&bfa_buf), self.gpa); + var stack = if (!opts.update_tracking) std.heap.BufferFirstAllocator.init(@ptrCast(&bfa_buf), self.gpa); + const allocator = if (!opts.update_tracking) stack.allocator(); - var reg_locks = if (opts.update_tracking) {} else try std.array_list.Managed(RegisterLock).initCapacity( - stack.allocator(), + var reg_locks = if (!opts.update_tracking) try std.ArrayList(RegisterLock).initCapacity( + allocator, @typeInfo(ExpectedContents).array.len, ); defer if (!opts.update_tracking) { for (reg_locks.items) |lock| self.register_manager.unlockReg(lock); - reg_locks.deinit(); + reg_locks.deinit(allocator); }; for ( @@ -174250,7 +174408,7 @@ fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, co self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking); } } else if (target_maybe_inst) |_| - try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(reg_index)); + try reg_locks.append(allocator, self.register_manager.lockRegIndexAssumeUnused(reg_index)); } if (opts.emit_instructions) if (self.eflags_inst) |inst| try self.inst_tracking.getPtr(inst).?.spill(self, inst); @@ -174463,7 +174621,13 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE .register_overflow, .register_mask, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, => unreachable, // not a valid pointer .immediate, @@ -174516,7 +174680,13 @@ fn store( .register_overflow, .register_mask, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, => unreachable, // not a valid pointer .immediate, @@ -174561,12 +174731,18 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: .register_overflow, .register_mask, .indirect_load_frame, + .indirect_mask, .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym, .lea_extern_func, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, // unmodifiable destination @@ -175256,7 +175432,13 @@ fn genBinOpMir( .lea_lazy_sym, .lea_extern_func, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, // unmodifiable destination @@ -175293,7 +175475,13 @@ fn genBinOpMir( .register_overflow, .register_mask, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, => unreachable, .register, @@ -175465,7 +175653,13 @@ fn genBinOpMir( .register_overflow, .register_mask, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, @@ -175569,7 +175763,13 @@ fn genBinOpMir( .register_overflow, .register_mask, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, @@ -175683,120 +175883,255 @@ fn genBinOpMir( } } -fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void { - const zcu = self.pt.zcu; - const arg_index = for (self.args, 0..) |arg, arg_index| { +fn airArg(cg: *CodeGen, inst: Air.Inst.Index) !void { + const zcu = cg.pt.zcu; + const arg_index = for (cg.args, 0..) |arg, arg_index| { if (arg != .none) break arg_index; } else unreachable; - const src_mcv = self.args[arg_index]; - self.args = self.args[arg_index + 1 ..]; - const result: MCValue = if (self.mod.strip and self.liveness.isUnused(inst)) .unreach else result: { - const arg_ty = self.typeOfIndex(inst); + const src_mcv = cg.args[arg_index]; + cg.args = cg.args[arg_index + 1 ..]; + const result: MCValue = if (cg.mod.strip and cg.liveness.isUnused(inst)) .unreach else result: { + const arg_ty = cg.typeOfIndex(inst); switch (src_mcv) { - .register, .register_pair, .load_frame => { - for (src_mcv.getRegs()) |reg| self.register_manager.getRegAssumeFree(reg, inst); + .register, + .register_pair, + .register_triple, + .register_quadruple, + .register_mask, + .load_frame, + => { + for (src_mcv.getRegs()) |reg| cg.register_manager.getRegAssumeFree(reg, inst); break :result src_mcv; }, .indirect => |reg_off| { - self.register_manager.getRegAssumeFree(reg_off.reg, null); - const dst_mcv = try self.allocRegOrMem(inst, false); - try self.genCopy(arg_ty, dst_mcv, src_mcv, .{}); + cg.register_manager.getRegAssumeFree(reg_off.reg, null); + const dst_mcv = try cg.allocRegOrMem(inst, false); + try cg.genCopy(arg_ty, dst_mcv, src_mcv, .{}); break :result dst_mcv; }, + .indirect_mask => |reg_mask| { + cg.register_manager.getRegAssumeFree(reg_mask.reg, null); + const dst_reg = try cg.register_manager.allocReg(inst, abi.RegisterClass.sse); + const mask_size: u32 = @intCast( + @divExact(reg_mask.info.scalar.bitSize(cg.target), 8) * arg_ty.vectorLen(zcu), + ); + try cg.asmRegisterMemory( + .{ if (cg.hasFeature(.avx)) .v_dqa else ._dqa, .mov }, + registerAlias(dst_reg, mask_size), + .{ + .base = .{ .reg = reg_mask.reg }, + .mod = .{ .rm = .{ .size = .fromSize(mask_size) } }, + }, + ); + break :result .{ .register_mask = .{ .reg = dst_reg, .info = reg_mask.info } }; + }, .indirect_load_frame => |frame_addr| { - const dst_mcv = try self.allocRegOrMem(inst, false); - const ptr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); - const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg); - defer self.register_manager.unlockReg(ptr_lock); - try self.genSetReg(ptr_reg, .usize, .{ .load_frame = frame_addr }, .{}); - try self.genCopy(arg_ty, dst_mcv, .{ .indirect = .{ .reg = ptr_reg } }, .{}); + const dst_mcv = try cg.allocRegOrMem(inst, false); + const ptr_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gp); + const ptr_lock = cg.register_manager.lockRegAssumeUnused(ptr_reg); + defer cg.register_manager.unlockReg(ptr_lock); + try cg.genSetReg(ptr_reg, .usize, .{ .load_frame = frame_addr }, .{}); + try cg.genCopy(arg_ty, dst_mcv, .{ .indirect = .{ .reg = ptr_reg } }, .{}); break :result dst_mcv; }, - .elementwise_args => |regs_frame_addr| { - try self.spillEflagsIfOccupied(); + .elementwise_gpr, .elementwise_sse => |regs_frame_addr| { + const fn_info = zcu.typeToFunc(cg.fn_type).?; + const elem_ty = arg_ty.childType(zcu); + const elem_rc: Register.Class, const param_regs = switch (src_mcv) { + else => unreachable, + .elementwise_gpr => .{ .general_purpose, abi.getCAbiIntParamRegs(fn_info.cc) }, + .elementwise_sse => .{ .sse, abi.getCAbiSseParamRegs(fn_info.cc, cg.target) }, + }; + const len = arg_ty.vectorLen(zcu); + const param_reg_len: u31 = + @intCast(@min(param_regs.len - regs_frame_addr.info.reg_index, len)); - const fn_info = zcu.typeToFunc(self.fn_type).?; - const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); - var prev_reg: Register = undefined; - for ( - param_int_regs[param_int_regs.len - regs_frame_addr.regs ..], - 0.., - ) |dst_reg, elem_index| { - assert(self.register_manager.isRegFree(dst_reg)); - if (elem_index > 0) { - try self.asmRegisterImmediate(.{ ._l, .sh }, dst_reg.to8(), .u(elem_index)); - try self.asmRegisterRegister( - .{ ._, .@"or" }, - dst_reg.to8(), - prev_reg.to8(), + const elem_size = cg.memSize(elem_ty, .general_purpose); + const elem_abi_size = @divExact(elem_size.bitSize(cg.target), 8); + const strat = if (elem_ty.toIntern() == .bool_type) strat: { + try cg.spillEflagsIfOccupied(); + break :strat undefined; + } else try cg.moveStrategy(elem_ty, elem_rc, true); + + const dst_mcv = try cg.allocRegOrMem(inst, false); + { + var prev_reg: Register = undefined; + for ( + param_regs[regs_frame_addr.info.reg_index..][0..param_reg_len], + 0.., + ) |src_reg, elem_index| { + assert(cg.register_manager.isRegFree(src_reg)); + if (elem_ty.toIntern() == .bool_type) { + if (elem_index > 0) { + try cg.asmRegisterImmediate( + .{ ._l, .sh }, + src_reg.to8(), + .u(elem_index), + ); + try cg.asmRegisterRegister( + .{ ._, .@"or" }, + src_reg.to8(), + prev_reg.to8(), + ); + } + prev_reg = src_reg; + } else try strat.write(cg, try dst_mcv.mem(cg, .{ + .size = elem_size, + .disp = @intCast(elem_abi_size * elem_index), + }), src_reg.toSize(elem_size, cg.target)); + } + if (elem_ty.toIntern() == .bool_type) { + if (param_reg_len > 0) { + const prev_lock = cg.register_manager.lockRegAssumeUnused(prev_reg); + defer cg.register_manager.unlockReg(prev_lock); + try cg.asmMemoryRegister( + .{ ._, .mov }, + try dst_mcv.mem(cg, .{ .size = .byte }), + prev_reg.to8(), + ); + } + const clear_len = arg_ty.abiSize(zcu) - @intFromBool(param_reg_len > 0); + if (clear_len > 0) try cg.genInlineMemset( + dst_mcv.address().offset(@intFromBool(param_reg_len > 0)), + .{ .immediate = 0 }, + .{ .immediate = clear_len }, + .{}, + ); + } + } + if (len - param_reg_len > 0) { + const index_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gp); + const index_lock = cg.register_manager.lockRegAssumeUnused(index_reg); + defer cg.register_manager.unlockReg(index_lock); + try cg.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .u(param_reg_len)); + + const loop: Mir.Inst.Index = @intCast(cg.mir_instructions.len); + if (elem_ty.toIntern() == .bool_type) { + try cg.asmMemoryImmediate(.{ ._, .cmp }, .{ + .base = .{ .frame = regs_frame_addr.frame_index }, + .mod = .{ .rm = .{ + .size = .byte, + .index = index_reg.to64(), + .scale = .@"8", + .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len, + } }, + }, Immediate.u(0)); + const unset = try cg.asmJccReloc(.e, undefined); + try cg.asmMemoryRegister( + .{ ._s, .bt }, + try dst_mcv.mem(cg, .{ .size = .dword }), + index_reg.to32(), ); + cg.performReloc(unset); + } else { + const elem_reg = + try cg.register_manager.allocReg(null, regSetForRegClass(elem_rc)); + const elem_lock = cg.register_manager.lockRegAssumeUnused(elem_reg); + defer cg.register_manager.unlockReg(elem_lock); + + try strat.read(cg, elem_reg.toSize(elem_size, cg.target), .{ + .base = .{ .frame = regs_frame_addr.frame_index }, + .mod = .{ .rm = .{ + .size = elem_size, + .index = index_reg.to64(), + .scale = .@"8", + .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len, + } }, + }); + try strat.write(cg, try dst_mcv.mem(cg, .{ + .size = elem_size, + .index = index_reg.to64(), + .scale = .fromFactor(@intCast(elem_abi_size)), + }), elem_reg.toSize(elem_size, cg.target)); + } + if (cg.hasFeature(.slow_incdec)) { + try cg.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1)); + } else { + try cg.asmRegister(.{ ._c, .in }, index_reg.to32()); } - prev_reg = dst_reg; + try cg.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(len)); + _ = try cg.asmJccReloc(.b, loop); } - const prev_lock = if (regs_frame_addr.regs > 0) - self.register_manager.lockRegAssumeUnused(prev_reg) - else - null; - defer if (prev_lock) |lock| self.register_manager.unlockReg(lock); + break :result dst_mcv; + }, + .xwordwise_sse, .ywordwise_sse, .zwordwise_sse => |regs_frame_addr| { + const fn_info = zcu.typeToFunc(cg.fn_type).?; + const elem_size: Memory.Size, const elem_ty: Type = switch (src_mcv) { + else => unreachable, + .xwordwise_sse => .{ .xword, .vector_16_u8 }, + .ywordwise_sse => .{ .yword, .vector_32_u8 }, + .zwordwise_sse => .{ .zword, .vector_64_u8 }, + }; + const elem_abi_size: u31 = @intCast(@divExact(elem_size.bitSize(cg.target), 8)); + const strat = try cg.moveStrategy(elem_ty, .sse, true); + + const param_gpr_regs = abi.getCAbiIntParamRegs(fn_info.cc); + const len = @divExact(arg_ty.abiSize(zcu), elem_abi_size); + const param_gpr_len: u31 = + @intCast(@min(param_gpr_regs.len - regs_frame_addr.info.reg_index, len)); + + const part_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.sse); + const part_lock = cg.register_manager.lockRegAssumeUnused(part_reg); + defer cg.register_manager.unlockReg(part_lock); + const part_alias = part_reg.toSize(elem_size, cg.target); - const dst_mcv = try self.allocRegOrMem(inst, false); - if (regs_frame_addr.regs > 0) try self.asmMemoryRegister( - .{ ._, .mov }, - try dst_mcv.mem(self, .{ .size = .byte }), - prev_reg.to8(), - ); - try self.genInlineMemset( - dst_mcv.address().offset(@intFromBool(regs_frame_addr.regs > 0)), - .{ .immediate = 0 }, - .{ .immediate = arg_ty.abiSize(zcu) - @intFromBool(regs_frame_addr.regs > 0) }, - .{}, - ); + const dst_mcv = try cg.allocRegOrMem(inst, false); - const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); - const index_lock = self.register_manager.lockRegAssumeUnused(index_reg); - defer self.register_manager.unlockReg(index_lock); + var arg_offset: u31 = 0; + for (param_gpr_regs[regs_frame_addr.info.reg_index..][0..param_gpr_len]) |src_reg| { + try strat.read(cg, part_alias, .{ + .base = .{ .reg = src_reg }, + .mod = .{ .rm = .{ .size = elem_size } }, + }); + try strat.write(cg, try dst_mcv.mem(cg, .{ + .size = elem_size, + .disp = arg_offset, + }), part_alias); + arg_offset += elem_abi_size; + } + + if (len - param_gpr_len > 0) { + const index_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gp); + const index_lock = cg.register_manager.lockRegAssumeUnused(index_reg); + defer cg.register_manager.unlockReg(index_lock); + try cg.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .u(8 * param_gpr_len)); - try self.asmRegisterImmediate( - .{ ._, .mov }, - index_reg.to32(), - .u(regs_frame_addr.regs), - ); - const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); - try self.asmMemoryImmediate(.{ ._, .cmp }, .{ - .base = .{ .frame = regs_frame_addr.frame_index }, - .mod = .{ .rm = .{ - .size = .byte, - .index = index_reg.to64(), - .scale = .@"8", - .disp = regs_frame_addr.frame_off - @as(u6, regs_frame_addr.regs) * 8, - } }, - }, Immediate.u(0)); - const unset = try self.asmJccReloc(.e, undefined); - try self.asmMemoryRegister( - .{ ._s, .bt }, - try dst_mcv.mem(self, .{ .size = .dword }), - index_reg.to32(), - ); - self.performReloc(unset); - if (self.hasFeature(.slow_incdec)) { - try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1)); - } else { - try self.asmRegister(.{ ._c, .in }, index_reg.to32()); + const loop: Mir.Inst.Index = @intCast(cg.mir_instructions.len); + { + const ptr_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gp); + const ptr_lock = cg.register_manager.lockRegAssumeUnused(ptr_reg); + defer cg.register_manager.unlockReg(ptr_lock); + + try cg.asmRegisterMemory(.{ ._, .mov }, ptr_reg.to64(), .{ + .base = .{ .frame = regs_frame_addr.frame_index }, + .mod = .{ .rm = .{ + .size = .ptr, + .index = index_reg.to64(), + .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_gpr_len, + } }, + }); + try strat.read(cg, part_alias, .{ + .base = .{ .reg = ptr_reg }, + .mod = .{ .rm = .{ .size = elem_size } }, + }); + try strat.write(cg, try dst_mcv.mem(cg, .{ + .size = elem_size, + .index = index_reg.to64(), + .scale = .fromFactor(@intCast(@divExact(elem_abi_size, 8))), + }), part_alias); + } + try cg.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(8)); + try cg.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(8 * len)); + _ = try cg.asmJccReloc(.b, loop); } - try self.asmRegisterImmediate( - .{ ._, .cmp }, - index_reg.to32(), - .u(arg_ty.vectorLen(zcu)), - ); - _ = try self.asmJccReloc(.b, loop); break :result dst_mcv; }, - else => return self.fail("TODO implement arg for {f}", .{src_mcv}), + else => return cg.fail("TODO implement arg for {f}", .{src_mcv}), } }; - return self.finishAir(inst, result, .{ .none, .none, .none }); + return cg.finishAir(inst, result, .{ .none, .none, .none }); } fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue) !void { @@ -175804,7 +176139,18 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue _ = switch (air_tag) { else => unreachable, .arg, .dbg_var_val, .dbg_arg_inline => switch (mcv) { - .none, .unreach, .dead, .elementwise_args, .reserved_frame, .air_ref => unreachable, + .none, + .unreach, + .dead, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, + .reserved_frame, + .air_ref, + => unreachable, .immediate => |imm| if (std.math.cast(u32, imm)) |small| try cg.addInst(.{ .tag = .pseudo, .ops = switch (air_tag) { @@ -175852,7 +176198,18 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue }, .dbg_var_ptr => switch (mcv) { else => unreachable, - .none, .unreach, .dead, .elementwise_args, .reserved_frame, .air_ref => unreachable, + .none, + .unreach, + .dead, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, + .reserved_frame, + .air_ref, + => unreachable, .lea_frame => |frame_addr| try cg.addInst(.{ .tag = .pseudo, .ops = .pseudo_dbg_var_m, @@ -175910,10 +176267,10 @@ fn genLocalDebugInfo(cg: *CodeGen, air_tag: Air.Inst.Tag, ty: Type, mcv: MCValue }; } -fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier, opts: CopyOptions) !void { - if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); +fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier, opts: CopyOptions) !void { + if (modifier == .always_tail) return cg.fail("TODO implement tail calls for x86_64", .{}); - const call = self.air.unwrapCall(inst); + const call = cg.air.unwrapCall(inst); const arg_refs = call.args; const ExpectedContents = extern struct { @@ -175921,28 +176278,28 @@ fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier vals: [32][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)), }; var bfa_buf: [1]ExpectedContents = undefined; - var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa); + var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), cg.gpa); const allocator = bfa.allocator(); const arg_tys = try allocator.alloc(Type, arg_refs.len); defer allocator.free(arg_tys); - for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = self.typeOf(arg_ref); + for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = cg.typeOf(arg_ref); const arg_vals = try allocator.alloc(MCValue, arg_refs.len); defer allocator.free(arg_vals); for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref }; - const ret = try self.genCall(.{ .air = call.callee }, arg_tys, arg_vals, opts); + const ret = try cg.genCall(.{ .air = call.callee }, arg_tys, arg_vals, opts); - var bt = self.liveness.iterateBigTomb(inst); - try self.feed(&bt, call.callee); - for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref); + var bt = cg.liveness.iterateBigTomb(inst); + try cg.feed(&bt, call.callee); + for (arg_refs) |arg_ref| try cg.feed(&bt, arg_ref); - const result = if (self.liveness.isUnused(inst)) .unreach else ret; - return self.finishAirResult(inst, result); + const result = if (cg.liveness.isUnused(inst)) .unreach else ret; + return cg.finishAirResult(inst, result); } -fn genCall(self: *CodeGen, info: union(enum) { +fn genCall(cg: *CodeGen, info: union(enum) { air: Air.Inst.Ref, extern_func: struct { return_type: InternPool.Index, @@ -175950,13 +176307,13 @@ fn genCall(self: *CodeGen, info: union(enum) { sym: []const u8, }, }, arg_types: []const Type, args: []const MCValue, opts: CopyOptions) !MCValue { - const pt = self.pt; + const pt = cg.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; const fn_ty = switch (info) { .air => |callee| fn_info: { - const callee_ty = self.typeOf(callee); + const callee_ty = cg.typeOf(callee); break :fn_info switch (callee_ty.zigTypeTag(zcu)) { .@"fn" => callee_ty, .pointer => callee_ty.childType(zcu), @@ -175966,7 +176323,7 @@ fn genCall(self: *CodeGen, info: union(enum) { .extern_func => |extern_func| try pt.funcType(.{ .param_types = extern_func.param_types, .return_type = extern_func.return_type, - .cc = self.target.cCallingConvention().?, + .cc = cg.target.cCallingConvention().?, }), }; const fn_info = zcu.typeToFunc(fn_ty).?; @@ -175977,23 +176334,23 @@ fn genCall(self: *CodeGen, info: union(enum) { reg_locks: [32][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)), }; var bfa_buf: ExpectedContents = undefined; - var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa); + var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), cg.gpa); const allocator = bfa.allocator(); const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len); defer allocator.free(var_args); - for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty; + @memcpy(var_args, arg_types[fn_info.param_types.len..]); const frame_indices = try allocator.alloc(FrameIndex, args.len); defer allocator.free(frame_indices); - var reg_locks: std.array_list.Managed(?RegisterLock) = .init(allocator); - defer reg_locks.deinit(); - try reg_locks.ensureTotalCapacity(16); - defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); + var reg_locks: std.ArrayList(?RegisterLock) = .empty; + defer reg_locks.deinit(allocator); + try reg_locks.ensureTotalCapacity(allocator, 16); + defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| cg.register_manager.unlockReg(lock); - var call_info = try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); - defer call_info.deinit(self); + var call_info = try cg.resolveCallingConventionValues(fn_info, var_args, .call_frame); + defer call_info.deinit(cg); // We need a properly aligned and sized call frame to be able to call this function. { @@ -176001,7 +176358,7 @@ fn genCall(self: *CodeGen, info: union(enum) { .size = call_info.stack_byte_count, .alignment = call_info.stack_align, }); - const frame_allocs_slice = self.frame_allocs.slice(); + const frame_allocs_slice = cg.frame_allocs.slice(); const stack_frame_size = &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)]; stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); @@ -176010,112 +176367,228 @@ fn genCall(self: *CodeGen, info: union(enum) { stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align); } - try self.spillEflagsIfOccupied(); - try self.spillCallerPreservedRegs(fn_info.cc, call_info.err_ret_trace_reg); + try cg.spillEflagsIfOccupied(); + try cg.spillCallerPreservedRegs(fn_info.cc, call_info.err_ret_trace_reg); // set stack arguments first because this can clobber registers // also clobber spill arguments as we go switch (call_info.return_value.long) { .none, .unreach => {}, - .indirect => |reg_off| try self.register_manager.getReg(reg_off.reg, null), + .indirect => |reg_off| try cg.register_manager.getReg(reg_off.reg, null), else => unreachable, } - for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, *frame_index, arg_i| - switch (dst_arg) { - .none => {}, - .register => |reg| { - try self.register_manager.getReg(reg, null); - try reg_locks.append(self.register_manager.lockReg(reg)); + for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, *frame_index| switch (dst_arg) { + .none => {}, + .register => |reg| { + try cg.register_manager.getReg(reg, null); + try reg_locks.append(allocator, cg.register_manager.lockReg(reg)); + }, + inline .register_pair, .register_triple, .register_quadruple => |regs| { + for (regs) |reg| try cg.register_manager.getReg(reg, null); + try reg_locks.appendSlice(allocator, &cg.register_manager.lockRegs(regs.len, regs)); + }, + .register_mask => |reg_mask| { + try cg.register_manager.getReg(reg_mask.reg, null); + try reg_locks.append(allocator, cg.register_manager.lockReg(reg_mask.reg)); + }, + .indirect => |reg_off| { + frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu)); + try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts); + try cg.register_manager.getReg(reg_off.reg, null); + try reg_locks.append(allocator, cg.register_manager.lockReg(reg_off.reg)); + }, + .indirect_load_frame => |frame_addr| { + frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu)); + try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts); + try cg.genSetMem( + .{ .frame = frame_addr.index }, + frame_addr.off, + .usize, + .{ .lea_frame = .{ .index = frame_index.* } }, + opts, + ); + }, + .indirect_mask => |reg_mask| { + var src = switch (src_arg) { + else => try cg.tempInit(arg_ty, src_arg), + .air_ref => |src_ref| try cg.tempFromOperand(src_ref, false), + }; + var dst = try cg.tempInit(arg_ty, .{ .register_mask = .{ + .reg = try cg.register_manager.allocReg(null, abi.RegisterClass.sse), + .info = reg_mask.info, + } }); + dst.copyToMask(&src, cg) catch |err| switch (err) { + error.SelectFailed => return cg.fail("failed to select arg {f} {f} {f}", .{ + arg_ty.fmt(pt), + dst.tracking(cg), + src.tracking(cg), + }), + else => |e| return e, + }; + try src.die(cg); + const mask_size: u32 = @intCast( + @divExact(reg_mask.info.scalar.bitSize(cg.target), 8) * arg_ty.vectorLen(zcu), + ); + frame_index.* = try cg.allocFrameIndex(.init(.{ + .size = mask_size, + .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, mask_size)), + })); + try cg.asmMemoryRegister( + .{ if (cg.hasFeature(.avx)) .v_dqa else ._dqa, .mov }, + .{ + .base = .{ .frame = frame_index.* }, + .mod = .{ .rm = .{ .size = .fromSize(mask_size) } }, + }, + registerAlias(dst.tracking(cg).short.register_mask.reg, mask_size), + ); + try dst.die(cg); - if (fn_info.is_var_args and - fn_info.cc == .x86_64_win and - reg.class() == .sse and - arg_i < abi.Win64.c_abi_int_param_regs.len) - { - // Floating point arguments must be duplicated into the equivalent integer registers on this ABI - const int_reg = abi.Win64.c_abi_int_param_regs[arg_i]; - try reg_locks.append(self.register_manager.lockReg(int_reg)); - } - }, - .register_pair => |regs| { - for (regs) |reg| try self.register_manager.getReg(reg, null); - try reg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); - }, - .indirect => |reg_off| { - frame_index.* = try self.allocFrameIndex(.initType(arg_ty, zcu)); - try self.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts); - try self.register_manager.getReg(reg_off.reg, null); - try reg_locks.append(self.register_manager.lockReg(reg_off.reg)); - }, - .load_frame => { - try self.genCopy(arg_ty, dst_arg, src_arg, opts); - try self.freeValue(src_arg, .{}); - }, - .elementwise_args => |regs_frame_addr| { - const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); - const index_lock = self.register_manager.lockRegAssumeUnused(index_reg); - defer self.register_manager.unlockReg(index_lock); + try cg.register_manager.getReg(reg_mask.reg, null); + try reg_locks.append(allocator, cg.register_manager.lockReg(reg_mask.reg)); + }, + .load_frame => { + try cg.genCopy(arg_ty, dst_arg, src_arg, opts); + try cg.freeValue(src_arg, .{}); + }, + .register_tee => |regs| { + try reg_locks.ensureUnusedCapacity(allocator, regs.len); + for (regs) |reg| if (reg != .none) { + try cg.register_manager.getReg(reg, null); + reg_locks.appendAssumeCapacity(cg.register_manager.lockReg(reg)); + }; + }, + .elementwise_gpr, .elementwise_sse => |regs_frame_addr| { + const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(cg, .{ .size = .dword }) else .{ + .base = .{ .reg = try cg.copyToTmpRegister(.usize, switch (src_arg) { + else => src_arg, + .air_ref => |src_ref| try cg.resolveInst(src_ref), + }.address()) }, + .mod = .{ .rm = .{ .size = .dword } }, + }; + const src_lock = switch (src_mem.base) { + .reg => |src_reg| cg.register_manager.lockReg(src_reg), + else => null, + }; + defer if (src_lock) |lock| cg.register_manager.unlockReg(lock); + + const elem_rc: Register.Class, const param_regs = switch (dst_arg) { + else => unreachable, + .elementwise_gpr => .{ .general_purpose, abi.getCAbiIntParamRegs(fn_info.cc) }, + .elementwise_sse => .{ .sse, abi.getCAbiSseParamRegs(fn_info.cc, cg.target) }, + }; + const len = arg_ty.vectorLen(zcu); + const param_reg_len: u31 = + @intCast(@min(param_regs.len - regs_frame_addr.info.reg_index, len)); - const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{ - .base = .{ .reg = try self.copyToTmpRegister(.usize, switch (src_arg) { - else => src_arg, - .air_ref => |src_ref| try self.resolveInst(src_ref), - }.address()) }, - .mod = .{ .rm = .{ .size = .dword } }, - }; - const src_lock = switch (src_mem.base) { - .reg => |src_reg| self.register_manager.lockReg(src_reg), - else => null, - }; - defer if (src_lock) |lock| self.register_manager.unlockReg(lock); + if (len - param_reg_len > 0) { + const index_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gp); + const index_lock = cg.register_manager.lockRegAssumeUnused(index_reg); + defer cg.register_manager.unlockReg(index_lock); + try cg.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .u(param_reg_len)); - try self.asmRegisterImmediate( - .{ ._, .mov }, - index_reg.to32(), - .u(regs_frame_addr.regs), - ); - const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); - try self.asmMemoryRegister(.{ ._, .bt }, src_mem, index_reg.to32()); - try self.asmSetccMemory(.c, .{ - .base = .{ .frame = regs_frame_addr.frame_index }, - .mod = .{ .rm = .{ - .size = .byte, - .index = index_reg.to64(), - .scale = .@"8", - .disp = regs_frame_addr.frame_off - @as(u6, regs_frame_addr.regs) * 8, - } }, - }); - if (self.hasFeature(.slow_incdec)) { - try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1)); + const loop: Mir.Inst.Index = @intCast(cg.mir_instructions.len); + const elem_ty = arg_ty.childType(zcu); + if (elem_ty.toIntern() == .bool_type) { + try cg.asmMemoryRegister(.{ ._, .bt }, src_mem, index_reg.to32()); + try cg.asmSetccMemory(.c, .{ + .base = .{ .frame = regs_frame_addr.frame_index }, + .mod = .{ .rm = .{ + .size = .byte, + .index = index_reg.to64(), + .scale = .@"8", + .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len, + } }, + }); } else { - try self.asmRegister(.{ ._c, .in }, index_reg.to32()); - } - try self.asmRegisterImmediate( - .{ ._, .cmp }, - index_reg.to32(), - .u(arg_ty.vectorLen(zcu)), - ); - _ = try self.asmJccReloc(.b, loop); + const elem_reg = + try cg.register_manager.allocReg(null, regSetForRegClass(elem_rc)); + const elem_lock = cg.register_manager.lockRegAssumeUnused(elem_reg); + defer cg.register_manager.unlockReg(elem_lock); + const elem_size = cg.memSize(elem_ty, .general_purpose); + const elem_alias = elem_reg.toSize(elem_size, cg.target); - const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); - for (param_int_regs[param_int_regs.len - regs_frame_addr.regs ..]) |dst_reg| { - try self.register_manager.getReg(dst_reg, null); - try reg_locks.append(self.register_manager.lockReg(dst_reg)); + const strat = try cg.moveStrategy(elem_ty, elem_rc, true); + assert(src_mem.mod.rm.index == .none and src_mem.mod.rm.scale == .@"1"); + try strat.read(cg, elem_alias, .{ + .base = src_mem.base, + .mod = .{ .rm = .{ + .size = elem_size, + .index = index_reg.to64(), + .scale = .fromFactor(@intCast(@divExact(elem_size.bitSize(cg.target), 8))), + .disp = src_mem.mod.rm.disp, + } }, + }); + try strat.write(cg, .{ + .base = .{ .frame = regs_frame_addr.frame_index }, + .mod = .{ .rm = .{ + .size = elem_size, + .index = index_reg.to64(), + .scale = .@"8", + .disp = @as(i32, regs_frame_addr.info.frame_off) - 8 * param_reg_len, + } }, + }, elem_alias); + } + if (cg.hasFeature(.slow_incdec)) { + try cg.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1)); + } else { + try cg.asmRegister(.{ ._c, .in }, index_reg.to32()); } - }, - else => unreachable, - }; + try cg.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(len)); + _ = try cg.asmJccReloc(.b, loop); + } + + for (param_regs[regs_frame_addr.info.reg_index..][0..param_reg_len]) |dst_reg| { + try cg.register_manager.getReg(dst_reg, null); + try reg_locks.append(allocator, cg.register_manager.lockReg(dst_reg)); + } + }, + .xwordwise_sse, .ywordwise_sse, .zwordwise_sse => |regs_frame_addr| { + const elem_size: u31 = switch (dst_arg) { + else => unreachable, + .xwordwise_sse => 16, + .ywordwise_sse => 32, + .zwordwise_sse => 64, + }; + const param_gpr_regs = abi.getCAbiIntParamRegs(fn_info.cc); + const arg_size: u31 = @intCast(arg_ty.abiSize(zcu)); + const len = @divExact(arg_size, elem_size); + const param_gpr_len: u31 = + @intCast(@min(param_gpr_regs.len - regs_frame_addr.info.reg_index, len)); + + frame_index.* = try cg.allocFrameIndex(.initType(arg_ty, zcu)); + try cg.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts); + + var frame_offset: i32 = regs_frame_addr.info.frame_off; + var arg_offset = elem_size * param_gpr_len; + while (arg_size - arg_offset > 0) : ({ + frame_offset += 8; + arg_offset += elem_size; + }) try cg.genSetMem( + .{ .frame = regs_frame_addr.frame_index }, + frame_offset, + .usize, + .{ .lea_frame = .{ .index = frame_index.*, .off = arg_offset } }, + opts, + ); + + for (param_gpr_regs[regs_frame_addr.info.reg_index..][0..param_gpr_len]) |dst_reg| { + try cg.register_manager.getReg(dst_reg, null); + try reg_locks.append(allocator, cg.register_manager.lockReg(dst_reg)); + } + }, + else => unreachable, + }; if (call_info.err_ret_trace_reg != .none) { - if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { + if (cg.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { if (switch (err_ret_trace.short) { .register => |reg| call_info.err_ret_trace_reg != reg, else => true, }) { - try self.register_manager.getReg(call_info.err_ret_trace_reg, err_ret_trace_index); - try reg_locks.append(self.register_manager.lockReg(call_info.err_ret_trace_reg)); + try cg.register_manager.getReg(call_info.err_ret_trace_reg, err_ret_trace_index); + try reg_locks.append(allocator, cg.register_manager.lockReg(call_info.err_ret_trace_reg)); - try self.genSetReg(call_info.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); + try cg.genSetReg(call_info.err_ret_trace_reg, .usize, err_ret_trace.short, opts); err_ret_trace.trackMaterialize(err_ret_trace_index, .{ .long = err_ret_trace.long, .short = .{ .register = call_info.err_ret_trace_reg }, @@ -176129,79 +176602,130 @@ fn genCall(self: *CodeGen, info: union(enum) { .none, .unreach => {}, .indirect => |reg_off| { const ret_ty: Type = .fromInterned(fn_info.return_type); - const frame_index = try self.allocFrameIndex(.initSpill(ret_ty, zcu)); - try self.genSetReg(reg_off.reg, .usize, .{ + const frame_index = try cg.allocFrameIndex(.initSpill(ret_ty, zcu)); + try cg.genSetReg(reg_off.reg, .usize, .{ .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, - }, .{}); + }, opts); call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } }; - try reg_locks.append(self.register_manager.lockReg(reg_off.reg)); + try reg_locks.append(allocator, cg.register_manager.lockReg(reg_off.reg)); }, else => unreachable, } - for (call_info.args, arg_types, args, frame_indices, 0..) |dst_arg, arg_ty, src_arg, frame_index, arg_i| - switch (dst_arg) { - .none, .load_frame => {}, - .register => |dst_reg| switch (fn_info.cc) { - else => try self.genSetReg(registerAlias( + 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_pair, + .register_triple, + .register_quadruple, + => try cg.genCopy(arg_ty, dst_arg, src_arg, opts), + .register_mask => { + var src = switch (src_arg) { + else => try cg.tempInit(arg_ty, src_arg), + .air_ref => |src_ref| try cg.tempFromOperand(src_ref, false), + }; + var dst = try cg.tempInit(arg_ty, dst_arg); + dst.copyToMask(&src, cg) catch |err| switch (err) { + error.SelectFailed => return cg.fail("failed to select arg {f} {f} {f}", .{ + arg_ty.fmt(pt), + dst.tracking(cg), + src.tracking(cg), + }), + else => |e| return e, + }; + try src.die(cg); + try dst.die(cg); + }, + .indirect => |dst_reg_off| try cg.genSetReg(dst_reg_off.reg, .usize, .{ + .lea_frame = .{ .index = frame_index, .off = -dst_reg_off.off }, + }, opts), + .indirect_mask => |dst_reg_mask| try cg.genSetReg(dst_reg_mask.reg, .usize, .{ + .lea_frame = .{ .index = frame_index }, + }, opts), + .register_tee => |dst_regs| { + try cg.genSetReg(dst_regs[0], arg_ty, src_arg, opts); + for (dst_regs[1..]) |dst_reg| if (dst_reg != .none) try cg.genSetReg(dst_reg, arg_ty, .{ + .register = dst_regs[0], + }, opts); + }, + .elementwise_gpr, .elementwise_sse => |regs_frame_addr| { + const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(cg, .{ .size = .dword }) else .{ + .base = .{ .reg = try cg.copyToTmpRegister( + .usize, + switch (src_arg) { + else => src_arg, + .air_ref => |src_ref| try cg.resolveInst(src_ref), + }.address(), + ) }, + .mod = .{ .rm = .{ .size = .dword } }, + }; + const src_lock = switch (src_mem.base) { + .reg => |src_reg| cg.register_manager.lockReg(src_reg), + else => null, + }; + defer if (src_lock) |lock| cg.register_manager.unlockReg(lock); + + const elem_rc: Register.Class, const param_regs = switch (dst_arg) { + else => unreachable, + .elementwise_gpr => .{ .general_purpose, abi.getCAbiIntParamRegs(fn_info.cc) }, + .elementwise_sse => .{ .sse, abi.getCAbiSseParamRegs(fn_info.cc, cg.target) }, + }; + const len = arg_ty.vectorLen(zcu); + const elem_ty = arg_ty.childType(zcu); + const elem_size = cg.memSize(elem_ty, .general_purpose); + const elem_abi_size = @divExact(elem_size.bitSize(cg.target), 8); + const param_reg_len: u31 = + @intCast(@min(param_regs.len - regs_frame_addr.info.reg_index, len)); + const strat = if (elem_ty.toIntern() == .bool_type) strat: { + try cg.spillEflagsIfOccupied(); + break :strat undefined; + } else try cg.moveStrategy(elem_ty, elem_rc, true); + for ( + param_regs[regs_frame_addr.info.reg_index..][0..param_reg_len], + 0.., + ) |dst_reg, elem_index| if (elem_ty.toIntern() == .bool_type) { + try cg.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()); + try cg.asmMemoryImmediate(.{ ._, .bt }, src_mem, .u(elem_index)); + try cg.asmSetccRegister(.c, dst_reg.to8()); + } else try strat.read(cg, dst_reg.toSize(elem_size, cg.target), .{ + .base = src_mem.base, + .mod = .{ .rm = .{ + .size = elem_size, + .disp = src_mem.mod.rm.disp + @as(u31, @intCast(elem_abi_size * elem_index)), + } }, + }); + }, + .xwordwise_sse, .ywordwise_sse, .zwordwise_sse => |regs_frame_addr| { + const elem_size: u31 = switch (dst_arg) { + else => unreachable, + .xwordwise_sse => 16, + .ywordwise_sse => 32, + .zwordwise_sse => 64, + }; + const param_gpr_regs = abi.getCAbiIntParamRegs(fn_info.cc); + const len = @divExact(arg_ty.abiSize(zcu), elem_size); + const param_gpr_len: u31 = + @intCast(@min(param_gpr_regs.len - regs_frame_addr.info.reg_index, len)); + + var arg_offset: u31 = 0; + for (param_gpr_regs[regs_frame_addr.info.reg_index..][0..param_gpr_len]) |dst_reg| { + try cg.genSetReg( dst_reg, - @intCast(arg_ty.abiSize(zcu)), - ), arg_ty, src_arg, opts), - .x86_64_sysv, .x86_64_win => { - const promoted_ty = self.promoteInt(arg_ty); - const promoted_abi_size: u32 = @intCast(promoted_ty.abiSize(zcu)); - const dst_alias = registerAlias(dst_reg, promoted_abi_size); - try self.genSetReg(dst_alias, promoted_ty, src_arg, opts); - if (promoted_ty.toIntern() != arg_ty.toIntern()) - try self.truncateRegister(arg_ty, dst_alias); - - if (fn_info.is_var_args and - fn_info.cc == .x86_64_win and - dst_reg.class() == .sse and - arg_i < abi.Win64.c_abi_int_param_regs.len) - { - const int_dst_reg = abi.Win64.c_abi_int_param_regs[arg_i]; - const int_dst_alias = registerAlias(int_dst_reg, promoted_abi_size); - try self.genSetReg(int_dst_alias, promoted_ty, .{ .register = dst_alias }, opts); - } - }, - }, - .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg, opts), - .indirect => |reg_off| try self.genSetReg(reg_off.reg, .usize, .{ - .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, - }, .{}), - .elementwise_args => |regs_frame_addr| { - const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{ - .base = .{ .reg = try self.copyToTmpRegister( - .usize, - switch (src_arg) { - else => src_arg, - .air_ref => |src_ref| try self.resolveInst(src_ref), - }.address(), - ) }, - .mod = .{ .rm = .{ .size = .dword } }, - }; - const src_lock = switch (src_mem.base) { - .reg => |src_reg| self.register_manager.lockReg(src_reg), - else => null, - }; - defer if (src_lock) |lock| self.register_manager.unlockReg(lock); - - const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc); - for ( - param_int_regs[param_int_regs.len - regs_frame_addr.regs ..], - 0.., - ) |dst_reg, elem_index| { - try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()); - try self.asmMemoryImmediate(.{ ._, .bt }, src_mem, .u(elem_index)); - try self.asmSetccRegister(.c, dst_reg.to8()); - } - }, - else => unreachable, - }; + .usize, + .{ .lea_frame = .{ .index = frame_index, .off = arg_offset } }, + opts, + ); + arg_offset += elem_size; + } + }, + else => unreachable, + }; if (fn_info.is_var_args and fn_info.cc == .x86_64_sysv) - try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); + try cg.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count)); // Due to incremental compilation, how function calls are generated depends // on linking. @@ -176216,45 +176740,57 @@ fn genCall(self: *CodeGen, info: union(enum) { } else func_key, }) { else => unreachable, - .func => |func| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = func.owner_nav } }), - .@"extern" => |@"extern"| try self.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = @"extern".owner_nav } }), + .func => |func| try cg.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = func.owner_nav } }), + .@"extern" => |@"extern"| try cg.asmImmediate(.{ ._, .call }, .{ .nav = .{ .index = @"extern".owner_nav } }), } } else { - assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer); + assert(cg.typeOf(callee).zigTypeTag(zcu) == .pointer); const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc); - try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{}); - try self.asmRegister(.{ ._, .call }, scratch_reg); + try cg.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, opts); + try cg.asmRegister(.{ ._, .call }, scratch_reg); }, - .extern_func => |extern_func| try self.asmImmediate(.{ ._, .call }, .{ .extern_func = try self.addString(extern_func.sym) }), + .extern_func => |extern_func| try cg.asmImmediate(.{ ._, .call }, .{ .extern_func = try cg.addString(extern_func.sym) }), } return call_info.return_value.short; } -fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { - const pt = self.pt; - const zcu = pt.zcu; - const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; +fn airRet(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { + const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const ret_ty = self.fn_type.fnReturnType(zcu); - switch (self.ret_mcv.short) { + const ret_ty = cg.fn_type.fnReturnType(cg.pt.zcu); + switch (cg.ret_mcv.short) { .none => {}, .register => |reg| { - const reg_lock = self.register_manager.lockRegAssumeUnused(reg); - defer self.register_manager.unlockReg(reg_lock); - try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }); + const reg_lock = cg.register_manager.lockRegAssumeUnused(reg); + defer cg.register_manager.unlockReg(reg_lock); + try cg.genCopy(ret_ty, cg.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }); }, inline .register_pair, .register_triple, .register_quadruple => |regs| { - const reg_locks = self.register_manager.lockRegsAssumeUnused(regs.len, regs); - defer for (reg_locks) |reg_lock| self.register_manager.unlockReg(reg_lock); - try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }); + const reg_locks = cg.register_manager.lockRegsAssumeUnused(regs.len, regs); + defer for (reg_locks) |reg_lock| cg.register_manager.unlockReg(reg_lock); + try cg.genCopy(ret_ty, cg.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety }); + }, + .register_mask => { + var src = try cg.tempFromOperand(un_op, true); + var dst = try cg.tempInit(ret_ty, cg.ret_mcv.short); + dst.copyToMask(&src, cg) catch |err| switch (err) { + error.SelectFailed => return cg.fail("failed to select ret {f} {f} {f}", .{ + ret_ty.fmt(cg.pt), + dst.tracking(cg), + src.tracking(cg), + }), + else => |e| return e, + }; + try src.die(cg); + try dst.die(cg); }, .indirect => |reg_off| { - try self.register_manager.getReg(reg_off.reg, null); - const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg); - defer self.register_manager.unlockReg(lock); + try cg.register_manager.getReg(reg_off.reg, null); + const lock = cg.register_manager.lockRegAssumeUnused(reg_off.reg); + defer cg.register_manager.unlockReg(lock); - try self.genSetReg(reg_off.reg, .usize, self.ret_mcv.long, .{}); - try self.genSetMem( + try cg.genSetReg(reg_off.reg, .usize, cg.ret_mcv.long, .{}); + try cg.genSetMem( .{ .reg = reg_off.reg }, reg_off.off, ret_ty, @@ -176264,55 +176800,78 @@ fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { }, else => unreachable, } - self.ret_mcv.liveOut(self, inst); + cg.ret_mcv.liveOut(cg, inst); - if (self.err_ret_trace_reg != .none) { - if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { + if (cg.err_ret_trace_reg != .none) { + if (cg.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { if (switch (err_ret_trace.short) { - .register => |reg| self.err_ret_trace_reg != reg, + .register => |reg| cg.err_ret_trace_reg != reg, else => true, - }) try self.genSetReg(self.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); - err_ret_trace.liveOut(self, err_ret_trace_index); + }) try cg.genSetReg(cg.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); + err_ret_trace.liveOut(cg, err_ret_trace_index); } } - try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); + try cg.finishAir(inst, .unreach, .{ un_op, .none, .none }); // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction // which is available if the jump is 127 bytes or less forward. - const jmp_reloc = try self.asmJmpReloc(undefined); - try self.epilogue_relocs.append(self.gpa, jmp_reloc); + const jmp_reloc = try cg.asmJmpReloc(undefined); + try cg.epilogue_relocs.append(cg.gpa, jmp_reloc); } -fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void { - const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; - const ptr = try self.resolveInst(un_op); - - const ptr_ty = self.typeOf(un_op); - switch (self.ret_mcv.short) { +fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void { + const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; + switch (cg.ret_mcv.short) { .none => {}, - .register, .register_pair => try self.load(self.ret_mcv.short, ptr_ty, ptr), - .indirect => |reg_off| try self.genSetReg(reg_off.reg, ptr_ty, ptr, .{}), + .register, + .register_pair, + .register_triple, + .register_quadruple, + => try cg.load(cg.ret_mcv.short, cg.typeOf(un_op), try cg.resolveInst(un_op)), + .register_mask => { + var ptr = try cg.tempFromOperand(un_op, true); + const ret_ty = ptr.typeOf(cg).childType(cg.pt.zcu); + var src = try ptr.load(ret_ty, .{}, cg); + try ptr.die(cg); + var dst = try cg.tempInit(ret_ty, cg.ret_mcv.short); + dst.copyToMask(&src, cg) catch |err| switch (err) { + error.SelectFailed => return cg.fail("failed to select ret_load {f} {f} {f}", .{ + ret_ty.fmt(cg.pt), + dst.tracking(cg), + src.tracking(cg), + }), + else => |e| return e, + }; + try src.die(cg); + try dst.die(cg); + }, + .indirect => |dst_reg_off| try cg.genSetReg( + dst_reg_off.reg, + cg.typeOf(un_op), + try cg.resolveInst(un_op), + .{}, + ), else => unreachable, } - self.ret_mcv.liveOut(self, inst); + cg.ret_mcv.liveOut(cg, inst); - if (self.err_ret_trace_reg != .none) { - if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { + if (cg.err_ret_trace_reg != .none) { + if (cg.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| { if (switch (err_ret_trace.short) { - .register => |reg| self.err_ret_trace_reg != reg, + .register => |reg| cg.err_ret_trace_reg != reg, else => true, - }) try self.genSetReg(self.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); - err_ret_trace.liveOut(self, err_ret_trace_index); + }) try cg.genSetReg(cg.err_ret_trace_reg, .usize, err_ret_trace.short, .{}); + err_ret_trace.liveOut(cg, err_ret_trace_index); } } - try self.finishAir(inst, .unreach, .{ un_op, .none, .none }); + try cg.finishAir(inst, .unreach, .{ un_op, .none, .none }); // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction // which is available if the jump is 127 bytes or less forward. - const jmp_reloc = try self.asmJmpReloc(undefined); - try self.epilogue_relocs.append(self.gpa, jmp_reloc); + const jmp_reloc = try cg.asmJmpReloc(undefined); + try cg.epilogue_relocs.append(cg.gpa, jmp_reloc); } fn airTry(self: *CodeGen, inst: Air.Inst.Index) !void { @@ -176504,17 +177063,13 @@ fn isErrPtr(self: *CodeGen, maybe_inst: ?Air.Inst.Index, ptr_ty: Type, ptr_mcv: defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); const err_off: u31 = @intCast(codegen.errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu)); - try self.asmMemoryImmediate( - .{ ._, .cmp }, - .{ - .base = .{ .reg = ptr_reg }, - .mod = .{ .rm = .{ - .size = self.memSize(.anyerror), - .disp = err_off, - } }, - }, - .u(0), - ); + try self.asmMemoryImmediate(.{ ._, .cmp }, .{ + .base = .{ .reg = ptr_reg }, + .mod = .{ .rm = .{ + .size = self.memSize(.anyerror, .general_purpose), + .disp = err_off, + } }, + }, .u(0)); if (maybe_inst) |inst| self.eflags_inst = inst; return MCValue{ .eflags = .a }; @@ -176662,7 +177217,7 @@ fn lowerSwitchBr( }; const condition_index_lock = cg.register_manager.lockReg(condition_index_reg); defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock); - try cg.truncateRegister(condition_ty, condition_index_reg); + try cg.truncateRegister(unsigned_condition_ty, condition_index_reg); const ptr_size = @divExact(cg.target.ptrBitWidth(), 8); try cg.asmMemory(.{ ._mp, .j }, .{ .base = .table, @@ -177138,13 +177693,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { const inputs = unwrapped_asm.inputs; var result: MCValue = .none; - var args: std.array_list.Managed(MCValue) = .init(self.gpa); - try args.ensureTotalCapacity(outputs.len + inputs.len); + var args = try self.gpa.alloc(MCValue, outputs.len + inputs.len); + var args_len: usize = 0; defer { - for (args.items) |arg| if (arg.getReg()) |reg| self.register_manager.unlockReg(.{ + for (args[0..args_len]) |arg| if (arg.getReg()) |reg| self.register_manager.unlockReg(.{ .tracked_index = RegisterManager.indexOfRegIntoTracked(reg) orelse continue, }); - args.deinit(); + self.gpa.free(args); } var arg_map: std.StringHashMap(u8) = .init(self.gpa); try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len)); @@ -177203,10 +177758,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { return self.fail("invalid register constraint: '{s}'", .{out.constraint}) else if (rest.len == 1 and std.ascii.isDigit(rest[0])) { const index = std.fmt.charToDigit(rest[0], 10) catch unreachable; - if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{ + if (index >= args_len) return self.fail("constraint out of bounds: '{s}'", .{ out.constraint, }); - break :arg_mcv args.items[index]; + break :arg_mcv args[index]; } else return self.fail("invalid constraint: '{s}'", .{out.constraint}); break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: { const ptr_mcv = try self.resolveInst(out.operand); @@ -177224,8 +177779,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { _ = self.register_manager.lockRegIndexAssumeUnused(tracked_index); }; if (!std.mem.eql(u8, out.name, "_")) - arg_map.putAssumeCapacityNoClobber(out.name, @intCast(args.items.len)); - args.appendAssumeCapacity(arg_mcv); + arg_map.putAssumeCapacityNoClobber(out.name, @intCast(args_len)); + args[args_len] = arg_mcv; + args_len += 1; if (out.operand == .none) result = arg_mcv; if (is_read) try self.load(arg_mcv, self.typeOf(out.operand), .{ .air_ref = out.operand }); } @@ -177308,17 +177864,19 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { break :arg .{ .register = reg }; } else if (in.constraint.len == 1 and std.ascii.isDigit(in.constraint[0])) arg: { const index = std.fmt.charToDigit(in.constraint[0], 10) catch unreachable; - if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{in.constraint}); - try self.genCopy(ty, args.items[index], input_mcv, .{}); - break :arg args.items[index]; + if (index >= args_len) return self.fail("constraint out of bounds: '{s}'", .{in.constraint}); + try self.genCopy(ty, args[index], input_mcv, .{}); + break :arg args[index]; } else return self.fail("invalid constraint: '{s}'", .{in.constraint}); if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { _ = self.register_manager.lockReg(reg); }; if (!std.mem.eql(u8, in.name, "_")) - arg_map.putAssumeCapacityNoClobber(in.name, @intCast(args.items.len)); - args.appendAssumeCapacity(arg_mcv); + arg_map.putAssumeCapacityNoClobber(in.name, @intCast(args_len)); + args[args_len] = arg_mcv; + args_len += 1; } + assert(args_len == args.len); const ip = &zcu.intern_pool; const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers); @@ -177469,6 +178027,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { fixed_mnem_size: { const fixed_mnem_size: Memory.Size = switch (mnem_tag) { .clflush => .byte, + .crc32 => { + mnem_size.op_has_size.unset(1); + break :fixed_mnem_size; + }, .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word, .fldenv, .fnstenv, .fstenv => .none, .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none, @@ -177551,7 +178113,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { op_str[colon_pos + ":".len .. op_str.len - "]".len] else ""; - op.* = switch (args.items[ + op.* = switch (args[ arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse return self.fail("no matching constraint: '{s}'", .{op_str}) ]) { @@ -177695,7 +178257,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { op_str[colon_pos + ":".len .. open - "]".len] else ""; - break :disp switch (args.items[ + break :disp switch (args[ arg_map.get(op_str["%[".len .. colon orelse open - "]".len]) orelse return self.fail("no matching constraint: '{s}'", .{op_str}) ]) { @@ -177855,7 +178417,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { it = unwrapped_asm.iterateOutputs(); while (it.next()) |out| { - const arg_mcv = args.items[it.current - 1]; + const arg_mcv = args[it.current - 1]; if (out.operand == .none) continue; if (arg_mcv != .register) continue; if (out.constraint.len == 2 and std.ascii.isDigit(out.constraint[1])) continue; @@ -178297,12 +178859,18 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C .register_overflow, .register_mask, .indirect_load_frame, + .indirect_mask, .lea_frame, .lea_nav, .lea_uav, .lea_lazy_sym, .lea_extern_func, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, // unmodifiable destination @@ -178313,7 +178881,12 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C .dead, .undef, .register_overflow, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, => unreachable, .immediate, @@ -178414,9 +178987,9 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C for ([_]bool{ false, true }) |emit_hazard| { var hazard_count: u3 = 0; - var part_disp: i32 = 0; + var part_disp: u31 = 0; for (dst_regs, try self.splitType(dst_regs.len, ty), 0..) |dst_reg, dst_ty, part_i| { - defer part_disp += @intCast(dst_ty.abiSize(pt.zcu)); + defer part_disp += @intCast(self.unalignedSize(dst_ty)); const is_hazard = if (src_mcv.getReg()) |src_reg| dst_reg.id() == src_reg.id() else if (src_info) |info| @@ -178483,36 +179056,45 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C } fn genSetReg( - self: *CodeGen, + cg: *CodeGen, dst_reg: Register, ty: Type, src_mcv: MCValue, opts: CopyOptions, ) InnerError!void { - const pt = self.pt; + const pt = cg.pt; const zcu = pt.zcu; const abi_size: u32 = @intCast(ty.abiSize(zcu)); - const dst_alias = registerAlias(dst_reg, abi_size); - if (ty.bitSize(zcu) > dst_alias.size().bitSize(self.target)) - return self.fail("genSetReg called with a value larger than dst_reg", .{}); + const dst_alias = registerAlias(dst_reg, @intCast(cg.unalignedSize(ty))); + { + const ty_bit_size = if (ty.hasBitRepresentation(zcu)) ty.bitSize(zcu) else 8 * abi_size; + if (ty_bit_size > dst_alias.size().bitSize(cg.target)) + return cg.fail("genSetReg called with a value larger than dst_reg", .{}); + } switch (src_mcv) { .none, .unreach, .dead, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, => unreachable, .undef => if (opts.safety) switch (dst_reg.class()) { .general_purpose, .gphi => switch (abi_size) { - 1 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to8(), .u(0xaa)), - 2 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to16(), .u(0xaaaa)), - 3...4 => try self.asmRegisterImmediate( + 1 => try cg.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to8(), .u(0xaa)), + 2 => try cg.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to16(), .u(0xaaaa)), + 3...4 => try cg.asmRegisterImmediate( .{ ._, .mov }, dst_reg.to32(), .s(@as(i32, @bitCast(@as(u32, 0xaaaaaaaa)))), ), - 5...8 => try self.asmRegisterImmediate( + 5...8 => try cg.asmRegisterImmediate( .{ ._, .mov }, dst_reg.to64(), .u(0xaaaaaaaaaaaaaaaa), @@ -178521,36 +179103,36 @@ fn genSetReg( }, .segment, .mmx, .sse => { const full_ty = try pt.vectorType(.{ - .len = self.vectorSize(.float), + .len = cg.vectorSize(.float), .child = .u8_type, }); - try self.genSetReg(dst_reg, full_ty, try self.lowerValue( + try cg.genSetReg(dst_reg, full_ty, try cg.lowerValue( try pt.aggregateSplatValue(full_ty, try pt.intValue(.u8, 0xaa)), ), opts); }, - .x87 => try self.genSetReg(dst_reg, .f80, try self.lowerValue( + .x87 => try cg.genSetReg(dst_reg, .f80, try cg.lowerValue( try pt.floatValue(.f80, @as(f80, @bitCast(@as(u80, 0xaaaaaaaaaaaaaaaaaaaa)))), ), opts), .ip, .cr, .dr => unreachable, }, - .eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()), + .eflags => |cc| try cg.asmSetccRegister(cc, dst_reg.to8()), .immediate => |imm| { if (imm == 0) { // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit // register is the fastest way to zero a register. - try self.spillEflagsIfOccupied(); - try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()); + try cg.spillEflagsIfOccupied(); + try cg.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()); } else if (abi_size > 4 and std.math.cast(u32, imm) != null) { // 32-bit moves zero-extend to 64-bit. - try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), .u(imm)); + try cg.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), .u(imm)); } else if (abi_size <= 4 and @as(i64, @bitCast(imm)) < 0) { - try self.asmRegisterImmediate( + try cg.asmRegisterImmediate( .{ ._, .mov }, dst_alias, .s(@intCast(@as(i64, @bitCast(imm)))), ); } else { - try self.asmRegisterImmediate( + try cg.asmRegisterImmediate( .{ ._, .mov }, dst_alias, .u(imm), @@ -178559,44 +179141,44 @@ fn genSetReg( }, .register => |src_reg| if (dst_reg.id() != src_reg.id()) switch (dst_reg.class()) { .general_purpose => switch (src_reg.class()) { - .general_purpose => try self.asmRegisterRegister( + .general_purpose => try cg.asmRegisterRegister( .{ ._, .mov }, dst_alias, - registerAlias(src_reg, abi_size), + registerAlias(src_reg, @intCast(cg.unalignedSize(ty))), ), - .gphi => if (dst_reg.isClass(.gphi)) try self.asmRegisterRegister( + .gphi => if (dst_reg.isClass(.gphi)) try cg.asmRegisterRegister( .{ ._, .mov }, dst_alias, - registerAlias(src_reg, abi_size), + registerAlias(src_reg, @intCast(cg.unalignedSize(ty))), ) else { - const src_lock = self.register_manager.lockReg(src_reg); - defer if (src_lock) |lock| self.register_manager.unlockReg(lock); - const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gphi); + const src_lock = cg.register_manager.lockReg(src_reg); + defer if (src_lock) |lock| cg.register_manager.unlockReg(lock); + const tmp_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gphi); - try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg.to8(), src_reg); - try self.asmRegisterRegister(.{ ._, .mov }, dst_alias, tmp_reg.to8()); + try cg.asmRegisterRegister(.{ ._, .mov }, tmp_reg.to8(), src_reg); + try cg.asmRegisterRegister(.{ ._, .mov }, dst_alias, tmp_reg.to8()); }, - .segment => try self.asmRegisterRegister( + .segment => try cg.asmRegisterRegister( .{ ._, .mov }, dst_alias, src_reg, ), .x87, .mmx, .ip, .cr, .dr => unreachable, - .sse => if (self.hasFeature(.sse2)) try self.asmRegisterRegister( + .sse => if (cg.hasFeature(.sse2)) try cg.asmRegisterRegister( switch (abi_size) { - 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, - 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, + 1...4 => if (cg.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, + 5...8 => if (cg.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, else => unreachable, }, - registerAlias(dst_reg, @max(abi_size, 4)), + registerAlias(dst_reg, @intCast(@max(cg.unalignedSize(ty), 4))), src_reg.to128(), ) else { const frame_size = std.math.ceilPowerOfTwoAssert(u32, @max(abi_size, 4)); - const frame_index = try self.allocFrameIndex(.init(.{ + const frame_index = try cg.allocFrameIndex(.init(.{ .size = frame_size, .alignment = .fromNonzeroByteUnits(frame_size), })); - try self.asmMemoryRegister(switch (frame_size) { + try cg.asmMemoryRegister(switch (frame_size) { 4 => .{ ._ss, .mov }, 8 => .{ ._ps, .movl }, 16 => .{ ._ps, .mov }, @@ -178605,82 +179187,85 @@ fn genSetReg( .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .fromSize(frame_size) } }, }, src_reg.to128()); - try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + try cg.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .fromSize(abi_size) } }, }); }, }, .gphi => switch (src_reg.class()) { - .general_purpose => if (src_reg.isClass(.gphi)) try self.asmRegisterRegister( + .general_purpose => if (src_reg.isClass(.gphi)) try cg.asmRegisterRegister( .{ ._, .mov }, dst_alias, - registerAlias(src_reg, abi_size), + registerAlias(src_reg, @intCast(cg.unalignedSize(ty))), ) else { - const dst_lock = self.register_manager.lockReg(dst_reg); - defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); - const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gphi); + const dst_lock = cg.register_manager.lockReg(dst_reg); + defer if (dst_lock) |lock| cg.register_manager.unlockReg(lock); + const tmp_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.gphi); - try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg.to8(), src_reg.to8()); - try self.asmRegisterRegister(.{ ._, .mov }, dst_reg, tmp_reg.to8()); + try cg.asmRegisterRegister(.{ ._, .mov }, tmp_reg.to8(), src_reg.to8()); + try cg.asmRegisterRegister(.{ ._, .mov }, dst_reg, tmp_reg.to8()); }, - .gphi => try self.asmRegisterRegister( + .gphi => try cg.asmRegisterRegister( .{ ._, .mov }, dst_alias, - registerAlias(src_reg, abi_size), + registerAlias(src_reg, @intCast(cg.unalignedSize(ty))), ), .segment, .x87, .mmx, .ip, .cr, .dr, .sse => unreachable, }, - .segment => try self.asmRegisterRegister( + .segment => try cg.asmRegisterRegister( .{ ._, .mov }, dst_reg, switch (src_reg.class()) { - .general_purpose, .gphi, .segment => registerAlias(src_reg, abi_size), + .general_purpose, + .gphi, + .segment, + => registerAlias(src_reg, @intCast(cg.unalignedSize(ty))), .x87, .mmx, .ip, .cr, .dr => unreachable, - .sse => try self.copyToTmpRegister(ty, src_mcv), + .sse => try cg.copyToTmpRegister(ty, src_mcv), }, ), .x87 => switch (src_reg.class()) { .general_purpose, .gphi, .segment, .mmx, .ip, .cr, .dr => unreachable, .x87 => switch (src_reg) { - .st0 => try self.asmRegister(.{ .f_, .st }, dst_reg), + .st0 => try cg.asmRegister(.{ .f_, .st }, dst_reg), .st1, .st2, .st3, .st4, .st5, .st6 => switch (dst_reg) { .st0 => { - try self.asmRegister(.{ .f_p, .st }, .st0); - try self.asmRegister(.{ .f_, .ld }, @enumFromInt(@intFromEnum(src_reg) - 1)); + try cg.asmRegister(.{ .f_p, .st }, .st0); + try cg.asmRegister(.{ .f_, .ld }, @enumFromInt(@intFromEnum(src_reg) - 1)); }, - .st2, .st3, .st4, .st5, .st6 => if (self.register_manager.isKnownRegFree(.st7)) { - try self.asmRegister(.{ .f_, .ld }, src_reg); - try self.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1)); + .st2, .st3, .st4, .st5, .st6 => if (cg.register_manager.isKnownRegFree(.st7)) { + try cg.asmRegister(.{ .f_, .ld }, src_reg); + try cg.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1)); } else { - try self.asmRegister(.{ .f_, .xch }, src_reg); - try self.asmRegister(.{ .f_, .xch }, dst_reg); - try self.asmRegister(.{ .f_, .xch }, src_reg); + try cg.asmRegister(.{ .f_, .xch }, src_reg); + try cg.asmRegister(.{ .f_, .xch }, dst_reg); + try cg.asmRegister(.{ .f_, .xch }, src_reg); }, .st7 => { - if (!self.register_manager.isKnownRegFree(.st7)) try self.asmRegister(.{ .f_, .free }, dst_reg); - try self.asmRegister(.{ .f_, .ld }, src_reg); - try self.asmOpOnly(.{ .f_cstp, .in }); + if (!cg.register_manager.isKnownRegFree(.st7)) try cg.asmRegister(.{ .f_, .free }, dst_reg); + try cg.asmRegister(.{ .f_, .ld }, src_reg); + try cg.asmOpOnly(.{ .f_cstp, .in }); }, else => unreachable, }, else => unreachable, }, .sse => if (abi_size <= 16) { - const frame_index = try self.allocFrameIndex(.init(.{ + const frame_index = try cg.allocFrameIndex(.init(.{ .size = 16, .alignment = .@"16", })); - try self.asmMemoryRegister(if (self.hasFeature(.avx)) + try cg.asmMemoryRegister(if (cg.hasFeature(.avx)) .{ .v_dqa, .mov } - else if (self.hasFeature(.sse2)) + else if (cg.hasFeature(.sse2)) .{ ._dqa, .mov } else .{ ._ps, .mova }, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .xword } }, }, src_reg.to128()); - try MoveStrategy.read(.load_store_x87, self, dst_reg, .{ + try MoveStrategy.read(.load_store_x87, cg, dst_reg, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .tbyte } }, }); @@ -178688,29 +179273,29 @@ fn genSetReg( }, .mmx => unreachable, .sse => switch (src_reg.class()) { - .general_purpose, .gphi => if (self.hasFeature(.sse2)) try self.asmRegisterRegister( + .general_purpose, .gphi => if (cg.hasFeature(.sse2)) try cg.asmRegisterRegister( switch (abi_size) { - 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, - 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, + 1...4 => if (cg.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, + 5...8 => if (cg.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, else => unreachable, }, dst_reg.to128(), - registerAlias(src_reg, @max(abi_size, 4)), + registerAlias(src_reg, @intCast(@max(cg.unalignedSize(ty), 4))), ) else { const frame_size = std.math.ceilPowerOfTwoAssert(u32, @max(abi_size, 4)); - const frame_index = try self.allocFrameIndex(.init(.{ + const frame_index = try cg.allocFrameIndex(.init(.{ .size = frame_size, .alignment = .fromNonzeroByteUnits(frame_size), })); - try self.asmMemoryRegister(.{ ._, .mov }, .{ + try cg.asmMemoryRegister(.{ ._, .mov }, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .fromSize(abi_size) } }, - }, registerAlias(src_reg, abi_size)); + }, registerAlias(src_reg, @intCast(cg.unalignedSize(ty)))); switch (frame_size) { else => {}, - 8 => try self.asmRegisterRegister(.{ ._ps, .xor }, dst_reg.to128(), dst_reg.to128()), + 8 => try cg.asmRegisterRegister(.{ ._ps, .xor }, dst_reg.to128(), dst_reg.to128()), } - try self.asmRegisterMemory(switch (frame_size) { + try cg.asmRegisterMemory(switch (frame_size) { 4 => .{ ._ss, .mov }, 8 => .{ ._ps, .movl }, 16 => .{ ._ps, .mova }, @@ -178720,24 +179305,24 @@ fn genSetReg( .mod = .{ .rm = .{ .size = .fromSize(frame_size) } }, }); }, - .segment => try self.genSetReg( + .segment => try cg.genSetReg( dst_reg, ty, - .{ .register = try self.copyToTmpRegister(ty, src_mcv) }, + .{ .register = try cg.copyToTmpRegister(ty, src_mcv) }, opts, ), .x87 => if (abi_size <= 16) { - const frame_index = try self.allocFrameIndex(.init(.{ + const frame_index = try cg.allocFrameIndex(.init(.{ .size = 16, .alignment = .@"16", })); - try MoveStrategy.write(.load_store_x87, self, .{ + try MoveStrategy.write(.load_store_x87, cg, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .tbyte } }, }, src_reg); - try self.asmRegisterMemory(if (self.hasFeature(.avx)) + try cg.asmRegisterMemory(if (cg.hasFeature(.avx)) .{ .v_dqa, .mov } - else if (self.hasFeature(.sse2)) + else if (cg.hasFeature(.sse2)) .{ ._dqa, .mov } else .{ ._ps, .mova }, dst_reg.to128(), .{ @@ -178746,46 +179331,46 @@ fn genSetReg( }); } else unreachable, .mmx, .ip, .cr, .dr => unreachable, - .sse => try self.asmRegisterRegister( + .sse => try cg.asmRegisterRegister( @as(?Mir.Inst.FixedTag, switch (ty.scalarType(zcu).zigTypeTag(zcu)) { else => switch (abi_size) { - 1...16 => if (self.hasFeature(.avx)) + 1...16 => if (cg.hasFeature(.avx)) .{ .v_dqa, .mov } - else if (self.hasFeature(.sse2)) + else if (cg.hasFeature(.sse2)) .{ ._dqa, .mov } else .{ ._ps, .mova }, - 17...32 => if (self.hasFeature(.avx)) .{ .v_dqa, .mov } else null, + 17...32 => if (cg.hasFeature(.avx)) .{ .v_dqa, .mov } else null, else => null, }, - .float => switch (ty.scalarType(zcu).floatBits(self.target)) { + .float => switch (ty.scalarType(zcu).floatBits(cg.target)) { 16, 128 => switch (abi_size) { - 2...16 => if (self.hasFeature(.avx)) + 2...16 => if (cg.hasFeature(.avx)) .{ .v_dqa, .mov } - else if (self.hasFeature(.sse2)) + else if (cg.hasFeature(.sse2)) .{ ._dqa, .mov } else .{ ._ps, .mova }, - 17...32 => if (self.hasFeature(.avx)) .{ .v_dqa, .mov } else null, + 17...32 => if (cg.hasFeature(.avx)) .{ .v_dqa, .mov } else null, else => null, }, - 32 => if (self.hasFeature(.avx)) .{ .v_ps, .mova } else .{ ._ps, .mova }, - 64 => if (self.hasFeature(.avx)) + 32 => if (cg.hasFeature(.avx)) .{ .v_ps, .mova } else .{ ._ps, .mova }, + 64 => if (cg.hasFeature(.avx)) .{ .v_pd, .mova } - else if (self.hasFeature(.sse2)) + else if (cg.hasFeature(.sse2)) .{ ._pd, .mova } else .{ ._ps, .mova }, 80 => null, else => unreachable, }, - }) orelse return self.fail("TODO implement genSetReg for {f}", .{ty.fmt(pt)}), + }) orelse return cg.fail("TODO implement genSetReg for {f}", .{ty.fmt(pt)}), dst_alias, - registerAlias(src_reg, abi_size), + registerAlias(src_reg, @intCast(cg.unalignedSize(ty))), ), }, .ip, .cr, .dr => unreachable, - } else if ((dst_reg.class() == .gphi) != (src_reg.class() == .gphi)) try self.asmRegisterRegister( + } else if ((dst_reg.class() == .gphi) != (src_reg.class() == .gphi)) try cg.asmRegisterRegister( .{ ._, .mov }, dst_reg.to8(), src_reg.to8(), @@ -178795,41 +179380,41 @@ fn genSetReg( .register_quadruple, => |src_regs| switch (dst_reg.class()) { .general_purpose => switch (src_regs[0].class()) { - .general_purpose => try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts), + .general_purpose => try cg.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts), else => unreachable, }, .sse => switch (src_regs[0].class()) { .general_purpose => if (abi_size <= 16) { - if (self.hasFeature(.avx)) { - try self.asmRegisterRegister(.{ .v_q, .mov }, dst_reg.to128(), src_regs[0].to64()); - try self.asmRegisterRegisterRegisterImmediate( + if (cg.hasFeature(.avx)) { + try cg.asmRegisterRegister(.{ .v_q, .mov }, dst_reg.to128(), src_regs[0].to64()); + try cg.asmRegisterRegisterRegisterImmediate( .{ .vp_q, .insr }, dst_reg.to128(), dst_reg.to128(), src_regs[1].to64(), .u(1), ); - } else if (self.hasFeature(.sse4_1)) { - try self.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64()); - try self.asmRegisterRegisterImmediate(.{ .p_q, .insr }, dst_reg.to128(), src_regs[1].to64(), .u(1)); - } else if (self.hasFeature(.sse2)) { - const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse); - const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); - defer self.register_manager.unlockReg(tmp_lock); + } else if (cg.hasFeature(.sse4_1)) { + try cg.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64()); + try cg.asmRegisterRegisterImmediate(.{ .p_q, .insr }, dst_reg.to128(), src_regs[1].to64(), .u(1)); + } else if (cg.hasFeature(.sse2)) { + const tmp_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.sse); + const tmp_lock = cg.register_manager.lockRegAssumeUnused(tmp_reg); + defer cg.register_manager.unlockReg(tmp_lock); - try self.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64()); - try self.asmRegisterRegister(.{ ._q, .mov }, tmp_reg.to128(), src_regs[1].to64()); - try self.asmRegisterRegister(.{ ._ps, .movlh }, dst_reg.to128(), tmp_reg.to128()); + try cg.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64()); + try cg.asmRegisterRegister(.{ ._q, .mov }, tmp_reg.to128(), src_regs[1].to64()); + try cg.asmRegisterRegister(.{ ._ps, .movlh }, dst_reg.to128(), tmp_reg.to128()); } else { - const frame_index = try self.allocFrameIndex(.init(.{ + const frame_index = try cg.allocFrameIndex(.init(.{ .size = 16, .alignment = .@"16", })); - for (src_regs, 0..) |src_reg, src_index| try self.asmMemoryRegister(.{ ._, .mov }, .{ + for (src_regs, 0..) |src_reg, src_index| try cg.asmMemoryRegister(.{ ._, .mov }, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .qword, .disp = @intCast(8 * src_index) } }, }, src_reg.to64()); - try self.asmRegisterMemory(.{ ._ps, .mova }, dst_reg.to128(), .{ + try cg.asmRegisterMemory(.{ ._ps, .mova }, dst_reg.to128(), .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .xword } }, }); @@ -178843,38 +179428,41 @@ fn genSetReg( .indirect, .load_frame, .lea_frame, - => try @as(MoveStrategy, switch (src_mcv) { - .register_offset => |reg_off| switch (reg_off.off) { - 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }, opts), - else => .{ .load_store = .{ ._, .lea } }, - }, - .indirect => try self.moveStrategy(ty, dst_reg.class(), false), - .load_frame => |frame_addr| try self.moveStrategy( - ty, - dst_reg.class(), - self.getFrameAddrAlignment(frame_addr).compare(.gte, .fromLog2Units( - std.math.log2_int_ceil(u64, @divExact(dst_reg.size().bitSize(self.target), 8)), - )), - ), - .lea_frame => .{ .load_store = .{ ._, .lea } }, - else => unreachable, - }).read(self, dst_alias, switch (src_mcv) { - .register_offset, .indirect => |reg_off| .{ - .base = .{ .reg = reg_off.reg.to64() }, - .mod = .{ .rm = .{ - .size = self.memSize(ty), - .disp = reg_off.off, - } }, - }, - .load_frame, .lea_frame => |frame_addr| .{ - .base = .{ .frame = frame_addr.index }, - .mod = .{ .rm = .{ - .size = self.memSize(ty), - .disp = frame_addr.off, - } }, - }, - else => unreachable, - }), + => { + const dst_rc = dst_reg.class(); + try @as(MoveStrategy, switch (src_mcv) { + .register_offset => |reg_off| switch (reg_off.off) { + 0 => return cg.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }, opts), + else => .{ .load_store = .{ ._, .lea } }, + }, + .indirect => try cg.moveStrategy(ty, dst_rc, false), + .load_frame => |frame_addr| try cg.moveStrategy( + ty, + dst_rc, + cg.getFrameAddrAlignment(frame_addr).compare(.gte, .fromLog2Units( + std.math.log2_int_ceil(u64, @divExact(dst_reg.size().bitSize(cg.target), 8)), + )), + ), + .lea_frame => .{ .load_store = .{ ._, .lea } }, + else => unreachable, + }).read(cg, dst_alias, switch (src_mcv) { + .register_offset, .indirect => |reg_off| .{ + .base = .{ .reg = reg_off.reg.to64() }, + .mod = .{ .rm = .{ + .size = cg.memSize(ty, dst_rc), + .disp = reg_off.off, + } }, + }, + .load_frame, .lea_frame => |frame_addr| .{ + .base = .{ .frame = frame_addr.index }, + .mod = .{ .rm = .{ + .size = cg.memSize(ty, dst_rc), + .disp = frame_addr.off, + } }, + }, + else => unreachable, + }); + }, .register_overflow => |src_reg_ov| { const ip = &zcu.intern_pool; const first_ty: Type = .fromInterned(first_ty: switch (ip.indexToKey(ty.toIntern())) { @@ -178891,116 +179479,189 @@ fn genSetReg( }); const first_size: u31 = @intCast(first_ty.abiSize(zcu)); const frame_size = std.math.ceilPowerOfTwoAssert(u32, abi_size); - const frame_index = try self.allocFrameIndex(.init(.{ + const frame_index = try cg.allocFrameIndex(.init(.{ .size = frame_size, .alignment = .fromNonzeroByteUnits(frame_size), })); - try self.asmMemoryRegister(.{ ._, .mov }, .{ + try cg.asmMemoryRegister(.{ ._, .mov }, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .fromSize(first_size) } }, }, registerAlias(src_reg_ov.reg, first_size)); - try self.asmSetccMemory(src_reg_ov.eflags, .{ + try cg.asmSetccMemory(src_reg_ov.eflags, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .byte, .disp = first_size } }, }); - try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{ + try cg.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .fromSize(frame_size) } }, }); }, .register_mask => |src_reg_mask| { assert(src_reg_mask.reg.isClass(.sse)); - const has_avx = self.hasFeature(.avx); + const has_avx = cg.hasFeature(.avx); const bits_reg = switch (dst_reg.class()) { .general_purpose => dst_reg, - else => try self.register_manager.allocReg(null, abi.RegisterClass.gp), + else => try cg.register_manager.allocReg(null, abi.RegisterClass.gp), }; - const bits_lock = self.register_manager.lockReg(bits_reg); - defer if (bits_lock) |lock| self.register_manager.unlockReg(lock); + const bits_lock = cg.register_manager.lockReg(bits_reg); + defer if (bits_lock) |lock| cg.register_manager.unlockReg(lock); + + var mask_size: u32 = @intCast( + @divExact(src_reg_mask.info.scalar.bitSize(cg.target), 8) * ty.vectorLen(zcu), + ); + const sign_reg = switch (src_reg_mask.info.kind) { + .lsb => sign_reg: { + const sign_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.sse); + const src_alias = registerAlias(src_reg_mask.reg, mask_size); + const sign_alias = registerAlias(sign_reg, mask_size); + if (cg.hasFeature(.avx2)) try cg.asmRegisterRegisterImmediate( + .{ switch (src_reg_mask.info.scalar) { + else => unreachable, + .byte, .word => .vp_w, + .dword => .vp_d, + .qword => .vp_q, + }, .sll }, + sign_alias, + src_alias, + .u(src_reg_mask.info.scalar.bitSize(cg.target) - 1), + ) else { + if (sign_alias != src_alias) try cg.asmRegisterRegister( + .{ ._dqa, .mov }, + sign_alias, + src_alias, + ); + try cg.asmRegisterImmediate( + .{ switch (src_reg_mask.info.scalar) { + else => unreachable, + .byte, .word => .p_w, + .dword => .p_d, + .qword => .p_q, + }, .sll }, + sign_alias, + .u(src_reg_mask.info.scalar.bitSize(cg.target) - 1), + ); + } + break :sign_reg sign_reg; + }, + .zero_extend => sign_reg: { + const sign_reg = try cg.register_manager.allocReg(null, abi.RegisterClass.sse); + const src_alias = registerAlias(src_reg_mask.reg, mask_size); + const sign_alias = registerAlias(sign_reg, mask_size); + if (has_avx) { + try cg.asmRegisterRegisterRegister( + .{ .vp_, .xor }, + sign_alias, + sign_alias, + sign_alias, + ); + try cg.asmRegisterRegisterRegister(.{ switch (src_reg_mask.info.scalar) { + else => unreachable, + .byte => .vp_b, + .word => .vp_w, + .dword => .vp_d, + .qword => .vp_q, + }, .sub }, sign_alias, sign_alias, src_alias); + } else { + try cg.asmRegisterRegister(.{ .p_, .xor }, sign_alias, sign_alias); + try cg.asmRegisterRegister(.{ switch (src_reg_mask.info.scalar) { + else => unreachable, + .byte => .p_b, + .word => .p_w, + .dword => .p_d, + .qword => .p_q, + }, .sub }, sign_alias, src_alias); + } + break :sign_reg sign_reg; + }, + .msb, .sign_extend => src_reg_mask.reg, + }; + const sign_lock = cg.register_manager.lockReg(sign_reg); + defer if (sign_lock) |lock| cg.register_manager.unlockReg(lock); const pack_reg = switch (src_reg_mask.info.scalar) { - else => src_reg_mask.reg, - .word => try self.register_manager.allocReg(null, abi.RegisterClass.sse), - }; - const pack_lock = self.register_manager.lockReg(pack_reg); - defer if (pack_lock) |lock| self.register_manager.unlockReg(lock); - - var mask_size: u32 = @intCast(ty.vectorLen(zcu) * @divExact(src_reg_mask.info.scalar.bitSize(self.target), 8)); - switch (src_reg_mask.info.scalar) { - else => {}, - .word => { - const src_alias = registerAlias(src_reg_mask.reg, mask_size); + else => sign_reg, + .word => pack_reg: { + const pack_reg = if (sign_reg == src_reg_mask.reg) + try cg.register_manager.allocReg(null, abi.RegisterClass.sse) + else + sign_reg; + const sign_alias = registerAlias(sign_reg, mask_size); const pack_alias = registerAlias(pack_reg, mask_size); if (has_avx) { - try self.asmRegisterRegisterRegister(.{ .vp_b, .ackssw }, pack_alias, src_alias, src_alias); + try cg.asmRegisterRegisterRegister(.{ .vp_b, .ackssw }, pack_alias, sign_alias, sign_alias); } else { - try self.asmRegisterRegister(.{ ._dqa, .mov }, pack_alias, src_alias); - try self.asmRegisterRegister(.{ .p_b, .ackssw }, pack_alias, pack_alias); + if (pack_alias != sign_alias) try cg.asmRegisterRegister(.{ ._dqa, .mov }, pack_alias, sign_alias); + try cg.asmRegisterRegister(.{ .p_b, .ackssw }, pack_alias, pack_alias); } mask_size = std.math.divCeil(u32, mask_size, 2) catch unreachable; + break :pack_reg pack_reg; }, - } - try self.asmRegisterRegister(.{ switch (src_reg_mask.info.scalar) { + }; + const pack_lock = cg.register_manager.lockReg(pack_reg); + defer if (pack_lock) |lock| cg.register_manager.unlockReg(lock); + + try cg.asmRegisterRegister(.{ switch (src_reg_mask.info.scalar) { + else => unreachable, .byte, .word => if (has_avx) .vp_b else .p_b, .dword => if (has_avx) .v_ps else ._ps, .qword => if (has_avx) .v_pd else ._pd, - else => unreachable, }, .movmsk }, bits_reg.to32(), registerAlias(pack_reg, mask_size)); - if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size)); - try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{}); + if (src_reg_mask.info.inverted) try cg.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size)); + try cg.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{}); }, .memory, .load_nav, .load_uav, .load_lazy_sym, .load_extern_func => { + const dst_rc = dst_reg.class(); switch (src_mcv) { .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| - return (try self.moveStrategy( + return (try cg.moveStrategy( ty, - dst_reg.class(), + dst_rc, ty.abiAlignment(zcu).check(@as(u32, @bitCast(small_addr))), - )).read(self, dst_alias, .{ + )).read(cg, dst_alias, .{ .base = .{ .reg = .ds }, .mod = .{ .rm = .{ - .size = self.memSize(ty), + .size = cg.memSize(ty, dst_rc), .disp = small_addr, } }, }), - .load_nav => |nav| switch (dst_reg.class()) { + .load_nav => |nav| switch (dst_rc) { .general_purpose, .gphi => { - try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + try cg.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ .base = .{ .nav = nav }, - .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + .mod = .{ .rm = .{ .size = cg.memSize(ty, dst_rc) } }, }); return; }, .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, - .load_uav => |uav| switch (dst_reg.class()) { + .load_uav => |uav| switch (dst_rc) { .general_purpose, .gphi => { - try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + try cg.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ .base = .{ .uav = uav }, - .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + .mod = .{ .rm = .{ .size = cg.memSize(ty, dst_rc) } }, }); return; }, .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, - .load_lazy_sym => |lazy_sym| switch (dst_reg.class()) { + .load_lazy_sym => |lazy_sym| switch (dst_rc) { .general_purpose, .gphi => { - try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + try cg.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ .base = .{ .lazy_sym = lazy_sym }, - .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + .mod = .{ .rm = .{ .size = cg.memSize(ty, dst_rc) } }, }); return; }, .segment, .mmx, .ip, .cr, .dr => unreachable, .x87, .sse => {}, }, - .load_extern_func => |extern_func| switch (dst_reg.class()) { + .load_extern_func => |extern_func| switch (dst_rc) { .general_purpose, .gphi => { - try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ + try cg.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{ .base = .{ .extern_func = extern_func }, - .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + .mod = .{ .rm = .{ .size = cg.memSize(ty, dst_rc) } }, }); return; }, @@ -179010,40 +179671,40 @@ fn genSetReg( else => unreachable, } - const addr_reg = try self.copyToTmpRegister(.usize, src_mcv.address()); - const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); - defer self.register_manager.unlockReg(addr_lock); + const addr_reg = try cg.copyToTmpRegister(.usize, src_mcv.address()); + const addr_lock = cg.register_manager.lockRegAssumeUnused(addr_reg); + defer cg.register_manager.unlockReg(addr_lock); - try (try self.moveStrategy(ty, dst_reg.class(), false)).read(self, dst_alias, .{ + try (try cg.moveStrategy(ty, dst_rc, false)).read(cg, dst_alias, .{ .base = .{ .reg = addr_reg.to64() }, - .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + .mod = .{ .rm = .{ .size = cg.memSize(ty, dst_rc) } }, }); }, - .lea_nav => |nav| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .lea_nav => |nav| try cg.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ .base = .{ .nav = nav }, }), - .lea_uav => |uav| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .lea_uav => |uav| try cg.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ .base = .{ .uav = uav }, }), - .lea_lazy_sym => |lazy_sym| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .lea_lazy_sym => |lazy_sym| try cg.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ .base = .{ .lazy_sym = lazy_sym }, }), - .lea_extern_func => |lazy_sym| try self.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ + .lea_extern_func => |lazy_sym| try cg.asmRegisterMemory(.{ ._, .lea }, dst_reg.to64(), .{ .base = .{ .extern_func = lazy_sym }, }), - .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts), + .air_ref => |src_ref| try cg.genSetReg(dst_reg, ty, try cg.resolveInst(src_ref), opts), } } fn genSetMem( - self: *CodeGen, + cg: *CodeGen, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCValue, opts: CopyOptions, ) InnerError!void { - const pt = self.pt; + const pt = cg.pt; const zcu = pt.zcu; const abi_size: u32 = @intCast(ty.abiSize(zcu)); const dst_ptr_mcv: MCValue = switch (base) { @@ -179053,11 +179714,11 @@ fn genSetMem( .table, .rip_inst, .lazy_sym => unreachable, .nav => |nav| { // hack around linker relocation bugs - const addr_reg = try self.copyToTmpRegister(.usize, .{ .lea_nav = nav }); - const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); - defer self.register_manager.unlockReg(addr_lock); + const addr_reg = try cg.copyToTmpRegister(.usize, .{ .lea_nav = nav }); + const addr_lock = cg.register_manager.lockRegAssumeUnused(addr_reg); + defer cg.register_manager.unlockReg(addr_lock); - return self.genSetMem(.{ .reg = addr_reg }, disp, ty, src_mcv, opts); + return cg.genSetMem(.{ .reg = addr_reg }, disp, ty, src_mcv, opts); }, .uav => |uav| .{ .lea_uav = uav }, .extern_func => |extern_func| .{ .lea_extern_func = extern_func }, @@ -179067,10 +179728,16 @@ fn genSetMem( .unreach, .dead, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, => unreachable, - .undef => if (opts.safety) try self.genInlineMemset( + .undef => if (opts.safety) try cg.genInlineMemset( dst_ptr_mcv, src_mcv, .{ .immediate = abi_size }, @@ -179085,7 +179752,7 @@ fn genSetMem( .signed => .s(@truncate(@as(i64, @bitCast(imm)))), .unsigned => .u(@as(u32, @intCast(imm))), }; - try self.asmMemoryImmediate( + try cg.asmMemoryImmediate( .{ ._, .mov }, .{ .base = base, .mod = .{ .rm = .{ .size = .fromSize(abi_size), @@ -179096,7 +179763,7 @@ fn genSetMem( }, 3, 5...7 => unreachable, else => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| { - try self.asmMemoryImmediate( + try cg.asmMemoryImmediate( .{ ._, .mov }, .{ .base = base, .mod = .{ .rm = .{ .size = .fromSize(abi_size), @@ -179106,7 +179773,7 @@ fn genSetMem( ); } else { var offset: i32 = 0; - while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate( + while (offset < abi_size) : (offset += 4) try cg.asmMemoryImmediate( .{ ._, .mov }, .{ .base = base, .mod = .{ .rm = .{ .size = .dword, @@ -179120,7 +179787,7 @@ fn genSetMem( ); }, }, - .eflags => |cc| try self.asmSetccMemory(cc, .{ .base = base, .mod = .{ + .eflags => |cc| try cg.asmSetccMemory(cc, .{ .base = base, .mod = .{ .rm = .{ .size = .byte, .disp = disp }, } }), .register => |src_reg| { @@ -179128,75 +179795,75 @@ fn genSetMem( const mem_size = switch (base) { .frame => |base_fi| mem_size: { assert(disp >= 0); - const frame_abi_size = self.frame_allocs.items(.abi_size)[@intFromEnum(base_fi)]; - const frame_spill_pad = self.frame_allocs.items(.spill_pad)[@intFromEnum(base_fi)]; + const frame_abi_size = cg.frame_allocs.items(.abi_size)[@intFromEnum(base_fi)]; + const frame_spill_pad = cg.frame_allocs.items(.spill_pad)[@intFromEnum(base_fi)]; assert(frame_abi_size - frame_spill_pad - disp >= abi_size); break :mem_size if (frame_abi_size - frame_spill_pad - disp == abi_size) frame_abi_size else abi_size; }, else => abi_size, }; - const src_alias = registerAlias(src_reg, @intCast(self.unalignedSize(ty))); - const src_class = src_alias.class(); - const src_size: Memory.Size = switch (src_class) { + const src_alias = registerAlias(src_reg, @intCast(cg.unalignedSize(ty))); + const src_rc = src_alias.class(); + const src_size: Memory.Size = switch (src_rc) { .general_purpose, .gphi, .segment, .ip, .cr, .dr => src_alias.size(), .mmx, .sse => .fromSize(abi_size), - .x87 => switch (abi.classifySystemV(ty, zcu, self.target, .other)[0]) { + .x87 => switch (abi.classifySystemV(ty, zcu, cg.target, .other)[0]) { else => unreachable, .float => .dword, .float_combine, .sse => .qword, .x87 => .tbyte, }, }; - const src_bit_size = src_size.bitSize(self.target); + const src_bit_size = src_size.bitSize(cg.target); const src_align: InternPool.Alignment = .fromNonzeroByteUnits(std.math.ceilPowerOfTwoAssert(u64, src_bit_size)); const src_byte_size = @divExact(src_bit_size, 8); if (src_byte_size > mem_size) { - const frame_index = try self.allocFrameIndex(.init(.{ + const frame_index = try cg.allocFrameIndex(.init(.{ .size = src_byte_size, .alignment = src_align, })); const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } }; - try (try self.moveStrategy(ty, src_class, true)).write(self, .{ + try (try cg.moveStrategy(ty, src_rc, true)).write(cg, .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = src_size } }, }, src_alias); - try self.genSetMem(base, disp, ty, frame_mcv, opts); - try self.freeValue(frame_mcv, .{}); - } else try (try self.moveStrategy(ty, src_class, switch (base) { + try cg.genSetMem(base, disp, ty, frame_mcv, opts); + try cg.freeValue(frame_mcv, .{}); + } else try (try cg.moveStrategy(ty, src_rc, switch (base) { .none => src_align.check(@as(u32, @bitCast(disp))), .reg => |reg| switch (reg) { .es, .cs, .ss, .ds => src_align.check(@as(u32, @bitCast(disp))), else => false, }, - .frame => |frame_index| self.getFrameAddrAlignment(.{ + .frame => |frame_index| cg.getFrameAddrAlignment(.{ .index = frame_index, .off = disp, }).compare(.gte, src_align), .table, .rip_inst, .lazy_sym, .extern_func => unreachable, .nav => |nav| ip.getNav(nav).resolved.?.@"align".compare(.gte, src_align), .uav => |uav| Type.fromInterned(uav.orig_ty).ptrAlignment(zcu).compare(.gte, src_align), - })).write(self, .{ + })).write(cg, .{ .base = base, .mod = .{ .rm = .{ .size = src_size, .disp = disp } }, }, src_alias); }, inline .register_pair, .register_triple, .register_quadruple => |src_regs| { var part_disp: i32 = disp; - for (try self.splitType(src_regs.len, ty), src_regs) |src_ty, src_reg| { - try self.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }, opts); - part_disp += @intCast(src_ty.abiSize(zcu)); + for (try cg.splitType(src_regs.len, ty), src_regs) |src_ty, src_reg| { + try cg.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }, opts); + part_disp += @intCast(cg.unalignedSize(src_ty)); } }, .register_overflow => |ro| switch (ty.zigTypeTag(zcu)) { .@"struct" => { - try self.genSetMem( + try cg.genSetMem( base, disp + @as(i32, @intCast(ty.structFieldOffset(0, zcu))), ty.fieldType(0, zcu), .{ .register = ro.reg }, opts, ); - try self.genSetMem( + try cg.genSetMem( base, disp + @as(i32, @intCast(ty.structFieldOffset(1, zcu))), ty.fieldType(1, zcu), @@ -179207,8 +179874,8 @@ fn genSetMem( .optional => { assert(!ty.optionalReprIsPayload(zcu)); const child_ty = ty.optionalChild(zcu); - try self.genSetMem(base, disp, child_ty, .{ .register = ro.reg }, opts); - try self.genSetMem( + try cg.genSetMem(base, disp, child_ty, .{ .register = ro.reg }, opts); + try cg.genSetMem( base, disp + @as(i32, @intCast(child_ty.abiSize(zcu))), .bool, @@ -179216,37 +179883,37 @@ fn genSetMem( opts, ); }, - else => return self.fail("TODO implement genSetMem for {s} of {f}", .{ + else => return cg.fail("TODO implement genSetMem for {s} of {f}", .{ @tagName(src_mcv), ty.fmt(pt), }), }, .register_offset => |reg_off| { - const src_reg = self.copyToTmpRegister(ty, src_mcv) catch |err| switch (err) { + const src_reg = cg.copyToTmpRegister(ty, src_mcv) catch |err| switch (err) { error.OutOfRegisters => { - const src_reg = registerAlias(reg_off.reg, abi_size); - try self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{ - .base = .{ .reg = src_reg }, + const src_alias = registerAlias(reg_off.reg, @intCast(cg.unalignedSize(ty))); + try cg.asmRegisterMemory(.{ ._, .lea }, src_alias, .{ + .base = .{ .reg = src_alias }, .mod = .{ .rm = .{ .disp = reg_off.off } }, }); - try self.genSetMem(base, disp, ty, .{ .register = reg_off.reg }, opts); - return self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{ - .base = .{ .reg = src_reg }, + try cg.genSetMem(base, disp, ty, .{ .register = reg_off.reg }, opts); + return cg.asmRegisterMemory(.{ ._, .lea }, src_alias, .{ + .base = .{ .reg = src_alias }, .mod = .{ .rm = .{ .disp = -reg_off.off } }, }); }, else => |e| return e, }; - const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); - defer self.register_manager.unlockReg(src_lock); + const src_lock = cg.register_manager.lockRegAssumeUnused(src_reg); + defer cg.register_manager.unlockReg(src_lock); - try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); + try cg.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); }, .register_mask => { - const src_reg = try self.copyToTmpRegister(ty, src_mcv); - const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); - defer self.register_manager.unlockReg(src_lock); + const src_reg = try cg.copyToTmpRegister(ty, src_mcv); + const src_lock = cg.register_manager.lockRegAssumeUnused(src_reg); + defer cg.register_manager.unlockReg(src_lock); - try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); + try cg.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); }, .memory, .indirect, @@ -179263,15 +179930,15 @@ fn genSetMem( => switch (abi_size) { 0 => {}, 1, 2, 4, 8 => { - const src_reg = try self.copyToTmpRegister(ty, src_mcv); - const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); - defer self.register_manager.unlockReg(src_lock); + const src_reg = try cg.copyToTmpRegister(ty, src_mcv); + const src_lock = cg.register_manager.lockRegAssumeUnused(src_reg); + defer cg.register_manager.unlockReg(src_lock); - try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); + try cg.genSetMem(base, disp, ty, .{ .register = src_reg }, opts); }, - else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }, .{ .no_alias = true }), + else => try cg.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }, .{ .no_alias = true }), }, - .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref), opts), + .air_ref => |src_ref| try cg.genSetMem(base, disp, ty, try cg.resolveInst(src_ref), opts), } } @@ -179476,14 +180143,19 @@ fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void { break :dst dst_mcv; }; - if (dst_ty.isRuntimeFloat()) break :result dst_mcv; + switch (dst_ty.zigTypeTag(zcu)) { + .float, .error_union, .error_set, .vector => break :result dst_mcv, + .@"struct", .@"union" => if (dst_ty.containerLayout(zcu) != .@"packed") break :result dst_mcv, + .optional, .pointer => if (!dst_ty.isPtrAtRuntime(zcu)) break :result dst_mcv, + else => {}, + } if (dst_ty.isAbiInt(zcu) and src_ty.isAbiInt(zcu) and src_ty.zigTypeTag(zcu) != .@"struct" and dst_ty.intInfo(zcu).signedness == src_ty.intInfo(zcu).signedness) break :result dst_mcv; const abi_size = dst_ty.abiSize(zcu); const bit_size = dst_ty.bitSize(zcu); - if (abi_size * 8 <= bit_size or dst_ty.isVector(zcu)) break :result dst_mcv; + if (abi_size * 8 <= bit_size) break :result dst_mcv; const dst_limbs_len = std.math.divCeil(u31, @intCast(bit_size), 64) catch unreachable; const high_mcv: MCValue = switch (dst_mcv) { @@ -179780,7 +180452,7 @@ fn atomicOp( mir_tag, sse_reg.to128(), sse_reg.to128(), - try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }), + try val_mcv.mem(self, .{ .size = self.memSize(val_ty, sse_reg.class()) }), ) else try self.asmRegisterRegisterRegister( mir_tag, sse_reg.to128(), @@ -179793,7 +180465,7 @@ fn atomicOp( ._ss, ._sd => if (val_mcv.isBase()) try self.asmRegisterMemory( mir_tag, sse_reg.to128(), - try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }), + try val_mcv.mem(self, .{ .size = self.memSize(val_ty, sse_reg.class()) }), ) else try self.asmRegisterRegister( mir_tag, sse_reg.to128(), @@ -180196,56 +180868,6 @@ fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none }); } -fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void { - const pt = self.pt; - const zcu = pt.zcu; - const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; - const vector_ty = self.typeOfIndex(inst); - const vector_len = vector_ty.vectorLen(zcu); - const scalar_ty = self.typeOf(ty_op.operand); - - const result: MCValue = result: { - if (scalar_ty.toIntern() != .bool_type) return self.fail("TODO implement airSplat for {f}", .{ - vector_ty.fmt(pt), - }); - const regs = - try self.register_manager.allocRegs(2, .{ inst, null }, abi.RegisterClass.gp); - const reg_locks = self.register_manager.lockRegsAssumeUnused(2, regs); - defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); - - try self.genSetReg(regs[1], vector_ty, .{ .immediate = 0 }, .{}); - try self.genSetReg( - regs[1], - vector_ty, - .{ .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - vector_len) }, - .{}, - ); - const src_mcv = try self.resolveInst(ty_op.operand); - const abi_size = @max(std.math.divCeil(u32, vector_len, 8) catch unreachable, 4); - try self.asmCmovccRegisterRegister( - switch (src_mcv) { - .eflags => |cc| cc, - .register => |src_reg| cc: { - try self.asmRegisterImmediate(.{ ._, .@"test" }, src_reg.to8(), .u(1)); - break :cc .nz; - }, - else => cc: { - try self.asmMemoryImmediate( - .{ ._, .@"test" }, - try src_mcv.mem(self, .{ .size = .byte }), - .u(1), - ); - break :cc .nz; - }, - }, - registerAlias(regs[0], abi_size), - registerAlias(regs[1], abi_size), - ); - break :result .{ .register = regs[0] }; - }; - return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); -} - fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { const pt = self.pt; const zcu = pt.zcu; @@ -180327,32 +180949,32 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { const dst_lock = self.register_manager.lockReg(dst_reg); defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); - const mir_tag = @as(?Mir.Inst.FixedTag, if ((pred_reg_mask.info.kind == .all and + const mir_tag = @as(?Mir.Inst.FixedTag, if ((pred_reg_mask.info.kind == .sign_extend and elem_ty.toIntern() != .f32_type and elem_ty.toIntern() != .f64_type) or pred_reg_mask.info.scalar == .byte) if (has_avx) .{ .vp_b, .blendv } else if (has_blend) .{ .p_b, .blendv } - else if (pred_reg_mask.info.kind == .all) + else if (pred_reg_mask.info.kind == .sign_extend) .{ .p_, undefined } else null - else if ((pred_reg_mask.info.kind == .all and (elem_ty.toIntern() != .f64_type or !self.hasFeature(.sse2))) or + else if ((pred_reg_mask.info.kind == .sign_extend and (elem_ty.toIntern() != .f64_type or !self.hasFeature(.sse2))) or pred_reg_mask.info.scalar == .dword) if (has_avx) .{ .v_ps, .blendv } else if (has_blend) .{ ._ps, .blendv } - else if (pred_reg_mask.info.kind == .all) + else if (pred_reg_mask.info.kind == .sign_extend) .{ ._ps, undefined } else null - else if (pred_reg_mask.info.kind == .all or pred_reg_mask.info.scalar == .qword) + else if (pred_reg_mask.info.kind == .sign_extend or pred_reg_mask.info.scalar == .qword) if (has_avx) .{ .v_pd, .blendv } else if (has_blend) .{ ._pd, .blendv } - else if (pred_reg_mask.info.kind == .all) + else if (pred_reg_mask.info.kind == .sign_extend) .{ ._pd, undefined } else null @@ -180369,7 +180991,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { mir_tag, dst_alias, rhs_alias, - try other_mcv.mem(self, .{ .size = self.memSize(ty) }), + try other_mcv.mem(self, .{ .size = self.memSize(ty, dst_reg.class()) }), mask_alias, ) else try self.asmRegisterRegisterRegisterRegister( mir_tag, @@ -180384,7 +181006,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { } else if (has_blend) if (other_mcv.isBase()) try self.asmRegisterMemoryRegister( mir_tag, dst_alias, - try other_mcv.mem(self, .{ .size = self.memSize(ty) }), + try other_mcv.mem(self, .{ .size = self.memSize(ty, dst_reg.class()) }), mask_alias, ) else try self.asmRegisterRegisterRegister( mir_tag, @@ -180527,7 +181149,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { } }))); const mask_mem: Memory = .{ .base = .{ .reg = try self.copyToTmpRegister(.usize, mask_mcv.address()) }, - .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + .mod = .{ .rm = .{ .size = self.memSize(ty, mask_reg.class()) } }, }; if (has_avx) try self.asmRegisterRegisterMemory( .{ .vp_b, .shuf }, @@ -180552,7 +181174,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { const mask_mcv = try self.lowerValue(try pt.aggregateValue(mask_ty, mask_elems)); const mask_mem: Memory = .{ .base = .{ .reg = try self.copyToTmpRegister(.usize, mask_mcv.address()) }, - .mod = .{ .rm = .{ .size = self.memSize(ty) } }, + .mod = .{ .rm = .{ .size = self.memSize(ty, mask_reg.class()) } }, }; if (has_avx) { try self.asmRegisterRegisterMemory( @@ -180671,7 +181293,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { mir_tag, dst_alias, rhs_alias, - try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }), + try lhs_mcv.mem(self, .{ .size = self.memSize(ty, dst_reg.class()) }), mask_alias, ) else try self.asmRegisterRegisterRegisterRegister( mir_tag, @@ -180686,7 +181308,7 @@ fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void { } else if (has_blend) if (lhs_mcv.isBase()) try self.asmRegisterMemoryRegister( mir_tag, dst_alias, - try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }), + try lhs_mcv.mem(self, .{ .size = self.memSize(ty, dst_reg.class()) }), mask_alias, ) else try self.asmRegisterRegisterRegister( mir_tag, @@ -181205,100 +181827,163 @@ fn resolveCallingConventionValues( result.stack_align = .fromByteUnits(cc_opts.incoming_stack_alignment orelse 16); switch (cc) { + else => unreachable, .x86_64_sysv => {}, .x86_64_win => result.stack_byte_count += @intCast(win64_shadow_space), - else => unreachable, } - // Return values - if (ret_ty.isNoReturn(zcu)) { - result.return_value = .init(.unreach); - } else if (!ret_ty.hasRuntimeBits(zcu)) { - // TODO: is this even possible for C calling convention? - result.return_value = .init(.none); - } else { - var ret_tracking: [4]InstTracking = undefined; - var ret_tracking_len: u32 = 0; - var ret_gpr = abi.getCAbiIntReturnRegs(cc); - var ret_sse = abi.getCAbiSseReturnRegs(cc); - var ret_x87 = abi.getCAbiX87ReturnRegs(cc); + result.return_value = switch (ret_ty.classify(zcu)) { + .no_possible_value => .init(.unreach), + .one_possible_value => .init(.none), + .runtime, .partially_comptime => return_value: { + var ret_tracking: [4]InstTracking = undefined; + var ret_tracking_len: u32 = 0; + var ret_gpr = abi.getCAbiIntReturnRegs(cc); + var ret_sse = abi.getCAbiSseReturnRegs(cc); + var ret_x87 = abi.getCAbiX87ReturnRegs(cc); - const classes: []const abi.Class = switch (cc) { - .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, cg.target, .ret), .none), - .x86_64_win => &.{abi.classifyWindows(ret_ty, zcu, cg.target, .ret)}, - else => unreachable, - }; - for (classes) |class| switch (class) { - .integer => { - ret_tracking[ret_tracking_len] = .init(.{ .register = registerAlias( - ret_gpr[0], - @intCast(@min(ret_ty.abiSize(zcu), 8)), - ) }); - ret_tracking_len += 1; - ret_gpr = ret_gpr[1..]; - }, - .sse, .float, .float_combine, .win_i128 => { - const abi_size: u32 = @intCast(ret_ty.abiSize(zcu)); - const reg_size = @min(abi_size, cg.vectorSize(.float)); - var byte_offset: u32 = 0; - while (byte_offset < abi_size) : (byte_offset += reg_size) { - const ret_sse_reg = registerAlias(ret_sse[0], reg_size); + var classes_buf: [8]abi.Class = undefined; + const classes = classes: switch (cc) { + else => unreachable, + .x86_64_sysv => { + classes_buf = abi.classifySystemV(ret_ty, zcu, cg.target, .ret); + break :classes &classes_buf; + }, + .x86_64_win => { + classes_buf[0] = abi.classifyWindows(ret_ty, zcu, cg.target, .ret); + break :classes classes_buf[0..1]; + }, + }; + for (classes) |class| switch (class) { + .integer => { + ret_tracking[ret_tracking_len] = .init(.{ .register = registerAlias( + ret_gpr[0], + @intCast(@min(ret_ty.abiSize(zcu), 8)), + ) }); + ret_tracking_len += 1; + ret_gpr = ret_gpr[1..]; + }, + .sse, .float, .float_combine, .win_i128 => { + ret_tracking[ret_tracking_len] = .init(.{ + .register = registerAlias(ret_sse[0], @intCast(ret_ty.abiSize(zcu))), + }); + ret_tracking_len += 1; ret_sse = ret_sse[1..]; - - ret_tracking[ret_tracking_len] = .init(.{ .register = ret_sse_reg }); + }, + .sseup => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.sse)), + .x87 => { + ret_tracking[ret_tracking_len] = .init(.{ .register = ret_x87[0] }); ret_tracking_len += 1; - } - }, - .sseup => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.sse)), - .x87 => { - ret_tracking[ret_tracking_len] = .init(.{ .register = ret_x87[0] }); - ret_tracking_len += 1; - ret_x87 = ret_x87[1..]; - }, - .x87up => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.x87)), - .memory, .integer_per_element => { - ret_tracking[ret_tracking_len] = .{ - .short = .{ .indirect = .{ .reg = ret_gpr[0].to64() } }, - .long = .{ .indirect = .{ .reg = param_gpr[param_gpr_index].to64() } }, - }; - ret_tracking_len += 1; - ret_gpr = ret_gpr[1..]; - param_gpr_index += 1; - }, - .none => unreachable, - }; - result.return_value = switch (ret_tracking_len) { - else => unreachable, - 1 => ret_tracking[0], - 2 => .init(.{ .register_pair = .{ - ret_tracking[0].short.register, - ret_tracking[1].short.register, - } }), - 3 => .init(.{ .register_triple = .{ - ret_tracking[0].short.register, - ret_tracking[1].short.register, - ret_tracking[2].short.register, - } }), - 4 => .init(.{ .register_quadruple = .{ - ret_tracking[0].short.register, - ret_tracking[1].short.register, - ret_tracking[2].short.register, - ret_tracking[3].short.register, - } }), - }; - } + ret_x87 = ret_x87[1..]; + }, + .x87up => assert(ret_tracking[ret_tracking_len - 1].short.register.isClass(.x87)), + .none => {}, + .memory => { + ret_tracking[ret_tracking_len] = .{ + .short = .{ .indirect = .{ .reg = ret_gpr[0].to64() } }, + .long = .{ .indirect = .{ .reg = param_gpr[param_gpr_index].to64() } }, + }; + ret_tracking_len += 1; + ret_gpr = ret_gpr[1..]; + param_gpr_index += 1; + }, + .bool_vector_mask => { + const len = ret_ty.vectorLen(zcu); + const elem_size = + @divExact(16, std.math.ceilPowerOfTwoAssert(u32, @min(len, 16))); + ret_tracking[ret_tracking_len] = .init(.{ .register_mask = .{ + .reg = registerAlias(ret_sse[0], elem_size * len), + .info = .{ .kind = .lsb, .scalar = .fromSize(elem_size) }, + } }); + ret_tracking_len += 1; + ret_sse = ret_sse[1..]; + }, + .integer_per_element => { + const len: u32 = @intCast(ret_ty.vectorLen(zcu)); + const alias_size: u32 = @intCast(@min(ret_ty.childType(zcu).abiSize(zcu), 8)); + for (ret_tracking[ret_tracking_len..][0..len], ret_gpr[0..len]) |*tracking, gpr| + tracking.* = .init(.{ .register = registerAlias(gpr, alias_size) }); + ret_tracking_len += len; + ret_gpr = ret_gpr[len..]; + }, + .sse_per_element => { + const len: u32 = @intCast(ret_ty.vectorLen(zcu)); + const alias_size: u32 = @intCast(@min(ret_ty.childType(zcu).abiSize(zcu), 8)); + for (ret_tracking[ret_tracking_len..][0..len], ret_sse[0..len]) |*tracking, sse| + tracking.* = .init(.{ .register = registerAlias(sse, alias_size) }); + ret_tracking_len += len; + ret_sse = ret_sse[len..]; + }, + .sse_sse_x87_per_qword, .sse_per_xword, .sse_per_yword, .sse_per_zword => { + const reg_size: u32 = switch (class) { + else => unreachable, + .sse_sse_x87_per_qword => 8, + .sse_per_xword => 16, + .sse_per_yword => 32, + .sse_per_zword => 64, + }; + var byte_offset: u32 = 0; + const unaligned_size = cg.unalignedSize(ret_ty); + while (byte_offset < unaligned_size) : (byte_offset += reg_size) { + switch (@as(enum { sse, x87 }, switch (class) { + else => unreachable, + .sse_sse_x87_per_qword => switch (byte_offset) { + 0 => .sse, // duck + 8 => .sse, // duck + else => .x87, // goose! + }, + .sse_per_xword, .sse_per_yword, .sse_per_zword => .sse, + })) { + .sse => { + ret_tracking[ret_tracking_len] = .init(.{ + .register = registerAlias(ret_sse[0], reg_size), + }); + ret_tracking_len += 1; + ret_sse = ret_sse[1..]; + }, + .x87 => { + ret_tracking[ret_tracking_len] = .init(.{ + .register = registerAlias(ret_x87[0], reg_size), + }); + ret_tracking_len += 1; + ret_x87 = ret_x87[1..]; + }, + } + } + }, + }; + break :return_value switch (ret_tracking_len) { + else => unreachable, + 1 => ret_tracking[0], + 2 => .init(.{ .register_pair = .{ + ret_tracking[0].short.register, + ret_tracking[1].short.register, + } }), + 3 => .init(.{ .register_triple = .{ + ret_tracking[0].short.register, + ret_tracking[1].short.register, + ret_tracking[2].short.register, + } }), + 4 => .init(.{ .register_quadruple = .{ + ret_tracking[0].short.register, + ret_tracking[1].short.register, + ret_tracking[2].short.register, + ret_tracking[3].short.register, + } }), + }; + }, + .fully_comptime => unreachable, + }; - // Input params - params: for (param_types, result.args) |ty, *arg| { - assert(ty.hasRuntimeBits(zcu)); + params: for (0.., param_types, result.args) |param_index, ty, *arg| { result.air_arg_count += 1; switch (cc) { + else => unreachable, .x86_64_sysv => {}, .x86_64_win => { param_gpr_index = @max(param_gpr_index, param_sse_index); param_sse_index = param_gpr_index; }, - else => unreachable, } const save_param_gpr_index = param_gpr_index; @@ -181307,17 +181992,25 @@ fn resolveCallingConventionValues( var arg_mcv: [4]MCValue = undefined; var arg_mcv_len: u32 = 0; - const classes = switch (cc) { - .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ty, zcu, cg.target, .arg), .none), - .x86_64_win => &.{abi.classifyWindows(ty, zcu, cg.target, .arg)}, + var classes_buf: [8]abi.Class = undefined; + const classes = classes: switch (cc) { else => unreachable, + .x86_64_sysv => { + classes_buf = abi.classifySystemV(ty, zcu, cg.target, .arg); + break :classes &classes_buf; + }, + .x86_64_win => { + classes_buf[0] = abi.classifyWindows(ty, zcu, cg.target, .arg); + break :classes classes_buf[0..1]; + }, }; classes: for (classes) |class| switch (class) { .integer => { if (param_gpr_index >= param_gpr.len) break; - arg_mcv[arg_mcv_len] = .{ - .register = registerAlias(param_gpr[param_gpr_index], @intCast(@min(ty.abiSize(zcu), 8))), - }; + arg_mcv[arg_mcv_len] = .{ .register = registerAlias( + param_gpr[param_gpr_index], + @intCast(@min(ty.abiSize(zcu), 8)), + ) }; arg_mcv_len += 1; param_gpr_index += 1; }, @@ -181327,62 +182020,138 @@ fn resolveCallingConventionValues( var byte_offset: u32 = 0; while (byte_offset < abi_size) : (byte_offset += reg_size) { if (param_sse_index >= param_sse.len) break :classes; - - const param_sse_reg = registerAlias(param_sse[param_sse_index], reg_size); + arg_mcv[arg_mcv_len] = arg_mcv: { + const param_sse_reg = + registerAlias(param_sse[param_sse_index], reg_size); + switch (cc) { + else => unreachable, + .x86_64_sysv => {}, + .x86_64_win => if (param_index >= fn_info.param_types.len) { + const param_gpr_reg = + registerAlias(param_gpr[param_gpr_index], reg_size); + param_gpr_index += 1; + break :arg_mcv .{ .register_tee = .{ + param_sse_reg, + param_gpr_reg, + .none, + .none, + } }; + }, + } + break :arg_mcv .{ .register = param_sse_reg }; + }; + arg_mcv_len += 1; param_sse_index += 1; - - arg_mcv[arg_mcv_len] = .{ .register = param_sse_reg }; - arg_mcv_len += 1; } }, .sseup => assert(arg_mcv[arg_mcv_len - 1].register.isClass(.sse)), .x87, .x87up, .memory, .win_i128 => switch (cc) { .x86_64_sysv => switch (class) { + else => unreachable, .x87, .x87up, .memory => break, - else => unreachable, }, - .x86_64_win => if (ty.abiSize(zcu) > 8) { - if (param_gpr_index < param_gpr.len) { - arg_mcv[arg_mcv_len] = .{ .indirect = .{ .reg = param_gpr[param_gpr_index].to64() } }; - arg_mcv_len += 1; - param_gpr_index += 1; - } else { - assert(arg_mcv_len == 0); - const param_align = Type.usize.abiAlignment(zcu); - result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count)); - result.stack_align = result.stack_align.max(param_align); - arg.* = .{ .indirect_load_frame = .{ - .index = stack_frame_base, - .off = result.stack_byte_count, - } }; - result.stack_byte_count += @intCast(Type.usize.abiSize(zcu)); - continue :params; - } - } else break, + .x86_64_win => if (param_gpr_index < param_gpr.len) { + arg_mcv[arg_mcv_len] = .{ .indirect = .{ + .reg = param_gpr[param_gpr_index].to64(), + } }; + arg_mcv_len += 1; + param_gpr_index += 1; + } else { + assert(arg_mcv_len == 0); + const param_align = Type.usize.abiAlignment(zcu); + result.stack_byte_count = + @intCast(param_align.forward(result.stack_byte_count)); + result.stack_align = result.stack_align.max(param_align); + arg.* = .{ .indirect_load_frame = .{ + .index = stack_frame_base, + .off = result.stack_byte_count, + } }; + result.stack_byte_count += @intCast(Type.usize.abiSize(zcu)); + continue :params; + }, else => unreachable, }, - .none => unreachable, - .integer_per_element => { - const remaining_param_gpr_len: u3 = @intCast(param_gpr.len - param_gpr_index); - param_gpr_index = @intCast(param_gpr.len); - + .none => {}, + .bool_vector_mask => { + arg_mcv[arg_mcv_len] = .{ .indirect_mask = .{ + .reg = param_gpr[param_gpr_index].to64(), + .info = .{ .kind = .lsb, .scalar = .fromSize(@divExact( + 16, + std.math.ceilPowerOfTwoAssert(u32, @min(ty.vectorLen(zcu), 16)), + )) }, + } }; + arg_mcv_len += 1; + param_gpr_index += 1; + }, + .integer_per_element, + .sse_per_element, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => { + const len = switch (class) { + else => unreachable, + .integer_per_element, .sse_per_element => ty.vectorLen(zcu), + .sse_per_xword => @divExact(ty.abiSize(zcu), 16), + .sse_per_yword => @divExact(ty.abiSize(zcu), 32), + .sse_per_zword => @divExact(ty.abiSize(zcu), 64), + }; + const param_reg_len: u32 = @intCast(@min(len, switch (class) { + else => unreachable, + .integer_per_element => param_gpr.len - param_gpr_index, + .sse_per_element, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => param_sse.len - param_sse_index, + })); + const frame_elem_len = len - param_reg_len; const frame_elem_align = 8; - const frame_elems_len = ty.vectorLen(zcu) - remaining_param_gpr_len; - const frame_elem_size = std.mem.alignForward(u64, ty.childType(zcu).abiSize(zcu), frame_elem_align); - const frame_size: u31 = @intCast(frame_elems_len * frame_elem_size); + const frame_elem_size = switch (class) { + else => unreachable, + .integer_per_element, .sse_per_element => std.mem.alignForward( + u64, + ty.childType(zcu).abiSize(zcu), + frame_elem_align, + ), + .sse_per_xword, .sse_per_yword, .sse_per_zword => 8, + }; + const frame_size: u31 = @intCast(frame_elem_size * frame_elem_len); - result.stack_byte_count = std.mem.alignForward(u31, result.stack_byte_count, frame_elem_align); - arg_mcv[arg_mcv_len] = .{ .elementwise_args = .{ - .regs = remaining_param_gpr_len, - .frame_off = @intCast(result.stack_byte_count), + if (frame_size > 0) result.stack_byte_count = + std.mem.alignForward(u31, result.stack_byte_count, frame_elem_align); + const info: ArgsInfo = .{ + .info = .{ + .reg_index = @intCast(param_gpr_index), + .frame_off = @intCast(result.stack_byte_count), + }, .frame_index = stack_frame_base, - } }; + }; + arg_mcv[arg_mcv_len] = switch (class) { + else => unreachable, + .integer_per_element => .{ .elementwise_gpr = info }, + .sse_per_element => .{ .elementwise_sse = info }, + .sse_per_xword => .{ .xwordwise_sse = info }, + .sse_per_yword => .{ .ywordwise_sse = info }, + .sse_per_zword => .{ .zwordwise_sse = info }, + }; arg_mcv_len += 1; + switch (class) { + else => unreachable, + .integer_per_element => param_gpr_index += param_reg_len, + .sse_per_element, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => param_sse_index += param_reg_len, + } result.stack_byte_count += frame_size; }, + .sse_sse_x87_per_qword => unreachable, // thank goodness } else { arg.* = switch (arg_mcv_len) { else => unreachable, + 0 => .none, 1 => arg_mcv[0], 2 => .{ .register_pair = .{ arg_mcv[0].register, @@ -181432,82 +182201,82 @@ fn resolveCallingConventionValues( param_gpr = param_gpr[0 .. param_gpr.len - 1]; } - // Return values - result.return_value = if (ret_ty.isNoReturn(zcu)) - .init(.unreach) - else if (!ret_ty.hasRuntimeBits(zcu)) - .init(.none) - else return_value: { - const ret_gpr = abi.getCAbiIntReturnRegs(cc); - const ret_size: u31 = @intCast(ret_ty.abiSize(zcu)); - if (abi.zigcc.return_in_regs) switch (cg.regClassForType(ret_ty)) { - .general_purpose, .gphi => if (ret_size <= @as(u4, switch (cg.target.cpu.arch) { - else => unreachable, - .x86 => 4, - .x86_64 => 8, - })) - break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) }) - else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu)) - break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }), - .segment, .mmx, .ip, .cr, .dr => unreachable, - .x87 => if (ret_size <= 16) break :return_value .init(.{ .register = .st0 }), - .sse => if (ret_size <= cg.vectorSize(.float)) break :return_value .init(.{ - .register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)), - }), - }; - const ret_indirect_reg = param_gpr[0]; - param_gpr = param_gpr[1..]; - break :return_value .{ - .short = .{ .indirect = .{ .reg = ret_gpr[0] } }, - .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, - }; + result.return_value = switch (ret_ty.classify(zcu)) { + .no_possible_value => .init(.unreach), + .one_possible_value => .init(.none), + .runtime, .partially_comptime => return_value: { + const ret_gpr = abi.getCAbiIntReturnRegs(cc); + const ret_size: u31 = @intCast(ret_ty.abiSize(zcu)); + if (abi.zigcc.return_in_regs) switch (cg.regClassForType(ret_ty)) { + .general_purpose, .gphi => if (ret_size <= @as(u4, switch (cg.target.cpu.arch) { + else => unreachable, + .x86 => 4, + .x86_64 => 8, + })) + break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) }) + else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu)) + break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }), + .segment, .mmx, .ip, .cr, .dr => unreachable, + .x87 => if (ret_size <= 16) break :return_value .init(.{ .register = .st0 }), + .sse => if (ret_size <= cg.vectorSize(.float)) break :return_value .init(.{ + .register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)), + }), + }; + const ret_indirect_reg = param_gpr[0]; + param_gpr = param_gpr[1..]; + break :return_value .{ + .short = .{ .indirect = .{ .reg = ret_gpr[0] } }, + .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, + }; + }, + .fully_comptime => unreachable, }; - // Input params - for (param_types, result.args) |param_ty, *arg| { - if (!param_ty.hasRuntimeBits(zcu)) { - arg.* = .none; - continue; - } - result.air_arg_count += 1; - const param_size: u31 = @intCast(param_ty.abiSize(zcu)); - if (abi.zigcc.params_in_regs) switch (cg.regClassForType(param_ty)) { - .general_purpose, .gphi => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (cg.target.cpu.arch) { - else => unreachable, - .x86 => 4, - .x86_64 => 8, - })) { - arg.* = .{ .register = registerAlias(param_gpr[0], param_size) }; - param_gpr = param_gpr[1..]; - continue; - } else if (param_gpr.len >= 2 and param_ty.isSliceAtRuntime(zcu)) { - arg.* = .{ .register_pair = param_gpr[0..2].* }; - param_gpr = param_gpr[2..]; - continue; - }, - .segment, .mmx, .ip, .cr, .dr => unreachable, - .x87 => if (param_x87.len >= 1 and param_size <= 16) { - arg.* = .{ .register = param_x87[0] }; - param_x87 = param_x87[1..]; - continue; - }, - .sse => if (param_sse.len >= 1 and param_size <= cg.vectorSize(.float)) { - arg.* = .{ - .register = registerAlias(param_sse[0], @max(param_size, 16)), - }; - param_sse = param_sse[1..]; - continue; - }, - }; - const param_align = param_ty.abiAlignment(zcu); - result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count)); - result.stack_align = result.stack_align.max(param_align); - arg.* = .{ .load_frame = .{ - .index = stack_frame_base, - .off = result.stack_byte_count, - } }; - result.stack_byte_count += param_size; - } + for (param_types, result.args) |param_ty, *arg| switch (param_ty.classify(zcu)) { + .no_possible_value => arg.* = .unreach, + .one_possible_value => arg.* = .none, + .runtime, .partially_comptime => { + result.air_arg_count += 1; + const param_size: u31 = @intCast(param_ty.abiSize(zcu)); + if (abi.zigcc.params_in_regs) switch (cg.regClassForType(param_ty)) { + .general_purpose, .gphi => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (cg.target.cpu.arch) { + else => unreachable, + .x86 => 4, + .x86_64 => 8, + })) { + arg.* = .{ .register = registerAlias(param_gpr[0], param_size) }; + param_gpr = param_gpr[1..]; + continue; + } else if (param_gpr.len >= 2 and param_ty.isSliceAtRuntime(zcu)) { + arg.* = .{ .register_pair = param_gpr[0..2].* }; + param_gpr = param_gpr[2..]; + continue; + }, + .segment, .mmx, .ip, .cr, .dr => unreachable, + .x87 => if (param_x87.len >= 1 and param_size <= 16) { + arg.* = .{ .register = param_x87[0] }; + param_x87 = param_x87[1..]; + continue; + }, + .sse => if (param_sse.len >= 1 and param_size <= cg.vectorSize(.float)) { + arg.* = .{ + .register = registerAlias(param_sse[0], @max(param_size, 16)), + }; + param_sse = param_sse[1..]; + continue; + }, + }; + const param_align = param_ty.abiAlignment(zcu); + result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count)); + result.stack_align = result.stack_align.max(param_align); + arg.* = .{ .load_frame = .{ + .index = stack_frame_base, + .off = result.stack_byte_count, + } }; + result.stack_byte_count += param_size; + }, + .fully_comptime => unreachable, + }; }, else => return cg.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}), } @@ -181593,14 +182362,17 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { }; } -fn memSize(self: *CodeGen, ty: Type) Memory.Size { +fn memSize(self: *CodeGen, ty: Type, class: Register.Class) Memory.Size { const zcu = self.pt.zcu; return if (self.floatBits(ty)) |float_bits| .fromBitSize(float_bits) else if (ty.isVector(zcu) and ty.vectorLen(zcu) == 1 and self.floatBits(ty.childType(zcu)) == 80) .tbyte else - .fromSize(@intCast(ty.abiSize(zcu))); + .fromSize(@intCast(switch (class) { + .general_purpose, .gphi, .segment, .x87, .ip, .cr, .dr => self.unalignedSize(ty), + .mmx, .sse => ty.abiSize(zcu), + })); } fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Type { @@ -181610,7 +182382,10 @@ fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Ty var parts: [parts_len]Type = undefined; switch (ip.indexToKey(ty.toIntern())) { .vector_type => |vector_type| if (std.math.divExact(u32, vector_type.len, parts_len)) |vec_len| { - return @splat(try pt.vectorType(.{ .len = vec_len, .child = vector_type.child })); + return @splat(switch (vec_len) { + 1 => .fromInterned(vector_type.child), + else => try pt.vectorType(.{ .len = vec_len, .child = vector_type.child }), + }); } else |err| switch (err) { error.DivisionByZero => unreachable, error.UnexpectedRemainder => {}, @@ -181656,7 +182431,7 @@ fn truncateRegister(self: *CodeGen, ty: Type, reg: Register) !void { const zcu = pt.zcu; const int_info: InternPool.Key.IntType = if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else .{ .signedness = .unsigned, - .bits = @intCast(ty.bitSize(zcu)), + .bits = @intCast(if (ty.hasBitRepresentation(zcu)) ty.bitSize(zcu) else ty.abiSize(zcu) * 8), }; const shift = std.math.cast(u6, 64 - int_info.bits % 64) orelse return; try self.spillEflagsIfOccupied(); @@ -181696,10 +182471,6 @@ fn regBitSize(self: *CodeGen, ty: Type) u64 { }; } -fn regExtraBits(self: *CodeGen, ty: Type) u64 { - return self.regBitSize(ty) - ty.bitSize(self.pt.zcu); -} - fn hasFeature(cg: *CodeGen, feature: std.Target.x86.Feature) bool { return switch (feature) { .@"64bit" => switch (cg.target.cpu.arch) { @@ -181768,13 +182539,11 @@ fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type { return Temp.typeOf(.{ .index = inst }, self); } -fn promoteInt(self: *CodeGen, ty: Type) Type { - const pt = self.pt; +fn promoteInt(cg: *CodeGen, ty: Type) Type { + const pt = cg.pt; const zcu = pt.zcu; - const int_info: InternPool.Key.IntType = switch (ty.toIntern()) { - .bool_type => .{ .signedness = .unsigned, .bits = 1 }, - else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return ty, - }; + const int_info = cg.intInfo(ty) orelse return ty; + if (int_info.bits == 0) return .void; for ([_]Type{ .c_int, .c_uint, .c_long, .c_ulong, @@ -181817,7 +182586,7 @@ fn nonBoolScalarBitSize(cg: *CodeGen, ty: Type) u32 { .bool_type => vector_type.len, else => @intCast(Type.fromInterned(vector_type.child).bitSize(zcu)), }, - else => @intCast(ty.bitSize(zcu)), + else => if (ty.hasBitRepresentation(zcu) or ty.isAbiInt(zcu)) @intCast(ty.bitSize(zcu)) else @intCast(ty.abiSize(zcu) * 8), }; } @@ -181942,6 +182711,7 @@ const Temp = struct { .memory, .indirect, .indirect_load_frame, + .indirect_mask, .lea_frame, .load_nav, .lea_nav, @@ -181951,7 +182721,12 @@ const Temp = struct { .lea_lazy_sym, .lea_extern_func, .load_extern_func, - .elementwise_args, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => false, @@ -182414,7 +183189,13 @@ const Temp = struct { .register_overflow, .register_mask, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, // not a valid pointer @@ -182546,7 +183327,7 @@ const Temp = struct { try cg.asmMemoryImmediate( .{ ._, .mov }, try ptr.tracking(cg).short.deref().mem(cg, .{ - .size = cg.memSize(val_ty), + .size = cg.memSize(val_ty, .general_purpose), }), val_op, ); @@ -182566,10 +183347,9 @@ const Temp = struct { try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }), ); }, - .register => |val_reg| try ptr.storeRegs(val_ty, &.{registerAlias( - val_reg, - @intCast(val_ty.abiSize(cg.pt.zcu)), - )}, cg), + .register => |val_reg| try ptr.storeRegs(val_ty, &.{ + registerAlias(val_reg, @intCast(cg.unalignedSize(val_ty))), + }, cg), inline .register_pair, .register_triple, .register_quadruple, @@ -182679,14 +183459,10 @@ const Temp = struct { .s(val_simm32) else continue :val_to_gpr; - try cg.asmMemoryImmediate( - .{ ._, .mov }, - try dst.tracking(cg).short.mem(cg, .{ - .size = cg.memSize(val_ty), - .disp = opts.disp, - }), - val_op, - ); + try cg.asmMemoryImmediate(.{ ._, .mov }, try dst.tracking(cg).short.mem(cg, .{ + .size = cg.memSize(val_ty, .general_purpose), + .disp = opts.disp, + }), val_op); }, .eflags => |cc| try cg.asmSetccMemory( cc, @@ -182758,7 +183534,7 @@ const Temp = struct { while (try ptr.toRegClass(false, .general_purpose, cg)) {}, } try strat.read(cg, dst_reg, try ptr.tracking(cg).short.deref().mem(cg, .{ - .size = cg.memSize(dst_ty), + .size = cg.memSize(dst_ty, dst_rc), })); } @@ -182767,7 +183543,9 @@ const Temp = struct { const ip = &zcu.intern_pool; var part_disp: u31 = 0; var deferred_disp: u31 = 0; - var src_abi_size: u32 = @intCast(src_ty.abiSize(cg.pt.zcu)); + const is_full = src_regs.len == 1 and + (src_regs[0].class() == .sse or !(src_ty.isRuntimeFloat() or src_ty.isVector(zcu))); + var src_size: u32 = @intCast(if (is_full) src_ty.abiSize(zcu) else cg.unalignedSize(src_ty)); for (src_regs, 0..) |src_reg, part_index| { const part_ty: Type = if (src_regs.len == 1) src_ty @@ -182782,13 +183560,17 @@ const Temp = struct { break :part_ty .usize; }, .array_type => { - assert(src_regs.len - part_index == std.math.divCeil(u32, src_abi_size, 8) catch unreachable); - break :part_ty try cg.pt.intType(.unsigned, @as(u16, 8) * @min(src_abi_size, 8)); + assert(src_regs.len - part_index == std.math.divCeil(u32, src_size, 8) catch unreachable); + break :part_ty try cg.pt.intType(.unsigned, @as(u16, 8) * @min(src_size, 8)); + }, + .vector_type => |vector_type| switch (@divExact(vector_type.len, src_regs.len)) { + 0 => unreachable, + 1 => .fromInterned(vector_type.child), + else => |len| try cg.pt.vectorType(.{ + .len = @intCast(len), + .child = vector_type.child, + }), }, - .vector_type => |vector_type| try cg.pt.vectorType(.{ - .len = @intCast(@divExact(vector_type.len, src_regs.len)), - .child = vector_type.child, - }), .opt_type => |opt_child| switch (ip.indexToKey(opt_child)) { else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, src_ty.fmt(cg.pt) }), .ptr_type => |ptr_info| { @@ -182798,8 +183580,8 @@ const Temp = struct { }, }, .struct_type, .union_type => { - assert(src_regs.len - part_index == std.math.divCeil(u32, src_abi_size, 8) catch unreachable); - break :part_ty switch (src_abi_size) { + assert(src_regs.len - part_index == std.math.divCeil(u32, src_size, 8) catch unreachable); + break :part_ty switch (src_size) { 0, 3, 5...7 => unreachable, 1 => .u8, 2 => .u16, @@ -182812,7 +183594,8 @@ const Temp = struct { break :part_ty .fromInterned(tuple_type.types.get(ip)[part_index]); }, }; - const part_size: u31 = @intCast(part_ty.abiSize(zcu)); + const part_size: u31 = + @intCast(if (is_full) part_ty.abiSize(zcu) else cg.unalignedSize(part_ty)); const src_rc = src_reg.class(); if (src_rc == .x87 or std.math.isPowerOfTwo(part_size)) { // hack around linker relocation bugs @@ -182827,8 +183610,9 @@ const Temp = struct { .x87 => switch (abi.classifySystemV(src_ty, zcu, cg.target, .other)[part_index]) { else => unreachable, .float => .dword, - .float_combine, .sse => .qword, - .x87 => .tbyte, + .float_combine, .sse, .sseup => .qword, + .x87, .x87up => .tbyte, + .none => .fromBitSize(8 * part_size), }, }, .disp = part_disp, @@ -182847,19 +183631,20 @@ const Temp = struct { try ptr.toOffset(deferred_disp, cg); deferred_disp = 0; var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } }); - try ptr.memcpy(&src_ptr, src_abi_size, cg); + try ptr.memcpy(&src_ptr, src_size, cg); try src_ptr.die(cg); } part_disp += part_size; deferred_disp += part_size; - src_abi_size -= part_size; + src_size -= part_size; } } fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) InnerError!void { - const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false); + const dst_rc = dst_reg.class(); + const strat = try cg.moveStrategy(dst_ty, dst_rc, false); try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{ - .size = cg.memSize(dst_ty), + .size = cg.memSize(dst_ty, dst_rc), .disp = disp, })); } @@ -182870,7 +183655,7 @@ const Temp = struct { if (src_rc == .x87 or std.math.isPowerOfTwo(src_abi_size)) { const strat = try cg.moveStrategy(src_ty, src_rc, false); try strat.write(cg, try dst.tracking(cg).short.mem(cg, .{ - .size = cg.memSize(src_ty), + .size = cg.memSize(src_ty, src_rc), .disp = disp, }), registerAlias(src_reg, src_abi_size)); } else { @@ -182906,14 +183691,36 @@ const Temp = struct { .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, - .sseup, .x87up, .none, .win_i128, .integer_per_element => unreachable, + .sseup, + .x87up, + .none, + .win_i128, + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => unreachable, }); const part_size = switch (class) { .integer, .sse, .memory => @min(8 * @as(u7, next_class_index - class_index), remaining_abi_size), .x87 => 16, .float => 4, .float_combine => 8, - .sseup, .x87up, .none, .win_i128, .integer_per_element => unreachable, + .sseup, + .x87up, + .none, + .win_i128, + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => unreachable, }; try dst.writeReg(part_disp, switch (class) { .integer => .u64, @@ -182926,7 +183733,19 @@ const Temp = struct { .x87 => .f80, .float => .f32, .float_combine => .vector_2_f32, - .sseup, .x87up, .memory, .none, .win_i128, .integer_per_element => unreachable, + .sseup, + .x87up, + .memory, + .none, + .win_i128, + .bool_vector_mask, + .integer_per_element, + .sse_per_element, + .sse_sse_x87_per_qword, + .sse_per_xword, + .sse_per_yword, + .sse_per_zword, + => unreachable, }, src_reg, cg); part_disp += part_size; remaining_abi_size -= part_size; @@ -182958,6 +183777,1331 @@ const Temp = struct { try cg.asmOpOnly(.{ .@"rep _sb", .sto }); } + fn copyToMask(dst: *Temp, src: *Temp, cg: *CodeGen) Select.Error!void { + var ops: [2]Temp = .{ dst.*, src.* }; + try cg.select(&.{}, &.{}, &ops, comptime &.{ .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1b, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1b, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_q, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_q, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .tmp2x, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .tmp2x, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_q, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_b, .shuf, .src0x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_mut_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .shuf, .src1x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src1x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src1x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_q, .sub, .src0x, .src1x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpckldq, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklqdq, .src0x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 2 }, .{ .exact_bool_vec = 2 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_mut_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 8 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .tmp2x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpckldq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklqdq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_q, .sub, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1b, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1b, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .tmp2x, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .tmp2x, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_b, .shuf, .src0x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_mut_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .shuf, .src1x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src1x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src1x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .sub, .src0x, .src1x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpckldq, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklqdq, .src0x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 4 }, .{ .exact_bool_vec = 4 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 4 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .tmp2x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpckldq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklqdq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .sub, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1b, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1b, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_b, .broadcast, .src0x, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .tmp2x, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .tmp2x, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp2x, ._ }, + .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp2x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_b, .shuf, .src0x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_mut_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .shuf, .src1x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src1x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src1x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .sub, .src0x, .src1x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpckldq, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklqdq, .src0x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 8 }, .{ .exact_bool_vec = 8 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward, .smear = 2 } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .tmp2x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpckldq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklqdq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .sub, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .word, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .lea(.tmp2x), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .vp_q, .broadcast, .tmp3x, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp3x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp3x, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .word, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .lea(.tmp2x), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .vp_q, .broadcast, .tmp3x, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp3x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp3x, ._ }, + .{ ._, .vp_, .xor, .tmp3x, .tmp3x, .tmp3x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp3x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .word, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .lea(.tmp2x), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .v_, .movddup, .tmp3x, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp3x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp3x, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .word, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .lea(.tmp2x), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .v_, .movddup, .tmp3x, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp3x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp3x, ._ }, + .{ ._, .vp_, .xor, .tmp3x, .tmp3x, .tmp3x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp3x, .src0x, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .word, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .usize, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_b, .shuf, .src0x, .lea(.tmp2x), ._, ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, ._, .movddup, .tmp3x, .lea(.tmp2q), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp3x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp3x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .ssse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_mut_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .word, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .p_b, .shuf, .src1x, .lea(.tmp2x), ._, ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, ._, .movddup, .src0x, .lea(.tmp2q), ._, ._ }, + .{ ._, .p_, .@"and", .src1x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src1x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .sub, .src0x, .src1x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .usize, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpckldq, .src0x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._, .movddup, .tmp2x, .lea(.tmp1q), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse3, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .usize, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .tmp2x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpckldq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._, .movddup, .src0x, .lea(.tmp1q), ._, ._ }, + .{ ._, .p_, .@"and", .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .sub, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .usize, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .src0x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .src0x, .src0x, ._, ._ }, + .{ ._, .p_, .unpckldq, .src0x, .src0x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .tmp2x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .src0x, .tmp2x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .sse2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 16 }, .{ .exact_bool_vec = 16 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .xword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .usize, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._dqa, .mov, .tmp2x, .src1x, ._, ._ }, + .{ ._, .p_, .unpcklbw, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpcklwd, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, .p_, .unpckldq, .tmp2x, .tmp2x, ._, ._ }, + .{ ._, ._, .lea, .tmp1p, .mem(.tmp0), ._, ._ }, + .{ ._, ._dqa, .mov, .src0x, .lea(.tmp1x), ._, ._ }, + .{ ._, .p_, .@"and", .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_b, .cmpeq, .tmp2x, .src0x, ._, ._ }, + .{ ._, .p_, .xor, .src0x, .src0x, ._, ._ }, + .{ ._, .p_b, .sub, .src0x, .tmp2x, ._, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 32 }, .{ .exact_bool_vec = 32 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .from_sign_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_d, .broadcast, .src0y, .src1d, ._, ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0y, .src0y, .lea(.tmp2y), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .vp_q, .broadcast, .tmp3y, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0y, .src0y, .tmp3y, ._ }, + .{ ._, .vp_b, .cmpeq, .src0y, .src0y, .tmp3y, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 32 }, .{ .exact_bool_vec = 32 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_d, .broadcast, .src0y, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0y, .src0y, .lea(.tmp2y), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .vp_q, .broadcast, .tmp3y, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0y, .src0y, .tmp3y, ._ }, + .{ ._, .vp_b, .cmpeq, .src0y, .src0y, .tmp3y, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 32 }, .{ .exact_bool_vec = 32 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .from_zero_extend, .is = .uninverted } }, .mem, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_d, .broadcast, .src0y, .src1d, ._, ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0y, .src0y, .lea(.tmp2y), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .vp_q, .broadcast, .tmp3y, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0y, .src0y, .tmp3y, ._ }, + .{ ._, .vp_b, .cmpeq, .src0y, .src0y, .tmp3y, ._ }, + .{ ._, .vp_, .xor, .tmp3y, .tmp3y, .tmp3y, ._ }, + .{ ._, .vp_b, .sub, .src0y, .tmp3y, .src0y, ._ }, + } }, + }, .{ + .required_features = .{ .avx2, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 32 }, .{ .exact_bool_vec = 32 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_8_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, .vp_d, .broadcast, .src0y, .src1x, ._, ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .src0y, .src0y, .lea(.tmp2y), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .vp_q, .broadcast, .tmp3y, .lea(.tmp2q), ._, ._ }, + .{ ._, .vp_, .@"and", .src0y, .src0y, .tmp3y, ._ }, + .{ ._, .vp_b, .cmpeq, .src0y, .src0y, .tmp3y, ._ }, + .{ ._, .vp_, .xor, .tmp3y, .tmp3y, .tmp3y, ._ }, + .{ ._, .vp_b, .sub, .src0y, .tmp3y, .src0y, ._ }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 32 }, .{ .exact_bool_vec = 32 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .from_sign_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .tmp3x, .src1x, .lea(.tmp2y), ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .lead(.tmp2y, 16), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp4x, .lea(.tmp2x), ._, ._ }, + .{ ._, .vp_, .@"and", .tmp3x, .tmp3x, .tmp4x, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp4x, ._ }, + .{ ._, .vp_b, .cmpeq, .tmp3x, .tmp3x, .tmp4x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp4x, ._ }, + .{ ._, .v_f128, .insert, .src0y, .tmp3y, .src0x, .ui(1) }, + } }, + }, .{ + .required_features = .{ .avx, null, null, null }, + .src_constraints = .{ .{ .exact_bool_vec = 32 }, .{ .exact_bool_vec = 32 }, .any }, + .patterns = &.{ + .{ .src = .{ .{ .reg_mask = .{ .size = .yword, .kind = .from_zero_extend, .is = .uninverted } }, .to_sse, .none } }, + }, + .extra_temps = .{ + .{ .type = .vector_32_u8, .kind = .{ .pshufb_bytes_mem = .{ .direction = .forward, .size = .dword, .smear = 8 } } }, + .{ .type = .vector_16_u8, .kind = .{ .bits_mem = .{ .direction = .forward } } }, + .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } }, + .unused, + .unused, + .unused, + .unused, + .unused, + .unused, + }, + .each = .{ .once = &.{ + .{ ._, ._, .lea, .tmp2p, .mem(.tmp0), ._, ._ }, + .{ ._, .vp_b, .shuf, .tmp3x, .src1x, .lea(.tmp2y), ._ }, + .{ ._, .vp_b, .shuf, .src0x, .src1x, .lead(.tmp2y, 16), ._ }, + .{ ._, ._, .lea, .tmp2p, .mem(.tmp1), ._, ._ }, + .{ ._, .v_dqa, .mov, .tmp4x, .lea(.tmp2x), ._, ._ }, + .{ ._, .vp_, .@"and", .tmp3x, .tmp3x, .tmp4x, ._ }, + .{ ._, .vp_, .@"and", .src0x, .src0x, .tmp4x, ._ }, + .{ ._, .vp_b, .cmpeq, .tmp3x, .tmp3x, .tmp4x, ._ }, + .{ ._, .vp_b, .cmpeq, .src0x, .src0x, .tmp4x, ._ }, + .{ ._, .vp_, .xor, .tmp4x, .tmp4x, .tmp4x, ._ }, + .{ ._, .vp_b, .sub, .tmp3x, .tmp4x, .tmp3x, ._ }, + .{ ._, .vp_b, .sub, .src0x, .tmp4x, .src0x, ._ }, + .{ ._, .v_f128, .insert, .src0y, .tmp3y, .src0x, .ui(1) }, + } }, + } }); + dst.*, src.* = ops; + } + fn wrapInt(temp: *Temp, cg: *CodeGen) Select.Error!void { var ops: [1]Temp = .{temp.*}; var res: [1]Temp = undefined; @@ -187486,7 +189630,13 @@ const Temp = struct { .unreach, .dead, .indirect_load_frame, - .elementwise_args, + .indirect_mask, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, .reserved_frame, .air_ref, => unreachable, @@ -188336,25 +190486,60 @@ const Select = struct { to_sse, mut_sse, to_mut_sse, - reg_mask: RegMaskSpec, - all_reg_mask: RegMaskSpec, - - const RegMaskSpec = struct { + reg_mask: struct { size: Memory.Size, + kind: enum { + any, + lsb, + msb, + zero_extend, + sign_extend, + from_lsb, + from_msb, + from_zero_extend, + from_sign_extend, + }, is: enum { any, uninverted, inverted, - - fn matches(is: @This(), inverted: bool) bool { - return switch (is) { - .any => true, - .uninverted => !inverted, - .inverted => inverted, - }; - } } = .any, - }; + + fn matches(spec: @This(), info: MaskInfo) bool { + return switch (spec.kind) { + .any => true, + .lsb => switch (info.kind) { + .lsb, .msb, .zero_extend, .sign_extend => true, + }, + .msb => switch (info.kind) { + .lsb, .zero_extend => false, + .msb, .sign_extend => true, + }, + .zero_extend => info.kind == .zero_extend, + .sign_extend => info.kind == .sign_extend, + .from_lsb => switch (info.kind) { + .lsb => true, + .msb, .zero_extend, .sign_extend => false, + }, + .from_msb => switch (info.kind) { + .lsb, .msb => true, + .zero_extend, .sign_extend => false, + }, + .from_sign_extend => switch (info.kind) { + .lsb, .msb, .sign_extend => true, + .zero_extend => false, + }, + .from_zero_extend => switch (info.kind) { + .lsb, .zero_extend => true, + .msb, .sign_extend => false, + }, + } and switch (spec.is) { + .any => true, + .uninverted => !info.inverted, + .inverted => info.inverted, + }; + } + }, fn matches(src: Src, temp: Temp, cg: *CodeGen) bool { return switch (src) { @@ -188439,13 +190624,7 @@ const Select = struct { .reg_mask => |mask_spec| switch (temp.tracking(cg).short) { .register_mask => |reg_mask| mask_spec.size.bitSize(cg.target) >= reg_mask.info.scalar.bitSize(cg.target) * temp.typeOf(cg).vectorLen(cg.pt.zcu) and - mask_spec.is.matches(reg_mask.info.inverted), - else => false, - }, - .all_reg_mask => |mask_spec| switch (temp.tracking(cg).short) { - .register_mask => |reg_mask| mask_spec.size.bitSize(cg.target) == - reg_mask.info.scalar.bitSize(cg.target) * temp.typeOf(cg).vectorLen(cg.pt.zcu) and - reg_mask.info.kind == .all and mask_spec.is.matches(reg_mask.info.inverted), + mask_spec.matches(reg_mask.info), else => false, }, }; @@ -188453,7 +190632,7 @@ const Select = struct { fn convert(src: Src, temp: *Temp, cg: *CodeGen) InnerError!bool { return switch (src) { - .none, .any, .imm, .imm8, .imm16, .imm32, .simm32, .reg_mask, .all_reg_mask => false, + .none, .any, .imm, .imm8, .imm16, .imm32, .simm32, .reg_mask => false, .mem, .to_mem => try temp.toBase(false, cg), .mut_mem, .to_mut_mem => try temp.toBase(true, cg), .to_reg => |reg| try temp.toReg(reg, cg), @@ -188524,8 +190703,8 @@ const Select = struct { pand_trunc_mem: struct { from: Memory.Size, to: Memory.Size }, pand_mask_mem: struct { ref: Select.Operand.Ref, invert: bool = false }, ptest_mask_mem: Select.Operand.Ref, - pshufb_bswap_mem: struct { repeat: u4 = 1, size: Memory.Size, smear: u4 = 1 }, - bits_mem: enum { forward, reverse }, + pshufb_bytes_mem: struct { direction: Direction, repeat: u4 = 1, size: Memory.Size, smear: u4 = 1 }, + bits_mem: struct { direction: Direction, smear: u4 = 1 }, splat_int_mem: struct { ref: Select.Operand.Ref, inside: enum { umin, smin, smax } = .umin, outside: enum { smin, smax } }, splat_float_mem: struct { ref: Select.Operand.Ref, inside: enum { zero } = .zero, outside: f16 }, frame: FrameIndex, @@ -188560,6 +190739,8 @@ const Select = struct { } }; + const Direction = enum { forward, reverse }; + fn lock(kind: Kind, cg: *CodeGen) ![2]?RegisterLock { var reg_locks: [2]?RegisterLock = @splat(null); const regs: [2]Register = switch (kind) { @@ -188881,11 +191062,15 @@ const Select = struct { var index: u7 = 0; for (0..@intCast(ref_ty.vectorLen(zcu))) |_| { switch (mask_info.kind) { - .sign => { + .lsb, .zero_extend => { + elems[index] = 1; + @memset(elems[index + 1 ..][0 .. elem_bytes - 1], std.math.minInt(u8)); + }, + .msb => { @memset(elems[index..][0 .. elem_bytes - 1], std.math.minInt(u8)); elems[index + elem_bytes - 1] = @bitCast(@as(i8, std.math.minInt(i8))); }, - .all => @memset(elems[index..][0..elem_bytes], std.math.maxInt(u8)), + .sign_extend => @memset(elems[index..][0..elem_bytes], std.math.maxInt(u8)), } index += elem_bytes; } @@ -188894,31 +191079,40 @@ const Select = struct { .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) }, } }))), true }; }, - .pshufb_bswap_mem => |bswap_spec| { + .pshufb_bytes_mem => |bytes_spec| { const zcu = pt.zcu; assert(spec.type.isVector(zcu) and spec.type.childType(zcu).toIntern() == .u8_type); var elem_buf: [32]u8 = @splat(1 << 7); const elems = elem_buf[0..spec.type.vectorLen(zcu)]; - const len: usize = @intCast(@divExact(bswap_spec.size.bitSize(cg.target), 8)); + const len: usize = @intCast(@divExact(bytes_spec.size.bitSize(cg.target), 8)); var to_index: u6 = 0; - for (0..bswap_spec.repeat) |_| for (0..len) |from_index| { - @memset(elems[to_index..][0..bswap_spec.smear], @intCast(len - 1 - from_index)); - to_index += bswap_spec.smear; + for (0..bytes_spec.repeat) |_| for (0..len) |from_index| { + @memset(elems[to_index..][0..bytes_spec.smear], @intCast(switch (bytes_spec.direction) { + .forward => from_index, + .reverse => len - 1 - from_index, + })); + to_index += bytes_spec.smear; }; return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = spec.type.toIntern(), .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) }, } }))), true }; }, - .bits_mem => |direction| { + .bits_mem => |bits_spec| { const zcu = pt.zcu; assert(spec.type.isVector(zcu) and spec.type.childType(zcu).toIntern() == .u8_type); - var bytes: [32]u8 = undefined; - const elems = bytes[0..spec.type.vectorLen(zcu)]; - for (elems, 0..) |*elem, index| elem.* = switch (direction) { - .forward => @as(u8, 1 << 0) << @truncate(index), - .reverse => @as(u8, 1 << 7) >> @truncate(index), - }; + var elem_buf: [32]u8 = @splat(1 << 7); + const elems = elem_buf[0..spec.type.vectorLen(zcu)]; + var from_index: u6 = 0; + var to_index: u6 = 0; + while (elems.len - to_index > 0) { + @memset(elems[to_index..][0..bits_spec.smear], @intCast(switch (bits_spec.direction) { + .forward => @as(u8, 1 << 0) << @truncate(from_index), + .reverse => @as(u8, 1 << 7) >> @truncate(from_index), + })); + from_index += 1; + to_index += bits_spec.smear; + } return .{ try cg.tempMemFromValue(.fromInterned(try pt.intern(.{ .aggregate = .{ .ty = spec.type.toIntern(), .storage = .{ .bytes = try zcu.intern_pool.getOrPutString(zcu.gpa, io, pt.tid, elems, .maybe_embedded_nulls) }, @@ -189053,6 +191247,9 @@ const Select = struct { unaligned_size_add_elem_size, unaligned_size_sub_elem_size, unaligned_size_sub_2_elem_size, + size_sub_bit_size_div_8_down_1_sub_1, + bit_size_sub_1_div_8_down_1, + bit_size_last_byte_mask, bit_size, src0_bit_size, @"8_size_sub_bit_size", @@ -189105,6 +191302,9 @@ const Select = struct { const add_unaligned_size_add_elem_size: Adjust = .{ .sign = .pos, .lhs = .unaligned_size_add_elem_size, .op = .mul, .rhs = .@"1" }; const add_unaligned_size_sub_elem_size: Adjust = .{ .sign = .pos, .lhs = .unaligned_size_sub_elem_size, .op = .mul, .rhs = .@"1" }; const add_unaligned_size_sub_2_elem_size: Adjust = .{ .sign = .pos, .lhs = .unaligned_size_sub_2_elem_size, .op = .mul, .rhs = .@"1" }; + const add_size_sub_bit_size_div_8_down_1_sub_1: Adjust = .{ .sign = .pos, .lhs = .size_sub_bit_size_div_8_down_1_sub_1, .op = .mul, .rhs = .@"1" }; + const add_bit_size_sub_1_div_8_down_1: Adjust = .{ .sign = .pos, .lhs = .bit_size_sub_1_div_8_down_1, .op = .mul, .rhs = .@"1" }; + const bit_size_last_byte_mask: Adjust = .{ .sign = .pos, .lhs = .bit_size_last_byte_mask, .op = .mul, .rhs = .@"1" }; const add_2_bit_size: Adjust = .{ .sign = .pos, .lhs = .bit_size, .op = .mul, .rhs = .@"2" }; const add_bit_size: Adjust = .{ .sign = .pos, .lhs = .bit_size, .op = .mul, .rhs = .@"1" }; const add_bit_size_rem_8: Adjust = .{ .sign = .pos, .lhs = .bit_size, .op = .rem_8_mul, .rhs = .@"1" }; @@ -190041,11 +192241,26 @@ const Select = struct { const ty = op.flags.base.ref.typeOf(s); break :lhs @intCast(s.cg.unalignedSize(ty) - ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * 2); }, + .size_sub_bit_size_div_8_down_1_sub_1 => { + const ty = op.flags.base.ref.typeOf(s); + const size: SignedImm = @intCast(ty.abiSize(s.cg.pt.zcu)); + const bit_size: SignedImm = @intCast(s.cg.nonBoolScalarBitSize(ty)); + break :lhs size - @divFloor(bit_size - 1, 8) - 1; + }, + .bit_size_sub_1_div_8_down_1 => { + const bit_size: SignedImm = @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s))); + break :lhs @divFloor(bit_size - 1, 8); + }, + .bit_size_last_byte_mask => { + const bit_size = s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)); + break :lhs @as(u8, std.math.maxInt(u8)) >> @intCast(7 - (bit_size - 1) % 8); + }, .bit_size => @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s))), .src0_bit_size => @intCast(s.cg.nonBoolScalarBitSize(Select.Operand.Ref.src0.typeOf(s))), .@"8_size_sub_bit_size" => { const ty = op.flags.base.ref.typeOf(s); - break :lhs @intCast(8 * ty.abiSize(s.cg.pt.zcu) - ty.bitSize(s.cg.pt.zcu)); + const bit_size = s.cg.intInfo(ty).?.bits; + break :lhs @intCast(8 * ty.abiSize(s.cg.pt.zcu) - bit_size); }, .len => @intCast(op.flags.base.ref.typeOf(s).vectorLen(s.cg.pt.zcu)), .elem_limbs => @intCast(@divExact( @@ -190152,7 +192367,16 @@ const Select = struct { .lea_lazy_sym => |lazy_sym| .{ .imm = .{ .lazy_sym = lazy_sym } }, .lea_extern_func => |extern_func| .{ .imm = .{ .extern_func = extern_func } }, else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = op.flags.base.size }) }, - .lea_frame, .elementwise_args, .reserved_frame, .air_ref => unreachable, + .lea_frame, + .register_tee, + .elementwise_gpr, + .elementwise_sse, + .xwordwise_sse, + .ywordwise_sse, + .zwordwise_sse, + .reserved_frame, + .air_ref, + => unreachable, }, 1...2 => |imm| switch (op.flags.base.ref.valueOf(s)) { inline .register_pair, .register_triple, .register_quadruple => |regs| .{ diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig index babadbe96b8bf23db4ad0d4c10de06c11a7710ca..1e8e60ffb665fc70709a5291040a32a1bebcb5af 100644 --- a/src/codegen/x86_64/Emit.zig +++ b/src/codegen/x86_64/Emit.zig @@ -113,6 +113,7 @@ pub fn emitMir(emit: *Emit) Error!void { .default => true, .hidden, .protected => false, }, + .is_dll_import = @"extern".is_dll_import, .force_pcrel_direct = switch (@"extern".relocation) { .any => false, .pcrel => true, @@ -154,20 +155,13 @@ pub fn emitMir(emit: *Emit) Error!void { @enumFromInt(try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)) else if (emit.bin_file.cast(.elf2)) |elf| try elf.externSymbol(.{ .name = extern_func.toSlice(&emit.lower.mir).?, - .lib_name = switch (comp.compiler_rt_strat) { - .none, .lib, .obj, .zcu => null, - .dyn_lib => "compiler_rt", - }, + .lib_name = null, .type = .FUNC, }) else if (emit.bin_file.cast(.macho)) |macho_file| @enumFromInt(try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null)) - else if (emit.bin_file.cast(.coff2)) |coff| @enumFromInt(@intFromEnum(try coff.globalSymbol( - extern_func.toSlice(&emit.lower.mir).?, - switch (comp.compiler_rt_strat) { - .none, .lib, .obj, .zcu => null, - .dyn_lib => "compiler_rt", - }, - ))) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), + else if (emit.bin_file.cast(.coff2)) |coff| @enumFromInt(@intFromEnum(try coff.globalSymbol(.{ + .name = extern_func.toSlice(&emit.lower.mir).?, + }))) else return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), .is_extern = true, } }, }, @@ -179,7 +173,13 @@ pub fn emitMir(emit: *Emit) Error!void { switch (lowered_inst.encoding.mnemonic) { .call => { reloc.target = .{ .branch = target }; - try emit.encodeInst(lowered_inst, reloc_info); + if (target.is_dll_import and emit.bin_file.cast(.coff2) != null) { + try emit.encodeInst(try .new(.none, .call, &.{ + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info); + } else { + try emit.encodeInst(lowered_inst, reloc_info); + } continue :lowered_inst; }, else => {}, @@ -255,7 +255,25 @@ pub fn emitMir(emit: *Emit) Error!void { else => unreachable, } } else if (emit.bin_file.cast(.coff2)) |_| { - switch (lowered_inst.encoding.mnemonic) { + if (target.is_dll_import) switch (lowered_inst.encoding.mnemonic) { + .lea => try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info), + .mov => { + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initRip(.ptr, 0) }, + }, emit.lower.target), reloc_info); + try emit.encodeInst(try .new(.none, .mov, &.{ + lowered_inst.ops[0], + .{ .mem = .initSib(lowered_inst.ops[reloc.op_index].mem.sib.ptr_size, .{ .base = .{ + .reg = lowered_inst.ops[0].reg.to64(), + } }) }, + }, emit.lower.target), &.{}); + }, + else => unreachable, + } else switch (lowered_inst.encoding.mnemonic) { .lea => try emit.encodeInst(try .new(.none, .lea, &.{ lowered_inst.ops[0], .{ .mem = .initRip(.none, 0) }, @@ -374,7 +392,7 @@ pub fn emitMir(emit: *Emit) Error!void { .op_index = 1, .target = .{ .symbol = .{ .symbol = @enumFromInt(@intFromEnum( - try coff.globalSymbol("__tls_index", null), + try coff.globalSymbol(.{ .name = "__tls_index" }), )), .is_extern = false, } }, @@ -409,7 +427,7 @@ pub fn emitMir(emit: *Emit) Error!void { .op_index = 1, .target = .{ .symbol = .{ .symbol = @enumFromInt(@intFromEnum( - try coff.globalSymbol("_tls_index", null), + try coff.globalSymbol(.{ .name = "_tls_index" }), )), .is_extern = false, } }, @@ -725,6 +743,7 @@ const RelocInfo = struct { const Symbol = struct { symbol: link.File.SymbolId, is_extern: bool, + is_dll_import: bool = false, force_pcrel_direct: bool = false, }; }; @@ -816,7 +835,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI @enumFromInt(@intFromEnum(emit.atom_id)), end_offset - 4, @enumFromInt(@intFromEnum(target.symbol)), - reloc.off, + .{ .known = reloc.off }, .{ .AMD64 = .REL32 }, ) else unreachable, .branch => |target| if (emit.bin_file.cast(.elf)) |elf_file| { @@ -854,7 +873,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI @enumFromInt(@intFromEnum(emit.atom_id)), end_offset - 4, @enumFromInt(@intFromEnum(target.symbol)), - reloc.off, + .{ .known = reloc.off }, .{ .AMD64 = .REL32 }, ) else return emit.fail("TODO implement {s} reloc for {s}", .{ @tagName(reloc.target), @tagName(emit.bin_file.tag), @@ -912,7 +931,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI @enumFromInt(@intFromEnum(emit.atom_id)), end_offset - 4, @enumFromInt(@intFromEnum(target.symbol)), - reloc.off, + .{ .known = reloc.off }, .{ .AMD64 = .SECREL }, ) else return emit.fail("TODO implement {s} reloc for {s}", .{ @tagName(reloc.target), @tagName(emit.bin_file.tag), diff --git a/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig index 6f620876521aeb4a2f866028c406ade71ee10a8c..3e7a9a548d54baee16d64a54de9a42c4650f7ea5 100644 --- a/src/codegen/x86_64/abi.zig +++ b/src/codegen/x86_64/abi.zig @@ -24,59 +24,40 @@ pub const Class = enum { float, /// A `Class.sse` containing two `f32`s. float_combine, - /// Clang passes each vector element in a separate `Class.integer`, but returns as `Class.memory`. + /// Clang uses different element sizes depending on the vector length. + bool_vector_mask, + /// Clang passes each vector element in a separate `Class.integer`. integer_per_element, + /// Clang passes each vector element in a separate `Class.sse`. + sse_per_element, + /// Just complete insanity, idk what to say. + sse_sse_x87_per_qword, + /// Clang passes each 16 bytes in a separate `Class.sse`. + sse_per_xword, + /// Clang passes each 32 bytes in a separate `Class.sse`. + sse_per_yword, + /// Clang passes each 64 bytes in a separate `Class.sse`. + sse_per_zword, - pub const one_integer: [8]Class = .{ - .integer, .none, .none, .none, - .none, .none, .none, .none, - }; - pub const two_integers: [8]Class = .{ - .integer, .integer, .none, .none, - .none, .none, .none, .none, - }; - pub const three_integers: [8]Class = .{ - .integer, .integer, .integer, .none, - .none, .none, .none, .none, - }; - pub const four_integers: [8]Class = .{ - .integer, .integer, .integer, .integer, - .none, .none, .none, .none, - }; - pub const len_integers: [8]Class = .{ - .integer_per_element, .none, .none, .none, - .none, .none, .none, .none, - }; + pub const zero_bit: [8]Class = .{ .none, .none, .none, .none, .none, .none, .none, .none }; + + pub const one_integer: [8]Class = .{ .integer, .none, .none, .none, .none, .none, .none, .none }; + pub const two_integers: [8]Class = .{ .integer, .integer, .none, .none, .none, .none, .none, .none }; + pub const three_integers: [8]Class = .{ .integer, .integer, .integer, .none, .none, .none, .none, .none }; + pub const four_integers: [8]Class = .{ .integer, .integer, .integer, .integer, .none, .none, .none, .none }; + pub const len_integers: [8]Class = .{ .integer_per_element, .none, .none, .none, .none, .none, .none, .none }; pub const @"f16" = @"f64"; - pub const @"f32": [8]Class = .{ - .float, .none, .none, .none, - .none, .none, .none, .none, - }; - pub const @"f64": [8]Class = .{ - .sse, .none, .none, .none, - .none, .none, .none, .none, - }; - pub const @"f80": [8]Class = .{ - .x87, .x87up, .none, .none, - .none, .none, .none, .none, - }; - pub const @"f128": [8]Class = .{ - .sse, .sseup, .none, .none, - .none, .none, .none, .none, - }; + pub const @"f32": [8]Class = .{ .float, .none, .none, .none, .none, .none, .none, .none }; + pub const @"f64": [8]Class = .{ .sse, .none, .none, .none, .none, .none, .none, .none }; + pub const @"f80": [8]Class = .{ .x87, .x87up, .none, .none, .none, .none, .none, .none }; + pub const @"f128": [8]Class = .{ .sse, .sseup, .none, .none, .none, .none, .none, .none }; /// COMPLEX_X87: This class consists of types that will be returned via the x87 /// FPU. - pub const complex_x87: [8]Class = .{ - .x87, .x87up, .x87, .x87up, - .none, .none, .none, .none, - }; + pub const complex_x87: [8]Class = .{ .x87, .x87up, .x87, .x87up, .none, .none, .none, .none }; - pub const stack: [8]Class = .{ - .memory, .none, .none, .none, - .none, .none, .none, .none, - }; + pub const stack: [8]Class = .{ .memory, .none, .none, .none, .none, .none, .none, .none }; pub fn isX87(class: Class) bool { return switch (class) { @@ -112,7 +93,7 @@ pub const Class = enum { pub const Context = enum { ret, arg, other }; -pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Context) Class { +pub fn classifyWindows(init_ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Context) Class { // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 // "There's a strict one-to-one correspondence between a function call's arguments // and the registers used for those arguments. Any argument that doesn't fit in 8 @@ -121,13 +102,13 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont // "All floating point operations are done using the 16 XMM registers." // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed // as if they were integers of the same size." - return switch (ty.zigTypeTag(zcu)) { + var ty = init_ty; + while (true) return switch (ty.zigTypeTag(zcu)) { + .void => return .none, + .bool, .pointer, .int, - .bool, .@"enum", - .void, - .noreturn, .error_set, .@"struct", .@"union", @@ -137,7 +118,7 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont .@"anyframe", .frame, => switch (ty.abiSize(zcu)) { - 0 => unreachable, + 0 => .none, 1, 2, 4, 8 => .integer, else => switch (ty.zigTypeTag(zcu)) { .int => .win_i128, @@ -148,15 +129,43 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont else => .memory, }, }, - + .noreturn => unreachable, .float => switch (ty.floatBits(target)) { 16, 32, 64 => .sse, 80 => .memory, 128 => if (ctx == .arg) .memory else .sse, else => unreachable, }, - .vector => .sse, - + .vector => { + const len = ty.vectorLen(zcu); + if (len == 0) return .none; + const elem_ty = ty.childType(zcu); + if (len == 1) { + ty = elem_ty; + continue; + } + const reg_size: u64, const split_class: Class = if (target.cpu.has(.x86, .avx512f)) + .{ 64, .sse_per_zword } + else if (target.cpu.has(.x86, .avx)) + .{ 32, .sse_per_yword } + else + .{ 16, .sse_per_xword }; + if (elem_ty.toIntern() == .bool_type) { + if (len > reg_size) return if (ctx == .arg) .integer_per_element else .memory; + return .bool_vector_mask; + } + const elem_size = elem_ty.abiSize(zcu); + const unaligned_size = elem_size * len; + if ((unaligned_size <= 8 or unaligned_size > reg_size) and !std.math.isPowerOfTwo(len)) { + if (ctx == .ret and len > Win64.c_abi_int_return_regs.len) return .memory; + if (!elem_ty.isRuntimeFloat()) return .integer_per_element; + if (ctx == .ret and len > 2 and elem_size == 8) return .sse_sse_x87_per_qword; + return .sse_per_element; + } + if (unaligned_size <= reg_size) return if (ctx == .arg) .memory else .sse; + if (ctx == .ret and unaligned_size > reg_size * Win64.c_abi_sse_return_regs.len) return .memory; + return split_class; + }, .type, .comptime_float, .comptime_int, @@ -164,6 +173,7 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont .null, .@"fn", .@"opaque", + .spirv, .enum_literal, => unreachable, }; @@ -173,19 +183,18 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont /// the beginning of the array; unused slots are filled with .none. pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Context) [8]Class { switch (ty.zigTypeTag(zcu)) { - .pointer => switch (ty.ptrSize(zcu)) { - .slice => return Class.two_integers, - else => return Class.one_integer, - }, + .void => return Class.zero_bit, + .bool => return Class.one_integer, + .noreturn => unreachable, .int, .@"enum", .error_set => { const bits = ty.intInfo(zcu).bits; + if (bits == 0) return Class.zero_bit; if (bits <= 64 * 1) return Class.one_integer; if (bits <= 64 * 2) return Class.two_integers; if (bits <= 64 * 3) return Class.three_integers; if (bits <= 64 * 4) return Class.four_integers; return Class.stack; }, - .bool, .void, .noreturn => return Class.one_integer, .float => switch (ty.floatBits(target)) { 16 => { if (ctx == .other) return Class.stack; @@ -204,61 +213,61 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont 80 => return Class.f80, else => unreachable, }, + .pointer => switch (ty.ptrSize(zcu)) { + .slice => return Class.two_integers, + else => return Class.one_integer, + }, .vector => { + const len = ty.vectorLen(zcu); + if (len == 0) return Class.zero_bit; const elem_ty = ty.childType(zcu); - const bits = elem_ty.bitSize(zcu) * ty.arrayLen(zcu); if (elem_ty.toIntern() == .bool_type) { - if (bits <= 32) return Class.one_integer; - if (bits <= 64) return Class.f64; - if (ctx == .other) return Class.stack; - if (bits <= 128) return Class.len_integers; - if (bits <= 256 and target.cpu.has(.x86, .avx)) return Class.len_integers; - if (bits <= 512 and target.cpu.has(.x86, .avx512f)) return Class.len_integers; + if (len <= 32) return Class.one_integer; + if (len <= 64) return Class.f64; + if (ctx != .arg) return Class.stack; + if (len <= 128) return Class.len_integers; + if (len <= 256 and target.cpu.has(.x86, .avx)) return Class.len_integers; + if (len <= 512 and target.cpu.has(.x86, .avx512f)) return Class.len_integers; return Class.stack; } - if (elem_ty.isRuntimeFloat() and elem_ty.floatBits(target) == 80) { - if (bits <= 80 * 1) return Class.f80; - if (bits <= 80 * 2) return Class.complex_x87; + if (elem_ty.isRuntimeFloat() and elem_ty.floatBits(target) == 80) switch (len) { + 0 => unreachable, + 1 => return Class.f80, + 2 => return Class.complex_x87, + else => return Class.stack, + }; + 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) 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 + 8 * 2 * 2, 8 * 2 * 4 => return .{ .sse_per_xword, .none, .none, .none, .none, .none, .none, .none }, + }; return Class.stack; } - if (bits <= 64 * 1) return .{ - .sse, .none, .none, .none, - .none, .none, .none, .none, - }; - if (bits <= 64 * 2) return .{ - .sse, .sseup, .none, .none, - .none, .none, .none, .none, - }; - if (ctx == .arg and !target.cpu.has(.x86, .avx)) return Class.stack; - if (bits <= 64 * 3) return .{ - .sse, .sseup, .sseup, .none, - .none, .none, .none, .none, - }; - if (bits <= 64 * 4) return .{ - .sse, .sseup, .sseup, .sseup, - .none, .none, .none, .none, - }; - if (ctx == .arg and !target.cpu.has(.x86, .avx512f)) return Class.stack; - if (bits <= 64 * 5) return .{ - .sse, .sseup, .sseup, .sseup, - .sseup, .none, .none, .none, - }; - if (bits <= 64 * 6) return .{ - .sse, .sseup, .sseup, .sseup, - .sseup, .sseup, .none, .none, - }; - if (bits <= 64 * 7) return .{ - .sse, .sseup, .sseup, .sseup, - .sseup, .sseup, .sseup, .none, - }; - if (bits <= 64 * 8 or (ctx == .ret and bits <= @as(u64, if (target.cpu.has(.x86, .avx512f)) - 64 * 32 - else if (target.cpu.has(.x86, .avx)) - 64 * 16 - else - 64 * 8))) return .{ - .sse, .sseup, .sseup, .sseup, - .sseup, .sseup, .sseup, .sseup, + if (unaligned_size <= 8 * 3) return .{ .sse, .sseup, .sseup, .none, .none, .none, .none, .none }; + if (unaligned_size <= 8 * 4) return .{ .sse, .sseup, .sseup, .sseup, .none, .none, .none, .none }; + if (!target.cpu.has(.x86, .avx512f)) { + if (ctx == .ret) switch (unaligned_size) { + else => {}, + 8 * 4 * 2, 8 * 4 * 4 => return .{ .sse_per_yword, .none, .none, .none, .none, .none, .none, .none }, + }; + return Class.stack; + } + if (unaligned_size <= 8 * 5) return .{ .sse, .sseup, .sseup, .sseup, .sseup, .none, .none, .none }; + if (unaligned_size <= 8 * 6) return .{ .sse, .sseup, .sseup, .sseup, .sseup, .sseup, .none, .none }; + if (unaligned_size <= 8 * 7) return .{ .sse, .sseup, .sseup, .sseup, .sseup, .sseup, .sseup, .none }; + if (unaligned_size <= 8 * 8) return .{ .sse, .sseup, .sseup, .sseup, .sseup, .sseup, .sseup, .sseup }; + if (ctx == .ret) switch (unaligned_size) { + else => {}, + 8 * 8 * 2, 8 * 8 * 4 => return .{ .sse_per_zword, .none, .none, .none, .none, .none, .none, .none }, }; return Class.stack; }, @@ -274,6 +283,7 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont // "If the size of the aggregate exceeds a single eightbyte, each is classified // separately.". const ty_size = ty.abiSize(zcu); + if (ty_size == 0) return Class.zero_bit; switch (ty.containerLayout(zcu)) { .auto => unreachable, .@"extern" => {}, @@ -324,6 +334,7 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont }, .array => { const ty_size = ty.abiSize(zcu); + if (ty_size == 0) return Class.zero_bit; if (ty_size <= 8) return Class.one_integer; if (ty_size <= 16) return Class.two_integers; return Class.stack; @@ -456,7 +467,7 @@ pub const SysV = struct { pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 }; pub const c_abi_x87_param_regs = x87_regs[0..0]; pub const c_abi_sse_param_regs = sse_avx_regs[0..8]; - pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx }; + pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx, .rcx }; pub const c_abi_x87_return_regs = x87_regs[0..2]; pub const c_abi_sse_return_regs = sse_avx_regs[0..4]; }; @@ -473,9 +484,9 @@ pub const Win64 = struct { pub const c_abi_int_param_regs = [_]Register{ .rcx, .rdx, .r8, .r9 }; pub const c_abi_x87_param_regs = x87_regs[0..0]; pub const c_abi_sse_param_regs = sse_avx_regs[0..4]; - pub const c_abi_int_return_regs = [_]Register{.rax}; - pub const c_abi_x87_return_regs = x87_regs[0..0]; - pub const c_abi_sse_return_regs = sse_avx_regs[0..1]; + pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx, .rcx }; + pub const c_abi_x87_return_regs = x87_regs[0..1]; + pub const c_abi_sse_return_regs = sse_avx_regs[0..4]; }; pub fn getCalleePreservedRegs(cc: std.lang.CallingConvention.Tag) []const Register { diff --git a/src/crash_report.zig b/src/crash_report.zig index b177af3bb6033ffc4e10e15a8aaf7c7e74c0bf03..63370d0557d6799fe584794a84026963077b7a71 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -84,6 +84,25 @@ pub const CodegenFunc = if (enabled) struct { pub fn stop(_: InternPool.Index) void {} }; +pub const LinkerOp = if (enabled) struct { + lf: *link.File, + tid: Zcu.PerThread.Id, + threadlocal var current: ?LinkerOp = null; + pub fn start(lf: *link.File, tid: Zcu.PerThread.Id) void { + std.debug.assert(current == null); + current = .{ .lf = lf, .tid = tid }; + } + pub fn stop(lf: *link.File, tid: Zcu.PerThread.Id) void { + std.debug.assert(current.?.lf == lf and current.?.tid == tid); + current = null; + } +} else struct { + const current: ?noreturn = null; + // Dummy implementation + pub fn start(_: *link.File, _: Zcu.PerThread.Id) void {} + pub fn stop(_: *link.File, _: Zcu.PerThread.Id) void {} +}; + fn dumpCrashContext() Io.Writer.Error!void { const S = struct { /// In the case of recursive panics or segfaults, don't print the context for a second time. @@ -111,6 +130,15 @@ fn dumpCrashContext() Io.Writer.Error!void { try w.print("Generating function '{f}'\n\n", .{func_fqn.fmt(&cg.zcu.intern_pool)}); } else if (AnalyzeBody.current) |anal| { try dumpCrashContextSema(anal, w, &S.crash_heap); + } else if (LinkerOp.current) |linker_op| { + try w.writeAll("Linker snapshot:\n"); + switch (try linker_op.lf.dump(w, linker_op.tid)) { + .unimplemented => try w.writeAll("(backend does not support link snapshots)"), + .needs_extensions => try w.writeAll("(build with -Ddebug-extensions to dump linker state)"), + .disabled => try w.writeAll("(run with --debug-link-snapshot to dump linker state)"), + .enabled => {}, + } + try w.writeAll("\n\n"); } else { try w.writeAll("(no context)\n\n"); } @@ -185,6 +213,7 @@ const Zir = std.zig.Zir; const Sema = @import("Sema.zig"); const Zcu = @import("Zcu.zig"); +const link = @import("link.zig"); const InternPool = @import("InternPool.zig"); const dev = @import("dev.zig"); const print_zir = @import("print_zir.zig"); diff --git a/src/dev.zig b/src/dev.zig index f3c4016faf2338e1f80b1e96953d207e7fed866f..bba67696f2f92cf522949f68ffc35370f3daf86d 100644 --- a/src/dev.zig +++ b/src/dev.zig @@ -52,6 +52,10 @@ pub const Env = enum { /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-` @"x86_64-linux", + /// - sema + /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-windows --listen=-` + @"x86_64-windows", + pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool { return switch (dev_env) { .full => true, @@ -216,6 +220,16 @@ pub const Env = enum { => true, else => Env.sema.supports(feature), }, + .@"x86_64-windows" => switch (feature) { + .build_command, + .stdio_listen, + .incremental, + .legalize, + .x86_64_backend, + .coff2_linker, + => true, + else => Env.sema.supports(feature), + }, }; } diff --git a/src/fmt.zig b/src/fmt.zig index a3cd7c8d74591f0ac85e52d5472de98f6709e7d4..73d8a1c162328f720e9687d17cf7e2129b431da2 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -23,6 +23,7 @@ const usage_fmt = \\ --ast-check Run zig ast-check on every file \\ --exclude [file] Exclude file or directory from formatting \\ --zon Treat all input files as ZON, regardless of file extension + \\ --complexity Print a complexity report for each file as well as total \\ \\ ; @@ -39,6 +40,10 @@ const Fmt = struct { out_buffer: std.Io.Writer.Allocating, stdout_writer: *Io.File.Writer, + complexity: bool, + total_tokens: u64, + total_nodes: u64, + const SeenMap = std.AutoHashMap(Io.File.INode, void); }; @@ -48,8 +53,11 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! var check_flag = false; var check_ast_flag = false; var force_zon = false; + var complexity = false; + var input_files = std.array_list.Managed([]const u8).init(gpa); defer input_files.deinit(); + var excluded_files = std.array_list.Managed([]const u8).init(gpa); defer excluded_files.deinit(); @@ -68,7 +76,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! i += 1; const next_arg = args[i]; color = std.meta.stringToEnum(Color, next_arg) orelse { - fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg}); + fatal("expected [auto|on|off] after --color, found {q}", .{next_arg}); }; } else if (mem.eql(u8, arg, "--stdin")) { stdin_flag = true; @@ -76,6 +84,8 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! check_flag = true; } else if (mem.eql(u8, arg, "--ast-check")) { check_ast_flag = true; + } else if (mem.eql(u8, arg, "--complexity")) { + complexity = true; } else if (mem.eql(u8, arg, "--exclude")) { if (i + 1 >= args.len) { fatal("expected parameter after --exclude", .{}); @@ -86,7 +96,7 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! } else if (mem.eql(u8, arg, "--zon")) { force_zon = true; } else { - fatal("unrecognized parameter: '{s}'", .{arg}); + fatal("unrecognized parameter: {q}", .{arg}); } } else { try input_files.append(arg); @@ -175,6 +185,9 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! .color = color, .out_buffer = .init(gpa), .stdout_writer = &stdout_writer, + .complexity = complexity, + .total_tokens = 0, + .total_nodes = 0, }; defer fmt.seen.deinit(); defer fmt.out_buffer.deinit(); @@ -198,7 +211,12 @@ pub fn run(gpa: Allocator, arena: Allocator, io: Io, args: []const []const u8) ! for (input_files.items) |file_path| { try fmtPath(&fmt, file_path, check_flag, Io.Dir.cwd(), file_path); } - try fmt.stdout_writer.interface.flush(); + + if (complexity) { + std.log.info("total: tokens={d} nodes={d}", .{ fmt.total_tokens, fmt.total_nodes }); + } + + try fmt.stdout_writer.flush(); if (fmt.any_error) { process.exit(1); } @@ -208,7 +226,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: Io.Dir, sub_ fmtPathFile(fmt, file_path, check_mode, dir, sub_path) catch |err| switch (err) { error.IsDir, error.AccessDenied => return fmtPathDir(fmt, file_path, check_mode, dir, sub_path), else => { - std.log.err("unable to format '{s}': {s}", .{ file_path, @errorName(err) }); + std.log.err("formatting {q}: {t}", .{ file_path, err }); fmt.any_error = true; return; }, @@ -244,7 +262,7 @@ fn fmtPathDir( try fmtPathDir(fmt, full_path, check_mode, dir, entry.name); } else { fmtPathFile(fmt, full_path, check_mode, dir, entry.name) catch |err| { - std.log.err("unable to format '{s}': {t}", .{ full_path, err }); + std.log.err("unable to format {q}: {t}", .{ full_path, err }); fmt.any_error = true; return; }; @@ -341,6 +359,12 @@ fn fmtPathFile( } } + if (fmt.complexity) { + std.log.info("{s}: tokens={d} nodes={d}", .{ file_path, tree.tokens.len, tree.nodes.len }); + fmt.total_tokens += tree.tokens.len; + fmt.total_nodes += tree.nodes.len; + } + // As a heuristic, we make enough capacity for the same as the input source. fmt.out_buffer.clearRetainingCapacity(); try fmt.out_buffer.ensureTotalCapacity(source_code.len); @@ -365,13 +389,7 @@ fn fmtPathFile( } /// Provided for debugging/testing purposes; unused by the compiler. -pub fn main() !void { - const gpa = std.heap.smp_allocator; - var arena_instance = std.heap.ArenaAllocator.init(gpa); - const arena = arena_instance.allocator(); - const args = try process.argsAlloc(arena); - var threaded: std.Io.Threaded = .init(gpa, .{}); - defer threaded.deinit(); - const io = threaded.io(); - return run(gpa, arena, io, args[1..]); +pub fn main(init: process.Init) !void { + const args = try init.minimal.args.toSlice(init.arena.allocator()); + return run(init.gpa, init.arena.allocator(), init.io, args[1..]); } diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 384af94084d98f65316f16f74c019e5a57292dfc..a19a83e044ce28800257497b1e76bb9fc6cbf9cb 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -14,9 +14,12 @@ const dev = @import("../dev.zig"); const def = @import("mingw/def.zig"); const implib = @import("mingw/implib.zig"); +const Preprocessor = @import("mingw/Preprocessor.zig"); + test { _ = def; _ = implib; + _ = Preprocessor; } pub const CrtFile = enum { @@ -204,9 +207,14 @@ fn addCrtCcArgs( }); } -pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { +pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.Progress.Node) !Cache.Path { dev.check(.build_import_lib); + log.debug("buildImportLib({s})", .{lib_name}); + + const sub_node = prog_node.start(lib_name, 0); + defer sub_node.end(); + const gpa = comp.gpa; const io = comp.io; @@ -215,14 +223,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { const arena = arena_allocator.allocator(); const def_file_path = findDef(arena, io, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) { - error.FileNotFound => { - log.debug("no {s}.def file available to make a DLL import {s}.lib", .{ lib_name, lib_name }); - // In this case we will end up putting foo.lib onto the linker line and letting the linker - // use its library paths to look for libraries and report any problems. - return; - }, + error.FileNotFound => return error.DefNotFound, else => |e| return e, }; + // Only .def.in files need preprocessing + const def_needs_preprocessing = mem.endsWith(u8, def_file_path, ".def.in"); const target = comp.getTarget(); @@ -258,14 +263,16 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { comp.mutex.lockUncancelable(io); defer comp.mutex.unlock(io); try comp.crt_files.ensureUnusedCapacity(gpa, 1); + + const crt_file_path: Cache.Path = .{ + .root_dir = comp.dirs.global_cache, + .sub_path = sub_path, + }; comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{ - .full_object_path = .{ - .root_dir = comp.dirs.global_cache, - .sub_path = sub_path, - }, + .full_object_path = crt_file_path, .lock = man.toOwnedLock(), }); - return; + return crt_file_path; } const digest = man.final(); @@ -273,22 +280,6 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { var o_dir = try comp.dirs.global_cache.handle.createDirPathOpen(io, o_sub_path, .{}); defer o_dir.close(io); - const aro = @import("aro"); - var diagnostics: aro.Diagnostics = .{ - .output = .{ .to_list = .{ .arena = .init(gpa) } }, - }; - defer diagnostics.deinit(); - var aro_comp = try aro.Compilation.init(.{ - .gpa = gpa, - .arena = arena, - .io = io, - .diagnostics = &diagnostics, - .environ_map = null, - }); - defer aro_comp.deinit(); - - aro_comp.target = .fromZigTarget(target.*); - const include_dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "def-include" }); if (comp.verbose_cc) { @@ -304,39 +295,30 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { }; } - try aro_comp.search_path.append(gpa, .{ .path = include_dir, .kind = .normal }); - - const builtin_macros = try aro_comp.generateBuiltinMacros(.include_system_defines); - const def_file_source = try aro_comp.addSourceFromPath(def_file_path); - - var pp = try aro.Preprocessor.init(&aro_comp, .{ .base_file = .unused }); - defer pp.deinit(); - pp.linemarkers = .none; - pp.preserve_whitespace = true; - - try pp.preprocessSources(.{ .main = def_file_source, .builtin = builtin_macros }); - - if (aro_comp.diagnostics.output.to_list.messages.items.len != 0) { - var buffer: [64]u8 = undefined; - const stderr = try io.lockStderr(&buffer, null); - defer io.unlockStderr(); - for (aro_comp.diagnostics.output.to_list.messages.items) |msg| { - if (msg.kind == .@"fatal error" or msg.kind == .@"error") { - msg.write(stderr.terminal(), true) catch |err| switch (err) { - error.WriteFailed => return stderr.file_writer.err.?, - error.Canceled, error.Unexpected => |e| return e, - }; - return error.AroPreprocessorFailed; - } - } - } - const members = members: { - var aw: Io.Writer.Allocating = .init(gpa); - errdefer aw.deinit(); - try pp.prettyPrintTokens(&aw.writer, .result_only); + const members_node = sub_node.start("Members", 0); + defer members_node.end(); - const input = try aw.toOwnedSliceSentinel(0); + const input = switch (def_needs_preprocessing) { + true => pp: { + var aw: Io.Writer.Allocating = .init(gpa); + errdefer aw.deinit(); + + var pp_arena = std.heap.ArenaAllocator.init(gpa); + defer pp_arena.deinit(); + var pp: Preprocessor = .{ + .io = io, + .arena = pp_arena.allocator(), + .include_dir = include_dir, + .target = target, + }; + try pp.preprocess(def_file_path); + try pp.prettyPrintTokens(&aw.writer); + + break :pp try aw.toOwnedSliceSentinel(0); + }, + false => try Io.Dir.cwd().readFileAllocOptions(io, def_file_path, gpa, .unlimited, .of(u8), 0), + }; defer gpa.free(input); const machine_type = target.toCoffMachine(); @@ -380,13 +362,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void { comp.mutex.lockUncancelable(io); defer comp.mutex.unlock(io); + const crt_file_path: Cache.Path = .{ + .root_dir = comp.dirs.global_cache, + .sub_path = lib_final_path, + }; try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{ - .full_object_path = .{ - .root_dir = comp.dirs.global_cache, - .sub_path = lib_final_path, - }, + .full_object_path = crt_file_path, .lock = man.toOwnedLock(), }); + return crt_file_path; } pub fn libExists( @@ -853,7 +837,6 @@ const mingw32_x86_src = [_][]const u8{ "math" ++ path.sep_str ++ "fmal.c", "math" ++ path.sep_str ++ "llrintl.c", "math" ++ path.sep_str ++ "llroundl.c", - "math" ++ path.sep_str ++ "lroundl.c", "math" ++ path.sep_str ++ "tgammal.c", "math" ++ path.sep_str ++ "x86" ++ path.sep_str ++ "_chgsignl.S", "math" ++ path.sep_str ++ "x86" ++ path.sep_str ++ "acoshl.c", diff --git a/src/libs/mingw/Preprocessor.zig b/src/libs/mingw/Preprocessor.zig new file mode 100644 index 0000000000000000000000000000000000000000..ee108e9644ce7a25c5fa1bb23d871337085f5464 --- /dev/null +++ b/src/libs/mingw/Preprocessor.zig @@ -0,0 +1,975 @@ +const std = @import("std"); +const Tokenizer = @import("./Tokenizer.zig"); +const Allocator = std.mem.Allocator; +const Token = Tokenizer.Token; +const mem = std.mem; +const assert = std.debug.assert; + +test { + _ = Tokenizer; +} + +const TokenList = std.MultiArrayList(Token); +const RawTokenList = std.ArrayList(Token); + +const ExpandBuf = std.ArrayList(Token); + +const Preprocessor = @This(); +const DefineMap = std.StringArrayHashMapUnmanaged(Macro); + +const GeneratedTokens = std.ArrayList(u8); + +const MacroArgument = []const Token; + +pub const Source = struct { + pub const generated: Source.Id = std.math.maxInt(usize); + pub const Id = usize; + id: Id = generated, + path: []const u8, + buf: []const u8, +}; + +sources: std.StringArrayHashMapUnmanaged(Source) = .empty, + +arena: Allocator, +io: std.Io, +include_dir: []const u8, + +top_expansion_buf: ExpandBuf = .empty, +add_expansion_nl: usize = 0, +token_buf: RawTokenList = .empty, +generated_tokens: GeneratedTokens = .empty, +generated_line: u32 = 1, +defines: DefineMap = .empty, +tokens: TokenList = .empty, +target: *const std.Target, + +const Macro = struct { + param: []const u8, + tokens: []const Token, + is_func: bool, +}; + +const IfContext = struct { + const Backing = u2; + const Nesting = enum(Backing) { + until_else, + until_endif, + until_endif_seen_else, + }; + + const buf_size_bits = @bitSizeOf(Backing) * 256; + kind: [buf_size_bits / std.mem.byte_size_in_bits]u8, + level: u8, + + fn get(self: *const IfContext) Nesting { + return @enumFromInt(std.mem.readPackedInt(Backing, &self.kind, @as(usize, self.level) * 2, .native)); + } + + fn set(self: *IfContext, context: Nesting) void { + std.mem.writePackedInt(Backing, &self.kind, @as(usize, self.level) * 2, @intFromEnum(context), .native); + } + + fn increment(self: *IfContext) void { + self.level += 1; + } + + fn decrement(self: *IfContext) void { + self.level -= 1; + } + + const default: IfContext = .{ .kind = @splat(0xFF), .level = 0 }; +}; + +fn addToken(pp: *Preprocessor, tok: Token) !void { + try pp.tokens.append(pp.arena, tok); +} + +fn addTokenAssumeCapacity(pp: *Preprocessor, tok: Token) void { + pp.tokens.appendAssumeCapacity(tok); +} + +fn defineBuiltins(pp: *Preprocessor) !void { + var buf: [5]u8 = undefined; + var val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.longdouble)}) catch unreachable; + try pp.defineBuiltinValue("__SIZEOF_LONG_DOUBLE__", val, .pp_num); + val = std.fmt.bufPrint(&buf, "{d}", .{pp.target.cTypeBitSize(.double)}) catch unreachable; + try pp.defineBuiltinValue("__SIZEOF_DOUBLE__", val, .pp_num); + + if (pp.target.abi.isGnu()) { + try pp.defineBuiltinValue("__cdecl", "__attribute__((__cdecl__))", .identifier); + } + + const arch = switch (pp.target.cpu.arch) { + .aarch64 => "__aarch64__", + .x86 => "__i386__", + .x86_64 => "__x86_64__", + .arm, .thumb => "__arm__", + else => return error.ArchitectureNotSupported, + }; + try pp.defineBuiltin(arch); +} + +fn defineBuiltinValue(pp: *Preprocessor, name: []const u8, value: []const u8, id: Token.Id) !void { + const start = pp.generated_tokens.items.len; + try pp.generated_tokens.appendSlice(pp.arena, value); + const end = pp.generated_tokens.items.len; + + const token_list = try pp.arena.alloc(Token, 1); + token_list[0] = .{ .source = Source.generated, .id = id, .start = @intCast(start), .end = @intCast(end) }; + try pp.defines.putNoClobber(pp.arena, name, .{ + .is_func = false, + .param = "", + .tokens = token_list, + }); +} + +fn defineBuiltin(pp: *Preprocessor, name: []const u8) !void { + return pp.defines.putNoClobber(pp.arena, name, .{ + .tokens = &.{}, + .param = "", + .is_func = false, + }); +} + +pub fn preprocess(pp: *Preprocessor, file_path: []const u8) !void { + const source = try pp.addSourceFromPath(file_path); + try pp.preprocessFile(source); +} + +fn preprocessFile(pp: *Preprocessor, src: Source) !void { + try pp.defineBuiltins(); + const eof = try pp.preprocessFileExtra(src); + try pp.addToken(eof); +} + +fn preprocessFileExtra(pp: *Preprocessor, src: Source) !Token { + var tokenizer: Tokenizer = .init(src.buf, src.id); + var if_context: IfContext = .default; + + while (true) { + var tok = tokenizer.next(); + switch (tok.id) { + .hash => { + const directive = tokenizer.nextNoWS(); + switch (directive.id) { + .keyword_define => try pp.define(&tokenizer), + .keyword_if => { + if_context.increment(); + if (try pp.expr(&tokenizer)) { + if_context.set(.until_endif); + } else { + if_context.set(.until_else); + try pp.skip(&tokenizer, .until_else); + } + }, + .keyword_ifdef => { + if_context.increment(); + const macro_name = pp.expectMacroName(&tokenizer); + skipToNl(&tokenizer); + if (pp.defines.get(macro_name) != null) { + if_context.set(.until_endif); + } else { + if_context.set(.until_else); + try pp.skip(&tokenizer, .until_else); + } + }, + .keyword_ifndef => { + if_context.increment(); + const macro_name = pp.expectMacroName(&tokenizer); + skipToNl(&tokenizer); + if (pp.defines.get(macro_name) == null) { + if_context.set(.until_endif); + } else { + if_context.set(.until_else); + try pp.skip(&tokenizer, .until_else); + } + }, + .keyword_elif => { + assert(if_context.level > 0); + switch (if_context.get()) { + .until_else => if (try pp.expr(&tokenizer)) { + if_context.set(.until_endif); + } else { + try pp.skip(&tokenizer, .until_else); + }, + .until_endif => try pp.skip(&tokenizer, .until_endif), + .until_endif_seen_else => unreachable, //elif after endif + } + }, + .keyword_else => { + skipToNl(&tokenizer); + assert(if_context.level > 0); + switch (if_context.get()) { + .until_else => if_context.set(.until_endif_seen_else), + .until_endif => try pp.skip(&tokenizer, .until_endif), + .until_endif_seen_else => unreachable, // else after else + } + }, + .keyword_endif => { + skipToNl(&tokenizer); + assert(if_context.level > 0); + if_context.decrement(); + }, + .keyword_undef => { + const macro_name = tokenizer.nextNoWS(); + assert(macro_name.id == .identifier); + pp.undefineMacro(macro_name); + skipToNl(&tokenizer); + }, + .keyword_include => { + try pp.include(&tokenizer); + continue; + }, + .keyword_defined, .keyword_error => {}, + else => unreachable, + } + tok.id = .nl; + try pp.addToken(tok); + }, + .whitespace, .nl => try pp.addToken(tok), + .eof => { + assert(if_context.level == 0); + return tok; + }, + else => try pp.expandMacro(&tokenizer, tok), + } + } +} + +fn include(pp: *Preprocessor, tokenizer: *Tokenizer) anyerror!void { + const first = tokenizer.nextNoWS(); + const src = try findIncludeSource(pp, tokenizer, first); + + _ = try pp.preprocessFileExtra(src); + if (pp.tokens.items(.id)[pp.tokens.len - 1] != .nl) { + try pp.addToken(.{ .id = .nl, .source = Source.generated }); + } +} + +fn findIncludeSource( + pp: *Preprocessor, + tokenizer: *Tokenizer, + first: Token, +) !Source { + const filename_tok = first; + skipToNl(tokenizer); + const tok_slice = pp.expandToken(filename_tok); + assert(tok_slice.len >= 3); + const filename = tok_slice[1 .. tok_slice.len - 1]; + return (try pp.findInclude(filename, first)) orelse @panic("include not found"); +} + +fn expectMacroName(pp: *const Preprocessor, tokenizer: *Tokenizer) []const u8 { + const macro_name = tokenizer.nextNoWS(); + assert(macro_name.id.isMacroIdentifier()); + return pp.expandToken(macro_name); +} + +fn skipToNl(tokenizer: *Tokenizer) void { + while (true) { + const tok = tokenizer.next(); + if (tok.id == .nl or tok.id == .eof) return; + if (tok.id == .whitespace) continue; + } +} + +fn define(pp: *Preprocessor, tokenizer: *Tokenizer) !void { + const macro_name = tokenizer.nextNoWS(); + assert(macro_name.id == .identifier); + + const first = tokenizer.nextNoWS(); + switch (first.id) { + .nl, .eof => return pp.defineMacro(macro_name, .{ + .is_func = false, + .tokens = &.{}, + .param = "", + }), + .l_paren => return pp.defineFn(tokenizer, macro_name), + else => {}, + } +} + +fn defineMacro(pp: *Preprocessor, tok: Token, macro: Macro) !void { + const token_value = pp.expandToken(tok); + try pp.defines.putNoClobber(pp.arena, token_value, macro); +} + +fn undefineMacro(pp: *Preprocessor, tok: Token) void { + const token_value = pp.expandToken(tok); + _ = pp.defines.orderedRemove(token_value); +} + +fn defineFn( + pp: *Preprocessor, + tokenizer: *Tokenizer, + macro_name: Token, +) !void { + var tok = tokenizer.nextNoWS(); + assert(tok.id == .identifier); + const param = pp.expandToken(tok); + tok = tokenizer.nextNoWS(); + assert(tok.id == .r_paren); + + pp.token_buf.items.len = 0; + var need_ws = false; + while (true) { + tok = tokenizer.next(); + switch (tok.id) { + .nl, .eof => break, + .whitespace => need_ws = pp.token_buf.items.len != 0, + .hash => unreachable, + .hash_hash => { + need_ws = false; + try pp.token_buf.append(pp.arena, tok); + }, + else => { + if (need_ws) { + need_ws = false; + try pp.token_buf.append(pp.arena, .{ .id = .whitespace, .source = Source.generated }); + } + + if (tok.id.isMacroIdentifier()) { + tok.id = .identifier; + const s = pp.expandToken(tok); + if (mem.eql(u8, param, s)) { + tok.id = .macro_param; + tok.end = 0; + } + } + try pp.token_buf.append(pp.arena, tok); + }, + } + } + + const token_list = try pp.arena.dupe(Token, pp.token_buf.items); + try pp.defineMacro(macro_name, .{ + .tokens = token_list, + .is_func = true, + .param = param, + }); +} + +fn expandToken(pp: *const Preprocessor, tok: Token) []const u8 { + return switch (tok.source) { + Source.generated => pp.generated_tokens.items, + else => blk: { + const src = pp.sources.values()[tok.source]; + break :blk src.buf; + }, + }[@intCast(tok.start)..@intCast(tok.end)]; +} + +fn skip( + pp: *Preprocessor, + tokenizer: *Tokenizer, + cont: IfContext.Nesting, +) !void { + var ifs_seen: u32 = 0; + var line_start = true; + while (tokenizer.index < tokenizer.buf.len) { + if (line_start) { + const tokenizer_bkp = tokenizer.*; + const hash = tokenizer.nextNoWS(); + if (hash.id == .nl) continue; + line_start = false; + if (hash.id != .hash) continue; + const directive = tokenizer.nextNoWS(); + switch (directive.id) { + .keyword_else => { + if (ifs_seen != 0) continue; + assert(cont != .until_endif_seen_else); // else after else; + tokenizer.* = tokenizer_bkp; + return; + }, + .keyword_elif => { + if (ifs_seen != 0 or cont == .until_endif) continue; + assert(cont != .until_endif_seen_else); // elif after else; + tokenizer.* = tokenizer_bkp; + return; + }, + .keyword_endif => { + if (ifs_seen == 0) { + tokenizer.* = tokenizer_bkp; + return; + } + ifs_seen -= 1; + }, + .keyword_if, .keyword_ifdef, .keyword_ifndef => ifs_seen += 1, + else => {}, + } + } else if (tokenizer.buf[tokenizer.index] == '\n') { + line_start = true; + tokenizer.index += 1; + try pp.addToken(.{ .id = .nl, .source = Source.generated }); + } else { + line_start = false; + tokenizer.index += 1; + } + } +} + +fn ensureUnusedTokenCapacity(pp: *Preprocessor, capacity: usize) !void { + try pp.tokens.ensureUnusedCapacity(pp.arena, capacity); +} + +fn expr(pp: *Preprocessor, tokenizer: *Tokenizer) !bool { + const token_state = pp.tokens.len; + defer pp.tokens.len = token_state; + + pp.top_expansion_buf.items.len = 0; + while (true) { + const tok = tokenizer.next(); + switch (tok.id) { + .nl, .eof => break, + .whitespace => if (pp.top_expansion_buf.items.len == 0) continue, + else => {}, + } + try pp.top_expansion_buf.append(pp.arena, tok); + } else unreachable; + if (pp.top_expansion_buf.items.len != 0) { + try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, pp.top_expansion_buf.items.len, false, .expr); + } + try pp.ensureUnusedTokenCapacity(pp.top_expansion_buf.items.len); + var i: usize = 0; + const items = pp.top_expansion_buf.items; + while (i < items.len) : (i += 1) { + var tok = items[i]; + switch (tok.id) { + .string_literal, + .semicolon, + .hash_hash, + => unreachable, + .whitespace => continue, + else => if (tok.id == .keyword_defined) { + i += try pp.handleKeywordDefined(&tok, items[i + 1 ..]); + }, + } + pp.addTokenAssumeCapacity(tok); + } + + try pp.addToken(.{ .id = .eof, .source = Source.generated }); + return pp.evalExpression(token_state); +} + +fn handleKeywordDefined( + pp: *Preprocessor, + macro_tok: *Token, + tokens: []const Token, +) !usize { + assert(macro_tok.id == .keyword_defined); + var it = TokenIterator.init(tokens); + + _ = it.expectNoWS(.l_paren); + const second = it.expectNoWS(.identifier); + _ = it.expectNoWS(.r_paren); + + macro_tok.id = if (pp.defines.contains(pp.expandToken(second))) .one else .zero; + + return it.i; +} + +const TokenIterator = struct { + toks: []const Token, + i: usize, + + fn init(toks: []const Token) TokenIterator { + return .{ .toks = toks, .i = 0 }; + } + + fn nextNoWS(self: *TokenIterator) ?Token { + while (self.i < self.toks.len) : (self.i += 1) { + const tok = self.toks[self.i]; + if (tok.id == .whitespace) continue; + + self.i += 1; + return tok; + } + return null; + } + + fn expectNext(self: *TokenIterator) Token { + assert(self.i < self.toks.len); + const t = self.toks[self.i]; + self.i += 1; + return t; + } + + fn expectNoWS(self: *TokenIterator, expected: Token.Id) Token { + if (self.nextNoWS()) |tok| { + if (tok.id != expected) { + std.debug.panic("expected token {any} but got {any}\n", .{ expected, tok.id }); + } + return tok; + } + std.debug.panic("expected token {any} but got null\n", .{expected}); + } +}; + +fn expandMacro(pp: *Preprocessor, tokenizer: *Tokenizer, tok: Token) !void { + if (!tok.id.isMacroIdentifier()) { + return pp.addToken(tok); + } + pp.top_expansion_buf.items.len = 0; + try pp.top_expansion_buf.append(pp.arena, tok); + try pp.expandMacroExhaustive(tokenizer, &pp.top_expansion_buf, 0, 1, true, .non_expr); + try pp.addTokensFromExpandBuf(pp.top_expansion_buf.items, .{ .id = .nl, .source = Source.generated }); +} + +fn addTokensFromExpandBuf(pp: *Preprocessor, tokens: []Token, tokenizer_nl: Token) !void { + try pp.ensureUnusedTokenCapacity(tokens.len); + for (tokens) |tok| { + pp.addTokenAssumeCapacity(tok); + } + try pp.ensureUnusedTokenCapacity(pp.add_expansion_nl); + while (pp.add_expansion_nl > 0) : (pp.add_expansion_nl -= 1) { + pp.addTokenAssumeCapacity(tokenizer_nl); + } +} + +const EvalContext = enum { + expr, + non_expr, +}; + +fn expandMacroExhaustive( + pp: *Preprocessor, + tokenizer: *Tokenizer, + buf: *ExpandBuf, + start_idx: usize, + end_idx: usize, + extend_buf: bool, + eval_ctx: EvalContext, +) !void { + var moving_end_idx = end_idx; + var advance_index: usize = 0; + var do_rescan = true; + while (do_rescan) { + do_rescan = false; + var idx: usize = start_idx + advance_index; + while (idx < moving_end_idx) { + const macro_tok = buf.items[idx]; + if (macro_tok.id == .keyword_defined and eval_ctx == .expr) { + idx += 1; + var it = TokenIterator.init(buf.items[idx..moving_end_idx]); + if (it.nextNoWS()) |tok| { + switch (tok.id) { + .l_paren => { + _ = it.nextNoWS(); + _ = it.nextNoWS(); + }, + else => {}, + } + } + idx += it.i; + continue; + } + if (!macro_tok.id.isMacroIdentifier()) { + idx += 1; + continue; + } + const expanded = pp.expandToken(macro_tok); + const macro = pp.defines.getPtr(expanded) orelse { + idx += 1; + continue; + }; + + if (macro.is_func) { + var macro_scan_idx = idx; + const arg = try pp.collectMacroArgument( + tokenizer, + buf, + ¯o_scan_idx, + &moving_end_idx, + extend_buf, + ); + const expanded_arg = arg: { + var expand_buf: ExpandBuf = .empty; + errdefer expand_buf.deinit(pp.arena); + try expand_buf.appendSlice(pp.arena, arg); + try pp.expandMacroExhaustive(tokenizer, &expand_buf, 0, expand_buf.items.len, false, eval_ctx); + break :arg try expand_buf.toOwnedSlice(pp.arena); + }; + + const res = try pp.expandFuncMacro(macro, arg, expanded_arg); + const tokens_added = res.items.len; + const tokens_removed = macro_scan_idx - idx + 1; + try buf.replaceRange(pp.arena, idx, tokens_removed, res.items); + + moving_end_idx += tokens_added; + moving_end_idx -|= tokens_removed; + idx += tokens_added; + do_rescan = true; + } else { + var res = try pp.expandObjMacro(macro); + defer res.deinit(pp.arena); + var increment_idx_by = res.items.len; + + for (res.items, 0..) |*tok, i| { + if (i < increment_idx_by and pp.defines.contains(pp.expandToken(tok.*))) { + increment_idx_by = i; + } + } + try buf.replaceRange(pp.arena, idx, 1, res.items); + idx += res.items.len; + moving_end_idx = moving_end_idx + res.items.len - 1; + do_rescan = true; + } + if (idx - start_idx == advance_index + 1 and !do_rescan) { + advance_index += 1; + } + } + } + buf.items.len = moving_end_idx; +} + +fn collectMacroArgument( + pp: *Preprocessor, + tokenizer: *Tokenizer, + buf: *ExpandBuf, + start_idx: *usize, + end_idx: *usize, + extend_buf: bool, +) !MacroArgument { + var parens: u32 = 0; + var argument: std.ArrayList(Token) = .empty; + defer argument.deinit(pp.arena); + + while (true) { + const tok = try nextBufToken(pp, tokenizer, buf, start_idx, end_idx, extend_buf); + switch (tok.id) { + .nl, .whitespace => {}, + .l_paren => break, + else => unreachable, + } + } + + while (true) { + const tok = try nextBufToken(pp, tokenizer, buf, start_idx, end_idx, extend_buf); + switch (tok.id) { + .l_paren => { + try argument.append(pp.arena, tok); + parens += 1; + }, + .r_paren => { + if (parens == 0) { + return try argument.toOwnedSlice(pp.arena); + } else { + try argument.append(pp.arena, tok); + parens -= 1; + } + }, + .nl, .whitespace => try argument.append(pp.arena, .{ .id = .whitespace, .source = Source.generated }), + .eof => unreachable, + else => try argument.append(pp.arena, tok), + } + } +} + +fn expandObjMacro(pp: *Preprocessor, simple_macro: *const Macro) !ExpandBuf { + var buf: ExpandBuf = .empty; + errdefer buf.deinit(pp.arena); + try buf.appendSlice(pp.arena, simple_macro.tokens); + return buf; +} + +fn expandFuncMacro( + pp: *Preprocessor, + func_macro: *const Macro, + arg: MacroArgument, + expanded_arg: MacroArgument, +) !ExpandBuf { + var buf: ExpandBuf = .empty; + errdefer buf.deinit(pp.arena); + try buf.ensureTotalCapacity(pp.arena, func_macro.tokens.len); + + var tok_i: usize = 0; + while (tok_i < func_macro.tokens.len) : (tok_i += 1) { + const tok = func_macro.tokens[tok_i]; + switch (tok.id) { + .hash_hash => while (tok_i + 1 < func_macro.tokens.len) { + tok_i += 1; + const tok_next = func_macro.tokens[tok_i]; + const next = switch (tok_next.id) { + .whitespace => continue, + .hash_hash => continue, + .macro_param => arg, + else => &[1]Token{tok_next}, + }; + try pp.pasteTokens(&buf, next); + if (next.len != 0) break; + }, + .macro_param => { + try buf.appendSlice(pp.arena, expanded_arg); + }, + else => try buf.append(pp.arena, tok), + } + } + + return buf; +} + +fn pasteTokens( + pp: *Preprocessor, + lhs_toks: *ExpandBuf, + rhs_toks: []const Token, +) !void { + const lhs = while (lhs_toks.pop()) |lhs| { + if (lhs.id != .whitespace) break lhs; + } else { + return lhs_toks.appendSlice(pp.arena, rhs_toks); + }; + + var rhs_rest: u32 = 1; + const rhs = for (rhs_toks) |rhs| { + if (rhs.id != .whitespace) break rhs; + rhs_rest += 1; + } else { + return lhs_toks.appendAssumeCapacity(lhs); + }; + + const start = pp.generated_tokens.items.len; + const end = start + pp.expandToken(lhs).len + pp.expandToken(rhs).len; + try pp.generated_tokens.ensureTotalCapacity(pp.arena, end + 1); + pp.generated_tokens.appendSliceAssumeCapacity(pp.expandToken(lhs)); + pp.generated_tokens.appendSliceAssumeCapacity(pp.expandToken(rhs)); + pp.generated_tokens.appendAssumeCapacity('\n'); + + var tmp_tokenizer: Tokenizer = .{ + .index = @intCast(start), + .buf = pp.generated_tokens.items, + .source = Source.generated, + }; + const pasted_token = tmp_tokenizer.nextNoWS(); + const next = tmp_tokenizer.nextNoWS(); + + try lhs_toks.append(pp.arena, pp.makeGeneratedToken(start, end, pasted_token.id)); + assert(next.id == .nl or next.id == .eof); + + return lhs_toks.appendSlice(pp.arena, rhs_toks[rhs_rest..]); +} + +fn nextBufToken( + pp: *Preprocessor, + tokenizer: *Tokenizer, + buf: *ExpandBuf, + start_idx: *usize, + end_idx: *usize, + extend_buf: bool, +) !Token { + start_idx.* += 1; + if (start_idx.* == buf.items.len and start_idx.* >= end_idx.*) { + if (extend_buf) { + const tok = tokenizer.next(); + if (tok.id == .nl) pp.add_expansion_nl += 1; + + end_idx.* += 1; + try buf.append(pp.arena, tok); + return tok; + } + return .{ .id = .eof, .source = Source.generated }; + } + + return buf.items[start_idx.*]; +} + +fn makeGeneratedToken( + pp: *Preprocessor, + start: usize, + end: usize, + id: Token.Id, +) Token { + const pasted_token: Token = .{ + .id = id, + .source = Source.generated, + .start = @intCast(start), + .end = @intCast(end), + }; + pp.generated_line += 1; + return pasted_token; +} + +fn findInclude( + pp: *Preprocessor, + filename: []const u8, + includer_token: Token, +) !?Source { + const other_file = pp.sources.values()[includer_token.source].path; + const dir = std.fs.path.dirname(other_file) orelse "."; + if (try pp.checkIncludeDir(filename, dir)) |res| return res; + + return pp.checkIncludeDir(filename, pp.include_dir); +} + +fn checkIncludeDir( + pp: *Preprocessor, + include_path: []const u8, + include_dir: []const u8, +) !?Source { + const format = "{s}{c}{s}"; + var bfa_buf: [1024]u8 = undefined; + var bfa_state: std.heap.BufferFirstAllocator = .init(&bfa_buf, pp.arena); + const bfa = bfa_state.allocator(); + const header_path = try std.fmt.allocPrint(bfa, format, .{ + include_dir, + std.fs.path.sep, + include_path, + }); + defer bfa.free(header_path); + + return pp.addSourceFromPath(header_path) catch |err| switch (err) { + error.OutOfMemory => |e| return e, + else => return null, + }; +} + +pub fn addSourceFromPath(pp: *Preprocessor, path: []const u8) !Source { + if (pp.sources.get(path)) |src| return src; + try pp.sources.ensureUnusedCapacity(pp.arena, 1); + + const contents = try std.Io.Dir.cwd().readFileAlloc(pp.io, path, pp.arena, .limited(std.math.maxInt(u32))); + const duped_path = try pp.arena.dupe(u8, path); + + const src: Source = .{ + .buf = contents, + .path = duped_path, + .id = pp.sources.count(), + }; + + pp.sources.putAssumeCapacityNoClobber(duped_path, src); + return src; +} + +fn evalExpression( + pp: *Preprocessor, + start: usize, +) !bool { + const s = pp.tokens.slice(); + const len = s.len - start; + const ss = s.subslice(start, len); + + const ids: []Token.Id = ss.items(.id); + const starts: []u32 = ss.items(.start); + const ends: []u32 = ss.items(.end); + const srcs: []usize = ss.items(.source); + + var toks = try pp.arena.alloc(Token, len); + defer pp.arena.free(toks); + + for (0..len) |i| { + toks[i] = .{ + .id = ids[i], + .source = srcs[i], + .start = starts[i], + .end = ends[i], + }; + } + + return pp.evaluateExpressionTokens(toks); +} + +fn evaluateExpressionTokens( + pp: *const Preprocessor, + toks: []const Token, +) bool { + var it = TokenIterator.init(toks); + + const left = evalToken(&it); + assert(!left.id.isInfix()); + + const op = evalToken(&it); + if (op.id == .eof) return left.id == .one; + + assert(op.id.isInfix()); + const right = evalToken(&it); + + return pp.evalInfix(left, op, right); +} + +fn evalToken(it: *TokenIterator) Token { + const tok = it.expectNext(); + if (tok.id != .bang) { + return tok; + } + + var op = it.expectNext(); + const flipped: Token.Id = switch (op.id) { + .one => .zero, + .zero => .one, + else => unreachable, + }; + op.id = flipped; + return op; +} + +fn evalInfix( + pp: *const Preprocessor, + left: Token, + op: Token, + right: Token, +) bool { + switch (op.id) { + .pipe_pipe => return (left.id == .one) or (right.id == .one), + .equal_equal => { + switch (left.id) { + .one, .zero => { + assert(right.id == .one or right.id == .zero); + return left.id == right.id; + }, + .pp_num => { + assert(right.id == .pp_num); + const lval = pp.expandToken(left); + const rval = pp.expandToken(right); + return std.mem.eql(u8, lval, rval); + }, + else => unreachable, + } + }, + else => unreachable, + } +} + +pub fn prettyPrintTokens(pp: *Preprocessor, w: *std.Io.Writer) !void { + const tok_ids = pp.tokens.items(.id); + var i: usize = 0; + var last_nl = true; + outer: while (true) : (i += 1) { + const cur: Token = pp.tokens.get(i); + switch (cur.id) { + .eof => { + if (!last_nl) try w.writeByte('\n'); + try w.flush(); + return; + }, + .nl => { + var newlines: u32 = 0; + for (tok_ids[i..], i..) |id, j| { + if (id == .nl) { + newlines += 1; + } else if (id == .eof) { + if (!last_nl) try w.writeByte('\n'); + try w.flush(); + return; + } else if (id != .whitespace) { + if (newlines < 2) break; + + i = @intCast((j - 1) - @intFromBool(tok_ids[j - 1] == .whitespace)); + if (!last_nl) try w.writeAll("\n"); + continue :outer; + } + } + last_nl = true; + try w.writeAll("\n"); + }, + .whitespace => { + try w.writeByte(' '); + last_nl = false; + }, + else => { + const slice = pp.expandToken(cur); + try w.writeAll(slice); + last_nl = false; + }, + } + } +} diff --git a/src/libs/mingw/Tokenizer.zig b/src/libs/mingw/Tokenizer.zig new file mode 100644 index 0000000000000000000000000000000000000000..07db83108fa9f168f99a56d496e439cc39416dcc --- /dev/null +++ b/src/libs/mingw/Tokenizer.zig @@ -0,0 +1,359 @@ +const std = @import("std"); +const assert = std.debug.assert; +const Source = @import("Preprocessor.zig").Source; + +const Tokenizer = @This(); + +pub fn init(buf: []const u8, source: Source.Id) Tokenizer { + return .{ .buf = buf, .source = source }; +} + +buf: []const u8, +index: u32 = 0, +source: Source.Id, + +pub const Token = struct { + pub const Id = enum { + bang, + eof, + equal_equal, + hash, + hash_hash, + macro_param, + identifier, + keyword_if, + keyword_ifndef, + keyword_ifdef, + keyword_define, + keyword_endif, + keyword_defined, + keyword_include, + keyword_elif, + keyword_else, + keyword_undef, + keyword_error, + l_paren, + nl, + pp_num, + pipe_pipe, + r_paren, + semicolon, + string_literal, + whitespace, + one, + zero, + + pub fn isInfix(id: Id) bool { + switch (id) { + .pipe_pipe, .equal_equal => return true, + else => return false, + } + } + + pub fn isMacroIdentifier(id: Id) bool { + switch (id) { + .keyword_if, + .keyword_ifndef, + .keyword_ifdef, + .keyword_define, + .keyword_endif, + .keyword_defined, + .keyword_include, + .keyword_elif, + .keyword_else, + .keyword_undef, + .keyword_error, + .identifier, + => return true, + else => return false, + } + } + }; + + const all_kws = std.StaticStringMap(Id).initComptime(.{ + .{ "define", .keyword_define }, + .{ "defined", .keyword_defined }, + .{ "else", .keyword_else }, + .{ "endif", .keyword_endif }, + .{ "if", .keyword_if }, + .{ "elif", .keyword_elif }, + .{ "ifdef", .keyword_ifdef }, + .{ "ifndef", .keyword_ifndef }, + .{ "include", .keyword_include }, + .{ "undef", .keyword_undef }, + .{ "error", .keyword_error }, + }); + + id: Id, + source: Source.Id, + start: u32 = 0, + end: u32 = 0, + + fn getTokenId(str: []const u8) Id { + return all_kws.get(str) orelse .identifier; + } +}; + +pub fn next(self: *Tokenizer) Token { + var state: enum { + start, + cr, + string_literal, + identifier, + equal, + slash, + line_comment, + hash, + pipe, + pp_num, + } = .start; + + const start = self.index; + var id: Token.Id = .eof; + + while (self.index < self.buf.len) : (self.index += 1) { + const c = self.buf[self.index]; + switch (state) { + .start => switch (c) { + '\r' => { + id = .nl; + state = .cr; + }, + '\n' => { + id = .nl; + self.index += 1; + break; + }, + '!' => { + id = .bang; + self.index += 1; + break; + }, + '"' => { + id = .string_literal; + state = .string_literal; + }, + '|' => state = .pipe, + '=' => state = .equal, + '(' => { + id = .l_paren; + self.index += 1; + break; + }, + ')' => { + id = .r_paren; + self.index += 1; + break; + }, + ';' => { + id = .semicolon; + self.index += 1; + break; + }, + '/' => state = .slash, + '#' => state = .hash, + '0'...'9' => state = .pp_num, + ' ' => { + id = .whitespace; + self.index += 1; + break; + }, + else => state = .identifier, + }, + .cr => switch (c) { + '\n' => { + self.index += 1; + break; + }, + else => break, + }, + .pipe => switch (c) { + '|' => { + id = .pipe_pipe; + self.index += 1; + break; + }, + else => unreachable, + }, + .hash => switch (c) { + '#' => { + id = .hash_hash; + self.index += 1; + break; + }, + else => { + id = .hash; + break; + }, + }, + .string_literal => switch (c) { + '"' => { + self.index += 1; + break; + }, + else => {}, + }, + .identifier => switch (c) { + 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, + else => { + id = Token.getTokenId(self.buf[start..self.index]); + break; + }, + }, + .equal => switch (c) { + '=' => { + id = .equal_equal; + self.index += 1; + break; + }, + else => unreachable, + }, + .slash => switch (c) { + '/' => state = .line_comment, + else => { + id = .identifier; + break; + }, + }, + .line_comment => switch (c) { + '\n' => { + self.index -= 1; + state = .start; + }, + else => {}, + }, + .pp_num => switch (c) { + '0'...'9' => {}, + else => { + id = .pp_num; + break; + }, + }, + } + } else if (self.index == self.buf.len) { + switch (state) { + .start, .line_comment, .cr => {}, + .identifier => id = Token.getTokenId(self.buf[start..self.index]), + .hash => id = .hash, + .pp_num => id = .pp_num, + else => unreachable, + } + } + + return .{ + .id = id, + .start = start, + .end = self.index, + .source = self.source, + }; +} + +pub fn nextNoWS(self: *Tokenizer) Token { + var tok = self.next(); + while (tok.id == .whitespace) tok = self.next(); + return tok; +} + +fn expectToken(expected: Token.Id, actual: Token) !void { + try std.testing.expectEqual(expected, actual.id); +} + +fn testToken(buf: []const u8, expected: Token.Id) !void { + var tokenizer = Tokenizer.init(buf, Source.generated); + const t = tokenizer.next(); + try expectToken(expected, t); + try expectToken(.eof, tokenizer.next()); +} + +test "tokens" { + try testToken("TEST", .identifier); + try testToken("__x86_64__", .identifier); + try testToken("122", .pp_num); + try testToken("==", .equal_equal); + try testToken("#", .hash); + try testToken("##", .hash_hash); + try testToken("undef", .keyword_undef); + try testToken("||", .pipe_pipe); + try testToken("!", .bang); + try testToken("else", .keyword_else); + try testToken("endif", .keyword_endif); + try testToken("include", .keyword_include); + try testToken("define", .keyword_define); + try testToken("defined", .keyword_defined); + try testToken("if", .keyword_if); + try testToken("ifdef", .keyword_ifdef); + try testToken("ifndef", .keyword_ifndef); + try testToken("(", .l_paren); + try testToken("\n", .nl); + try testToken("\r", .nl); + try testToken("\r\n", .nl); + try testToken("5", .pp_num); + try testToken(")", .r_paren); + try testToken("\"str\"", .string_literal); + try testToken(" ", .whitespace); +} + +fn expectTokens(contents: []const u8, expected_tokens: []const Token.Id) !void { + var tokenizer: Tokenizer = .init(contents, Source.generated); + var i: usize = 0; + while (i < expected_tokens.len) { + const token = tokenizer.next(); + if (token.id == .whitespace) continue; + const expected_token_id = expected_tokens[i]; + i += 1; + if (!std.meta.eql(token.id, expected_token_id)) { + std.debug.print("expected {s}, found {s}\n", .{ @tagName(expected_token_id), @tagName(token.id) }); + return error.TokensDoNotEqual; + } + } + const last_token = tokenizer.next(); + try std.testing.expect(last_token.id == .eof); +} + +test "preprocessor keywords" { + try expectTokens( + \\#if + \\#ifndef + \\#ifdef + \\#define + \\#endif + \\defined + \\#include + \\#elif + \\#else + \\#undef + \\#error + , &.{ + .hash, + .keyword_if, + .nl, + .hash, + .keyword_ifndef, + .nl, + .hash, + .keyword_ifdef, + .nl, + .hash, + .keyword_define, + .nl, + .hash, + .keyword_endif, + .nl, + .keyword_defined, + .nl, + .hash, + .keyword_include, + .nl, + .hash, + .keyword_elif, + .nl, + .hash, + .keyword_else, + .nl, + .hash, + .keyword_undef, + .nl, + .hash, + .keyword_error, + }); +} diff --git a/src/libs/mingw/implib.zig b/src/libs/mingw/implib.zig index 525129fe119046846ca70b798bd38fc0c4cfadd0..f3cf24b3b88cf41323fbe62d4890277ca8ca5f8b 100644 --- a/src/libs/mingw/implib.zig +++ b/src/libs/mingw/implib.zig @@ -245,7 +245,7 @@ pub fn getMembers( }; var renames: std.ArrayList(DeferredExport) = .empty; defer renames.deinit(allocator); - var regular_imports: std.StringArrayHashMapUnmanaged([]const u8) = .empty; + var regular_imports: std.array_hash_map.String([]const u8) = .empty; defer regular_imports.deinit(allocator); for (module_def.exports.items) |*e| { @@ -1012,7 +1012,7 @@ fn getShortImport( fn writeSymbol(writer: *std.Io.Writer, symbol: std.coff.Symbol) !void { try writer.writeAll(&symbol.name); try writer.writeInt(u32, symbol.value, .little); - try writer.writeInt(u16, @intFromEnum(symbol.section_number), .little); + try writer.writeInt(i16, @intFromEnum(symbol.section_number), .little); try writer.writeInt(u8, @intFromEnum(symbol.type.base_type), .little); try writer.writeInt(u8, @intFromEnum(symbol.type.complex_type), .little); try writer.writeInt(u8, @intFromEnum(symbol.storage_class), .little); diff --git a/src/libs/musl.zig b/src/libs/musl.zig index 2f56a417f2984e66d696830c5ecdf9dd40e4816a..fcf179894c6d6f0d542f04fb925788c76f82ca1a 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -784,8 +784,6 @@ const src_files = [_][]const u8{ "musl/src/math/aarch64/llrintf.c", "musl/src/math/aarch64/llround.c", "musl/src/math/aarch64/llroundf.c", - "musl/src/math/aarch64/lround.c", - "musl/src/math/aarch64/lroundf.c", "musl/src/math/aarch64/nearbyint.c", "musl/src/math/aarch64/nearbyintf.c", "musl/src/math/acosh.c", @@ -891,9 +889,6 @@ const src_files = [_][]const u8{ "musl/src/math/logbf.c", "musl/src/math/logbl.c", "musl/src/math/logl.c", - "musl/src/math/lround.c", - "musl/src/math/lroundf.c", - "musl/src/math/lroundl.c", "musl/src/math/__math_divzero.c", "musl/src/math/__math_divzerof.c", "musl/src/math/__math_invalid.c", @@ -919,8 +914,6 @@ const src_files = [_][]const u8{ "musl/src/math/pow_data.c", "musl/src/math/powerpc64/fma.c", "musl/src/math/powerpc64/fmaf.c", - "musl/src/math/powerpc64/lround.c", - "musl/src/math/powerpc64/lroundf.c", "musl/src/math/powerpc/fma.c", "musl/src/math/powerpc/fmaf.c", "musl/src/math/powf.c", diff --git a/src/libs/wasi_libc.zig b/src/libs/wasi_libc.zig index f5025666f61406a430b51ac582d147358803eefe..561966b01707194d277afc0d5afecb241a68f732 100644 --- a/src/libs/wasi_libc.zig +++ b/src/libs/wasi_libc.zig @@ -725,9 +725,6 @@ const libc_top_half_src_files = [_][]const u8{ "musl/src/math/logbf.c", "musl/src/math/logbl.c", "musl/src/math/logl.c", - "musl/src/math/lround.c", - "musl/src/math/lroundf.c", - "musl/src/math/lroundl.c", "musl/src/math/__math_divzero.c", "musl/src/math/__math_divzerof.c", "musl/src/math/__math_invalid.c", diff --git a/src/link.zig b/src/link.zig index 12d12a959bbd626d505f544a9972bc044e6efab4..4764e0c291f4c048812f5f30dc94d1f948c9b442 100644 --- a/src/link.zig +++ b/src/link.zig @@ -25,12 +25,15 @@ const Package = @import("Package.zig"); const dev = @import("dev.zig"); const target_util = @import("target.zig"); const codegen = @import("codegen.zig"); +const crash_report = @import("crash_report.zig"); pub const aarch64 = @import("link/aarch64.zig"); pub const LdScript = @import("link/LdScript.zig"); pub const Queue = @import("link/Queue.zig"); pub const ConstPool = @import("link/ConstPool.zig"); +pub const loongarch = @import("link/loongarch.zig"); + pub const Error = Allocator.Error || Io.Cancelable || error{ /// An error message has already been stored in persistent state on `Compilation` or `Zcu`, for /// instance in `Compilation.link_diags`. @@ -471,7 +474,7 @@ pub const File = struct { /// wrapper for a system function. The wrapper function should be called /// __wrap_symbol. If it wishes to call the system function, it should call /// __real_symbol. - symbol_wrap_set: std.StringArrayHashMapUnmanaged(void), + symbol_wrap_set: std.array_hash_map.String(void), compatibility_version: ?std.SemanticVersion, @@ -481,7 +484,7 @@ pub const File = struct { rpath_list: []const []const u8, /// Zig compiler development linker flags. - /// Enable dumping of linker's state as JSON. + /// Enable dumping of linker's state. enable_link_snapshots: bool, /// Darwin-specific linker flags: @@ -790,6 +793,7 @@ pub const File = struct { assert(base.comp.zcu.?.llvm_object == null); const nav = pt.zcu.intern_pool.getNav(nav_index); assert(nav.resolved.?.value != .none); + switch (base.tag) { .lld => unreachable, .plan9 => unreachable, @@ -841,7 +845,6 @@ pub const File = struct { assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .lld => unreachable, - .spirv => unreachable, // see corresponding special case in `Zcu.PerThread.runCodegenInner` .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); @@ -925,6 +928,9 @@ pub const File = struct { /// Commit pending changes and write headers. Takes into account final output mode. /// `arena` has the lifetime of the call to `Compilation.update`. pub fn flush(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) Error!void { + crash_report.LinkerOp.start(base, tid); + defer crash_report.LinkerOp.stop(base, tid); + const comp = base.comp; const io = comp.io; if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) { @@ -934,8 +940,8 @@ pub const File = struct { // Until then, we do `lld -r -o output.o input.o` even though the output is the same // as the input. For the preprocessing case (`zig cc -E -o foo`) we copy the file // to the final location. See also the corresponding TODO in Coff linking. - assert(comp.c_object_table.count() == 1); - const the_key = comp.c_object_table.keys()[0]; + assert(comp.c_objects.items.len == 1); + const the_key = comp.c_objects.items[0]; const cached_pp_file_path = the_key.status.success.object_path; Io.Dir.copyFile( cached_pp_file_path.root_dir.handle, @@ -976,6 +982,10 @@ pub const File = struct { export_indices: []const Zcu.Export.Index, ) Error!void { assert(base.comp.zcu.?.llvm_object == null); + + crash_report.LinkerOp.start(base, pt.tid); + defer crash_report.LinkerOp.stop(base, pt.tid); + switch (base.tag) { .lld => unreachable, .plan9 => unreachable, @@ -1007,6 +1017,7 @@ pub const File = struct { /// Never called when LLVM is codegenning the ZCU. pub fn getNavVAddr(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: RelocInfo) Error!u64 { assert(base.comp.zcu.?.llvm_object == null); + switch (base.tag) { .lld => unreachable, .c => unreachable, @@ -1028,6 +1039,7 @@ pub const File = struct { decl_align: InternPool.Alignment, ) Error!SymbolId { assert(base.comp.zcu.?.llvm_object == null); + switch (base.tag) { .lld => unreachable, .c => unreachable, @@ -1044,6 +1056,7 @@ pub const File = struct { /// Never called when LLVM is codegenning the ZCU. pub fn getUavVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) Error!u64 { assert(base.comp.zcu.?.llvm_object == null); + switch (base.tag) { .lld => unreachable, .c => unreachable, @@ -1064,6 +1077,7 @@ pub const File = struct { name: InternPool.NullTerminatedString, ) void { assert(base.comp.zcu.?.llvm_object == null); + switch (base.tag) { .lld => unreachable, .plan9 => unreachable, @@ -1078,6 +1092,31 @@ pub const File = struct { } } + pub const DumpResult = enum { + unimplemented, + needs_extensions, + disabled, + enabled, + }; + + pub fn dump(base: *File, w: *Io.Writer, tid: Zcu.PerThread.Id) !DumpResult { + if (!build_options.enable_debug_extensions) return .not_built; + switch (base.tag) { + .elf, + .macho, + .c, + .wasm, + .spirv, + .plan9, + .lld, + => return .unimplemented, + inline else => |tag| { + dev.check(tag.devFeature()); + return @as(*tag.Type(), @fieldParentPtr("base", base)).dump(w, tid); + }, + } + } + /// Opens a path as an object file and parses it into the linker. fn openLoadObject(base: *File, path: Path) anyerror!void { if (base.tag == .lld) return; @@ -1179,8 +1218,9 @@ pub const File = struct { pub fn loadInput(base: *File, input: Input) anyerror!void { if (base.tag == .lld) return; assert(!base.post_prelink); + switch (base.tag) { - inline .elf, .elf2, .wasm => |tag| { + inline .coff2, .elf, .elf2, .wasm, .spirv => |tag| { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input); }, @@ -1442,7 +1482,8 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { const target = &comp.root_mod.resolved_target.result; const flags = target_util.libcFullLinkFlags(target); - const crt_dir = comp.libc_installation.?.crt_dir.?; + const libc_installation = comp.libc_installation.?; + const crt_dir = libc_installation.crt_dir.?; const sep = std.fs.path.sep_str; for (flags) |flag| { assert(mem.startsWith(u8, flag, "-l")); @@ -1494,6 +1535,54 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { }, } } + + if (target.os.tag == .windows and target.abi == .msvc) { + const inputs: []const struct { + dir: enum { crt, msvc_lib, kernel32_lib }, + name: []const u8, + } = switch (comp.config.link_mode) { + .dynamic => &.{ + .{ .dir = .msvc_lib, .name = "msvcrt.lib" }, + .{ .dir = .msvc_lib, .name = "vcruntime.lib" }, + .{ .dir = .msvc_lib, .name = "legacy_stdio_definitions.lib" }, + .{ .dir = .crt, .name = "ucrt.lib" }, + .{ .dir = .kernel32_lib, .name = "kernel32.lib" }, + .{ .dir = .kernel32_lib, .name = "ntdll.lib" }, + }, + .static => &.{ + .{ .dir = .msvc_lib, .name = "libcmt.lib" }, + .{ .dir = .msvc_lib, .name = "libvcruntime.lib" }, + .{ .dir = .msvc_lib, .name = "legacy_stdio_definitions.lib" }, + .{ .dir = .crt, .name = "libucrt.lib" }, + .{ .dir = .kernel32_lib, .name = "kernel32.lib" }, + .{ .dir = .kernel32_lib, .name = "ntdll.lib" }, + }, + }; + + for (inputs) |lib| { + const path = Path.initCwd( + std.fmt.allocPrint(comp.arena, "{s}" ++ sep ++ "{s}", .{ + switch (lib.dir) { + .crt => crt_dir, + .msvc_lib => libc_installation.msvc_lib_dir.?, + .kernel32_lib => libc_installation.kernel32_lib_dir.?, + }, + lib.name, + }) catch return diags.setAllocFailure(), + ); + if (std.mem.endsWith(u8, lib.name, "lib")) { + base.openLoadArchive(path, false) catch |err| switch (err) { + error.LinkFailure => return, // error reported via diags + else => |e| diags.addParseError(path, "failed to parse archive: {s}", .{@errorName(e)}), + }; + } else { + base.openLoadObject(path) catch |err| switch (err) { + error.LinkFailure => return, // error reported via diags + else => |e| diags.addParseError(path, "failed to parse object: {s}", .{@errorName(e)}), + }; + } + } + } }, .load_object => |path| { const prog_node = comp.link_prog_node.start("Parse Object", 0); @@ -1529,8 +1618,9 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void const diags = &comp.link_diags; const zcu = comp.zcu.?; const ip = &zcu.intern_pool; - const pt: Zcu.PerThread = .activate(zcu, tid); - defer pt.deactivate(); + const active = zcu.activate(tid); + defer active.deactivate(); + const pt = active.pt; var timer = comp.startTimer(); diff --git a/src/link/C.zig b/src/link/C.zig index 23225d7b7a86ea3fdba3c5dbed401f14e3b72599..127485171314adc352096f6e13b448b28d12e173 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -44,10 +44,10 @@ type_dependencies: std.ArrayList(link.ConstPool.Index), align_dependency_masks: std.ArrayList(u64), /// All NAVs, regardless of whether they are functions or simple constants, are put in this map. -navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, RenderedDecl), +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 /// rendered C code stored here, because we don't know the alignment a UAV needs until `flush`. -uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, RenderedDecl), +uavs: std.array_hash_map.Auto(InternPool.Index, RenderedDecl), /// Contains all types which are needed by some other rendered code. Does not contain any constants /// other than types. type_pool: link.ConstPool, @@ -59,10 +59,10 @@ types: std.ArrayList(RenderedType), /// The set of big int types required by *any* generated code so far. These are always safe to emit, /// so they do not participate in the dependency graph traversal in `flush`. Therefore, redundant /// big-int types may be emitted under incremental compilation. -bigint_types: std.AutoArrayHashMapUnmanaged(codegen.CType.BigInt, void), +bigint_types: std.array_hash_map.Auto(codegen.CType.BigInt, void), -exported_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, String), -exported_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, String), +exported_navs: std.array_hash_map.Auto(InternPool.Nav.Index, String), +exported_uavs: std.array_hash_map.Auto(InternPool.Index, String), /// A reference into `string_bytes`. const String = extern struct { @@ -133,10 +133,10 @@ const RenderedDecl = struct { fwd_decl: String, code: String, ctype_deps: CTypeDependencies, - need_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), - need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), - need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), - need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void), + need_uavs: std.array_hash_map.Auto(InternPool.Index, Alignment), + need_tag_name_funcs: std.array_hash_map.Auto(InternPool.Index, void), + need_never_tail_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void), + need_never_inline_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void), const init: RenderedDecl = .{ .fwd_decl = .empty, @@ -728,8 +728,9 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog const zcu = c.base.comp.zcu.?; const ip = &zcu.intern_pool; const target = zcu.getTarget(); - const pt: Zcu.PerThread = .activate(zcu, tid); - defer pt.deactivate(); + const active = zcu.activate(tid); + defer active.deactivate(); + const pt = active.pt; // If it's somehow not made it into the pool, we need to generate the type `[:0]const u8` for // error names. @@ -745,7 +746,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog // incremental updates which is invalid C (due to e.g. types changing). Machine code backends // don't have this problem because there are, of course, no type checking performed when you // *execute* a binary! - var need_navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty; + var need_navs: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty; defer need_navs.deinit(gpa); { const unit_references = try zcu.resolveReferences(); @@ -773,23 +774,23 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog // // At the same time, we will discover the set of lazy functions which are referenced. - var need_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .empty; + var need_uavs: std.array_hash_map.Auto(InternPool.Index, Alignment) = .empty; defer need_uavs.deinit(gpa); - var need_types: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void) = .empty; + var need_types: std.array_hash_map.Auto(link.ConstPool.Index, void) = .empty; defer need_types.deinit(gpa); - var need_errunion_types: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void) = .empty; + var need_errunion_types: std.array_hash_map.Auto(link.ConstPool.Index, void) = .empty; defer need_errunion_types.deinit(gpa); - var need_aligned_types: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, u64) = .empty; + var need_aligned_types: std.array_hash_map.Auto(link.ConstPool.Index, u64) = .empty; defer need_aligned_types.deinit(gpa); - var need_tag_name_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty; + var need_tag_name_funcs: std.array_hash_map.Auto(InternPool.Index, void) = .empty; defer need_tag_name_funcs.deinit(gpa); - var need_never_tail_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty; + var need_never_tail_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty; defer need_never_tail_funcs.deinit(gpa); - var need_never_inline_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty; + var need_never_inline_funcs: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty; defer need_never_inline_funcs.deinit(gpa); // As mentioned above, we need this type for error names. @@ -1283,9 +1284,9 @@ pub fn deleteExport( fn mergeNeededCTypes( c: *C, - need_types: *std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void), - need_errunion_types: *std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void), - need_aligned_types: *std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, u64), + need_types: *std.array_hash_map.Auto(link.ConstPool.Index, void), + need_errunion_types: *std.array_hash_map.Auto(link.ConstPool.Index, void), + need_aligned_types: *std.array_hash_map.Auto(link.ConstPool.Index, u64), deps: *const CTypeDependencies, ) Allocator.Error!void { const gpa = c.base.comp.gpa; @@ -1311,8 +1312,8 @@ fn mergeNeededCTypes( fn mergeNeededUavs( zcu: *const Zcu, - global: *std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), - new: *const std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), + global: *std.array_hash_map.Auto(InternPool.Index, Alignment), + new: *const std.array_hash_map.Auto(InternPool.Index, Alignment), ) Allocator.Error!void { const gpa = zcu.comp.gpa; @@ -1421,12 +1422,12 @@ const FlushTypes = struct { c: *C, f: *Flush, - aligned_types: *const std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, u64), + aligned_types: *const std.array_hash_map.Auto(link.ConstPool.Index, u64), aligned_type_strings: []const []const u8, - status: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, bool), - errunion_status: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, bool), - aligned_status: std.AutoArrayHashMapUnmanaged(link.ConstPool.Index, void), + status: std.array_hash_map.Auto(link.ConstPool.Index, bool), + errunion_status: std.array_hash_map.Auto(link.ConstPool.Index, bool), + aligned_status: std.array_hash_map.Auto(link.ConstPool.Index, void), fn processDeps(ft: *FlushTypes, deps: *const CTypeDependencies) void { const resolved = deps.get(ft.c); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 2d41c3bc582ccd62799e8b8fa1ec6ec178d8c460..fcb4dcc2a50b7e4e00aa0526056e75ffbd77863b 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -7,6 +7,7 @@ const std = @import("std"); const Io = std.Io; const assert = std.debug.assert; const log = std.log.scoped(.link); +const Crc32 = std.hash.crc.@"CRC-32/JAMCRC"; const codegen = @import("../codegen.zig"); const Compilation = @import("../Compilation.zig"); @@ -17,11 +18,40 @@ const target_util = @import("../target.zig"); const Type = @import("../Type.zig"); const Value = @import("../Value.zig"); const Zcu = @import("../Zcu.zig"); +const ModuleDefinition = @import("../libs/mingw/def.zig").ModuleDefinition; +const implib = @import("../libs/mingw/implib.zig"); +const Path = std.Build.Cache.Path; base: link.File, +options: link.File.OpenOptions, mf: MappedFile, nodes: std.MultiArrayList(Node), +members: std.ArrayList(Member), +pending_members: std.array_hash_map.Auto(Member.Index, void), +lib_string_table: std.ArrayList(String), +lib_string_len: u32, +long_names_table: LongNamesTable, import_table: ImportTable, +export_table: ExportTable, +symbol_table: SymbolTable, +inputs: std.array_hash_map.Custom(std.Build.Cache.Path, void, std.Build.Cache.Path.TableAdapter, false), +input_archives: std.ArrayList(InputArchive), +input_archive_members: std.ArrayList(InputArchive.Member), +input_archive_symbols: std.ArrayList(InputArchive.Member.Symbol), +input_archive_symbol_indices: std.array_hash_map.Auto(String, InputArchive.SearchList), +pending_input: ?InputArchive.Member.Index, +pending_default_libs: std.ArrayList(struct { + path: []const u8, + ioi: InputObject.Index, +}), +alternate_names: std.array_hash_map.Auto(String, String), +input_objects: std.ArrayList(InputObject), +input_symbols: std.ArrayList(struct { si: Symbol.Index, name: String }), +input_sections: std.ArrayList(Node.InputSection), +input_section_pending_index: u32, +inputs_complete: bool, +exports_complete: bool, +pending_special_symbol: SpecialSymbol, strings: std.HashMapUnmanaged( u32, void, @@ -29,24 +59,31 @@ strings: std.HashMapUnmanaged( std.hash_map.default_max_load_percentage, ), string_bytes: std.ArrayList(u8), -image_section_table: std.ArrayList(Symbol.Index), -pseudo_section_table: std.AutoArrayHashMapUnmanaged(String, Symbol.Index), -object_section_table: std.AutoArrayHashMapUnmanaged(String, Symbol.Index), -symbol_table: std.ArrayList(Symbol), -globals: std.AutoArrayHashMapUnmanaged(GlobalName, Symbol.Index), +section_table: std.array_hash_map.Auto(String, Section), +pseudo_section_table: std.array_hash_map.Auto(String, Symbol.Index), +object_section_table: std.array_hash_map.Auto(String, Symbol.Index), +section_merges: std.array_hash_map.Auto(String, String), +section_merge_pending_index: u32, +symbols: std.ArrayList(Symbol), +globals: std.array_hash_map.Auto(String, Global), global_pending_index: u32, -navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), -uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), +navs: std.array_hash_map.Auto(InternPool.Nav.Index, Symbol.Index), +uavs: std.array_hash_map.Auto(InternPool.Index, Symbol.Index), lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { - map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), + map: std.array_hash_map.Auto(InternPool.Index, Symbol.Index), pending_index: u32, }), -pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { +pending_uavs: std.array_hash_map.Auto(Node.UavMapIndex, struct { alignment: InternPool.Alignment, }), relocs: std.ArrayList(Reloc), +first_free_reloc: Reloc.Index, +last_free_reloc: Reloc.Index, const_prog_node: std.Progress.Node, synth_prog_node: std.Progress.Node, +symbol_prog_node: std.Progress.Node, +member_prog_node: std.Progress.Node, +input_prog_node: std.Progress.Node, pub const default_file_alignment: u16 = 0x200; pub const default_size_of_stack_reserve: u32 = 0x1000000; @@ -54,6 +91,17 @@ pub const default_size_of_stack_commit: u32 = 0x1000; pub const default_size_of_heap_reserve: u32 = 0x100000; pub const default_size_of_heap_commit: u32 = 0x1000; +pub const imp_prefix = "__imp_"; + +const header_name_max_len = @typeInfo(@FieldType(std.coff.SectionHeader, "name")).array.len; + +const Error = link.Error || error{MappedFileIo}; +const LoadInputError = Error || + Io.File.SeekError || + Io.File.Reader.SizeError || + Io.Reader.Error || + MappedFile.Error; + /// This is the start of a Portable Executable (PE) file. /// It starts with a MS-DOS header followed by a MS-DOS stub program. /// This data does not change so we include it as follows in all binaries. @@ -134,25 +182,53 @@ pub const msdos_stub: [120]u8 = .{ pub const Node = union(enum) { file, header, + /// Images and archives only. signature, + /// Archives only. + archive_member_header: Member.Index, + archive_member: Member.Index, + coff_header, + + /// Image only optional_header, data_directories, + section_table, + + /// Archives and objects only + symbol_table, + string_table, + relocation_table: Symbol.SectionNumber, + relocation_table_entry: Reloc.Index, + image_section: Symbol.Index, + /// Images only import_directory_table, import_lookup_table: ImportTable.Index, import_address_table: ImportTable.Index, import_hint_name_table: ImportTable.Index, + /// Images only + export_directory_table, + export_address_table, + export_name_pointer_table, + export_ordinal_table, + export_name_table, + pseudo_section: PseudoSectionMapIndex, object_section: ObjectSectionMapIndex, - global: GlobalMapIndex, + input_section: InputSection.Index, + import_thunk: GlobalMapIndex, nav: NavMapIndex, uav: UavMapIndex, lazy_code: LazyMapRef.Index(.code), lazy_const_data: LazyMapRef.Index(.const_data), + builtin: Symbol.Index, + + /// Takes the place of a known node index when that node is not present in the output + placeholder, pub const PseudoSectionMapIndex = enum(u32) { _, @@ -179,14 +255,30 @@ pub const Node = union(enum) { }; pub const GlobalMapIndex = enum(u32) { + none, _, - pub fn globalName(gmi: GlobalMapIndex, coff: *const Coff) GlobalName { - return coff.globals.keys()[@intFromEnum(gmi)]; + pub fn wrap(i: ?u32) GlobalMapIndex { + return @enumFromInt((i orelse return .none) + 1); + } + + pub fn unwrap(gmi: GlobalMapIndex) ?u32 { + return switch (gmi) { + .none => null, + _ => @intFromEnum(gmi) - 1, + }; + } + + pub fn name(gmi: GlobalMapIndex, coff: *const Coff) String { + return coff.globals.keys()[gmi.unwrap().?]; } pub fn symbol(gmi: GlobalMapIndex, coff: *const Coff) Symbol.Index { - return coff.globals.values()[@intFromEnum(gmi)]; + return coff.globals.values()[gmi.unwrap().?].si; + } + + pub fn libName(gmi: GlobalMapIndex, coff: *const Coff) String.Optional { + return coff.globals.values()[gmi.unwrap().?].lib_name; } }; @@ -214,6 +306,47 @@ pub const Node = union(enum) { } }; + const InputSection = struct { + ioi: InputObject.Index, + si: Symbol.Index, + comdat_si: Symbol.Index, + file_location: MappedFile.Node.FileLocation, + first_li: Node.InputSection.LocalIndex, + crc: u32, + + pub const Index = enum(u32) { + _, + + pub fn inputSection(isi: Index, coff: *const Coff) *InputSection { + return &coff.input_sections.items[@intFromEnum(isi)]; + } + + pub fn input(isi: Index, coff: *const Coff) InputObject.Index { + return coff.input_sections.items[@intFromEnum(isi)].ioi; + } + + pub fn fileLocation(isi: Index, coff: *const Coff) MappedFile.Node.FileLocation { + return coff.input_sections.items[@intFromEnum(isi)].file_location; + } + + pub fn symbol(isi: Index, coff: *const Coff) Symbol.Index { + return coff.input_sections.items[@intFromEnum(isi)].si; + } + + pub fn firstSymbol(isi: Index, coff: *const Coff) LocalIndex { + return coff.input_sections.items[@intFromEnum(isi)].first_li; + } + }; + + const LocalIndex = enum(u32) { + _, + + pub fn name(isli: LocalIndex, coff: *const Coff) String { + return coff.input_symbols.items[@intFromEnum(isli)].name; + } + }; + }; + pub const LazyMapRef = struct { kind: link.File.LazySymbol.Kind, index: u32, @@ -253,6 +386,14 @@ pub const Node = union(enum) { file, header, signature, + first_linker_member_header, + first_linker_member, + second_linker_member_header, + second_linker_member, + longnames_member_header, + longnames_member, + zcu_member_header, + zcu_member, coff_header, optional_header, data_directories, @@ -270,14 +411,338 @@ pub const Node = union(enum) { } }; +pub const InputArchive = struct { + path: std.Build.Cache.Path, + + const Index = enum(u32) { + _, + + pub fn path(iai: InputArchive.Index, coff: *Coff) std.Build.Cache.Path { + return coff.input_archives.items[@intFromEnum(iai)].path; + } + }; + + pub const Member = struct { + iai: InputArchive.Index, + name: String, + content: union(enum) { + // This range includes the member header + object: MappedFile.Node.FileLocation, + import: struct { + symbol_name: String, + lib_name: String, + // Either ordinal or hint, depending on value of name_type + import_ordinal_hint: u16, + type: std.coff.ImportType, + name_type: std.coff.ImportNameType, + }, + }, + flags: packed struct { + // Set if an attempt was made to load this member + is_loaded: bool, + }, + + const Index = enum(u32) { + _, + + pub fn member(iami: InputArchive.Member.Index, coff: *Coff) *InputArchive.Member { + return &coff.input_archive_members.items[@intFromEnum(iami)]; + } + }; + + pub const Symbol = struct { + iami: InputArchive.Member.Index, + // Set to its own index to indicate its the last in the list + next: InputArchive.Member.Symbol.Index, + + const Index = enum(u32) { + _, + }; + }; + }; + + pub const SearchList = struct { + first: InputArchive.Member.Symbol.Index, + last: InputArchive.Member.Symbol.Index, + }; +}; + +pub const InputObject = struct { + path: std.Build.Cache.Path, + member_name: ?[]const u8, + source_name: String.Optional, + + pub const Index = enum(u32) { + _, + + pub fn path(ioi: Index, coff: *const Coff) std.Build.Cache.Path { + return coff.input_objects.items[@intFromEnum(ioi)].path; + } + + pub fn memberName(ioi: Index, coff: *const Coff) ?[]const u8 { + return coff.input_objects.items[@intFromEnum(ioi)].member_name; + } + }; +}; + +pub const Member = struct { + kind: std.coff.ArchiveMemberHeader.Kind, + header_ni: MappedFile.Node.Index, + content_ni: MappedFile.Node.Index, + first_linker_indices: std.array_hash_map.Auto(struct { + mi: Member.Index, + name: String, + }, FirstLinkerIndex), + + pub const Index = enum(u16) { + first, + second, + longnames, + _, + + const known_count = @typeInfo(Index).@"enum".field_names.len; + + pub fn get(member_index: Member.Index, coff: *Coff) *Member { + return &coff.members.items[@intFromEnum(member_index)]; + } + }; + + pub const FirstLinkerIndex = enum(u32) { + _, + }; + + pub fn headerPtr(member: *Member, coff: *Coff) *std.coff.ArchiveMemberHeader { + return @ptrCast(@alignCast(member.header_ni.slice(&coff.mf))); + } + + /// Sets `name` as the name field of this member's header, either directly (if it's short enough), + /// or by creating an entry in the longnames member and storing a reference to that entry. + pub fn initHeader(member: *Member, coff: *Coff, name: []const u8, timestamp: u32) !void { + const max_name_len = @typeInfo(@FieldType(std.coff.ArchiveMemberHeader, "name")).array.len; + const opt_name_offset = if (name.len >= max_name_len) offset: { + const gpa = coff.base.comp.gpa; + const entries_ctx = LongNamesTable.Adapter{ .coff = coff }; + const gop = try coff.long_names_table.entries.getOrPutAdapted( + gpa, + name, + entries_ctx, + ); + + if (!gop.found_existing) { + errdefer _ = coff.export_table.entries.pop(); + + _, const old_size = Node.known.longnames_member.location(&coff.mf).resolve(&coff.mf); + const new_size = old_size + name.len + 1; + assert(new_size < comptime try std.math.powi(u64, 10, max_name_len - 1)); + + try Node.known.longnames_member.resize(&coff.mf, gpa, new_size); + const name_table_slice = Node.known.longnames_member.slice(&coff.mf); + const name_slice = name_table_slice[@intCast(old_size)..][0 .. name.len + 1]; + @memcpy(name_slice[0..name.len], name); + name_slice[name.len] = 0; + + gop.value_ptr.* = .{ + .offset = old_size, + .len = name.len, + }; + } + + break :offset gop.value_ptr.offset; + } else null; + + const header = member.headerPtr(coff); + if (opt_name_offset) |name_offset| { + header.name[0] = '/'; + storeHeaderDecimalStr(header.name[1..], name_offset); + } else { + @memcpy(header.name[0..name.len], name); + header.name[name.len] = '/'; + const padding = max_name_len - name.len - 1; + @memset(header.name[max_name_len - padding ..], ' '); + } + + storeHeaderDecimalStr(&header.date, timestamp); + + // Matching the Microsoft behaviour of emitting blanks for these fields + header.user_id = @splat(' '); + header.group_id = @splat(' '); + + // file_mode is actually octal, but we only ever write 0 to it + storeHeaderDecimalStr(&header.file_mode, 0); + if (!member.content_ni.hasResized(&coff.mf)) + storeHeaderDecimalStr( + &header.size, + member.content_ni.location(&coff.mf).resolve(&coff.mf)[1], + ); + + @memcpy(&header.end_of_header, std.coff.archive_end_of_header); + } + + pub fn storeHeaderDecimalStr(field_ptr: anytype, value: u64) void { + const array_info = @typeInfo(@typeInfo(@TypeOf(field_ptr)).pointer.child).array; + assert(array_info.child == u8); + assert(value < comptime try std.math.powi(u64, 10, array_info.len)); + _ = std.fmt.printInt(field_ptr, value, 10, .lower, .{ + .width = array_info.len, + .alignment = .left, + .fill = ' ', + }); + } + + pub fn loadHeaderDecimalStr(field_ptr: anytype, value: u64) void { + const array_info = @typeInfo(@typeInfo(@TypeOf(field_ptr)).pointer.child).array; + assert(array_info.child == u8); + assert(value < comptime try std.math.powi(u64, 10, array_info.len)); + _ = std.fmt.printInt(field_ptr, value, 10, .lower, .{ + .width = array_info.len, + .alignment = .left, + .fill = ' ', + }); + } +}; + +pub const LongNamesTable = struct { + ni: MappedFile.Node.Index = .none, + entries: std.array_hash_map.Auto(void, Entry), + + pub const Entry = struct { + offset: u64, + len: u64, + }; + + const Adapter = struct { + coff: *Coff, + + pub fn eql(adapter: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { + assert(adapter.coff.isArchive()); + const longnames_slice = Node.known.longnames_member.slice(&adapter.coff.mf); + const rhs = adapter.coff.long_names_table.entries.values()[rhs_index]; + return std.mem.eql(u8, longnames_slice[@intCast(rhs.offset)..][0..@intCast(rhs.len)], lhs_key); + } + + pub fn hash(_: Adapter, key: []const u8) u32 { + assert(std.mem.indexOfScalar(u8, key, 0) == null); + return std.array_hash_map.hashString(key); + } + }; +}; + +pub const SymbolTable = struct { + ni: MappedFile.Node.Index, + strings_ni: MappedFile.Node.Index, + strings: std.array_hash_map.Auto(String, StringIndex), + symbols: std.array_hash_map.Auto(Symbol.Index, SymbolTable.Index), + pending_symbol_index: u32, + + // Resizing the symbol table node has the result of accumulating padding + // between the last symbol in the symbol table node and the start of the + // string table node, due to the shifting method when resizing the parent in MappedFile. + // The spec requires the string table begin immediately after the last symbol, + // so we compact the symbol table node and move the string table back if needed. + pending_shrink: bool, + + pub const StringIndex = enum(u32) { + _, + }; + + pub const SymbolName = union(enum) { + short: []const u8, + long: StringIndex, + + pub fn store(name: SymbolName, coff: *const Coff, field: *[8]u8) void { + switch (name) { + .short => |s| { + @memcpy(field[0..s.len], s); + @memset(field[s.len..], 0); + }, + .long => |l| { + @memset(field[0..4], 0); + std.mem.writePackedInt(u32, field[4..], 0, @intFromEnum(l), coff.targetEndian()); + }, + } + } + }; + + // Symbol.Index does not map 1:1 with SymbolTable.Index: + // - Not all symbols need a symbol table entry + // - A variable number of auxiliary entries may trail each symbol + pub const Index = enum(u32) { + none, + _, + + pub fn wrap(i: u32) Index { + return @enumFromInt(i + 1); + } + + pub fn unwrap(sti: Index) ?u32 { + return switch (sti) { + .none => null, + _ => @intFromEnum(sti) - 1, + }; + } + }; +}; + +pub const ExportTable = struct { + ni: MappedFile.Node.Index, + export_directory_table_ni: MappedFile.Node.Index, + export_address_table_si: Symbol.Index, + name_pointer_table_ni: MappedFile.Node.Index, + ordinal_table_ni: MappedFile.Node.Index, + name_table_ni: MappedFile.Node.Index, + entries: std.array_hash_map.Auto(void, Entry), + pending_sort: bool = false, + + pub const Entry = struct { + si: Symbol.Index, + name_index: u32, + name_len: u32, + export_address_table_ri: Reloc.Index, + }; + + const Adapter = struct { + coff: *Coff, + + pub fn eql(adapter: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool { + const coff = adapter.coff; + const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf); + const rhs = coff.export_table.entries.values()[rhs_index]; + return std.mem.eql(u8, name_table_slice[rhs.name_index..][0..rhs.name_len], lhs_key); + } + + pub fn hash(_: Adapter, key: []const u8) u32 { + assert(std.mem.indexOfScalar(u8, key, 0) == null); + return std.array_hash_map.hashString(key); + } + }; + + pub const Ordinal = enum(u16) { + _, + + pub fn get(export_index: ExportTable.Ordinal, coff: *Coff) *Entry { + return &coff.export_table.entries.values()[@intFromEnum(export_index)]; + } + }; +}; + pub const ImportTable = struct { ni: MappedFile.Node.Index, - entries: std.AutoArrayHashMapUnmanaged(void, Entry), + entries: std.array_hash_map.Auto(void, Entry), + iat_symbol_indices: std.array_hash_map.Auto(struct { + iti: ImportTable.Index, + name: String.Optional, + // If name == .none this is the ordinal, otherwise the hint + ordinal_hint: u16, + }, u32), pub const Entry = struct { import_lookup_table_ni: MappedFile.Node.Index, import_address_table_si: Symbol.Index, import_hint_name_table_ni: MappedFile.Node.Index, + // All .iat_ptr globals that reference this table. + // This is separate from `iat_symbol_indices` because multiple symbols + // can reference to the same iat entry, after name demangling. + import_address_table_symbols: std.ArrayList(Symbol.Index), len: u32, hint_name_len: u32, }; @@ -314,13 +779,32 @@ pub const String = enum(u32) { @".rdata" = 13, @".text" = 20, @".tls$" = 26, + @".edata" = 32, + @".ctors" = 39, + @".ctors$ZZZ" = 46, + @".dtors" = 57, + @".dtors$ZZZ" = 64, + @".bss" = 75, + @".fptable" = 80, + @".tls" = 89, + @".thunks" = 94, _, pub const Optional = enum(u32) { @".data" = @intFromEnum(String.@".data"), + @".idata" = @intFromEnum(String.@".idata"), @".rdata" = @intFromEnum(String.@".rdata"), @".text" = @intFromEnum(String.@".text"), @".tls$" = @intFromEnum(String.@".tls$"), + @".edata" = @intFromEnum(String.@".edata"), + @".ctors" = @intFromEnum(String.@".ctors"), + @".ctors$ZZZ" = @intFromEnum(String.@".ctors$ZZZ"), + @".dtors" = @intFromEnum(String.@".dtors"), + @".dtors$ZZZ" = @intFromEnum(String.@".dtors$ZZZ"), + @".bss" = @intFromEnum(String.@".bss"), + @".fptable" = @intFromEnum(String.@".fptable"), + @".tls" = @intFromEnum(String.@".tls"), + @".thunks" = @intFromEnum(String.@".thunks"), none = std.math.maxInt(u32), _, @@ -346,20 +830,176 @@ pub const String = enum(u32) { } }; -pub const GlobalName = struct { name: String, lib_name: String.Optional }; +pub const Section = struct { + si: Symbol.Index, + relocation_table_ni: MappedFile.Node.Index, + + pub const RelocationIndex = enum(u16) { + none, + _, + + pub fn wrap(i: ?u16) RelocationIndex { + return @enumFromInt((i orelse return .none) + 1); + } + + pub fn unwrap(sri: RelocationIndex) ?u16 { + return switch (sri) { + .none => null, + _ => @intFromEnum(sri) - 1, + }; + } + + pub fn entry( + sri: RelocationIndex, + coff: *Coff, + sn: Symbol.SectionNumber, + ) ?*align(2) std.coff.Relocation { + if (sri == .none) return null; + const table_slice = sn.section(coff).relocation_table_ni.slice(&coff.mf); + return @ptrCast(@alignCast(&table_slice[@as(u32, sri.unwrap().?) * std.coff.Relocation.sizeOf()])); + } + }; +}; + +pub const Global = struct { + si: Symbol.Index, + lib_name: String.Optional, +}; + +pub const WeakExternalStrat = enum(u3) { + none, + no_library, + library, + alias, + anti_dependency, + + pub fn fromFlag(flag: std.coff.WeakExternalFlag) WeakExternalStrat { + return switch (flag) { + .SEARCH_NOLIBRARY => .no_library, + .SEARCH_LIBRARY => .library, + .SEARCH_ALIAS => .alias, + .ANTI_DEPENDENCY => .anti_dependency, + _ => unreachable, + }; + } +}; + +const SpecialSymbol = enum { + entry, + tls, + none, +}; pub const Symbol = struct { ni: MappedFile.Node.Index, rva: u32, - size: u32, + value: std.meta.BareUnion(Symbol.Value), + extra: std.meta.BareUnion(Symbol.Extra), + flags: packed struct(u16) { + value_tag: ValueTag, + extra_tag: ExtraTag, + type: Symbol.Type, + dll_storage_class: DllStorageClass, + weak_external_strat: WeakExternalStrat, + _: u5 = 0, + }, /// Relocations contained within this symbol loc_relocs: Reloc.Index, /// Relocations targeting this symbol target_relocs: Reloc.Index, section_number: SectionNumber, - unused0: u32 = 0, - unused1: u32 = 0, - unused2: u16 = 0, + gmi: Node.GlobalMapIndex, + + pub const DllStorageClass = enum(u2) { + default, + dllimport, + dllexport, + }; + + pub const Type = enum(u2) { + unknown, + code, + data, + }; + + const ValueTag = enum(u2) { + none, + node_offset, + weak_alias_si, + weak_alias_name, + }; + + pub const Value = union(ValueTag) { + none, + /// The offset of the symbol within its node. Used with symbols that + /// don't create their own nodes: .input_section, .import_address_table + /// Images only. + node_offset: u32, + /// Images: the weak alias that should replace this symbol if it is not resolved. + /// Objects: he target of a weak external that hasn't been assigned an sti yet. + /// Globals only. + weak_alias_si: Symbol.Index, + /// For weak externals that have an alias that is also an undef + /// external, this is the name of the alias global that should + /// be generated and resolved if this symbol is not resolved. + /// Globals only, images only. + weak_alias_name: String, + }; + + const ExtraTag = enum(u2) { + size, + isli, + next_alias_si, + }; + + pub const Extra = union(ExtraTag) { + // The size of the symbol + size: u32, + /// Only valid when .ni == .input_section and .value_tag == .node_offset + isli: Node.InputSection.LocalIndex, + /// The next symbol in the list of aliases of this symbol. + next_alias_si: Symbol.Index, + }; + + pub fn setValue(sym: *Symbol, value: Symbol.Value) void { + sym.flags.value_tag = std.meta.activeTag(value); + sym.value = switch (sym.flags.value_tag) { + inline else => |t| @unionInit( + @FieldType(Symbol, "value"), + @tagName(t), + @field(value, @tagName(t)), + ), + }; + } + + pub fn setExtra(sym: *Symbol, extra: Symbol.Extra) void { + sym.flags.extra_tag = std.meta.activeTag(extra); + sym.extra = switch (sym.flags.extra_tag) { + inline else => |t| @unionInit( + @FieldType(Symbol, "extra"), + @tagName(t), + @field(extra, @tagName(t)), + ), + }; + } + + pub fn nodeOffset(sym: *const Symbol, coff: *Coff) u32 { + return switch (sym.flags.value_tag) { + .node_offset => offset: { + assert(switch (coff.getNode(sym.ni)) { + // Separate nodes are not created for these entries per-symbol + .input_section, .import_address_table => true, + else => false, + }); + break :offset sym.value.node_offset; + }, + else => 0, + }; + } + + pub fn size(sym: *const Symbol) u32 { + return if (sym.flags.extra_tag == .size) sym.extra.size else 0; + } pub const SectionNumber = enum(i16) { UNDEFINED = 0, @@ -371,8 +1011,20 @@ pub const Symbol = struct { return @intCast(@intFromEnum(sn) - 1); } + fn hasIndex(sn: SectionNumber) bool { + return @intFromEnum(sn) > 0; + } + pub fn symbol(sn: SectionNumber, coff: *const Coff) Symbol.Index { - return coff.image_section_table.items[sn.toIndex()]; + return sn.section(coff).si; + } + + pub fn name(sn: SectionNumber, coff: *const Coff) String { + return coff.section_table.keys()[sn.toIndex()]; + } + + pub fn section(sn: SectionNumber, coff: *const Coff) *Section { + return &coff.section_table.values()[sn.toIndex()]; } pub fn header(sn: SectionNumber, coff: *Coff) *std.coff.SectionHeader { @@ -382,6 +1034,7 @@ pub const Symbol = struct { pub const Index = enum(u32) { null, + bss, data, rdata, text, @@ -390,7 +1043,12 @@ pub const Symbol = struct { const known_count = @typeInfo(Index).@"enum".field_names.len; pub fn get(si: Symbol.Index, coff: *Coff) *Symbol { - return &coff.symbol_table.items[@intFromEnum(si)]; + return &coff.symbols.items[@intFromEnum(si)]; + } + + pub fn unwrap(si: Symbol.Index) ?Symbol.Index { + if (si == .null) return null; + return si; } pub fn node(si: Symbol.Index, coff: *Coff) MappedFile.Node.Index { @@ -399,37 +1057,92 @@ pub const Symbol = struct { return ni; } - pub fn flushMoved(si: Symbol.Index, coff: *Coff) void { + pub fn sti(si: Symbol.Index, coff: *Coff) SymbolTable.Index { + assert(!coff.isImage()); + return coff.symbol_table.symbols.get(si) orelse .none; + } + + pub fn next(si: Symbol.Index) Symbol.Index { + return @enumFromInt(@intFromEnum(si) + 1); + } + + pub fn knownString(si: Symbol.Index) String.Optional { + return switch (si) { + .null, _ => .none, + inline else => |tag| @field(String.Optional, "." ++ @tagName(tag)), + }; + } + + pub fn flushMoved(si: Symbol.Index, coff: *Coff) !void { const sym = si.get(coff); - sym.rva = coff.computeNodeRva(sym.ni); - si.applyLocationRelocs(coff); - si.applyTargetRelocs(coff); - } + sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff); + try si.applyLocationRelocs(coff); + try si.applyTargetRelocs(coff, .none); - pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void { - for (coff.relocs.items[@intFromEnum(si.get(coff).loc_relocs)..]) |*reloc| { - if (reloc.loc != si) break; - reloc.apply(coff); + var alias_sym = sym; + while (alias_sym.flags.extra_tag == .next_alias_si) { + const alias_si = alias_sym.extra.next_alias_si; + alias_sym = alias_si.get(coff); + assert(alias_sym.ni == sym.ni); + alias_sym.rva = sym.rva; + try alias_si.applyTargetRelocs(coff, .none); } } - pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff) void { - var ri = si.get(coff).target_relocs; + pub fn flushSymbolTableIndex(si: Symbol.Index, coff: *Coff) void { + const sym = si.get(coff); + const index = si.sti(coff).unwrap().?; + var ri = sym.target_relocs; while (ri != .none) { const reloc = ri.get(coff); assert(reloc.target == si); - reloc.apply(coff); + if (reloc.sri.entry(coff, reloc.loc.get(coff).section_number)) |entry| + coff.targetStore(&entry.symbol_table_index, index); + ri = reloc.next; + } + } + + pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) !void { + const sym = si.get(coff); + switch (sym.loc_relocs) { + .none => {}, + else => |loc_relocs| { + for (coff.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| { + if (reloc.loc != si) break; + if (reloc.sri.entry(coff, sym.section_number)) |entry| coff.targetStore( + &entry.virtual_address, + @intCast(coff.computeSymbolSectionOffset(sym, .image) + reloc.offset), + ); + try reloc.apply(coff); + } + }, + } + } + + pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff, end: Reloc.Index) !void { + const sym = si.get(coff); + + var ri = sym.target_relocs; + while (ri != end) { + const reloc = ri.get(coff); + assert(reloc.target == si); + try reloc.apply(coff); ri = reloc.next; } } pub fn deleteLocationRelocs(si: Symbol.Index, coff: *Coff) void { const sym = si.get(coff); - for (coff.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| { - if (reloc.loc != si) break; - reloc.delete(coff); + switch (sym.loc_relocs) { + .none => {}, + else => |loc_relocs| { + for (coff.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| { + if (reloc.loc != si) break; + reloc.delete(coff); + } + sym.loc_relocs = .none; + }, } - sym.loc_relocs = .none; } }; @@ -439,14 +1152,24 @@ pub const Symbol = struct { }; pub const Reloc = extern struct { + offset: u64, + addend: i64, type: Reloc.Type, + sri: Section.RelocationIndex, prev: Reloc.Index, next: Reloc.Index, loc: Symbol.Index, target: Symbol.Index, - unused: u32, - offset: u64, - addend: i64, + flags: packed struct(u8) { + /// Indicates the addend is not known and should be recovered from the location itself. + /// COFF relocation tables don't encode the addend, only the location. + recover_addend: bool, + /// Set if this reloc is in the free list. + /// When set, `prev` / `next` refer to other relocs in the free list. + /// All other fields are undefined. + free: bool, + _: u6 = 0, + }, pub const Type = extern union { AMD64: std.coff.IMAGE.REL.AMD64, @@ -458,141 +1181,326 @@ pub const Reloc = extern struct { IA64: std.coff.IMAGE.REL.IA64, MIPS: std.coff.IMAGE.REL.MIPS, M32R: std.coff.IMAGE.REL.M32R, + u16: u16, }; pub const Index = enum(u32) { none = std.math.maxInt(u32), _, - pub fn get(si: Reloc.Index, coff: *Coff) *Reloc { - return &coff.relocs.items[@intFromEnum(si)]; + pub fn wrap(i: ?u32) Reloc.Index { + return @enumFromInt((i orelse return .none) + 1); + } + + pub fn get(ri: Reloc.Index, coff: *Coff) *Reloc { + return &coff.relocs.items[@intFromEnum(ri)]; } }; - pub fn apply(reloc: *const Reloc, coff: *Coff) void { + pub fn apply(reloc: *Reloc, coff: *Coff) !void { const loc_sym = reloc.loc.get(coff); switch (loc_sym.ni) { .none => return, else => |ni| if (ni.hasMoved(&coff.mf)) return, } - const target_sym = reloc.target.get(coff); - switch (target_sym.ni) { - .none => return, - else => |ni| if (ni.hasMoved(&coff.mf)) return, - } + const loc_slice = loc_sym.ni.slice(&coff.mf)[@intCast(reloc.offset)..]; + const target_endian = coff.targetEndian(); + const target_machine = coff.targetLoad(&coff.headerPtr().machine); + + if (!coff.isImage()) { + assert(!reloc.flags.recover_addend); + switch (target_machine) { + else => |machine| @panic(@tagName(machine)), + .AMD64 => switch (reloc.type.AMD64) { + else => |kind| @panic(@tagName(kind)), + .ABSOLUTE => {}, + .ADDR64 => std.mem.writeInt( + u64, + loc_slice[0..8], + @intCast(reloc.addend), + target_endian, + ), + .ADDR32, + .ADDR32NB, + .SECREL, + => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(reloc.addend), + target_endian, + ), + .REL32, + .REL32_1, + .REL32_2, + .REL32_3, + .REL32_4, + .REL32_5, + => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(reloc.addend), + target_endian, + ), + }, + .I386 => switch (reloc.type.I386) { + else => |kind| @panic(@tagName(kind)), + .ABSOLUTE => {}, + .DIR16, + => std.mem.writeInt( + u16, + loc_slice[0..2], + @intCast(reloc.addend), + target_endian, + ), + .REL16, + => std.mem.writeInt( + i16, + loc_slice[0..2], + @intCast(reloc.addend), + target_endian, + ), + .DIR32, + .DIR32NB, + .SECREL, + => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(reloc.addend), + target_endian, + ), + .REL32, + => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(reloc.addend), + target_endian, + ), + }, + } + + return; + } else if (reloc.flags.recover_addend) { + reloc.flags.recover_addend = false; + reloc.addend = switch (target_machine) { + else => |machine| @panic(@tagName(machine)), + .AMD64 => switch (reloc.type.AMD64) { + else => |kind| @panic(@tagName(kind)), + .ABSOLUTE => 0, + .ADDR64 => @bitCast(std.mem.readInt( + u64, + loc_slice[0..8], + target_endian, + )), + .ADDR32, + .ADDR32NB, + .SECREL, + .REL32, + .REL32_1, + .REL32_2, + .REL32_3, + .REL32_4, + .REL32_5, + => std.mem.readInt( + i32, + loc_slice[0..4], + target_endian, + ), + }, + .I386 => switch (reloc.type.I386) { + else => |kind| @panic(@tagName(kind)), + .ABSOLUTE => 0, + .DIR16, + .REL16, + => std.mem.readInt( + i16, + loc_slice[0..2], + target_endian, + ), + .DIR32, + .DIR32NB, + .SECREL, + .REL32, + => std.mem.readInt( + i32, + loc_slice[0..4], + target_endian, + ), + }, + }; + } + + const target_sym = reloc.target.get(coff); + const is_abs = switch (target_sym.ni) { + .none => if (target_sym.section_number == .ABSOLUTE) true else return, + else => |ni| if (ni.hasMoved(&coff.mf)) return else false, + }; + const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend)); - const target_endian = coff.targetEndian(); - switch (coff.targetLoad(&coff.headerPtr().machine)) { - else => |machine| @panic(@tagName(machine)), - .AMD64 => switch (reloc.type.AMD64) { - else => |kind| @panic(@tagName(kind)), - .ABSOLUTE => {}, - .ADDR64 => std.mem.writeInt( - u64, - loc_slice[0..8], - coff.optionalHeaderField(.image_base) + target_rva, - target_endian, - ), - .ADDR32 => std.mem.writeInt( - u32, - loc_slice[0..4], - @intCast(coff.optionalHeaderField(.image_base) + target_rva), - target_endian, - ), - .ADDR32NB => std.mem.writeInt( - u32, - loc_slice[0..4], - @intCast(target_rva), - target_endian, - ), - .REL32 => std.mem.writeInt( - i32, - loc_slice[0..4], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), - target_endian, - ), - .REL32_1 => std.mem.writeInt( - i32, - loc_slice[0..4], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))), - target_endian, - ), - .REL32_2 => std.mem.writeInt( - i32, - loc_slice[0..4], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))), - target_endian, - ), - .REL32_3 => std.mem.writeInt( - i32, - loc_slice[0..4], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))), - target_endian, - ), - .REL32_4 => std.mem.writeInt( - i32, - loc_slice[0..4], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))), - target_endian, - ), - .REL32_5 => std.mem.writeInt( - i32, - loc_slice[0..4], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))), - target_endian, - ), - .SECREL => std.mem.writeInt( - u32, - loc_slice[0..4], - coff.computeNodeSectionOffset(target_sym.ni), - target_endian, - ), - }, - .I386 => switch (reloc.type.I386) { - else => |kind| @panic(@tagName(kind)), - .ABSOLUTE => {}, - .DIR16 => std.mem.writeInt( - u16, - loc_slice[0..2], - @intCast(coff.optionalHeaderField(.image_base) + target_rva), - target_endian, - ), - .REL16 => std.mem.writeInt( - i16, - loc_slice[0..2], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))), - target_endian, - ), - .DIR32 => std.mem.writeInt( - u32, - loc_slice[0..4], - @intCast(coff.optionalHeaderField(.image_base) + target_rva), - target_endian, - ), - .DIR32NB => std.mem.writeInt( - u32, - loc_slice[0..4], - @intCast(target_rva), - target_endian, - ), - .REL32 => std.mem.writeInt( - i32, - loc_slice[0..4], - @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), - target_endian, - ), - .SECREL => std.mem.writeInt( - u32, - loc_slice[0..4], - coff.computeNodeSectionOffset(target_sym.ni), - target_endian, - ), - }, + if (is_abs) { + switch (target_machine) { + else => |machine| @panic(@tagName(machine)), + .AMD64 => switch (reloc.type.AMD64) { + // TODO: Could wait to report these later, in reportUndefs -> reportRelocErrs, + // so that this function doesn't return an err + else => |kind| return coff.base.comp.link_diags.fail( + "absolute symbol '{s}' targeted by invalid relocation type: {t}", + .{ target_sym.gmi.name(coff).toSlice(coff), kind }, + ), + .ABSOLUTE => {}, + .ADDR64 => std.mem.writeInt( + u64, + loc_slice[0..8], + target_rva, + target_endian, + ), + .ADDR32 => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(target_rva), + target_endian, + ), + }, + .I386 => switch (reloc.type.I386) { + else => |kind| return coff.base.comp.link_diags.fail( + "absolute symbol '{s}' targeted by invalid relocation type: {t}", + .{ target_sym.gmi.name(coff).toSlice(coff), kind }, + ), + .ABSOLUTE => {}, + .DIR16 => std.mem.writeInt( + u16, + loc_slice[0..2], + @intCast(target_rva), + target_endian, + ), + .DIR32 => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(target_rva), + target_endian, + ), + }, + } + } else { + switch (target_machine) { + else => |machine| @panic(@tagName(machine)), + .AMD64 => switch (reloc.type.AMD64) { + else => |kind| @panic(@tagName(kind)), + .ABSOLUTE => {}, + .ADDR64 => std.mem.writeInt( + u64, + loc_slice[0..8], + coff.optionalHeaderField(.image_base) + target_rva, + target_endian, + ), + .ADDR32 => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(coff.optionalHeaderField(.image_base) + target_rva), + target_endian, + ), + .ADDR32NB => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(target_rva), + target_endian, + ), + .REL32 => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), + target_endian, + ), + .REL32_1 => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))), + target_endian, + ), + .REL32_2 => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))), + target_endian, + ), + .REL32_3 => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))), + target_endian, + ), + .REL32_4 => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))), + target_endian, + ), + .REL32_5 => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))), + target_endian, + ), + .SECREL => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(coff.computeSymbolSectionOffset(target_sym, .pseudo) + reloc.addend), + target_endian, + ), + }, + .I386 => switch (reloc.type.I386) { + else => |kind| @panic(@tagName(kind)), + .ABSOLUTE => {}, + .DIR16 => std.mem.writeInt( + u16, + loc_slice[0..2], + @intCast(coff.optionalHeaderField(.image_base) + target_rva), + target_endian, + ), + .REL16 => std.mem.writeInt( + i16, + loc_slice[0..2], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))), + target_endian, + ), + .DIR32 => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(coff.optionalHeaderField(.image_base) + target_rva), + target_endian, + ), + .DIR32NB => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(target_rva), + target_endian, + ), + .REL32 => std.mem.writeInt( + i32, + loc_slice[0..4], + @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))), + target_endian, + ), + .SECREL => std.mem.writeInt( + u32, + loc_slice[0..4], + @intCast(coff.computeSymbolSectionOffset(target_sym, .pseudo) + reloc.addend), + target_endian, + ), + }, + } } } pub fn delete(reloc: *Reloc, coff: *Coff) void { + if (reloc.sri != .none) { + // TODO: Need to remove this from the COFF relocation table (maybe removeswap?) + // TODO: If this was the last reloc causing something to be in the symbol table, we should remove + // the symbol table entry (and unset sti). That will require flushSymbolTableIndex on the + // swapped symbol if we exchange indices + @panic("TODO implement symbol table reloc deletions"); + } + switch (reloc.prev) { .none => { const target = reloc.target.get(coff); @@ -605,7 +1513,24 @@ pub const Reloc = extern struct { .none => {}, else => |next| next.get(coff).prev = reloc.prev, } + reloc.* = undefined; + reloc.flags = .{ + .recover_addend = false, + .free = true, + }; + + const ri: Reloc.Index = .wrap(@intCast(reloc - coff.relocs.items.ptr)); + if (coff.last_free_reloc == .none) { + assert(coff.first_free_reloc == .none); + coff.first_free_reloc = ri; + coff.last_free_reloc = ri; + } else { + coff.last_free_reloc.get(coff).next = ri; + reloc.prev = coff.last_free_reloc; + reloc.next = .none; + coff.last_free_reloc = ri; + } } comptime { @@ -639,14 +1564,6 @@ fn create( assert(target.ofmt == .coff); if (target.cpu.arch.endian() != comptime targetEndian(undefined)) return error.UnsupportedCOFFArchitecture; - const is_image = switch (comp.config.output_mode) { - .Exe => true, - .Lib => switch (comp.config.link_mode) { - .static => false, - .dynamic => true, - }, - .Obj => false, - }; const machine = target.toCoffMachine(); const timestamp: u32 = 0; const major_subsystem_version = options.major_subsystem_version orelse 6; @@ -689,18 +1606,61 @@ fn create( .allow_shlib_undefined = false, .stack_size = 0, }, + .options = options, .mf = try .init(file, comp.gpa, io), .nodes = .empty, + .members = .empty, + .pending_members = .empty, + .lib_string_table = .empty, + .lib_string_len = 0, + .long_names_table = .{ + .entries = .empty, + }, .import_table = .{ .ni = .none, .entries = .empty, + .iat_symbol_indices = .empty, }, + .export_table = .{ + .ni = .none, + .export_directory_table_ni = .none, + .export_address_table_si = .null, + .name_pointer_table_ni = .none, + .ordinal_table_ni = .none, + .name_table_ni = .none, + .entries = .empty, + }, + .symbol_table = .{ + .ni = .none, + .strings_ni = .none, + .strings = .empty, + .symbols = .empty, + .pending_symbol_index = 0, + .pending_shrink = false, + }, + .inputs = .empty, + .input_archives = .empty, + .input_archive_members = .empty, + .input_archive_symbols = .empty, + .input_archive_symbol_indices = .empty, + .pending_input = null, + .pending_default_libs = .empty, + .alternate_names = .empty, + .input_objects = .empty, + .input_symbols = .empty, + .input_sections = .empty, + .input_section_pending_index = 0, + .inputs_complete = false, + .exports_complete = false, + .pending_special_symbol = .entry, .strings = .empty, .string_bytes = .empty, - .image_section_table = .empty, + .section_table = .empty, .pseudo_section_table = .empty, .object_section_table = .empty, - .symbol_table = .empty, + .section_merges = .empty, + .section_merge_pending_index = 0, + .symbols = .empty, .globals = .empty, .global_pending_index = 0, .navs = .empty, @@ -711,8 +1671,13 @@ fn create( }), .pending_uavs = .empty, .relocs = .empty, + .first_free_reloc = .none, + .last_free_reloc = .none, .const_prog_node = .none, .synth_prog_node = .none, + .symbol_prog_node = .none, + .member_prog_node = .none, + .input_prog_node = .none, }; errdefer coff.deinit(); @@ -725,14 +1690,20 @@ fn create( } try coff.initHeaders( - is_image, machine, timestamp, major_subsystem_version, minor_subsystem_version, magic, + if (options.subsystem) |s| switch (s) { + .console => .WINDOWS_CUI, + .windows => .WINDOWS_GUI, + else => return error.UnsupportedCOFFSubsystem, + } else .WINDOWS_CUI, section_align, + std.fs.path.basename(path.sub_path), ); + try coff.initBuiltins(); return coff; } @@ -740,13 +1711,31 @@ pub fn deinit(coff: *Coff) void { const gpa = coff.base.comp.gpa; coff.mf.deinit(gpa); coff.nodes.deinit(gpa); + coff.pending_members.deinit(gpa); + coff.lib_string_table.deinit(gpa); + coff.long_names_table.entries.deinit(gpa); coff.import_table.entries.deinit(gpa); + coff.import_table.iat_symbol_indices.deinit(gpa); + coff.export_table.entries.deinit(gpa); + coff.symbol_table.strings.deinit(gpa); + coff.symbol_table.symbols.deinit(gpa); + coff.inputs.deinit(gpa); + coff.input_archives.deinit(gpa); + coff.input_archive_members.deinit(gpa); + coff.input_archive_symbols.deinit(gpa); + coff.input_archive_symbol_indices.deinit(gpa); + for (coff.pending_default_libs.items) |l| gpa.free(l.path); + coff.pending_default_libs.deinit(gpa); + coff.alternate_names.deinit(gpa); + coff.input_objects.deinit(gpa); + coff.input_symbols.deinit(gpa); + coff.input_sections.deinit(gpa); coff.strings.deinit(gpa); coff.string_bytes.deinit(gpa); - coff.image_section_table.deinit(gpa); + coff.section_table.deinit(gpa); coff.pseudo_section_table.deinit(gpa); coff.object_section_table.deinit(gpa); - coff.symbol_table.deinit(gpa); + coff.symbols.deinit(gpa); coff.globals.deinit(gpa); coff.navs.deinit(gpa); coff.uavs.deinit(gpa); @@ -756,21 +1745,65 @@ pub fn deinit(coff: *Coff) void { coff.* = undefined; } +fn isImage(coff: *const Coff) bool { + const comp = coff.base.comp; + return switch (comp.config.output_mode) { + .Exe => true, + .Lib => switch (comp.config.link_mode) { + .static => false, + .dynamic => true, + }, + .Obj => false, + }; +} + +fn isArchive(coff: *const Coff) bool { + const comp = coff.base.comp; + return switch (comp.config.output_mode) { + .Exe => false, + .Lib => switch (comp.config.link_mode) { + .static => true, + .dynamic => false, + }, + .Obj => false, + }; +} + +fn isExe(coff: *const Coff) bool { + return coff.base.comp.config.output_mode == .Exe; +} + +fn isObj(coff: *const Coff) bool { + return coff.base.comp.config.output_mode == .Obj; +} + +fn hasCoffHeader(coff: *const Coff) bool { + return coff.base.comp.zcu != null or !coff.isArchive(); +} + +fn sectionParent(coff: *Coff) MappedFile.Node.Index { + assert(coff.hasCoffHeader()); + return if (coff.isArchive()) Node.known.zcu_member else Node.known.file; +} + fn initHeaders( coff: *Coff, - is_image: bool, machine: std.coff.IMAGE.FILE.MACHINE, timestamp: u32, major_subsystem_version: u16, minor_subsystem_version: u16, magic: std.coff.OptionalHeader.Magic, + subsystem: std.coff.Subsystem, section_align: std.mem.Alignment, + file_name: []const u8, ) !void { const comp = coff.base.comp; const gpa = comp.gpa; const target_endian = coff.targetEndian(); const file_align: std.mem.Alignment = comptime .fromByteUnits(default_file_alignment); - + const is_image = coff.isImage(); + const is_archive = coff.isArchive(); + const target = &comp.root_mod.resolved_target.result; const optional_header_size: u16 = if (is_image) switch (magic) { _ => unreachable, inline else => |ct_magic| @sizeOf(@field(std.coff.OptionalHeader, @tagName(ct_magic))), @@ -780,33 +1813,120 @@ fn initHeaders( else 0; - const expected_nodes_len = Node.known_count + 6 + - @as(usize, @intFromBool(comp.config.any_non_single_threaded)) * 2; + var expected_nodes_len: usize = Node.known_count; + if (coff.hasCoffHeader()) { + // Sections + expected_nodes_len += 4; + + if (is_image) { + // Pseudo-sections and import / export table + expected_nodes_len += 9; + if (comp.config.link_libc and target.abi == .msvc) + expected_nodes_len += 1; + } else + // Symbol table + expected_nodes_len += 2; + + // TLS section + if (comp.config.any_non_single_threaded) { + if (!is_image) expected_nodes_len += 1; + expected_nodes_len += 1; + } + } + defer assert(coff.nodes.len == expected_nodes_len); + try coff.nodes.ensureTotalCapacity(gpa, expected_nodes_len); coff.nodes.appendAssumeCapacity(.file); const header_ni = Node.known.header; - assert(header_ni == try coff.mf.addOnlyChildNode(gpa, .root, .{ + assert(header_ni == try coff.mf.addOnlyChildNode(gpa, Node.known.file, .{ .alignment = coff.mf.flags.block_size, .fixed = true, })); coff.nodes.appendAssumeCapacity(.header); const signature_ni = Node.known.signature; - assert(signature_ni == try coff.mf.addOnlyChildNode(gpa, header_ni, .{ - .size = (if (is_image) msdos_stub.len else 0) + "PE\x00\x00".len, + assert(signature_ni == try coff.mf.addLastChildNode(gpa, if (is_image or !is_archive) header_ni else Node.known.file, .{ + .size = if (is_image) + msdos_stub.len + std.coff.pe_signature.len + else if (is_archive) + std.coff.archive_signature.len + else + 0, .alignment = .@"4", .fixed = true, })); coff.nodes.appendAssumeCapacity(.signature); - { - const signature_slice = signature_ni.slice(&coff.mf); - if (is_image) @memcpy(signature_slice[0..msdos_stub.len], &msdos_stub); - @memcpy(signature_slice[signature_slice.len - 4 ..], "PE\x00\x00"); + + const signature_slice = signature_ni.slice(&coff.mf); + if (is_image) { + @memcpy(signature_slice[0..msdos_stub.len], &msdos_stub); + @memcpy(signature_slice[signature_slice.len - std.coff.pe_signature.len ..], std.coff.pe_signature); + } else if (is_archive) { + @memcpy(signature_slice, std.coff.archive_signature); } + const opt_coff_parent_ni = if (is_archive) parent: { + const initial_member_count = Member.Index.known_count + @intFromBool(comp.zcu != null); + try coff.members.ensureTotalCapacity(gpa, initial_member_count); + + assert(Member.Index.first == try coff.addMemberAssumeCapacity(.first_linker, @sizeOf(u32))); + coff.targetStore(coff.firstLinkerMemberNumSymbolsPtr(), 0); + + assert(Member.Index.second == try coff.addMemberAssumeCapacity(.second_linker, 2 * @sizeOf(u32))); + coff.targetStore(coff.secondLinkerMemberNumMembersPtr(), 0); + coff.targetStore(coff.secondLinkerMemberNumSymbolsPtr(), 0); + + assert(Member.Index.longnames == try coff.addMemberAssumeCapacity(.longnames, 0)); + + const first_linker_member = Member.Index.first.get(coff); + const second_linker_member = Member.Index.second.get(coff); + const longnames_member = Member.Index.longnames.get(coff); + + try first_linker_member.initHeader(coff, "", timestamp); + try second_linker_member.initHeader(coff, "", timestamp); + try longnames_member.initHeader(coff, "/", timestamp); + + if (comp.zcu) |zcu| { + const zcu_mi = try coff.addMemberAssumeCapacity(.coff, @sizeOf(std.coff.Header)); + const zcu_member = zcu_mi.get(coff); + try zcu_member.initHeader(coff, zcu.main_mod.fully_qualified_name, timestamp); + + break :parent zcu_member.content_ni; + } + + // These placeholder nodes are placed before the first member - if there are + // no other members then the last linker member (longnames) needs to expand + // to fill the padding at the end of the file. + assert(Node.known.zcu_member_header == try coff.mf.addNodeAfter(gpa, Node.known.header, .{})); + assert(Node.known.zcu_member == try coff.mf.addNodeAfter(gpa, Node.known.header, .{})); + coff.nodes.appendAssumeCapacity(.placeholder); + coff.nodes.appendAssumeCapacity(.placeholder); + + break :parent null; + } else parent: { + // TODO: Not ideal to have this many placeholder nodes - use two distinct `Node.known` types? + while (true) { + const placeholder_ni = try coff.mf.addLastChildNode(gpa, Node.known.file, .{}); + coff.nodes.appendAssumeCapacity(.placeholder); + if (placeholder_ni == Node.known.zcu_member) break; + } + + break :parent Node.known.header; + }; + + const coff_parent_ni = opt_coff_parent_ni orelse { + // If we're not generating any code, no more known nodes are used + while (coff.nodes.len < Node.known_count) { + _ = try coff.mf.addNodeAfter(gpa, Node.known.header, .{}); + coff.nodes.appendAssumeCapacity(.placeholder); + } + + return; + }; + const coff_header_ni = Node.known.coff_header; - assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ + assert(coff_header_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ .size = @sizeOf(std.coff.Header), .alignment = .@"4", .fixed = true, @@ -834,7 +1954,7 @@ fn initHeaders( } const optional_header_ni = Node.known.optional_header; - assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ + assert(optional_header_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ .size = optional_header_size, .alignment = .@"4", .fixed = true, @@ -876,7 +1996,7 @@ fn initHeaders( .size_of_image = 0, .size_of_headers = 0, .checksum = 0, - .subsystem = .WINDOWS_CUI, + .subsystem = subsystem, .dll_flags = .{ .HIGH_ENTROPY_VA = true, .DYNAMIC_BASE = true, @@ -925,7 +2045,7 @@ fn initHeaders( .size_of_image = 0, .size_of_headers = 0, .checksum = 0, - .subsystem = .WINDOWS_CUI, + .subsystem = subsystem, .dll_flags = .{ .HIGH_ENTROPY_VA = true, .DYNAMIC_BASE = true, @@ -946,13 +2066,13 @@ fn initHeaders( } const data_directories_ni = Node.known.data_directories; - assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ + assert(data_directories_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ .size = data_directories_size, .alignment = .@"4", .fixed = true, })); coff.nodes.appendAssumeCapacity(.data_directories); - { + if (is_image) { const data_directories = coff.dataDirectorySlice(); @memset(data_directories, .{ .virtual_address = 0, .size = 0 }); if (target_endian != native_endian) std.mem.byteSwapAllFields( @@ -962,7 +2082,7 @@ fn initHeaders( } const section_table_ni = Node.known.section_table; - assert(section_table_ni == try coff.mf.addLastChildNode(gpa, header_ni, .{ + assert(section_table_ni == try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ .alignment = .@"4", .fixed = true, })); @@ -970,65 +2090,292 @@ fn initHeaders( assert(coff.nodes.len == Node.known_count); - try coff.symbol_table.ensureTotalCapacity(gpa, Symbol.Index.known_count); - coff.symbol_table.addOneAssumeCapacity().* = .{ - .ni = .none, - .rva = 0, - .size = 0, - .loc_relocs = .none, - .target_relocs = .none, - .section_number = .UNDEFINED, - }; - assert(try coff.addSection(".data", .{ + if (!is_image) { + // TODO: These two nodes could be inside one movable node? + coff.symbol_table.ni = try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ + .alignment = .@"2", + .fixed = true, + .moved = true, + }); + coff.nodes.appendAssumeCapacity(.symbol_table); + + coff.symbol_table.strings_ni = try coff.mf.addLastChildNode(gpa, coff_parent_ni, .{ + .size = @sizeOf(u32), + .fixed = true, + .resized = true, + }); + coff.nodes.appendAssumeCapacity(.string_table); + coff.targetStore(coff.symbolTableStringLenPtr(), @sizeOf(u32)); + } + + try coff.symbols.ensureTotalCapacity(gpa, Symbol.Index.known_count); + assert(coff.addSymbolAssumeCapacity() == .null); + + // TODO: How do we tell MappedFile not to allocate physical space for .bss? + // TODO: Could have a node flag 'virtual' that can never have slice* or fileLocation called on it + // TODO: Instead of it's own section, place .bss as a pseudo-section at the end of .text in the extra space + assert(try coff.addSection(.@".bss", .{ + .CNT_UNINITIALIZED_DATA = true, + .MEM_READ = true, + .MEM_WRITE = true, + }) == .bss); + assert(try coff.addSection(.@".data", .{ .CNT_INITIALIZED_DATA = true, .MEM_READ = true, .MEM_WRITE = true, }) == .data); - assert(try coff.addSection(".rdata", .{ + assert(try coff.addSection(.@".rdata", .{ .CNT_INITIALIZED_DATA = true, .MEM_READ = true, }) == .rdata); - assert(try coff.addSection(".text", .{ + assert(try coff.addSection(.@".text", .{ .CNT_CODE = true, .MEM_EXECUTE = true, .MEM_READ = true, }) == .text); - coff.import_table.ni = try coff.mf.addLastChildNode( - gpa, - (try coff.objectSectionMapIndex( - .@".idata", + if (is_image) { + if (comp.config.link_libc and target.abi == .msvc) { + // This section contains a function pointer table used by control flow guard: + // https://learn.microsoft.com/en-us/windows/win32/secbp/control-flow-guard + // The page containing it is set to PAGE_READONLY during startup, so this can't + // be merged into .data this protection would overlap writable memory. + _ = try coff.addSection(.@".fptable", .{ + .CNT_INITIALIZED_DATA = true, + .MEM_READ = true, + .MEM_WRITE = true, + }); + } + + // TODO: Lazily initialize this instead, avoid the extra logic for this in flushMoved / flushResized + coff.import_table.ni = try coff.mf.addLastChildNode( + gpa, + (try coff.objectSectionMapIndex( + .@".idata", + coff.mf.flags.block_size, + .{ .read = true, .initialized = true }, + )).symbol(coff).node(coff), + .{ .alignment = .@"4" }, + ); + coff.nodes.appendAssumeCapacity(.import_directory_table); + + coff.export_table.ni = (try coff.pseudoSectionMapIndex( + .@".edata", + .of(std.coff.ExportDirectoryTable), + .{ .read = true, .initialized = true }, + )).symbol(coff).node(coff); + + coff.export_table.export_directory_table_ni = try coff.mf.addLastChildNode( + gpa, + coff.export_table.ni, + .{ + .size = @sizeOf(std.coff.ExportDirectoryTable) + file_name.len + 1, + .moved = true, + .fixed = true, + }, + ); + coff.nodes.appendAssumeCapacity(.export_directory_table); + + const name_index = @sizeOf(std.coff.ExportDirectoryTable); + const table_slice = coff.export_table.export_directory_table_ni.slice(&coff.mf); + @memcpy(table_slice[name_index..][0..file_name.len], file_name[0..file_name.len]); + @memset(table_slice[name_index + file_name.len ..], 0); + + const export_address_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ + .alignment = .of(std.coff.ExportAddressTableEntry), + .moved = true, + }); + coff.nodes.appendAssumeCapacity(.export_address_table); + + try coff.symbols.ensureUnusedCapacity(gpa, 1); + coff.export_table.export_address_table_si = coff.addSymbolAssumeCapacity(); + + const export_address_table_sym = coff.export_table.export_address_table_si.get(coff); + export_address_table_sym.ni = export_address_table_ni; + assert(export_address_table_sym.loc_relocs == .none); + export_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + export_address_table_sym.section_number = + coff.getNode(coff.export_table.ni).pseudo_section.symbol(coff).get(coff).section_number; + + coff.export_table.name_pointer_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ + .alignment = .of(std.coff.ExportNamePointerTableEntry), + .moved = true, + }); + coff.nodes.appendAssumeCapacity(.export_name_pointer_table); + + coff.export_table.ordinal_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ + .alignment = .of(std.coff.ExportOrdinalTableEntry), + .moved = true, + }); + coff.nodes.appendAssumeCapacity(.export_ordinal_table); + + coff.export_table.name_table_ni = try coff.mf.addLastChildNode(gpa, coff.export_table.ni, .{ + .alignment = .of(u8), + .moved = true, + }); + coff.nodes.appendAssumeCapacity(.export_name_table); + + const export_directory_table = coff.exportDirectoryTable(); + export_directory_table.* = .{ + .flags = 0, + .time_date_stamp = timestamp, + .major_version = 0, + .minor_version = 0, + .name_rva = 0, + .ordinal_base = 1, + .number_of_entries = 0, + .number_of_names = 0, + .export_address_table_rva = 0, + .name_pointer_table_rva = 0, + .ordinal_table_rva = 0, + }; + if (target_endian != native_endian) + std.mem.byteSwapAllFields(std.coff.ExportDirectoryTable, export_directory_table); + } + + if (comp.config.any_non_single_threaded) { + if (!is_image) + _ = try coff.addSection(.@".tls$", .{ + .CNT_INITIALIZED_DATA = true, + .MEM_READ = true, + .MEM_WRITE = true, + }); + + // While tls variables allocated at runtime are writable, the template itself is not. + // In images, the template is in a .tls pseudo section in .rdata. + // In objects / archives, this section is part of the above .tls$ section. The suffix + // is maintained so merging can occur with other input tls symbols when linked later. + _ = try coff.pseudoSectionMapIndex( + if (is_image) .@".tls" else .@".tls$", coff.mf.flags.block_size, - .{ .read = true }, - )).symbol(coff).node(coff), - .{ .alignment = .@"4", .moved = true }, - ); - coff.nodes.appendAssumeCapacity(.import_directory_table); - - // While tls variables allocated at runtime are writable, the template itself is not - if (comp.config.any_non_single_threaded) _ = try coff.objectSectionMapIndex( - .@".tls$", - coff.mf.flags.block_size, - .{ .read = true }, - ); - - assert(coff.nodes.len == expected_nodes_len); + .{ .read = true, .write = !is_image, .initialized = true }, + ); + } +} + +pub fn initBuiltins(coff: *Coff) !void { + const comp = coff.base.comp; + const gpa = comp.gpa; + const target = &comp.root_mod.resolved_target.result; + if (coff.isImage()) { + const si = try coff.globalSymbol(.{ .name = "__ImageBase", .type = .data }); + const sym = si.get(coff); + sym.ni = Node.known.header; + } + + defer coff.flushSectionMerges() catch unreachable; + if (coff.isImage() and target.isMinGW() and comp.config.link_libc) { + try coff.symbols.ensureUnusedCapacity(gpa, 8); + try coff.globals.ensureUnusedCapacity(gpa, 2); + try coff.nodes.ensureUnusedCapacity(gpa, 8); + try coff.section_merges.ensureUnusedCapacity(gpa, 2); + + const lists: []const struct { global: []const u8, start: String, end: String } = &.{ + .{ .global = "__CTOR_LIST__", .start = .@".ctors", .end = .@".ctors$ZZZ" }, + .{ .global = "__DTOR_LIST__", .start = .@".dtors", .end = .@".dtors$ZZZ" }, + }; + + // We need to explicitly merge these into .rdata as in objects they can be marked + // as MEM_WRITE, and would have mismatced section flags. + try coff.section_merges.put(gpa, .@".ctors", .@".rdata"); + try coff.section_merges.put(gpa, .@".dtors", .@".rdata"); + + for (lists) |list| { + const addr_info = coff.targetAddrInfo(); + + // Any .(c|d)tor$(.*) input sections will merge in between these sections + const start_osmi = try coff.objectSectionMapIndex( + list.start, + addr_info.alignment, + .{ .read = true, .initialized = true }, + ); + const end_osmi = try coff.objectSectionMapIndex( + list.end, + addr_info.alignment, + .{ .read = true, .initialized = true }, + ); + + // Additional nodes are used here, instead of just adding the sentinel + // directly to the section data, since once input sections are added + // as children, they would overwrite that data. + const start_sym = start_osmi.symbol(coff).get(coff); + const list_len_si = try coff.globalSymbol(.{ .name = list.global, .type = .data }); + const list_len_sym = list_len_si.get(coff); + list_len_sym.setExtra(.{ .size = addr_info.size }); + list_len_sym.ni = try coff.mf.addFirstChildNode(gpa, start_sym.ni, .{ + .size = addr_info.size, + .fixed = true, + }); + coff.nodes.appendAssumeCapacity(.{ .builtin = list_len_si }); + list_len_sym.section_number = start_sym.section_number; + + const start_slice = list_len_sym.ni.slice(&coff.mf); + switch (addr_info.magic) { + _ => unreachable, + inline .PE32, .@"PE32+" => |t| { + const addr: *TargetAddr(t) = @ptrCast(@alignCast(start_slice)); + // For __CTOR_LIST__ -1 indicates that the list is null terminated. + // For __DTOR_LIST__, this value is ignored, the list is always null terminated + coff.targetStore(addr, std.math.maxInt(TargetAddr(t))); + }, + } + + const end_sym = end_osmi.symbol(coff).get(coff); + const list_end_si = coff.addSymbolAssumeCapacity(); + const list_end_sym = list_end_si.get(coff); + list_end_sym.setExtra(.{ .size = addr_info.size }); + list_end_sym.ni = try coff.mf.addFirstChildNode(gpa, end_sym.ni, .{ + .size = addr_info.size, + .fixed = true, + }); + coff.nodes.appendAssumeCapacity(.{ .builtin = list_end_si }); + list_end_sym.section_number = start_sym.section_number; + + @memset(list_end_sym.ni.slice(&coff.mf), 0); + + try list_len_si.flushMoved(coff); + try list_end_si.flushMoved(coff); + } + } } pub fn startProgress(coff: *Coff, prog_node: std.Progress.Node) void { prog_node.increaseEstimatedTotalItems(3); coff.const_prog_node = prog_node.start("Constants", coff.pending_uavs.count()); coff.synth_prog_node = prog_node.start("Synthetics", count: { - var count = coff.globals.count() - coff.global_pending_index; + var count = + coff.globals.count() - coff.global_pending_index + + coff.section_merges.count() - coff.section_merge_pending_index; + for (&coff.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; break :count count; }); + if (!isImage(coff)) { + prog_node.increaseEstimatedTotalItems(2); + coff.symbol_prog_node = prog_node.start( + "Symbols", + coff.symbol_table.symbols.count() - coff.symbol_table.pending_symbol_index, + ); + coff.member_prog_node = prog_node.start("Members", coff.pending_members.count()); + } + coff.input_prog_node = prog_node.start( + "Inputs", + coff.input_sections.items.len - coff.input_section_pending_index, + ); coff.mf.update_prog_node = prog_node.start("Relocations", coff.mf.updates.items.len); } pub fn endProgress(coff: *Coff) void { coff.mf.update_prog_node.end(); coff.mf.update_prog_node = .none; + coff.input_prog_node.end(); + coff.input_prog_node = .none; + if (!coff.isImage()) { + coff.member_prog_node.end(); + coff.member_prog_node = .none; + coff.symbol_prog_node.end(); + coff.symbol_prog_node = .none; + } coff.synth_prog_node.end(); coff.synth_prog_node = .none; coff.const_prog_node.end(); @@ -1044,10 +2391,20 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { .file, .header, .signature, + .archive_member_header, + .archive_member, .coff_header, .optional_header, .data_directories, .section_table, + .export_name_table, + .placeholder, + .symbol_table, + .string_table, + .relocation_table, + .relocation_table_entry, + .input_section, + .builtin, => unreachable, .image_section => |si| si, .import_directory_table => break :parent_rva coff.targetLoad( @@ -1062,9 +2419,21 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { .import_hint_name_table => |import_index| break :parent_rva coff.targetLoad( &coff.importDirectoryEntryPtr(import_index).name_rva, ), + .export_directory_table => break :parent_rva coff.targetLoad( + &coff.dataDirectoryPtr(.EXPORT).virtual_address, + ), + .export_address_table => break :parent_rva coff.targetLoad( + &coff.exportDirectoryTable().export_address_table_rva, + ), + .export_name_pointer_table => break :parent_rva coff.targetLoad( + &coff.exportDirectoryTable().name_pointer_table_rva, + ), + .export_ordinal_table => break :parent_rva coff.targetLoad( + &coff.exportDirectoryTable().ordinal_table_rva, + ), inline .pseudo_section, .object_section, - .global, + .import_thunk, .nav, .uav, .lazy_code, @@ -1076,24 +2445,55 @@ fn computeNodeRva(coff: *Coff, ni: MappedFile.Node.Index) u32 { const offset, _ = ni.location(&coff.mf).resolve(&coff.mf); return @intCast(parent_rva + offset); } -fn computeNodeSectionOffset(coff: *Coff, ni: MappedFile.Node.Index) u32 { - var section_offset: u32 = 0; - var parent_ni = ni; + +fn computeSymbolSectionOffset( + coff: *Coff, + sym: *const Symbol, + relative_to: enum { image, pseudo }, +) u32 { + var section_offset: u32 = sym.nodeOffset(coff); + var parent_ni = sym.ni; while (true) { const offset, _ = parent_ni.location(&coff.mf).resolve(&coff.mf); section_offset += @intCast(offset); parent_ni = parent_ni.parent(&coff.mf); switch (coff.getNode(parent_ni)) { else => unreachable, - .image_section, .pseudo_section => return section_offset, - .object_section => {}, + .image_section => break, + .pseudo_section => if (relative_to == .pseudo) break, + .object_section, + => {}, } } + + return section_offset; } pub inline fn targetEndian(_: *const Coff) std.lang.Endian { return .little; } + +fn targetAddrInfo(coff: *Coff) struct { + size: u8, + alignment: std.mem.Alignment, + magic: std.coff.OptionalHeader.Magic, +} { + const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); + switch (magic) { + _ => unreachable, + .PE32 => return .{ .size = 4, .alignment = .@"4", .magic = magic }, + .@"PE32+" => return .{ .size = 8, .alignment = .@"8", .magic = magic }, + } +} + +fn TargetAddr(comptime magic: std.coff.OptionalHeader.Magic) type { + return switch (magic) { + _ => comptime unreachable, + .PE32 => u32, + .@"PE32+" => u64, + }; +} + fn targetLoad(coff: *const Coff, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.child { const Child = @typeInfo(@TypeOf(ptr)).pointer.child; return switch (@typeInfo(Child)) { @@ -1122,9 +2522,55 @@ fn targetStore(coff: *const Coff, ptr: anytype, val: @typeInfo(@TypeOf(ptr)).poi } pub fn headerPtr(coff: *Coff) *std.coff.Header { + assert(coff.hasCoffHeader()); return @ptrCast(@alignCast(Node.known.coff_header.slice(&coff.mf))); } +pub fn firstLinkerMemberNumSymbolsPtr(coff: *Coff) *u32 { + assert(coff.isArchive()); + return @ptrCast(@alignCast(Node.known.first_linker_member.slice(&coff.mf))); +} + +pub fn firstLinkerMemberOffsetsSlice(coff: *Coff) []u32 { + const len = std.mem.toNative(u32, coff.firstLinkerMemberNumSymbolsPtr().*, .big); + return @ptrCast(@alignCast(Node.known.first_linker_member.slice(&coff.mf)[@sizeOf(u32)..][0 .. len * @sizeOf(u32)])); +} + +pub fn secondLinkerMemberNumMembersPtr(coff: *Coff) *align(2) u32 { + assert(coff.isArchive()); + return @ptrCast(@alignCast(Node.known.second_linker_member.slice(&coff.mf))); +} + +pub fn secondLinkerMemberOffsetsSlice(coff: *Coff) []align(2) u32 { + const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); + return @ptrCast(@alignCast( + Node.known.second_linker_member.slice(&coff.mf)[@sizeOf(u32)..][0 .. num_members * @sizeOf(u32)], + )); +} + +pub fn secondLinkerMemberNumSymbolsPtr(coff: *Coff) *align(2) u32 { + const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); + return @ptrCast(@alignCast( + Node.known.second_linker_member.slice(&coff.mf)[(1 + num_members) * @sizeOf(u32) ..], + )); +} + +pub fn secondLinkerMemberIndicesSlice(coff: *Coff) []u16 { + const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); + const num_symbols = coff.targetLoad(coff.secondLinkerMemberNumSymbolsPtr()); + return @ptrCast(@alignCast( + Node.known.second_linker_member.slice(&coff.mf)[(2 + num_members) * @sizeOf(u32) ..][0 .. num_symbols * @sizeOf(u16)], + )); +} + +pub fn secondLinkerMemberStringsSlice(coff: *Coff) []u8 { + const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); + const num_symbols = coff.targetLoad(coff.secondLinkerMemberNumSymbolsPtr()); + return @ptrCast(@alignCast( + Node.known.second_linker_member.slice(&coff.mf)[(2 + num_members) * @sizeOf(u32) + num_symbols * @sizeOf(u16) ..], + )); +} + pub fn optionalHeaderStandardPtr(coff: *Coff) *std.coff.OptionalHeader { return @ptrCast(@alignCast( Node.known.optional_header.slice(&coff.mf)[0..@sizeOf(std.coff.OptionalHeader)], @@ -1136,6 +2582,7 @@ pub const OptionalHeaderPtr = union(std.coff.OptionalHeader.Magic) { @"PE32+": *std.coff.OptionalHeader.@"PE32+", }; pub fn optionalHeaderPtr(coff: *Coff) OptionalHeaderPtr { + assert(coff.isImage()); const slice = Node.known.optional_header.slice(&coff.mf); return switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { _ => unreachable, @@ -1150,6 +2597,7 @@ pub fn optionalHeaderField( coff: *Coff, comptime field: std.meta.FieldEnum(std.coff.OptionalHeader.@"PE32+"), ) @FieldType(std.coff.OptionalHeader.@"PE32+", @tagName(field)) { + assert(coff.isImage()); return switch (coff.optionalHeaderPtr()) { inline else => |optional_header| coff.targetLoad(&@field(optional_header, @tagName(field))), }; @@ -1158,6 +2606,7 @@ pub fn optionalHeaderField( pub fn dataDirectorySlice( coff: *Coff, ) *[std.coff.IMAGE.DIRECTORY_ENTRY.len]std.coff.ImageDataDirectory { + assert(coff.isImage()); return @ptrCast(@alignCast(Node.known.data_directories.slice(&coff.mf))); } pub fn dataDirectoryPtr( @@ -1168,10 +2617,48 @@ pub fn dataDirectoryPtr( } pub fn sectionTableSlice(coff: *Coff) []std.coff.SectionHeader { - return @ptrCast(@alignCast(Node.known.section_table.slice(&coff.mf))); + return @ptrCast(@alignCast( + Node.known.section_table.slice(&coff.mf)[0 .. coff.section_table.count() * @sizeOf(std.coff.SectionHeader)], + )); +} + +pub fn symbolTableEntryStoragePtr(coff: *Coff, index: u32) *[std.coff.Symbol.sizeOf()]u8 { + assert(!coff.isImage()); + const offset = index * std.coff.Symbol.sizeOf(); + return @ptrCast(@alignCast(coff.symbol_table.ni.slice(&coff.mf)[offset..][0..std.coff.Symbol.sizeOf()])); +} + +pub fn symbolTableEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.coff.Symbol { + if (sti.unwrap()) |index| + return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, index))) + else + return null; +} + +pub fn symbolTableSectionAuxEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.coff.SectionDefinition { + if (symbolTableEntryPtr(coff, sti)) |entry| { + assert(entry.storage_class == .STATIC and entry.number_of_aux_symbols == 1); + return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, sti.unwrap().? + 1))); + } else { + return null; + } +} + +pub fn symbolTableWeakExternalAuxEntryPtr(coff: *Coff, sti: SymbolTable.Index) ?*align(2) std.coff.WeakExternalDefinition { + if (symbolTableEntryPtr(coff, sti)) |entry| { + assert(entry.storage_class == .WEAK_EXTERNAL and entry.number_of_aux_symbols == 1); + return @ptrCast(@alignCast(symbolTableEntryStoragePtr(coff, sti.unwrap().? + 1))); + } else { + return null; + } +} + +pub fn symbolTableStringLenPtr(coff: *Coff) *align(1) u32 { + return @ptrCast(@alignCast(coff.symbol_table.strings_ni.slice(&coff.mf)[0..@sizeOf(u32)])); } pub fn importDirectoryTableSlice(coff: *Coff) []std.coff.ImportDirectoryEntry { + assert(coff.isImage()); return @ptrCast(@alignCast(coff.import_table.ni.slice(&coff.mf))); } pub fn importDirectoryEntryPtr( @@ -1181,16 +2668,40 @@ pub fn importDirectoryEntryPtr( return &coff.importDirectoryTableSlice()[@intFromEnum(import_index)]; } +pub fn exportDirectoryTable(coff: *Coff) *std.coff.ExportDirectoryTable { + return @ptrCast(@alignCast(coff.export_table.export_directory_table_ni.slice(&coff.mf))); +} + +pub fn exportNamePointerTableSlice(coff: *Coff) []std.coff.ExportNamePointerTableEntry { + const debug = coff.export_table.name_pointer_table_ni.slice(&coff.mf); + _ = debug; + + return @ptrCast(@alignCast(coff.export_table.name_pointer_table_ni.slice(&coff.mf))); +} + +pub fn exportOrdinalTableSlice(coff: *Coff) []std.coff.ExportOrdinalTableEntry { + return @ptrCast(@alignCast(coff.export_table.ordinal_table_ni.slice(&coff.mf))); +} + fn addSymbolAssumeCapacity(coff: *Coff) Symbol.Index { - defer coff.symbol_table.addOneAssumeCapacity().* = .{ + defer coff.symbols.addOneAssumeCapacity().* = .{ .ni = .none, .rva = 0, - .size = 0, + .value = .{ .none = {} }, + .extra = .{ .size = 0 }, + .flags = .{ + .value_tag = .none, + .extra_tag = .size, + .type = .unknown, + .dll_storage_class = .default, + .weak_external_strat = .none, + }, .loc_relocs = .none, .target_relocs = .none, .section_number = .UNDEFINED, + .gmi = .none, }; - return @enumFromInt(coff.symbol_table.items.len); + return @enumFromInt(coff.symbols.items.len); } fn initSymbolAssumeCapacity(coff: *Coff) !Symbol.Index { @@ -1205,12 +2716,55 @@ fn getOrPutString(coff: *Coff, string: []const u8) !String { fn getOrPutOptionalString(coff: *Coff, string: ?[]const u8) !String.Optional { return (try coff.getOrPutString(string orelse return .none)).toOptional(); } +fn getString(coff: *Coff, string: []const u8) String.Optional { + if (coff.strings.getKeyAdapted( + string, + std.hash_map.StringIndexAdapter{ .bytes = &coff.string_bytes }, + )) |key| + return @as(String, @enumFromInt(key)).toOptional() + else + return .none; +} +/// If the name does not fit in the symbol header, adds it to the symbol table string table. +/// If the caller knows this name already has a String associated with it, they can avoid +/// a redundant call to `getOrPutString` by specifying `opt_string`. +/// The lifetime of the return value matches that of `name`. +fn getOrPutSymbolName(coff: *Coff, name: []const u8, opt_string: ?String) !SymbolTable.SymbolName { + assert(!coff.isImage()); + const gpa = coff.base.comp.gpa; + + return if (name.len > header_name_max_len) name: { + const string = opt_string orelse try coff.getOrPutString(name); + const string_gop = try coff.symbol_table.strings.getOrPut(gpa, string); + if (!string_gop.found_existing) { + const string_index = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf)[1]; + string_gop.value_ptr.* = @enumFromInt(string_index); + + try coff.symbol_table.strings_ni.resize(&coff.mf, gpa, string_index + name.len + 1); + const slice = coff.symbol_table.strings_ni.slice(&coff.mf); + @memcpy(slice[@intCast(string_index)..][0..name.len], name); + slice[@intCast(string_index + name.len)] = 0; + } + + break :name .{ .long = string_gop.value_ptr.* }; + } else .{ .short = name }; +} + +/// `len` does not include null terminators fn ensureUnusedStringCapacity(coff: *Coff, len: usize) !void { const gpa = coff.base.comp.gpa; try coff.strings.ensureUnusedCapacityContext(gpa, 1, .{ .bytes = &coff.string_bytes }); try coff.string_bytes.ensureUnusedCapacity(gpa, len + 1); } + +/// `total_len` includes null terminators +fn ensureManyUnusedStringCapacity(coff: *Coff, num_strings: u32, total_len: usize) !void { + const gpa = coff.base.comp.gpa; + try coff.strings.ensureUnusedCapacityContext(gpa, num_strings, .{ .bytes = &coff.string_bytes }); + try coff.string_bytes.ensureUnusedCapacity(gpa, total_len + num_strings); +} + fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { const gop = coff.strings.getOrPutAssumeCapacityAdapted( string, @@ -1225,18 +2779,78 @@ fn getOrPutStringAssumeCapacity(coff: *Coff, string: []const u8) String { return @enumFromInt(gop.key_ptr.*); } -pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbol.Index { - const gpa = coff.base.comp.gpa; - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); - const sym_gop = try coff.globals.getOrPut(gpa, .{ - .name = try coff.getOrPutString(name), - .lib_name = try coff.getOrPutOptionalString(lib_name), - }); +const GlobalOptions = struct { + name: []const u8, + lib_name: ?[]const u8 = null, + type: Symbol.Type = .unknown, + dll_storage_class: Symbol.DllStorageClass = .default, +}; + +fn getOrPutGlobalSymbol( + coff: *Coff, + opts: GlobalOptions, +) !std.array_hash_map.Auto(String, Global).GetOrPutResult { + const comp = coff.base.comp; + const gpa = comp.gpa; + try coff.symbols.ensureUnusedCapacity(gpa, 1); + + const lib_name: String.Optional = if (opts.lib_name) |lib_name| lib_name: { + const is_libc = std.zig.target.isLibCLibName(&comp.root_mod.resolved_target.result, lib_name); + if (is_libc) { + // This is guaranteed by Sema.handleExternLibName + if (!comp.config.link_libc) unreachable; + + // TODO: The user has requested this symbol come from libc, but this logic allows + // it to come from anywhere. We need to know what inputs are libc inputs, + // and set a flag to only search them for this symbol. + break :lib_name .none; + } + + break :lib_name (try coff.getOrPutString(lib_name)).toOptional(); + } else .none; + + const sym_gop = try coff.globals.getOrPut(gpa, try coff.getOrPutString(opts.name)); if (!sym_gop.found_existing) { - sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); + const si = coff.addSymbolAssumeCapacity(); + const sym = si.get(coff); + sym.gmi = .wrap(@intCast(sym_gop.index)); + sym.flags.type = opts.type; + sym.flags.dll_storage_class = opts.dll_storage_class; + sym_gop.value_ptr.* = .{ + .si = si, + .lib_name = lib_name, + }; coff.synth_prog_node.increaseEstimatedTotalItems(1); + + log.debug("globalSymbol({s}, {?s}) = {d}", .{ opts.name, opts.lib_name, si }); + } + + return sym_gop; +} + +fn getDefinedGlobal(coff: *Coff, name: []const u8) Symbol.Index { + if (coff.globals.get( + coff.getString(name).unwrap() orelse return .null, + )) |global| if (global.si.get(coff).ni != .none) return global.si; + return .null; +} + +pub fn globalSymbol(coff: *Coff, opts: GlobalOptions) !Symbol.Index { + const gop = try coff.getOrPutGlobalSymbol(opts); + return gop.value_ptr.si; +} + +pub fn pendingSymbolTableEntry(coff: *Coff, si: Symbol.Index) !void { + assert(!coff.isImage()); + const sym = si.get(coff); + + assert(sym.ni != .none or sym.gmi != .none); + const gpa = coff.base.comp.gpa; + const gop = try coff.symbol_table.symbols.getOrPut(gpa, si); + if (!gop.found_existing) { + coff.symbol_prog_node.increaseEstimatedTotalItems(1); + gop.value_ptr.* = .none; } - return sym_gop.value_ptr.*; } fn navSection( @@ -1247,13 +2861,13 @@ fn navSection( const ip = &zcu.intern_pool; const default: String, const attributes: ObjectSectionAttributes = if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{ - .@".tls$", .{ .read = true, .write = true }, + .@".tls$", .{ .read = true, .write = true, .initialized = true }, } else if (ip.isFunctionType(nav_resolved.type)) .{ .@".text", .{ .read = true, .execute = true }, } else if (nav_resolved.@"const") .{ - .@".rdata", .{ .read = true }, + .@".rdata", .{ .read = true, .initialized = true }, } else .{ - .@".data", .{ .read = true, .write = true }, + .@".data", .{ .read = true, .write = true, .initialized = true }, }; return (try coff.objectSectionMapIndex( @@ -1270,7 +2884,7 @@ fn navSection( } fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { const gpa = zcu.gpa; - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); + try coff.symbols.ensureUnusedCapacity(gpa, 1); const sym_gop = try coff.navs.getOrPut(gpa, nav_index); if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); return @enumFromInt(sym_gop.index); @@ -1278,17 +2892,20 @@ fn navMapIndex(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.Na pub fn navSymbol(coff: *Coff, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); - if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol( - @"extern".name.toSlice(ip), - @"extern".lib_name.toSlice(ip), - ); + if (nav.getExtern(ip)) |@"extern"| return coff.globalSymbol(.{ + .name = @"extern".name.toSlice(ip), + .lib_name = @"extern".lib_name.toSlice(ip), + // TODO: Threadlocal as well? + .type = if (ip.isFunctionType(nav.resolved.?.type)) .code else .data, + .dll_storage_class = if (@"extern".is_dll_import) .dllimport else .default, + }); const nmi = try coff.navMapIndex(zcu, nav_index); return nmi.symbol(coff); } fn uavMapIndex(coff: *Coff, uav_val: InternPool.Index) !Node.UavMapIndex { const gpa = coff.base.comp.gpa; - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); + try coff.symbols.ensureUnusedCapacity(gpa, 1); const sym_gop = try coff.uavs.getOrPut(gpa, uav_val); if (!sym_gop.found_existing) sym_gop.value_ptr.* = coff.addSymbolAssumeCapacity(); return @enumFromInt(sym_gop.index); @@ -1300,7 +2917,7 @@ pub fn uavSymbol(coff: *Coff, uav_val: InternPool.Index) !Symbol.Index { pub fn lazySymbol(coff: *Coff, lazy: link.File.LazySymbol) !Symbol.Index { const gpa = coff.base.comp.gpa; - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); + try coff.symbols.ensureUnusedCapacity(gpa, 1); const sym_gop = try coff.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); if (!sym_gop.found_existing) { sym_gop.value_ptr.* = try coff.initSymbolAssumeCapacity(); @@ -1314,7 +2931,7 @@ pub fn getNavVAddr( pt: Zcu.PerThread, nav: InternPool.Nav.Index, reloc_info: link.File.RelocInfo, -) !u64 { +) link.Error!u64 { return coff.getVAddr(reloc_info, try coff.navSymbol(pt.zcu, nav)); } @@ -1322,30 +2939,426 @@ pub fn getUavVAddr( coff: *Coff, uav: InternPool.Index, reloc_info: link.File.RelocInfo, -) !u64 { +) link.Error!u64 { return coff.getVAddr(reloc_info, try coff.uavSymbol(uav)); } -pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { +pub fn getVAddr(coff: *Coff, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) link.Error!u64 { try coff.addReloc( @enumFromInt(@intFromEnum(reloc_info.parent.atom_index)), reloc_info.offset, target_si, - reloc_info.addend, + .{ .known = reloc_info.addend }, switch (coff.targetLoad(&coff.headerPtr().machine)) { else => unreachable, .AMD64 => .{ .AMD64 = .ADDR64 }, .I386 => .{ .I386 = .DIR32 }, }, ); - return coff.optionalHeaderField(.image_base) + target_si.get(coff).rva; + + var vaddr: u64 = target_si.get(coff).rva; + if (coff.isImage()) vaddr += coff.optionalHeaderField(.image_base); + return vaddr; +} + +/// Caller guarantees there is capacity for one member and two nodes +fn addMemberAssumeCapacity(coff: *Coff, kind: std.coff.ArchiveMemberHeader.Kind, size: u64) !Member.Index { + const comp = coff.base.comp; + const gpa = comp.gpa; + + // TODO: These two nodes could to be inside a movable node if kind == .coff|.import + const header_ni = try coff.mf.addLastChildNode(gpa, Node.known.file, .{ + .size = @sizeOf(std.coff.ArchiveMemberHeader), + .alignment = .@"2", + .fixed = true, + .moved = true, + }); + + const content_ni = try coff.mf.addLastChildNode(gpa, Node.known.file, .{ + // The actual alignment required by the spec is 2, but to allow aligned access to + // the various COFF data structures in-place during linking we overalign + .alignment = switch (kind) { + .coff => .@"4", + else => .@"2", + }, + .size = size, + .resized = size > 0, + .fixed = true, + }); + + const mi: Member.Index = @enumFromInt(coff.members.items.len); + coff.members.appendAssumeCapacity(.{ + .kind = kind, + .header_ni = header_ni, + .content_ni = content_ni, + .first_linker_indices = .empty, + }); + + coff.nodes.appendAssumeCapacity(.{ .archive_member_header = mi }); + coff.nodes.appendAssumeCapacity(.{ .archive_member = mi }); + + switch (kind) { + .first_linker, .second_linker, .longnames => {}, + else => { + const new_num_members = coff.members.items.len - Member.Index.known_count; + coff.targetStore( + coff.secondLinkerMemberNumMembersPtr(), + @intCast(new_num_members), + ); + + const old_size = Node.known.second_linker_member.location(&coff.mf).resolve(&coff.mf)[1]; + const old_header_size = new_num_members * @sizeOf(u32); + const trailing_size: usize = @intCast(old_size - old_header_size); + try Node.known.second_linker_member.resize(&coff.mf, gpa, old_size + @sizeOf(u32)); + + const slice = Node.known.second_linker_member.slice(&coff.mf); + @memmove( + slice[old_header_size + @sizeOf(u32) ..][0..trailing_size], + slice[old_header_size..][0..trailing_size], + ); + + // Offset will be written by flushMoved on header_ni + }, + } + + switch (kind) { + .first_linker, + .longnames, + .import, + => {}, + .second_linker, + .coff, + => { + try coff.pending_members.ensureTotalCapacity( + gpa, + coff.pending_members.capacity() + 1, + ); + coff.member_prog_node.increaseEstimatedTotalItems(1); + }, + } + + return mi; +} + +fn appendMemberSymbolString( + coff: *Coff, + strings_ni: MappedFile.Node.Index, + new_size: u64, + name: []const u8, + offset: u64, +) !void { + try strings_ni.resize(&coff.mf, coff.base.comp.gpa, new_size); + const name_slice = strings_ni.slice(&coff.mf)[offset..][0 .. name.len + 1]; + @memcpy(name_slice[0..name.len], name); + name_slice[name.len] = 0; } -fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags) !Symbol.Index { +fn ensureMemberSymbol(coff: *Coff, mi: Member.Index, name: String) !void { + const gpa = coff.base.comp.gpa; + const member = mi.get(coff); + assert(member.kind == .coff); + + const gop = try member.first_linker_indices.getOrPut(gpa, .{ .mi = mi, .name = name }); + if (gop.found_existing) return; + + const mfli: Member.FirstLinkerIndex = blk: { + const num_symbols_ptr = coff.firstLinkerMemberNumSymbolsPtr(); + const num_symbols = std.mem.toNative(u32, num_symbols_ptr.*, .big); + num_symbols_ptr.* = std.mem.nativeTo(u32, num_symbols + 1, .big); + break :blk @enumFromInt(num_symbols); + }; + + gop.value_ptr.* = mfli; + + // Linker member fields are not modeled as nodes because MappedFile + // can't guarantee that they will be tightly packed after resizing + + const name_slice = name.toSlice(coff); + const new_string_table_size: u32 = @intCast(coff.lib_string_len + name_slice.len + 1); + defer coff.lib_string_len = new_string_table_size; + + { + const old_header_size: usize = @intCast(@sizeOf(u32) + @intFromEnum(mfli) * @sizeOf(u32)); + const new_header_size: usize = @intCast(old_header_size + @sizeOf(u32)); + try Node.known.first_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size); + + const slice = Node.known.first_linker_member.slice(&coff.mf); + @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); + @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]); + slice[new_header_size + coff.lib_string_len + name_slice.len] = 0; + + // New offset entry is written in flushMember + } + + { + const num_members = coff.targetLoad(coff.secondLinkerMemberNumMembersPtr()); + const old_header_size = 2 * @sizeOf(u32) + num_members * @sizeOf(u32) + @intFromEnum(mfli) * @sizeOf(u16); + const new_header_size = old_header_size + @sizeOf(u16); + try Node.known.second_linker_member.resize(&coff.mf, gpa, new_header_size + new_string_table_size); + + const old_needs_sort = coff.pending_members.get(Member.Index.second) != null; + const needs_sort = old_needs_sort or (if (coff.lib_string_table.items.len > 0) + std.mem.lessThan( + u8, + name_slice, + coff.lib_string_table.items[coff.lib_string_table.items.len - 1].toSlice(coff), + ) + else + false); + + try coff.lib_string_table.append(gpa, name); + + const slice = Node.known.second_linker_member.slice(&coff.mf); + coff.targetStore(coff.secondLinkerMemberNumSymbolsPtr(), @intFromEnum(mfli) + 1); + if (!needs_sort) { + @memmove(slice[new_header_size..][0..coff.lib_string_len], slice[old_header_size..][0..coff.lib_string_len]); + @memcpy(slice[new_header_size + coff.lib_string_len ..][0..name_slice.len], name_slice[0..name_slice.len]); + slice[new_header_size + coff.lib_string_len + name_slice.len] = 0; + } else if (!old_needs_sort) { + // The entire string table is rebuilt in flushMember after sorting + coff.pending_members.putAssumeCapacity(Member.Index.second, {}); + } + + // Indices in this table are 1-based + const index_ptr: *u16 = @ptrCast(@alignCast(slice[old_header_size..])); + coff.targetStore(index_ptr, @intCast(@intFromEnum(mi) - Member.Index.known_count + 1)); + } + + coff.pending_members.putAssumeCapacity(mi, {}); + coff.member_prog_node.increaseEstimatedTotalItems(1); +} + +fn flushSymbolTableEntry(coff: *Coff, index: u32, pt: Zcu.PerThread) !void { + assert(!coff.isImage()); + const gpa = coff.base.comp.gpa; + + const si = coff.symbol_table.symbols.keys()[index]; + const sti = &coff.symbol_table.symbols.values()[index]; + + const sym = si.get(coff); + assert(sym.ni != .none or sym.gmi != .none); + + const entry = coff.symbolTableEntryPtr(sti.*) orelse entry: { + var buf: [15]u8 = undefined; + const symbol_name, const num_aux_symbols: u8, const complex_type: std.coff.ComplexType = + if (sym.gmi != .none) blk: { + const name = sym.gmi.name(coff); + break :blk .{ + try coff.getOrPutSymbolName(name.toSlice(coff), name), + @intFromBool(sym.flags.weak_external_strat != .none), + if (Symbol.Index.text.get(coff).section_number == sym.section_number) + .FUNCTION + else + .NULL, + }; + } else blk: switch (coff.getNode(sym.ni)) { + .image_section => .{ + try coff.getOrPutSymbolName(&sym.section_number.header(coff).name, null), + 1, + .NULL, + }, + .nav => |nmi| { + const zcu = coff.base.comp.zcu.?; + const ip = &zcu.intern_pool; + const nav = ip.getNav(nmi.navIndex(coff)); + break :blk .{ + try coff.getOrPutSymbolName(nav.fqn.toSlice(ip), null), + 0, + if (ip.isFunctionType(nav.resolved.?.type)) .FUNCTION else .NULL, + }; + }, + .uav => |umi| { + var w = Io.Writer.fixed(&buf); + w.print("__anon_{x}", .{umi.uavValue(coff)}) catch unreachable; + break :blk .{ + try coff.getOrPutSymbolName(w.buffered(), null), + 0, + .NULL, + }; + }, + inline .lazy_code, .lazy_const_data => |mi, tag| { + const lazy_sym = mi.lazySymbol(coff); + const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ + @tagName(lazy_sym.kind), + Type.fromInterned(lazy_sym.ty).fmt(pt), + }); + defer gpa.free(name); + + const string = try coff.getOrPutString(name); + break :blk .{ + try coff.getOrPutSymbolName(string.toSlice(coff), string), + 0, + if (tag == .lazy_code) .FUNCTION else .NULL, + }; + }, + else => { + log.err("TODO implement symbol table init for {s} ({d})", .{ @tagName(coff.getNode(sym.ni)), si }); + unreachable; + }, + }; + + const old_num_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols); + const new_num_symbols = old_num_symbols + 1 + num_aux_symbols; + coff.targetStore(&coff.headerPtr().number_of_symbols, new_num_symbols); + + try coff.symbol_table.ni.resize(&coff.mf, gpa, new_num_symbols * std.coff.Symbol.sizeOf()); + + sti.* = .wrap(old_num_symbols); + si.flushSymbolTableIndex(coff); + + const entry = coff.symbolTableEntryPtr(sti.*).?; + symbol_name.store(coff, &entry.name); + + entry.section_number = @enumFromInt(@intFromEnum(sym.section_number)); + entry.type = .{ + .complex_type = complex_type, + .base_type = .NULL, + }; + + entry.storage_class = if (sym.gmi != .none) + .EXTERNAL + else if (sym.flags.extra_tag == .next_alias_si) storage: { + var alias_sym = sym; + const weak_external = while (alias_sym.flags.extra_tag == .next_alias_si) { + const alias_si = alias_sym.extra.next_alias_si; + alias_sym = alias_si.get(coff); + assert(alias_sym.ni == sym.ni); + if (alias_sym.flags.weak_external_strat != .none) + break true; + } else false; + break :storage if (weak_external) .EXTERNAL else .STATIC; + } else .STATIC; + + entry.number_of_aux_symbols = num_aux_symbols; + if (coff.targetEndian() != native_endian) + std.mem.byteSwapAllFieldsAligned(std.coff.Symbol, .@"2", entry); + + if (num_aux_symbols > 0) aux_init: { + if (sym.gmi != .none) { + entry.section_number = .UNDEFINED; + entry.storage_class = .WEAK_EXTERNAL; + + const tag_index = sym.value.weak_alias_si.sti(coff).unwrap().?; + const aux_ptr = coff.symbolTableWeakExternalAuxEntryPtr(sti.*).?; + aux_ptr.* = .{ + .tag_index = tag_index, + .flag = switch (sym.flags.weak_external_strat) { + .none => unreachable, + .no_library => .SEARCH_NOLIBRARY, + .library => .SEARCH_LIBRARY, + .alias => .SEARCH_ALIAS, + .anti_dependency => .ANTI_DEPENDENCY, + }, + .unused = @splat(0), + }; + if (coff.targetEndian() != native_endian) + std.mem.byteSwapAllFieldsAligned(std.coff.WeakExternalDefinition, .@"2", aux_ptr); + + break :aux_init; + } else switch (coff.getNode(sym.ni)) { + .image_section => |sec_si| { + assert(si == sec_si); + const header = sym.section_number.header(coff); + const aux_ptr = coff.symbolTableSectionAuxEntryPtr(sti.*).?; + aux_ptr.* = .{ + .length = @intCast(sym.ni.location(&coff.mf).resolve(&coff.mf)[1]), + .number_of_relocations = header.number_of_relocations, + .number_of_linenumbers = header.number_of_linenumbers, + .checksum = 0, + .number = 0, + .selection = .NONE, + .unused = @splat(0), + }; + if (coff.targetEndian() != native_endian) + std.mem.byteSwapAllFieldsAligned(std.coff.SectionDefinition, .@"2", aux_ptr); + + break :aux_init; + }, + else => {}, + } + + unreachable; + } + + break :entry entry; + }; + + coff.targetStore(&entry.value, switch (sym.section_number) { + .UNDEFINED => if (entry.storage_class == .WEAK_EXTERNAL) 0 else sym.size(), + .ABSOLUTE, + .DEBUG, + => unreachable, + else => switch (coff.getNode(sym.ni)) { + .image_section => 0, + else => coff.computeSymbolSectionOffset(sym, .image), + }, + }); + + log.debug("flushSymbolTableEntry({d}) = {d}", .{ si, sti.* }); +} + +fn flushInputMember(coff: *Coff, iami: InputArchive.Member.Index) !void { + const member = iami.member(coff); + assert(!member.flags.is_loaded); + defer member.flags.is_loaded = true; + switch (member.content) { + .import => unreachable, + .object => |file_location| { + if (file_location.size == 0) return; + const comp = coff.base.comp; + const io = comp.io; + const path = member.iai.path(coff); + const file = try path.root_dir.handle.openFile(io, path.sub_path, .{}); + defer file.close(io); + var buffer: [4096]u8 = undefined; + var fr = file.reader(io, &buffer); + const offset = file_location.offset + @sizeOf(std.coff.ArchiveMemberHeader); + try fr.seekTo(offset); + log.debug("flushInputMember({f}({s}))", .{ path, member.name.toSlice(coff) }); + try coff.loadObject(path, member.name.toSlice(coff), &fr, .{ + .offset = offset, + .size = file_location.size, + }); + }, + } +} + +fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void { + const file_loc = isi.fileLocation(coff); + if (file_loc.size == 0) return; + const comp = coff.base.comp; + const io = comp.io; + const gpa = comp.gpa; + const ioi = isi.input(coff); + const path = ioi.path(coff); + const file = try path.root_dir.handle.openFile(io, path.sub_path, .{}); + defer file.close(io); + var fr = file.reader(io, &.{}); + try fr.seekTo(file_loc.offset); + var nw: MappedFile.Node.Writer = undefined; + const si = isi.symbol(coff); + si.node(coff).writer(&coff.mf, gpa, &nw); + defer nw.deinit(); + log.debug("flushInputSection({f}{f}, {s}, {d}, n{d})", .{ + path, + fmtMemberNameString(ioi.memberName(coff)), + si.get(coff).section_number.name(coff).toSlice(coff), + si, + si.node(coff), + }); + if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size) + return error.EndOfStream; + try si.applyLocationRelocs(coff); +} + +fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index { + assert(coff.hasCoffHeader()); + const gpa = coff.base.comp.gpa; try coff.nodes.ensureUnusedCapacity(gpa, 1); - try coff.image_section_table.ensureUnusedCapacity(gpa, 1); - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); + try coff.section_table.ensureUnusedCapacity(gpa, 1); + try coff.symbols.ensureUnusedCapacity(gpa, 1); + if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1); const coff_header = coff.headerPtr(); const section_index = coff.targetLoad(&coff_header.number_of_sections); @@ -1356,21 +3369,32 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags gpa, @sizeOf(std.coff.SectionHeader) * section_table_len, ); - const ni = try coff.mf.addLastChildNode(gpa, .root, .{ + + const ni = try coff.mf.addLastChildNode(gpa, coff.sectionParent(), .{ .alignment = coff.mf.flags.block_size, .moved = true, .bubbles_moved = false, }); + const si = coff.addSymbolAssumeCapacity(); - coff.image_section_table.appendAssumeCapacity(si); + coff.section_table.putAssumeCapacity(name, .{ + .si = si, + .relocation_table_ni = .none, + }); coff.nodes.appendAssumeCapacity(.{ .image_section = si }); const section_table = coff.sectionTableSlice(); - const virtual_size = coff.optionalHeaderField(.section_alignment); - const rva: u32 = switch (section_index) { - 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), - else => coff.image_section_table.items[section_index - 1].get(coff).rva + - coff.targetLoad(§ion_table[section_index - 1].virtual_size), - }; + + const virtual_size, const rva = if (coff.isImage()) block: { + const virtual_size = coff.optionalHeaderField(.section_alignment); + const rva: u32 = switch (section_index) { + 0 => @intCast(Node.known.header.location(&coff.mf).resolve(&coff.mf)[1]), + else => coff.section_table.values()[section_index - 1].si.get(coff).rva + + coff.targetLoad(§ion_table[section_index - 1].virtual_size), + }; + + break :block .{ virtual_size, rva }; + } else .{ 0, 0 }; + { const sym = si.get(coff); sym.ni = ni; @@ -1390,16 +3414,24 @@ fn addSection(coff: *Coff, name: []const u8, flags: std.coff.SectionHeader.Flags .number_of_linenumbers = 0, .flags = flags, }; - @memcpy(section.name[0..name.len], name); - @memset(section.name[name.len..], 0); if (coff.targetEndian() != native_endian) std.mem.byteSwapAllFields(std.coff.SectionHeader, section); - switch (coff.optionalHeaderPtr()) { - inline else => |optional_header| coff.targetStore( - &optional_header.size_of_image, - @intCast(rva + virtual_size), - ), + + const name_slice = name.toSlice(coff); + if (coff.isImage()) { + @memcpy(section.name[0..name_slice.len], name_slice); + @memset(section.name[name_slice.len..], 0); + switch (coff.optionalHeaderPtr()) { + inline else => |optional_header| coff.targetStore( + &optional_header.size_of_image, + @intCast(rva + virtual_size), + ), + } + } else { + (try coff.getOrPutSymbolName(name_slice, name)).store(coff, §ion.name); + try coff.pendingSymbolTableEntry(si); } + return si; } @@ -1412,7 +3444,40 @@ const ObjectSectionAttributes = packed struct { nocache: bool = false, discard: bool = false, remove: bool = false, + initialized: bool = false, + uninitialized: bool = false, + + pub fn fromFlags(flags: std.coff.SectionHeader.Flags) ObjectSectionAttributes { + return .{ + .read = flags.MEM_READ, + .write = flags.MEM_WRITE, + .execute = flags.MEM_EXECUTE, + .shared = flags.MEM_SHARED, + .nopage = flags.MEM_NOT_PAGED, + .nocache = flags.MEM_NOT_CACHED, + .discard = flags.MEM_DISCARDABLE, + .remove = flags.LNK_REMOVE, + .initialized = flags.CNT_INITIALIZED_DATA, + .uninitialized = flags.CNT_UNINITIALIZED_DATA, + }; + } + + pub fn asFlags(attr: ObjectSectionAttributes) std.coff.SectionHeader.Flags { + return .{ + .MEM_READ = attr.read, + .MEM_WRITE = attr.write, + .MEM_EXECUTE = attr.execute, + .MEM_SHARED = attr.shared, + .MEM_NOT_PAGED = attr.nopage, + .MEM_NOT_CACHED = attr.nocache, + .MEM_DISCARDABLE = attr.discard, + .LNK_REMOVE = attr.remove, + .CNT_INITIALIZED_DATA = attr.uninitialized, + .CNT_UNINITIALIZED_DATA = attr.uninitialized, + }; + } }; + fn pseudoSectionMapIndex( coff: *Coff, name: String, @@ -1422,15 +3487,25 @@ fn pseudoSectionMapIndex( const gpa = coff.base.comp.gpa; const pseudo_section_gop = try coff.pseudo_section_table.getOrPut(gpa, name); const psmi: Node.PseudoSectionMapIndex = @enumFromInt(pseudo_section_gop.index); - if (!pseudo_section_gop.found_existing) { - const parent: Symbol.Index = if (attributes.execute) - .text - else if (attributes.write) - .data - else - .rdata; + const parent_sn = if (!pseudo_section_gop.found_existing) sn: { + const effective_name = coff.section_merges.get(name) orelse name; + const parent = if (coff.section_table.get(effective_name)) |existing_sec| + existing_sec.si + else if (coff.isImage()) parent: { + const parent: Symbol.Index = if (attributes.uninitialized) + .bss + else if (attributes.execute) + .text + else if (attributes.write) + .data + else + .rdata; + + break :parent parent; + } else try coff.addSection(effective_name, attributes.asFlags()); + try coff.nodes.ensureUnusedCapacity(gpa, 1); - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); + try coff.symbols.ensureUnusedCapacity(gpa, 1); const ni = try coff.mf.addLastChildNode(gpa, parent.node(coff), .{ .alignment = alignment }); const si = coff.addSymbolAssumeCapacity(); pseudo_section_gop.value_ptr.* = si; @@ -1441,9 +3516,30 @@ fn pseudoSectionMapIndex( assert(sym.loc_relocs == .none); sym.loc_relocs = @enumFromInt(coff.relocs.items.len); coff.nodes.appendAssumeCapacity(.{ .pseudo_section = psmi }); - } + break :sn sym.section_number; + } else pseudo_section_gop.value_ptr.get(coff).section_number; + + try coff.verifyParentSectionAttributes( + parent_sn, + name, + .pseudo, + .fromFlags(parent_sn.header(coff).flags), + attributes, + ); + return psmi; } + +fn objectSectionParentName(coff: *Coff, name: []const u8) []const u8 { + // In images we want to sort object sections into the final root section name. + // 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] + else + name; +} + fn objectSectionMapIndex( coff: *Coff, name: String, @@ -1451,16 +3547,23 @@ fn objectSectionMapIndex( attributes: ObjectSectionAttributes, ) !Node.ObjectSectionMapIndex { const gpa = coff.base.comp.gpa; + const name_slice = name.toSlice(coff); + // TODO: Should this be a section merge instead? + const effective_attributes = if (coff.isImage() and std.mem.startsWith(u8, name_slice, ".tls")) attr: { + // In images, the .tls section is a read-only template + var attr = attributes; + attr.write = false; + break :attr attr; + } else attributes; + const object_section_gop = try coff.object_section_table.getOrPut(gpa, name); const osmi: Node.ObjectSectionMapIndex = @enumFromInt(object_section_gop.index); - if (!object_section_gop.found_existing) { - try coff.ensureUnusedStringCapacity(name.toSlice(coff).len); - const name_slice = name.toSlice(coff); - const parent = (try coff.pseudoSectionMapIndex(coff.getOrPutStringAssumeCapacity( - name_slice[0 .. std.mem.indexOfScalar(u8, name_slice, '$') orelse name_slice.len], - ), alignment, attributes)).symbol(coff); + const sym = if (!object_section_gop.found_existing) sym: { + try coff.ensureUnusedStringCapacity(name_slice.len); + const parent_name = coff.getOrPutStringAssumeCapacity(coff.objectSectionParentName(name_slice)); + const parent = (try coff.pseudoSectionMapIndex(parent_name, alignment, effective_attributes)).symbol(coff); try coff.nodes.ensureUnusedCapacity(gpa, 1); - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); + try coff.symbols.ensureUnusedCapacity(gpa, 1); const parent_ni = parent.node(coff); var prev_ni: MappedFile.Node.Index = .none; var next_it = parent_ni.children(&coff.mf); @@ -1492,30 +3595,219 @@ fn objectSectionMapIndex( assert(sym.loc_relocs == .none); sym.loc_relocs = @enumFromInt(coff.relocs.items.len); coff.nodes.appendAssumeCapacity(.{ .object_section = osmi }); + break :sym sym; + } else object_section_gop.value_ptr.get(coff); + + const parent_ni = sym.ni.parent(&coff.mf); + const parent_alignment = parent_ni.alignment(&coff.mf); + if (alignment.compare(.gt, parent_alignment)) { + log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment }); + try parent_ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true }); } + + const old_alignment = sym.ni.alignment(&coff.mf); + if (alignment.compare(.gt, old_alignment)) { + log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment }); + try sym.ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true }); + } + + try coff.verifyParentSectionAttributes( + sym.section_number, + name, + .object, + .fromFlags(sym.section_number.header(coff).flags), + effective_attributes, + ); + return osmi; } +fn verifyParentSectionAttributes( + coff: *Coff, + parent: Symbol.SectionNumber, + child_name: String, + child_kind: enum { pseudo, object }, + parent_attrs: ObjectSectionAttributes, + child_attrs: ObjectSectionAttributes, +) !void { + if (parent_attrs == child_attrs) return; + + const was_merged = switch (child_kind) { + .pseudo => coff.section_merges.contains(child_name), + .object => if (coff.getString( + coff.objectSectionParentName(child_name.toSlice(coff)), + ).unwrap()) |pseudo_name| + coff.section_merges.contains(pseudo_name) + else + false, + }; + + // The section was intentionally merged by the user or builtin rule + if (was_merged) return; + + const BackingT = @typeInfo(ObjectSectionAttributes).@"struct".backing_integer.?; + const num_notes = @popCount(@as(BackingT, @bitCast(parent_attrs)) ^ @as(BackingT, @bitCast(child_attrs))); + var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes); + try err.addMsg("{t} section '{s}' was placed in parent section '{s}' with mismatched flags", .{ + child_kind, + child_name.toSlice(coff), + parent.name(coff).toSlice(coff), + }); + + inline for (comptime std.meta.fieldNames(ObjectSectionAttributes)) |field| { + if (@field(child_attrs, field) != @field(parent_attrs, field)) { + err.addNote("flags.{s} was {d} in {s}, but {d} in {s}", .{ + field, + @intFromBool(@field(child_attrs, field)), + child_name.toSlice(coff), + @intFromBool(@field(parent_attrs, field)), + parent.name(coff).toSlice(coff), + }); + } + } + + return error.AlreadyReported; +} + +const RelocAddend = union(enum) { + known: i64, + /// Relocs tables in input objects don't include the addend. + /// The value needs to be recovered from the reloc location. + pending: void, +}; + +// TODO: There should be an API where the caller can indicate how many contiguous relocs they need +// and it should attempt to allocate these from from the free list if available. We can cache +// the run length of each segment on Reloc when `free` is set. pub fn addReloc( coff: *Coff, loc_si: Symbol.Index, offset: u64, target_si: Symbol.Index, - addend: i64, + addend: RelocAddend, + @"type": Reloc.Type, +) link.Error!void { + const diags = &coff.base.comp.link_diags; + try coff.ensureUnusedRelocCapacity(loc_si, 1); + coff.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type") catch |err| switch (err) { + error.MappedFileIo => return diags.fail( + "failed to write output file: {t}", + .{coff.mf.io_err.?}, + ), + else => |e| return e, + }; +} + +fn ensureUnusedRelocCapacity(coff: *Coff, loc_si: Symbol.Index, len: usize) !void { + const gpa = coff.base.comp.gpa; + try coff.relocs.ensureUnusedCapacity(gpa, len); + if (isImage(coff)) return; + switch (loc_si.get(coff).section_number) { + .UNDEFINED, .ABSOLUTE, .DEBUG => {}, + else => |loc_sn| { + const section = loc_sn.section(coff); + if (section.relocation_table_ni == .none) + try coff.nodes.ensureUnusedCapacity(gpa, 1); + }, + } +} + +fn addRelocAssumeCapacity( + coff: *Coff, + loc_si: Symbol.Index, + offset: u64, + target_si: Symbol.Index, + addend: RelocAddend, @"type": Reloc.Type, ) !void { const gpa = coff.base.comp.gpa; const target = target_si.get(coff); + const ri: Reloc.Index = @enumFromInt(coff.relocs.items.len); - (try coff.relocs.addOne(gpa)).* = .{ + log.debug("addReloc({d}@{d}+0x{x} -> {d}@{d}+0x{x}{s}) = {d}", .{ + loc_si, + loc_si.get(coff).section_number, + offset, + target_si, + target_si.get(coff).section_number, + if (addend == .pending) 0 else addend.known, + if (addend == .pending) "p" else "k", + ri, + }); + + const sri: Section.RelocationIndex = if (isImage(coff)) + .none + else switch (loc_si.get(coff).section_number) { + .UNDEFINED, + .ABSOLUTE, + .DEBUG, + => .none, + else => |loc_sn| sri: { + // The target may not have a node yet, or it could be an extern that will never + // have a node. In that case, flushGlobal will create the symbol table entry. + const existing_sti = target_si.sti(coff); + const sti: SymbolTable.Index = if (existing_sti != .none) + existing_sti + else if (target.ni != .none) sti: { + try coff.pendingSymbolTableEntry(target_si); + break :sti .none; + } else .none; + + const sri: Section.RelocationIndex = blk: { + const section = loc_sn.section(coff); + const header = loc_sn.header(coff); + const old_num_relocations = coff.targetLoad(&header.number_of_relocations); + const new_num_relocations = old_num_relocations + 1; + const new_size = @as(u32, new_num_relocations) * std.coff.Relocation.sizeOf(); + + coff.targetStore(&header.number_of_relocations, new_num_relocations); + if (coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff).sti(coff))) |aux_ptr| + coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations); + + if (section.relocation_table_ni == .none) { + section.relocation_table_ni = try coff.mf.addLastChildNode( + gpa, + coff.sectionParent(), + .{ + .size = new_size, + .alignment = .@"2", + .moved = true, + .resized = true, + }, + ); + coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn }); + } else { + try section.relocation_table_ni.resize(&coff.mf, gpa, new_size); + } + + // TODO: These need to allocate from a free list, once deleting relocs from the table is supported + break :blk .wrap(old_num_relocations); + }; + + const entry = sri.entry(coff, loc_sn).?; + if (sti.unwrap()) |index| coff.targetStore(&entry.symbol_table_index, index); + + // applyLocationRelocs updates `virtual_address` + // flushSymbolTableIndex updates `symbol_table_index` + coff.targetStore(&entry.type, @"type".u16); + + break :sri sri; + }, + }; + + coff.relocs.addOneAssumeCapacity().* = .{ .type = @"type", .prev = .none, .next = target.target_relocs, .loc = loc_si, .target = target_si, - .unused = 0, + .sri = sri, .offset = offset, - .addend = addend, + .addend = if (addend == .pending) 0 else addend.known, + .flags = .{ + .recover_addend = addend == .pending, + .free = false, + }, }; switch (target.target_relocs) { .none => {}, @@ -1524,15 +3816,1641 @@ pub fn addReloc( target.target_relocs = ri; } +fn failLoadInput( + coff: *Coff, + err: LoadInputError, + fr: *Io.File.Reader, + path: std.Build.Cache.Path, +) link.Error { + const diags = &coff.base.comp.link_diags; + switch (err) { + else => |e| return e, + error.MappedFileIo => return diags.fail( + "failed to write output file: {t}", + .{coff.mf.io_err.?}, + ), + error.EndOfStream => return diags.failParse( + path, + "unexpected eof", + .{}, + ), + error.AccessDenied, + error.Unexpected, + error.Unseekable, + => |e| return diags.fail( + "failed to read \"{f}\": {t}", + .{ path.fmtEscapeString(), e }, + ), + error.PermissionDenied, + error.SystemResources, + error.Streaming, + => |e| return diags.fail( + "failed to stat \"{f}\": {t}", + .{ path.fmtEscapeString(), e }, + ), + error.ReadFailed => switch (fr.err.?) { + error.Canceled => |e| return e, + else => |e| return diags.fail( + "failed to read \"{f}\": {t}", + .{ path.fmtEscapeString(), e }, + ), + }, + } +} + +pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void { + const comp = coff.base.comp; + const io = comp.io; + + const path = input.path() orelse unreachable; + const gop = try coff.inputs.getOrPut(comp.gpa, path); + if (gop.found_existing) return; + errdefer _ = coff.inputs.swapRemove(path); + + var buf: [4096]u8 = undefined; + switch (input) { + .object => |object| { + var fr = object.file.reader(io, &buf); + coff.loadObject(object.path, null, &fr, .{ + .offset = fr.logicalPos(), + .size = fr.getSize() catch |err| + return coff.failLoadInput(err, &fr, object.path), + }) catch |err| return coff.failLoadInput(err, &fr, object.path); + }, + .archive => |archive| { + var fr = archive.file.reader(io, &buf); + coff.loadArchive(archive.path, &fr) catch |err| + return coff.failLoadInput(err, &fr, archive.path); + }, + .res => |res| { + var fr = res.file.reader(io, &buf); + coff.loadRes(res.path, &fr) catch |err| + return coff.failLoadInput(err, &fr, res.path); + }, + .dso => |dso| { + var fr = dso.file.reader(io, &buf); + coff.loadDll(dso.path, &fr) catch |err| + return coff.failLoadInput(err, &fr, dso.path); + }, + .dso_exact => unreachable, + } +} + +fn fmtMemberNameString(memberName: ?[]const u8) std.fmt.Alt(?[]const u8, memberNameStringEscape) { + return .{ .data = memberName }; +} + +fn memberNameStringEscape(memberName: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { + try w.print("({f})", .{std.zig.fmtString(memberName orelse return)}); +} + +fn inputSectionHeaderNameSlice( + coff: *Coff, + header: *const std.coff.SectionHeader, + string_table: []const u8, + path: std.Build.Cache.Path, + section_i: usize, +) ![]const u8 { + const diags = &coff.base.comp.link_diags; + return if (header.name[0] == '/') name: { + const offset_str = std.mem.sliceTo(header.name[1..], 0); + const name_offset = std.fmt.parseUnsigned(u24, offset_str, 10) catch + return diags.failParse(path, "ill-formed section name in section {d}: '{s}'", .{ + section_i, + header.name[0 .. offset_str.len + 1], + }); + + if (name_offset > string_table.len) + return diags.failParse(path, "out-of-bounds section name offset in section {d}: {d}", .{ section_i, name_offset }); + + break :name std.mem.sliceTo(string_table[name_offset..], 0); + } else std.mem.sliceTo(&header.name, 0); +} + +fn loadObject( + coff: *Coff, + path: std.Build.Cache.Path, + member_name: ?[]const u8, + fr: *Io.File.Reader, + fl: MappedFile.Node.FileLocation, +) LoadInputError!void { + const comp = coff.base.comp; + const gpa = comp.gpa; + const diags = &comp.link_diags; + const r = &fr.interface; + const target = &comp.root_mod.resolved_target.result; + const target_endian = coff.targetEndian(); + const is_archive = coff.isArchive(); + assert(!coff.isObj()); + // We want to evaluate new merges as we see them in .drectve sections to avoid redundant work + assert(coff.section_merge_pending_index == coff.section_merges.count()); + + log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberNameString(member_name) }); + + const header = try r.peekStruct(std.coff.Header, .little); + if (header.machine != target.toCoffMachine()) + return diags.failParse(path, "machine mismatch: expected {t}, found {t}", .{ + target.toCoffMachine(), + header.machine, + }); + if (header.number_of_sections == 0) return; + if (@sizeOf(std.coff.Header) + @as(usize, header.number_of_sections) * @sizeOf(std.coff.SectionHeader) > fl.size) + return diags.failParse(path, "invalid section table", .{}); + const unexpected_header_flags: []const std.meta.FieldEnum(std.coff.Header.Flags) = &.{ + .RELOCS_STRIPPED, + .EXECUTABLE_IMAGE, + .AGGRESSIVE_WS_TRIM, + .RESERVED, + .BYTES_REVERSED_LO, + .DLL, + .BYTES_REVERSED_HI, + }; + inline for (unexpected_header_flags) |flag| + if (@field(header.flags, @tagName(flag))) + return diags.failParse(path, "unexpected flag set: {t}", .{flag}); + + if (header.size_of_optional_header != 0) + return diags.failParse(path, "unexpected optional header", .{}); + + const symbol_table_len = header.number_of_symbols * std.coff.Symbol.sizeOf(); + const symbol_table_end = header.pointer_to_symbol_table + symbol_table_len; + // String table length (which includes the length field) immediately trails the symbol table + if (symbol_table_end + @sizeOf(u32) > fl.size) + return diags.failParse(path, "bad symbol table location", .{}); + + try fr.seekTo(fl.offset + symbol_table_end); + const string_table_len = try r.peekInt(u32, target_endian); + if (string_table_len < @sizeOf(u32) or + symbol_table_end + string_table_len > fl.size) + return diags.failParse(path, "bad string table length: 0x{x}", .{string_table_len}); + + const ioi: InputObject.Index = @enumFromInt(coff.input_objects.items.len); + try coff.input_objects.ensureUnusedCapacity(gpa, 1); + const input = coff.input_objects.addOneAssumeCapacity(); + input.* = .{ + .path = path, + .member_name = if (member_name) |m| try gpa.dupe(u8, m) else null, + .source_name = .none, + }; + + const string_table = string_table: { + const string_table = try gpa.alloc(u8, string_table_len); + errdefer gpa.free(string_table); + try r.readSliceAll(string_table); + break :string_table string_table; + }; + defer gpa.free(string_table); + + try coff.ensureManyUnusedStringCapacity( + header.number_of_sections + header.number_of_symbols, + header.number_of_sections * 9 + + header.number_of_symbols * 9 + + string_table_len - @sizeOf(u32), + ); + + const PendingSymbolIndex = enum(u32) { + none, + _, + + pub fn wrap(i: ?u32) @This() { + return @enumFromInt((i orelse return .none) + 1); + } + + pub fn unwrap(i: @This()) ?u32 { + return switch (i) { + .none => null, + _ => @intFromEnum(i) - 1, + }; + } + }; + + const PendingInputSection = struct { + header: std.coff.SectionHeader, + name: String, + si: Symbol.Index, + parent_si: Symbol.Index, + psi: PendingSymbolIndex, + num_symbols: u32, + comdat: std.coff.ComdatSelection, + comdat_psi: PendingSymbolIndex, + comdat_crc: u32, + comdat_association: Symbol.SectionNumber, + comdat_result: union(enum) { + pending, + // Root of the association chain + pending_association: Symbol.SectionNumber, + include, + skip, + }, + }; + + const sections: []PendingInputSection = if (coff.isImage()) sections: { + const sections = try gpa.alloc(PendingInputSection, header.number_of_sections); + errdefer gpa.free(sections); + + try fr.seekTo(fl.offset + @sizeOf(std.coff.Header)); + for (sections, 0..) |*section, section_i| { + section.* = .{ + .header = try r.takeStruct(std.coff.SectionHeader, target_endian), + .name = undefined, + .si = .null, + .parent_si = .null, + .psi = .none, + .num_symbols = 0, + .comdat = .NONE, + .comdat_psi = .none, + .comdat_crc = 0, + .comdat_association = .UNDEFINED, + .comdat_result = .pending, + }; + + const section_name_slice = if (section.header.name[0] == '/') name: { + const offset_str = std.mem.sliceTo(section.header.name[1..], 0); + const name_offset = std.fmt.parseUnsigned(u24, offset_str, 10) catch + return diags.failParse(path, "ill-formed section name offset in section {d}: '{s}'", .{ + section_i, + section.header.name[0 .. offset_str.len + 1], + }); + + if (name_offset > string_table.len) + return diags.failParse( + path, + "out-of-bounds section name offset in section {d}: {d}", + .{ section_i, name_offset }, + ); + + break :name std.mem.sliceTo(string_table[name_offset..], 0); + } else std.mem.sliceTo(§ion.header.name, 0); + section.name = coff.getOrPutStringAssumeCapacity(section_name_slice); + + if (section.header.pointer_to_linenumbers + + @as(u32, section.header.number_of_linenumbers) * std.coff.LineNumber.sizeOf() > fl.size) + return diags.failParse(path, "bad line numbers location in section {d} `{s}`", .{ + section_i, + section_name_slice, + }); + + if (section.header.pointer_to_relocations + + @as(u32, section.header.number_of_relocations) * std.coff.Relocation.sizeOf() > fl.size) + return diags.failParse(path, "bad relocations location in section {d} `{s}`", .{ + section_i, + section_name_slice, + }); + + if (section.header.pointer_to_raw_data + section.header.size_of_raw_data > fl.size) + return diags.failParse(path, "bad raw data location in section {d} `{s}`", .{ + section_i, + section_name_slice, + }); + } + + break :sections sections; + } else &.{}; + defer gpa.free(sections); + + const mi = if (is_archive) mi: { + try coff.nodes.ensureUnusedCapacity(gpa, 2); + try coff.members.ensureUnusedCapacity(gpa, 1); + const path_str = try path.toString(gpa); + defer gpa.free(path_str); + + const mi = try coff.addMemberAssumeCapacity(.coff, fl.size); + const member = mi.get(coff); + try member.initHeader(coff, path_str, header.time_date_stamp); + + { + // TODO: This should be deferred to an idle task (but resize it here!) + var nw: MappedFile.Node.Writer = undefined; + member.content_ni.writer(&coff.mf, gpa, &nw); + defer nw.deinit(); + + try fr.seekTo(fl.offset); + const written = nw.interface.sendFileAll(fr, .limited64(fl.size)) catch |err| switch (err) { + error.WriteFailed => return nw.err.?, + else => |e| return e, + }; + + if (written != fl.size) return error.EndOfStream; + } + + break :mi mi; + } else undefined; + + try fr.seekTo(fl.offset + header.pointer_to_symbol_table); + const symbol_size = std.coff.Symbol.sizeOf(); + + const PendingSymbol = struct { + name: String, + value: union(enum) { + // Size of the section + section: u32, + // If section is absolute, the symbol value. + // Otherwise, offset within the section. + static: u32, + // If section is undefined, the symbol size. + // If section is absolute, the symbol value. + // Otherwise offset within the section. + external: u32, + // The index of the target symbol of this weak external + weak_external: u32, + // Trails .weak_external + weak_external_aux: WeakExternalStrat, + }, + section_number: Symbol.SectionNumber, + si: Symbol.Index, + // If a weak external targets this symbol, the index of the weak external + weak_external_psi: PendingSymbolIndex, + }; + + var num_global_symbols: u32 = 0; + var pending_symbols: std.array_hash_map.Auto(u32, PendingSymbol) = .empty; + defer pending_symbols.deinit(gpa); + if (!is_archive) + try pending_symbols.ensureUnusedCapacity(gpa, header.number_of_symbols); + + var section_merges: std.ArrayList(struct { + from: String, + to: String, + }) = .empty; + defer section_merges.deinit(gpa); + + // Discover symbol names and COMDAT symbol mappings + var symbol_i: u32 = 0; + var num_included_symbols: u32 = 0; + while (symbol_i < header.number_of_symbols) { + var symbol: std.coff.Symbol = undefined; + @memcpy(std.mem.asBytes(&symbol)[0..symbol_size], try r.take(symbol_size)); + if (target_endian != native_endian) + std.mem.byteSwapAllFields(std.coff.Symbol, &symbol); + + const aux_symbols = if (symbol.number_of_aux_symbols > 0) + try r.take(symbol_size * symbol.number_of_aux_symbols) + else + &.{}; + defer symbol_i += symbol.number_of_aux_symbols + 1; + + const name = std.mem.sliceTo(if (std.mem.eql(u8, symbol.name[0..4], "\x00\x00\x00\x00")) name: { + const index = std.mem.readInt(u32, symbol.name[4..], target_endian); + if (index >= string_table.len) + return diags.failParse(path, "bad string offset for symbol 0x{x}", .{symbol_i}); + break :name string_table[index..]; + } else &symbol.name, 0); + + if (is_archive) { + if (switch (symbol.storage_class) { + .WEAK_EXTERNAL => true, + .EXTERNAL => symbol.section_number != .UNDEFINED, + else => false, + }) try coff.ensureMemberSymbol(mi, coff.getOrPutStringAssumeCapacity(name)); + + continue; + } + + switch (symbol.section_number) { + .UNDEFINED, .DEBUG, .ABSOLUTE => {}, + else => |sn| if (@intFromEnum(sn) > sections.len) + return diags.failParse(path, "out-of-bounds section number {d} in symbol 0x{x}", .{ sn, symbol_i }), + } + + const psi: PendingSymbolIndex = .wrap(@intCast(pending_symbols.count())); + const section_number: Symbol.SectionNumber = @enumFromInt(@intFromEnum(symbol.section_number)); + + const values: []const @FieldType(PendingSymbol, "value") = pending_symbols: switch (symbol.storage_class) { + .STATIC, .LABEL => |storage_class| switch (section_number) { + // TODO: Do we need to do anything with @feat.00? + // https://llvm.org/doxygen/namespacellvm_1_1COFF.html#aeffa16735e18df727a173beaf748c392 + .UNDEFINED, + .DEBUG, + => &.{}, + .ABSOLUTE => &.{.{ .static = symbol.value }}, + else => |sn| { + const section = §ions[sn.toIndex()]; + + // Section symbol + const is_section = storage_class == .STATIC and + symbol.value == 0 and + symbol.type == std.coff.SymType{ + .complex_type = .NULL, + .base_type = .NULL, + } and + symbol.number_of_aux_symbols > 0; + + if (is_section) { + if (symbol.number_of_aux_symbols > 1) + return diags.failParse(path, "invalid number of aux symbols for section symbol 0x{x}: {d}", .{ + symbol_i, + symbol.number_of_aux_symbols, + }); + + var section_def: std.coff.SectionDefinition = undefined; + @memcpy(std.mem.asBytes(§ion_def)[0..symbol_size], aux_symbols[0..symbol_size]); + if (target_endian != native_endian) + std.mem.byteSwapAllFields(std.coff.SectionDefinition, §ion_def); + + if (section_def.number_of_relocations != section.header.number_of_relocations) + return diags.failParse( + path, + "section aux symbol 0x{x} for '{s}' relocation count did not match section header: {d} vs {d}", + .{ symbol_i + 1, name, section_def.number_of_relocations, section.header.number_of_relocations }, + ); + + if (section_def.number_of_linenumbers != section.header.number_of_linenumbers) + return diags.failParse( + path, + "section aux symbol 0x{x} for '{s}' line number count did not match section header: {d} vs {d}", + .{ symbol_i + 1, name, section_def.number_of_linenumbers, section.header.number_of_linenumbers }, + ); + + if (section.header.flags.LNK_COMDAT) { + if (section_def.selection == .ASSOCIATIVE) { + if (section_def.number == 0 or section_def.number > sections.len) + return diags.failParse( + path, + "section aux symbol 0x{x} for '{s}' contained an invalid associated section number: 0x{x}", + .{ symbol_i + 1, name, section_def.number }, + ); + + section.comdat_association = @enumFromInt(section_def.number); + } + + section.comdat = section_def.selection; + section.comdat_crc = section_def.checksum; + } + + section.psi = psi; + } + + break :pending_symbols &.{if (is_section) + .{ .section = section.header.size_of_raw_data } + else + .{ .static = symbol.value }}; + }, + }, + .WEAK_EXTERNAL => switch (symbol.section_number) { + .UNDEFINED => { + if (symbol.value != 0) + return diags.failParse( + path, + "invalid value {d} for weak external symbol 0x{x}", + .{ symbol.value, symbol_i }, + ); + + var weak_external: std.coff.WeakExternalDefinition = undefined; + @memcpy(std.mem.asBytes(&weak_external)[0..symbol_size], aux_symbols[0..symbol_size]); + if (target_endian != native_endian) + std.mem.byteSwapAllFields(std.coff.WeakExternalDefinition, &weak_external); + + if (weak_external.tag_index >= header.number_of_symbols) + return diags.failParse( + path, + "invalid tag_index 0x{x} for weak external symbol 0x{x}", + .{ weak_external.tag_index, symbol_i }, + ); + + break :pending_symbols switch (weak_external.flag) { + else => |flag| &.{ + .{ .weak_external = weak_external.tag_index }, + .{ .weak_external_aux = WeakExternalStrat.fromFlag(flag) }, + }, + _ => return diags.failParse( + path, + "encountered unknown weak external characteristic 0x{x} for symbol 0x{x}", + .{ weak_external.flag, symbol_i }, + ), + }; + }, + else => |sn| return diags.failParse( + path, + "invalid section number {d} for weak external symbol 0x{x}", + .{ sn, symbol_i }, + ), + }, + .EXTERNAL => switch (section_number) { + .UNDEFINED, + .ABSOLUTE, + => &.{.{ .external = symbol.value }}, + .DEBUG => return diags.failParse( + path, + "unexpected external symbol 0x{x} in DEBUG section: '{s}'", + .{ symbol_i, name }, + ), + else => &.{.{ .external = symbol.value }}, + }, + .FILE => { + if (!std.mem.eql(u8, name, ".file")) + return diags.failParse( + path, + "unexpected symbol name '{s}' for file symbol 0x{x}", + .{ name, symbol_i }, + ); + + var file: std.coff.FileDefinition = undefined; + @memcpy(std.mem.asBytes(&file)[0..symbol_size], aux_symbols[0..symbol_size]); + + input.source_name = (try coff.getOrPutString(file.getFileName())).toOptional(); + break :pending_symbols &.{}; + }, + else => |storage_class| return diags.failParse( + path, + "TODO handle storage class {t} for symbol 0x{x}", + .{ storage_class, symbol_i }, + ), + }; + + for (values, 0..) |value, i| { + if (section_number == .ABSOLUTE) + num_included_symbols += 1; + + switch (value) { + .section => {}, + .static, + .external, + .weak_external, + => { + num_global_symbols += 1; + if (section_number.hasIndex()) { + const section = §ions[section_number.toIndex()]; + section.num_symbols += 1; + if (section.header.flags.LNK_COMDAT and section.comdat_psi == .none) + section.comdat_psi = psi; + } + }, + .weak_external_aux => {}, + } + + const symbol_name = coff.getOrPutStringAssumeCapacity(name); + pending_symbols.putAssumeCapacity(symbol_i + @as(u32, @intCast(i)), .{ + .name = symbol_name, + .value = value, + .section_number = section_number, + .si = .null, + .weak_external_psi = .none, + }); + } + } + + try coff.globals.ensureUnusedCapacity(gpa, num_global_symbols); + for (sections) |*section| { + if (section.header.flags.LNK_INFO) { + if (std.mem.eql(u8, §ion.header.name, ".drectve")) { + try fr.seekTo(fl.offset + section.header.pointer_to_raw_data); + // TODO: Don't really want an additional buffer here, but want to limit to size_of_raw_data + var buf: [128]u8 = undefined; + var section_r = r.limited(.limited(section.header.size_of_raw_data), &buf); + while (section_r.interface.takeDelimiter(' ') catch |err| switch (err) { + error.StreamTooLong => return diags.failParse(path, "unexpectedly long .drectve argument", .{}), + else => |e| return e, + }) |arg| { + // Microsoft tools emit 3 space characters into this section even with /Zl + if (arg.len == 0) continue; + + if (std.ascii.startsWithIgnoreCase(arg, "-exclude-symbols:")) { + // TODO: When implementing mingw auto-exports (if at all?), track this to not export this symbol + } else if (std.ascii.startsWithIgnoreCase(arg, "/include:")) { + _ = try coff.globalSymbol(.{ .name = arg["/include:".len..] }); + } else if (std.ascii.startsWithIgnoreCase(arg, "/alternatename:")) { + var split = std.mem.splitScalar(u8, arg["/alternatename:".len..], '='); + const orig = split.first(); + const alt = split.next() orelse + return diags.failParse(path, "malformed .drectve argument: '{s}'", .{arg}); + + try coff.ensureManyUnusedStringCapacity(2, orig.len + alt.len + 2); + const orig_str = coff.getOrPutStringAssumeCapacity(orig); + const alt_str = coff.getOrPutStringAssumeCapacity(alt); + const gop = try coff.alternate_names.getOrPut(gpa, orig_str); + if (!gop.found_existing) { + log.debug("alternateName({s}={s})", .{ orig, alt }); + gop.value_ptr.* = alt_str; + } else if (gop.value_ptr.* != alt_str) + return diags.failParse( + path, + "conflicting /alternatename .drectve arguments: first seen as {s}={s}, now seen as {s}={s}", + .{ orig, gop.value_ptr.toSlice(coff), orig, alt }, + ); + } else if (std.ascii.startsWithIgnoreCase(arg, "/guardsym:")) { + // TODO: https://learn.microsoft.com/en-us/windows/win32/secbp/pe-metadata + } else if (std.ascii.startsWithIgnoreCase(arg, "/merge:")) merge: { + var split = std.mem.splitScalar(u8, arg["/merge:".len..], '='); + const from = split.first(); + const to = split.next() orelse + return diags.failParse(path, "malformed .drectve argument: '{s}'", .{arg}); + if (to.len > header_name_max_len) + return diags.failParse( + path, + "/merge .drectve target exceeds max length of {d}: '{s}'", + .{ header_name_max_len, arg }, + ); + if (std.mem.eql(u8, from, to)) break :merge; + + try coff.ensureManyUnusedStringCapacity(2, from.len + to.len + 2); + const from_str = coff.getOrPutStringAssumeCapacity(from); + const to_str = coff.getOrPutStringAssumeCapacity(to); + + { + var iter = to_str; + while (coff.section_merges.get(iter)) |next_to| { + if (next_to == from_str) + return diags.failParse( + path, + "/merge .drectve argument would create a cycle: {s}={s} leads to {s}={s}", + .{ from, to, iter.toSlice(coff), to }, + ); + + iter = next_to; + } + } + + try coff.section_merges.ensureUnusedCapacity(gpa, 1); + const gop = coff.section_merges.getOrPutAssumeCapacity(from_str); + if (!gop.found_existing) { + coff.synth_prog_node.increaseEstimatedTotalItems(1); + gop.value_ptr.* = to_str; + } else if (gop.value_ptr.* != to_str) + return diags.failParse( + path, + "conflicting /merge .drectve arguments: first seen as {s}={s}, now seen as {s}={s}", + .{ from, gop.value_ptr.toSlice(coff), from, to }, + ); + } else if (std.ascii.startsWithIgnoreCase(arg, "/disallowlib:")) { + const lib_name = arg["/disallowlib:".len..]; + // TODO: Track these and issue error in prelink if any match + _ = lib_name; + } else if (std.ascii.startsWithIgnoreCase(arg, "/defaultlib:")) { + const lib_path = arg["/defaultlib:".len..]; + const trim = std.mem.trim(u8, lib_path, "\""); + if (lib_path.len == trim.len or lib_path.len - 2 == trim.len) { + if (!comp.config.link_libc or comp.libc_installation == null) + return diags.failParse(path, "encountered /DEFAULTLIB .drectve argument when libc was not available: {s}", .{arg}); + + (try coff.pending_default_libs.addOne(gpa)).* = .{ + .path = try gpa.dupe(u8, lib_path), + .ioi = ioi, + }; + } else return diags.failParse( + path, + "malformed /DEFAULTLIB .drectve argument: `{s}`", + .{arg}, + ); + } else return diags.failParse(path, "unsupported argument in .drectve section: `{s}`", .{arg}); + } + } + + section.comdat_result = .skip; + continue; + } + + if (section.header.flags.LNK_REMOVE or + section.header.flags.MEM_DISCARDABLE) + { + // TODO: Convert .debug$* sections into PDB + section.comdat_result = .skip; + continue; + } + + section.comdat_result = comdat: switch (section.comdat) { + .NONE => .include, + .ASSOCIATIVE => { + // Associative COMDAT sections have no COMDAT symbol. + // They are linked if the assocated section is linked. + var iter = section; + var iter_sn = iter.comdat_association; + while (iter.comdat == .ASSOCIATIVE) { + iter = §ions[iter_sn.toIndex()]; + iter_sn = iter.comdat_association; + if (iter == section) + return diags.failParse( + path, + "circular COMDAT association loop detected, starting at symbol 0x{x}", + .{pending_symbols.keys()[section.psi.unwrap().?]}, + ); + } + + assert(iter != section); + break :comdat switch (iter.comdat_result) { + .pending => .{ .pending_association = iter_sn }, + else => |iter_result| iter_result, + }; + }, + else => |comdat| { + const psi = section.comdat_psi.unwrap() orelse section.psi.unwrap().?; + const symbol = &pending_symbols.values()[psi]; + const si = existing: switch (symbol.value) { + .weak_external => unreachable, + .weak_external_aux => unreachable, + .static => break :comdat .include, + .section => { + assert(section.comdat_psi == .none); + if (coff.object_section_table.get(section.name)) |si| + break :existing si + else if (coff.pseudo_section_table.get(section.name)) |si| + break :existing si + else if (coff.section_table.get(section.name)) |s| + break :existing s.si + else + break :comdat .include; + }, + .external => { + const global_gop = try coff.getOrPutGlobalSymbol(.{ + .name = symbol.name.toSlice(coff), + }); + + // TODO: What if the same symbol is incorrectly defined twice in this obj? + // Would need to mark this global as pending, or notice it later when .ni != none + if (!global_gop.found_existing or global_gop.value_ptr.si.get(coff).ni == .none) { + symbol.si = global_gop.value_ptr.si; + break :comdat .include; + } + + break :existing global_gop.value_ptr.si; + }, + }; + + const index = pending_symbols.keys()[psi]; + switch (comdat) { + .NODUPLICATES => return coff.failMultipleDefinitions( + path, + member_name, + symbol.name, + index, + si, + .duplicate, + ), + .ANY => { + symbol.si = si; + break :comdat .skip; + }, + .SAME_SIZE => { + // TODO: Verify that this node isn't resized after creation + _, const size = si.get(coff).ni.location(&coff.mf).resolve(&coff.mf); + if (size == section.header.size_of_raw_data) { + symbol.si = si; + break :comdat .skip; + } + + return coff.failMultipleDefinitions( + path, + member_name, + symbol.name, + index, + si, + .{ .size = .{ .a = size, .b = section.header.size_of_raw_data } }, + ); + }, + .EXACT_MATCH => { + const sym = si.get(coff); + const existing_crc = switch (coff.getNode(sym.ni)) { + .input_section => |isi| isi.inputSection(coff).crc, + else => Crc32.hash(sym.ni.sliceConst(&coff.mf)), + }; + + if (existing_crc == section.comdat_crc) { + symbol.si = si; + break :comdat .skip; + } + + return coff.failMultipleDefinitions( + path, + member_name, + symbol.name, + index, + si, + .{ .crc = .{ .a = existing_crc, .b = section.comdat_crc } }, + ); + }, + .LARGEST => { + // TODO: Resize existing .ni and replace with this section's contents + // TODO: This will be tricky, what to do about existing InputSection? + unreachable; + }, + .NONE, .ASSOCIATIVE, _ => unreachable, + } + }, + }; + } + + try coff.flushSectionMerges(); + + // Resolve pending associations, create parent sections + var num_included_sections: u16 = 0; + var num_included_relocs: u32 = 0; + for (sections) |*section| { + comdat: switch (section.comdat_result) { + .pending_association => |root_assoc_sn| { + const root_result = sections[root_assoc_sn.toIndex()].comdat_result; + assert(root_result != .pending_association); + section.comdat_result = root_result; + continue :comdat root_result; + }, + .include => {}, + .skip => { + assert(switch (section.comdat) { + .NONE, .ASSOCIATIVE => true, + else => if (section.comdat_psi.unwrap()) |psi| + pending_symbols.values()[psi].si != .null + else + pending_symbols.values()[section.psi.unwrap().?].si != .null, + }); + continue; + }, + .pending => unreachable, + } + + // Until we support sorting .pdata, we shouldn't merge these in, the result would be invalid + const section_name = section.name.toSlice(coff); + if (std.mem.startsWith(u8, section_name, ".pdata")) + continue; + + num_included_sections += 1; + num_included_symbols += section.num_symbols; + num_included_relocs += section.header.number_of_relocations; + + section.parent_si = (try coff.objectSectionMapIndex( + section.name, + section.header.flags.ALIGN.alignment() orelse .@"1", + .fromFlags(section.header.flags), + )).symbol(coff); + } + + try coff.nodes.ensureUnusedCapacity(gpa, num_included_sections); + try coff.relocs.ensureUnusedCapacity(gpa, num_included_relocs); + try coff.symbols.ensureUnusedCapacity(gpa, num_included_symbols + num_included_sections); + try coff.input_sections.ensureUnusedCapacity(gpa, num_included_sections); + + for (sections) |*section| { + if (section.parent_si == .null) continue; + + const ni = try coff.mf.addLastChildNode(gpa, section.parent_si.node(coff), .{ + .size = section.header.size_of_raw_data, + .alignment = section.header.flags.ALIGN.alignment() orelse .@"1", + .moved = true, + }); + coff.nodes.appendAssumeCapacity(.{ .input_section = @enumFromInt(coff.input_sections.items.len) }); + + section.si = coff.addSymbolAssumeCapacity(); + if (section.psi.unwrap()) |psi| + pending_symbols.values()[psi].si = section.si; + + const sym = section.si.get(coff); + sym.ni = ni; + sym.section_number = section.parent_si.get(coff).section_number; + + coff.input_sections.addOneAssumeCapacity().* = .{ + .ioi = ioi, + .si = section.si, + .file_location = .{ + .offset = fl.offset + section.header.pointer_to_raw_data, + .size = section.header.size_of_raw_data, + }, + .first_li = @enumFromInt(coff.input_symbols.items.len), + .crc = section.comdat_crc, + .comdat_si = if (section.comdat_psi.unwrap()) |psi| + pending_symbols.values()[psi].si + else + .null, + }; + + log.debug( + "addInputSection({s}, 0x{x}) = {d}@{d}", + .{ section.name.toSlice(coff), section.comdat_crc, section.si, sym.section_number }, + ); + coff.synth_prog_node.increaseEstimatedTotalItems(1); + } + + for (pending_symbols.values(), pending_symbols.keys(), 0..) |*symbol, index, i| { + switch (symbol.value) { + .weak_external_aux => continue, + else => {}, + } + + defer log.debug("addInputSymbol({s}, 0x{x}@{d}, {t}=0x{x}) = n{d} {d}@{d}", .{ + symbol.name.toSlice(coff), + index, + symbol.section_number, + symbol.value, + switch (symbol.value) { + .weak_external_aux => unreachable, + inline else => |v| v, + }, + symbol.si.get(coff).ni, + symbol.si, + symbol.si.get(coff).section_number, + }); + + const section = switch (symbol.section_number) { + .UNDEFINED => switch (symbol.value) { + .section, + .static, + .weak_external_aux, + => unreachable, + .external => { + if (symbol.weak_external_psi.unwrap()) |weak_external_i| { + // If the alias itself is an undef external, we need to wait until flushing the weak + // external global before creating a global for the alias, as another input could + // still provide the weak external. + const weak_sym = pending_symbols.values()[weak_external_i].si.get(coff); + weak_sym.setValue(.{ .weak_alias_name = symbol.name }); + weak_sym.flags.weak_external_strat = pending_symbols.values()[weak_external_i + 1].value.weak_external_aux; + } + + // Deferred until referenced by a reloc in this object. + // vcruntime.lib defines symbols like this (ie. memcpy_$fo$) that are not referenced + continue; + }, + .weak_external => |alias_index| { + const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); + symbol.si = global_gop.value_ptr.si; + if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { + const sym = symbol.si.get(coff); + const alias = pending_symbols.getPtr(alias_index) orelse + return diags.failParse( + path, + "weak external 0x{x} {s}{f} targets unknown symbol index 0x{x}", + .{ + index, + symbol.name.toSlice(coff), + fmtMemberNameString(member_name), + alias_index, + }, + ); + + if (alias.si == .null and alias_index > index) { + // Resolve this once we see alias + alias.weak_external_psi = .wrap(@intCast(i)); + } else { + sym.setValue(if (alias.si.unwrap()) |alias_si| .{ + .weak_alias_si = alias_si, + } else .{ + .weak_alias_name = alias.name, + }); + sym.flags.weak_external_strat = pending_symbols.values()[i + 1].value.weak_external_aux; + } + } + + continue; + }, + }, + .ABSOLUTE => { + const value = sym: switch (symbol.value) { + .static => |value| { + symbol.si = coff.addSymbolAssumeCapacity(); + break :sym value; + }, + .external => |value| { + const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); + symbol.si = global_gop.value_ptr.si; + if (global_gop.found_existing) + return coff.failMultipleDefinitions( + path, + member_name, + symbol.name, + index, + global_gop.value_ptr.si, + .none, + ); + break :sym value; + }, + else => unreachable, + }; + + const sym = symbol.si.get(coff); + sym.rva = value; + sym.section_number = .ABSOLUTE; + continue; + }, + .DEBUG => continue, + else => |sn| §ions[sn.toIndex()], + }; + + if (section.si == .null) + continue; + + if (symbol.si == .null) { + switch (symbol.value) { + .section => unreachable, + .static => { + symbol.si = coff.addSymbolAssumeCapacity(); + }, + .external => { + assert(index != section.comdat_psi.unwrap()); + const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); + symbol.si = global_gop.value_ptr.si; + + const sym = symbol.si.get(coff); + if (global_gop.found_existing and sym.ni != .none) + return coff.failMultipleDefinitions( + path, + member_name, + symbol.name, + index, + global_gop.value_ptr.si, + .none, + ); + }, + .weak_external, + .weak_external_aux, + => unreachable, + } + + if (section.comdat_psi.unwrap() == @as(u32, @intCast(i))) + coff.getNode(section.si.get(coff).ni).input_section.inputSection(coff).comdat_si = symbol.si; + } + + if (symbol.weak_external_psi.unwrap()) |weak_external_i| { + assert(symbol.si != .null); + const weak_sym = pending_symbols.values()[weak_external_i].si.get(coff); + weak_sym.setValue(.{ .weak_alias_si = symbol.si }); + weak_sym.flags.weak_external_strat = pending_symbols.values()[weak_external_i + 1].value.weak_external_aux; + } + + if (section.si != symbol.si) { + const sym = symbol.si.get(coff); + assert(sym.ni == .none); + sym.ni = section.si.get(coff).ni; + switch (symbol.value) { + .section => |v| sym.setExtra(.{ .size = v }), + .static => |v| sym.setValue(.{ .node_offset = v }), + .external => |v| switch (symbol.section_number) { + .UNDEFINED, .ABSOLUTE, .DEBUG => unreachable, + else => sym.setValue(.{ .node_offset = v }), + }, + .weak_external, + .weak_external_aux, + => unreachable, + } + + sym.section_number = section.si.get(coff).section_number; + } + } + + const relocation_size = std.coff.Relocation.sizeOf(); + for (sections) |section| { + if (section.si == .null) continue; + + const loc_sym = section.si.get(coff); + assert(loc_sym.loc_relocs == .none); + loc_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + + if (section.header.number_of_relocations == 0) continue; + + try fr.seekTo(fl.offset + section.header.pointer_to_relocations); + for (0..section.header.number_of_relocations) |reloc_i| { + var reloc: std.coff.Relocation = undefined; + @memcpy(std.mem.asBytes(&reloc)[0..relocation_size], try r.take(relocation_size)); + if (target_endian != native_endian) + std.mem.byteSwapAllFields(std.coff.Relocation, &reloc); + + const symbol = pending_symbols.getPtr(reloc.symbol_table_index) orelse + return diags.failParse( + path, + "relocation 0x{x} in section '{s}' of {f}{f} targets invalid symbol index 0x{x}", + .{ + reloc_i, + section.name.toSlice(coff), + path.fmtEscapeString(), + fmtMemberNameString(member_name), + reloc.symbol_table_index, + }, + ); + + if (symbol.si == .null) { + assert(symbol.section_number == .UNDEFINED); + switch (symbol.value) { + .external => |size| { + const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) }); + symbol.si = global_gop.value_ptr.si; + if (!global_gop.found_existing or symbol.si.get(coff).ni == .none) { + const sym = symbol.si.get(coff); + sym.setExtra(.{ .size = @max(sym.size(), size) }); + } + }, + else => unreachable, + } + } + + assert(symbol.si != .null); + try coff.addReloc( + section.si, + reloc.virtual_address - section.header.virtual_address, + symbol.si, + .pending, + .{ .u16 = reloc.type }, + ); + } + } + + // Set up contiguous symbol ranges in `input_symbols` for both symbols we just created, + // and symbols that were previously created as undefined, but we just defined. + const SortContext = struct { + v: []const PendingSymbol, + + pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { + const lhs = &ctx.v[a_index]; + const rhs = &ctx.v[b_index]; + if (lhs.section_number == rhs.section_number) + return @intFromEnum(lhs.si) < @intFromEnum(rhs.si); + return @intFromEnum(lhs.section_number) < @intFromEnum(rhs.section_number); + } + }; + + pending_symbols.sortUnstable(SortContext{ .v = pending_symbols.values() }); + + try coff.input_symbols.ensureUnusedCapacity(gpa, num_included_symbols + num_included_sections); + var prev_sn: Symbol.SectionNumber = .DEBUG; + var include_section = false; + for (pending_symbols.values()) |symbol| { + // The symbol may have not been included, or it's an undefined external / aux + if (symbol.si == .null or symbol.si.get(coff).ni == .none) continue; + + if (prev_sn != symbol.section_number) { + prev_sn = symbol.section_number; + if (symbol.section_number.hasIndex()) { + const section = §ions[symbol.section_number.toIndex()]; + include_section = section.comdat_result == .include; + if (include_section) { + const isi = coff.getNode(section.si.get(coff).ni).input_section; + isi.inputSection(coff).first_li = @enumFromInt(coff.input_symbols.items.len); + } + } + } + + if (include_section) { + assert(coff.getNode(symbol.si.get(coff).ni) == .input_section); + symbol.si.get(coff).setExtra(.{ .isli = @enumFromInt(coff.input_symbols.items.len) }); + coff.input_symbols.addOneAssumeCapacity().* = .{ + .si = symbol.si, + .name = symbol.name, + }; + } + } +} + +fn failMultipleDefinitions( + coff: *Coff, + path: std.Build.Cache.Path, + member_name: ?[]const u8, + name: String, + index: u32, + existing_si: Symbol.Index, + comdat_reason: union(enum) { + none: void, + duplicate: void, + size: struct { a: u64, b: u64 }, + crc: struct { a: u32, b: u32 }, + }, +) error{ AlreadyReported, OutOfMemory } { + const num_notes: usize = 2 + @as(usize, @intFromBool(comdat_reason != .none)); + var err = try coff.base.comp.link_diags.addErrorWithNotes(num_notes); + try err.addMsg("multiple definitions of '{s}'", .{name.toSlice(coff)}); + + switch (coff.getNode(existing_si.get(coff).ni)) { + .input_section => |isi| { + const other_ioi = isi.input(coff); + err.addNote("first seen in input '{f}{f}'", .{ + other_ioi.path(coff).fmtEscapeString(), + fmtMemberNameString(other_ioi.memberName(coff)), + }); + }, + .nav, .uav => err.addNote("first seen in module '{s}'", .{ + coff.base.comp.zcu.?.root_mod.fully_qualified_name, + }), + else => unreachable, + } + + err.addNote("defined again in input '{f}{f}' (0x{x}))", .{ path, fmtMemberNameString(member_name), index }); + switch (comdat_reason) { + .none => {}, + .duplicate => err.addNote("COMDAT rule requires no duplicates", .{}), + .size => |s| err.addNote( + "COMDAT rule require duplicates to have the same size ({d} vs {d})", + .{ s.a, s.b }, + ), + .crc => |s| err.addNote( + "COMDAT rule require duplicates to have the same CRC (0x{x} vs 0x{x})", + .{ s.a, s.b }, + ), + } + + return error.AlreadyReported; +} + +const ArchiveMemberHeader = struct { + name: []const u8, + size: u34, +}; + +/// Return value lifetime is that of `header` +fn parseArchiveMemberHeader( + diags: *link.Diags, + path: std.Build.Cache.Path, + header: *const std.coff.ArchiveMemberHeader, + opt_longnames: ?[]const u8, +) !ArchiveMemberHeader { + return parseArchiveMemberHeaderInner(header, opt_longnames) catch |err| switch (err) { + error.BadName => return diags.failParse(path, "malformed member name: '{s}'", .{&header.name}), + error.BadSize => return diags.failParse(path, "malformed member size: '{s}'", .{&header.size}), + error.BadEndOfHeader => return diags.failParse(path, "end of header was invalid", .{}), + error.NoLongNames => return diags.failParse(path, "long name used without longnames member", .{}), + }; +} + +fn parseArchiveMemberHeaderInner( + header: *const std.coff.ArchiveMemberHeader, + opt_longnames: ?[]const u8, +) !ArchiveMemberHeader { + const name = try header.parseName(opt_longnames); + const size = header.parseSize() catch return error.BadSize; + + if (!std.mem.eql(u8, &header.end_of_header, std.coff.archive_end_of_header)) + return error.BadEndOfHeader; + + return .{ + .name = name, + .size = size, + }; +} + +fn loadArchive(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) LoadInputError!void { + const comp = coff.base.comp; + const gpa = comp.gpa; + const diags = &comp.link_diags; + const r = &fr.interface; + const target_endian = coff.targetEndian(); + + log.debug("loadArchive({f})", .{path.fmtEscapeString()}); + + const signature = try r.take(std.coff.archive_signature.len); + if (!std.mem.eql(u8, signature, std.coff.archive_signature)) + return diags.failParse(path, "bad signature", .{}); + + var opt_expected_kind: ?std.coff.ArchiveMemberHeader.Kind = .first_linker; + var opt_longnames: ?[]const u8 = null; + defer if (opt_longnames) |l| gpa.free(l); + + var members: std.ArrayList(struct { + offset: u32, + iami: ?InputArchive.Member.Index, + }) = .empty; + var symbol_member_indices: std.ArrayList(u32) = .empty; + + const iai: InputArchive.Index = @enumFromInt(coff.input_archives.items.len); + (try coff.input_archives.addOne(gpa)).* = .{ + .path = path, + }; + + const first_iami = coff.input_archive_members.items.len; + const first_iamsi = coff.input_archive_symbols.items.len; + const first_symbol_indices_index = coff.input_archive_symbol_indices.count(); + + errdefer { + for (coff.input_archive_symbol_indices.values()) |*v| { + if (@intFromEnum(v.last) < first_iamsi) continue; + if (@intFromEnum(v.first) >= first_iamsi) continue; + + var iter = v.first; + v.last = while (iter != v.last) { + const sym = &coff.input_archive_symbols.items[@intFromEnum(iter)]; + if (@intFromEnum(sym.next) >= first_iamsi) { + sym.next = iter; + break iter; + } + + iter = sym.next; + } else unreachable; + } + + // New entries in this map will only have pointed to iamsi we also just added + coff.input_archive_symbol_indices.shrinkRetainingCapacity(first_symbol_indices_index); + coff.input_archive_symbols.shrinkRetainingCapacity(first_iamsi); + coff.input_archive_members.shrinkRetainingCapacity(first_iami); + _ = coff.input_archives.pop(); + } + + var pos = fr.logicalPos(); + const size = try fr.getSize(); + while (pos < size) : (pos = fr.logicalPos()) { + if ((pos & 1) != 0) try r.discardAll(1); + const header = try r.takeStruct(std.coff.ArchiveMemberHeader, target_endian); + const res = try parseArchiveMemberHeader(diags, path, &header, opt_longnames); + + const member_end = fr.logicalPos() + res.size; + if (member_end > size) + return diags.failParse(path, "out-of-bounds length 0x{x} in member '{s}'", .{ res.size, res.name }); + + log.debug("loadArchiveMember({s})", .{res.name}); + + if (opt_expected_kind) |expected_kind| switch (expected_kind) { + .first_linker => { + if (!std.mem.eql(u8, res.name, "/")) + return diags.failParse(path, "expected first linker member, found '{s}'", .{res.name}); + + try fr.seekTo(fr.logicalPos() + res.size); + opt_expected_kind = .second_linker; + continue; + }, + .second_linker => { + if (!std.mem.eql(u8, res.name, "/")) + return diags.failParse(path, "expected second linker member, found '{s}'", .{res.name}); + + const num_members = try r.takeInt(u32, target_endian); + pos = fr.logicalPos(); + if (pos + num_members * @sizeOf(u32) > member_end) + return diags.failParse(path, "invalid member count 0x{x} in second linker member", .{num_members}); + + try members.ensureTotalCapacity(gpa, num_members); + for (0..num_members) |_| + members.addOneAssumeCapacity().* = .{ + .offset = try r.takeInt(u32, target_endian), + .iami = null, + }; + + const num_symbols = try r.takeInt(u32, target_endian); + pos = fr.logicalPos(); + if (pos + num_symbols * @sizeOf(u16) > member_end) + return diags.failParse(path, "invalid symbol count 0x{x} in second linker member", .{num_symbols}); + + try symbol_member_indices.ensureTotalCapacity(gpa, num_symbols); + for (0..num_symbols) |_| + symbol_member_indices.addOneAssumeCapacity().* = (try r.takeInt(u16, target_endian)) - 1; + + pos = fr.logicalPos(); + try coff.ensureManyUnusedStringCapacity(num_symbols, @intCast(member_end - pos)); + try coff.input_archive_members.ensureUnusedCapacity(gpa, num_members); + try coff.input_archive_symbols.ensureUnusedCapacity(gpa, num_symbols); + try coff.input_archive_symbol_indices.ensureUnusedCapacity(gpa, num_symbols); + + var symbol_i: u32 = 0; + while (pos < member_end and symbol_i < num_symbols) : ({ + pos = fr.logicalPos(); + symbol_i += 1; + }) { + const name = if (r.takeDelimiter(0) catch |err| switch (err) { + error.StreamTooLong => null, + else => |e| return e, + }) |n| n else return diags.failParse(path, "unterminated string found in second linker member", .{}); + + const string = coff.getOrPutStringAssumeCapacity(name); + const iamsi: InputArchive.Member.Symbol.Index = @enumFromInt(coff.input_archive_symbols.items.len); + const symbol_gop = coff.input_archive_symbol_indices.getOrPutAssumeCapacity(string); + if (!symbol_gop.found_existing) { + symbol_gop.value_ptr.* = .{ + .first = iamsi, + .last = iamsi, + }; + } else { + coff.input_archive_symbols.items[@intFromEnum(symbol_gop.value_ptr.last)].next = iamsi; + symbol_gop.value_ptr.last = iamsi; + } + + const iami = members.items[symbol_member_indices.items[symbol_i]].iami orelse iami: { + const iami: InputArchive.Member.Index = @enumFromInt(coff.input_archive_members.items.len); + const member_offset = members.items[symbol_member_indices.items[symbol_i]].offset; + coff.input_archive_members.addOneAssumeCapacity().* = .{ + .iai = iai, + .name = undefined, + .content = .{ + .object = .{ + .offset = member_offset, + .size = undefined, + }, + }, + .flags = .{ + .is_loaded = false, + }, + }; + + members.items[symbol_member_indices.items[symbol_i]].iami = iami; + break :iami iami; + }; + + log.debug("loadArchiveMemberSymbol({s}) = ({d}, {d}, {d})", .{ name, iai, iami, iamsi }); + + coff.input_archive_symbols.addOneAssumeCapacity().* = .{ + .iami = iami, + .next = iamsi, + }; + } + + if (symbol_i != num_symbols) + return diags.failParse( + path, + " expected {d} entries in second linker member string table, but found {d}", + .{ num_symbols, symbol_i }, + ); + + try fr.seekTo(member_end); + opt_expected_kind = .longnames; + continue; + }, + .longnames => { + // This member is optional + if (std.mem.eql(u8, res.name, "//")) + opt_longnames = try r.readAlloc(gpa, @intCast(res.size)); + + opt_expected_kind = null; + break; + }, + else => unreachable, + }; + } + + if (opt_expected_kind) |expected_kind| switch (expected_kind) { + .first_linker => return diags.failParse(path, "missing first linker member", .{}), + .second_linker => return diags.failParse(path, "missing second linker member", .{}), + else => {}, + }; + + // Validate / read names and sizes of all the referenced members, enumerate imports + for (coff.input_archive_members.items[first_iami..]) |*member| { + try fr.seekTo(member.content.object.offset); + + const header = try r.takeStruct(std.coff.ArchiveMemberHeader, target_endian); + const res = try parseArchiveMemberHeader(diags, path, &header, opt_longnames); + + try coff.ensureUnusedStringCapacity(res.name.len); + member.name = coff.getOrPutStringAssumeCapacity(res.name); + + const member_sig = try r.peek(4); + const machine: std.coff.IMAGE.FILE.MACHINE = + @enumFromInt(std.mem.readInt(u16, member_sig[0..2], target_endian)); + const sig = std.mem.readInt(u16, member_sig[2..4], target_endian); + + log.debug("verifyArchiveMember({s}) = 0x{x}+{x}", .{ + res.name, + member.content.object.offset, + res.size, + }); + + const expected_machine = comp.root_mod.resolved_target.result.toCoffMachine(); + if (machine == std.coff.IMAGE.FILE.MACHINE.UNKNOWN and sig == 0xffff) { + const import_header = try r.takeStruct(std.coff.ImportHeader, target_endian); + const strings = r.take(import_header.size_of_data) catch |err| switch (err) { + error.EndOfStream => return diags.failParse(path, "invalid data size in import header '{s}'", .{res.name}), + else => |e| return e, + }; + + var split = std.mem.splitScalar(u8, strings, 0); + const symbol_name = split.next() orelse + return diags.failParse(path, "invalid symbol name string in import header '{s}'", .{res.name}); + var lib_name = split.next() orelse + return diags.failParse(path, "invalid dll name string in import header '{s}' ('{s}')", .{ res.name, symbol_name }); + + if (import_header.machine != expected_machine) + return diags.failParse(path, "machine mismatch in import header '{s}' ('{s}'): expected {t}, found {t}", .{ + res.name, + symbol_name, + expected_machine, + machine, + }); + + const ext = ".dll"; + if (!std.mem.endsWith(u8, lib_name, ext)) + return diags.failParse( + path, + "unexpected extension for import '{s} ('{s}'): '{s}'", + .{ res.name, symbol_name, lib_name }, + ); + + lib_name = lib_name[0 .. lib_name.len - ext.len]; + log.debug("verifyArchiveImportHeader({s}, {s}, {s}) = {t} ({t})", .{ + res.name, + symbol_name, + lib_name, + import_header.types.type, + import_header.types.name_type, + }); + + try coff.ensureManyUnusedStringCapacity(2, strings.len - ext.len); + member.content = .{ + .import = .{ + .symbol_name = coff.getOrPutStringAssumeCapacity(symbol_name), + .lib_name = coff.getOrPutStringAssumeCapacity(lib_name), + .import_ordinal_hint = import_header.hint, + .type = import_header.types.type, + .name_type = import_header.types.name_type, + }, + }; + } else { + member.content.object.size = res.size; + // Microsoft's CRT contains members that set .UNKNOWN but do have undef symbols + if (machine != expected_machine and machine != .UNKNOWN) { + return diags.failParse(path, "machine mismatch in member header '{s}': expected {t}, found {t}", .{ + res.name, + expected_machine, + machine, + }); + } + } + } +} + +fn loadRes(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) LoadInputError!void { + const comp = coff.base.comp; + const gpa = comp.gpa; + const diags = &comp.link_diags; + const r = &fr.interface; + + log.debug("loadRes({f})", .{path.fmtEscapeString()}); + + _ = gpa; + _ = diags; + _ = r; +} + +fn loadDll(coff: *Coff, path: std.Build.Cache.Path, fr: *Io.File.Reader) LoadInputError!void { + const comp = coff.base.comp; + const gpa = comp.gpa; + const diags = &comp.link_diags; + const r = &fr.interface; + + log.debug("loadDll({f})", .{path.fmtEscapeString()}); + + _ = gpa; + _ = diags; + _ = r; +} + pub fn prelink(coff: *Coff, prog_node: std.Progress.Node) link.Error!void { - _ = coff; _ = prog_node; + const base = coff.base; + const comp = base.comp; + + log.debug("prelink()", .{}); + + if (coff.pending_default_libs.items.len > 0) { + // Libs provided by /DEFAULTLIB arguments in objects are searched after all other inputs + const gpa = comp.gpa; + const arena = comp.arena; + const target = &comp.root_mod.resolved_target.result; + + defer { + for (coff.pending_default_libs.items) |l| gpa.free(l.path); + coff.pending_default_libs.clearAndFree(gpa); + } + + assert(comp.config.link_libc); + const libc_installation = comp.libc_installation.?; + const all_paths: [3]?[]const u8 = .{ + libc_installation.crt_dir, + libc_installation.msvc_lib_dir, + libc_installation.kernel32_lib_dir, + }; + const search_paths = all_paths[0..if (target.abi == .msvc or target.abi == .itanium) 3 else 1]; + lib: for (coff.pending_default_libs.items) |lib| { + if (!std.mem.eql(u8, std.fs.path.extension(lib.path), ".lib")) + return comp.link_diags.failParse( + lib.ioi.path(coff), + "/DEFAULTLIB library '{s}' had unexpected extension", + .{lib.path}, + ); + + log.debug("loadDefaultLib({s}, {f})", .{ lib.path, lib.ioi.path(coff) }); + for (search_paths) |opt_path| if (opt_path) |search_path| { + const lib_path = try Path.initCwd(search_path).join(arena, lib.path); + const archive = link.openObject(comp.io, lib_path, false, false) catch |err| switch (err) { + error.FileNotFound => { + arena.free(lib_path.sub_path); + continue; + }, + else => |e| return comp.link_diags.failParse( + lib.ioi.path(coff), + "error opening /DEFAULTLIB library '{s}': {t}", + .{ lib.path, e }, + ), + }; + errdefer archive.file.close(comp.io); + + coff.loadInput(.{ .archive = archive }) catch |err| switch (err) { + else => |e| return comp.link_diags.failParse( + lib.ioi.path(coff), + "error loading /DEFAULTLIB library '{s}': {t}", + .{ lib.path, e }, + ), + }; + + break :lib; + }; + + return comp.link_diags.failParse( + lib.ioi.path(coff), + "/DEFAULTLIB library '{s}' was not found", + .{lib.path}, + ); + } + } + + coff.inputs_complete = true; + if (comp.zcu == null) + coff.exports_complete = true; } -pub fn updateNav(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { +pub fn updateNav(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) link.Error!void { coff.updateNavInner(pt, nav_index) catch |err| switch (err) { + error.MappedFileIo => return coff.base.cgFail( + nav_index, + "linker failed to update variable: {t}", + .{coff.mf.io_err.?}, + ), else => |e| return e, - error.MappedFileIo => return coff.base.cgFail(nav_index, "linker failed to update variable: {t}", .{coff.mf.io_err.?}), }; } fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { @@ -1546,11 +5464,13 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde const nmi = try coff.navMapIndex(zcu, nav_index); const si = nmi.symbol(coff); + log.debug("updateNav({f}) = {d}", .{ nav.fqn.fmt(ip), si }); const ni = ni: { switch (si.get(coff).ni) { .none => { const sec_si = try coff.navSection(zcu, nav.resolved.?); try coff.nodes.ensureUnusedCapacity(gpa, 1); + if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1); const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ .alignment = zcu.navAlignment(nav_index).toStdMem(), .moved = true, @@ -1565,6 +5485,9 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde const sym = si.get(coff); assert(sym.loc_relocs == .none); sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + if (!isImage(coff) and sym.target_relocs != .none) + try coff.pendingSymbolTableEntry(si); + break :ni sym.ni; }; @@ -1582,12 +5505,12 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde error.WriteFailed => return nw.err.?, else => |e| return e, }; - si.get(coff).size = @intCast(nw.interface.end); - si.applyLocationRelocs(coff); + si.get(coff).extra.size = @intCast(nw.interface.end); + try si.applyLocationRelocs(coff); } if (nav.resolved.?.@"linksection".unwrap()) |_| { - try ni.resize(&coff.mf, gpa, si.get(coff).size); + try ni.resize(&coff.mf, gpa, si.get(coff).extra.size); var parent_ni = ni; while (true) { parent_ni = parent_ni.parent(&coff.mf); @@ -1610,7 +5533,7 @@ pub fn lowerUav( pt: Zcu.PerThread, uav_val: InternPool.Index, uav_align: InternPool.Alignment, -) !link.File.SymbolId { +) link.Error!link.File.SymbolId { const zcu = pt.zcu; const gpa = zcu.gpa; @@ -1639,7 +5562,7 @@ pub fn updateFunc( pt: Zcu.PerThread, func_index: InternPool.Index, mir: *const codegen.AnyMir, -) !void { +) link.Error!void { coff.updateFuncInner(pt, func_index, mir) catch |err| switch (err) { else => |e| return e, error.MappedFileIo => return coff.base.cgFail( @@ -1669,6 +5592,7 @@ fn updateFuncInner( .none => { const sec_si = try coff.navSection(zcu, nav.resolved.?); try coff.nodes.ensureUnusedCapacity(gpa, 1); + if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1); const mod = zcu.navFileScope(func.owner_nav).mod.?; const target = &mod.resolved_target.result; const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ @@ -1694,6 +5618,8 @@ fn updateFuncInner( const sym = si.get(coff); assert(sym.loc_relocs == .none); sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + if (!isImage(coff) and sym.target_relocs != .none) + try coff.pendingSymbolTableEntry(si); break :ni sym.ni; }; @@ -1712,8 +5638,8 @@ fn updateFuncInner( error.WriteFailed => return nw.err.?, else => |e| return e, }; - si.get(coff).size = @intCast(nw.interface.end); - si.applyLocationRelocs(coff); + si.get(coff).extra.size = @intCast(nw.interface.end); + try si.applyLocationRelocs(coff); } pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void { @@ -1729,40 +5655,308 @@ pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void { }; } +fn flushImplib( + coff: *Coff, + implib_file: []const u8, +) !void { + // Emitting implibs is only valid for images + assert(coff.export_table.ni != .none); + + const comp = coff.base.comp; + const gpa = comp.gpa; + const io = comp.io; + + const image_name = std.mem.sliceTo( + coff.export_table.ni.slice(&coff.mf)[@sizeOf(std.coff.ExportDirectoryTable)..], + 0, + ); + const machine_type = coff.targetLoad(&coff.headerPtr().machine); + const members = members: { + const def_arena: std.heap.ArenaAllocator = .init(gpa); + var def: ModuleDefinition = .{ + .name = image_name, + .arena = def_arena, + .type = .mingw, + }; + defer def.deinit(); + + try def.exports.ensureUnusedCapacity( + def.arena.allocator(), + coff.export_table.entries.count(), + ); + + const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf); + for (coff.export_table.entries.values(), 0..) |entry, ord| { + const name = name_table_slice[entry.name_index..][0..entry.name_len]; + const section_number = entry.si.get(coff).section_number; + const import_type: std.coff.ImportType = switch (section_number.symbol(coff)) { + .data, .rdata => .DATA, + .text => .CODE, + else => return comp.link_diags.fail( + "unsupported section for export '{s}': {s}", + .{ name, §ion_number.header(coff).name }, + ), + }; + + def.exports.appendAssumeCapacity(.{ + .name = name, + .mangled_symbol_name = null, + .ext_name = null, + .import_name = null, + .export_as = null, + .no_name = false, + .ordinal = @intCast(ord), + .type = import_type, + .private = false, + }); + } + + def.fixupForImportLibraryGeneration(machine_type); + break :members try implib.getMembers(gpa, def, machine_type); + }; + defer members.deinit(); + + const lib_sub_path = try std.fs.path.join(gpa, &.{ + std.fs.path.dirname(coff.base.emit.sub_path) orelse "", + implib_file, + }); + defer gpa.free(lib_sub_path); + + const lib_final_file = try coff.base.emit.root_dir.handle.createFile(io, lib_sub_path, .{ .truncate = true }); + defer lib_final_file.close(io); + var buffer: [1024]u8 = undefined; + var file_writer = lib_final_file.writer(io, &buffer); + try implib.writeCoffArchive(gpa, &file_writer.interface, members); + try file_writer.interface.flush(); +} + +fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void { + const comp = coff.base.comp; + const gpa = comp.gpa; + const max_notes = 4; + + var undef_indices: std.ArrayListUnmanaged(u32) = .empty; + for (coff.relocs.items, 0..) |reloc, reloc_i| { + if (reloc.flags.free) continue; + const target_sym = reloc.target.get(coff); + switch (target_sym.ni) { + .none => { + assert(target_sym.gmi != .none); + if (target_sym.section_number == .ABSOLUTE) continue; + (try undef_indices.addOne(gpa)).* = @intCast(reloc_i); + }, + else => continue, + } + } + + if (undef_indices.items.len == 0) return; + + const undefLessThan = struct { + fn lessThan(ctx: *const Coff, lhs: u32, rhs: u32) bool { + const reloc_l = &ctx.relocs.items[lhs]; + const reloc_r = &ctx.relocs.items[rhs]; + if (reloc_l.target == reloc_r.target) + return @intFromEnum(reloc_l.loc) < @intFromEnum(reloc_r.loc) + else + return @intFromEnum(reloc_l.target) < @intFromEnum(reloc_r.target); + } + }.lessThan; + + std.mem.sortUnstable(u32, undef_indices.items, coff, undefLessThan); + + var start_i: usize = 0; + var num_unique_references: usize = 1; + for (0..undef_indices.items.len) |i| { + const target = coff.relocs.items[undef_indices.items[start_i]].target; + if (i == undef_indices.items.len - 1 or target != coff.relocs.items[undef_indices.items[i + 1]].target) { + defer { + start_i = i + 1; + num_unique_references = 1; + } + + const num_full_notes = @min(max_notes, num_unique_references); + var err = try comp.link_diags.addErrorWithNotes( + num_full_notes + @intFromBool(num_unique_references > max_notes), + ); + const target_sym = target.get(coff); + try err.addMsg("undefined symbol: {s}", .{target_sym.gmi.name(coff).toSlice(coff)}); + + // TODO: If lib_name is set, show the user + + var prev_loc_si: Symbol.Index = .null; + for (undef_indices.items[start_i .. i + 1]) |reference_i| { + if (err.note_slot == num_full_notes) break; + + const reloc = &coff.relocs.items[reference_i]; + const loc_si = reloc.loc; + if (loc_si == prev_loc_si) continue; + defer prev_loc_si = loc_si; + + const loc_sym = loc_si.get(coff); + + // TODO: Make this a helper for anything that needs to report "referenced by" notes + switch (coff.getNode(loc_sym.ni)) { + .data_directories => { + const dir: std.coff.IMAGE.DIRECTORY_ENTRY = + @enumFromInt(reloc.offset / @sizeOf(std.coff.ImageDataDirectory)); + err.addNote("referenced by data directory entry: {t}", .{dir}); + }, + .optional_header => err.addNote("referenced by optional header field", .{}), + .input_section => |isi| { + const other_ioi = isi.input(coff); + if (loc_sym.gmi == .none) { + const section = isi.inputSection(coff); + const section_name = coff.getNode(loc_sym.ni.parent(&coff.mf)) + .object_section.name(coff).toSlice(coff); + + if (section.comdat_si != .null) { + const comdat_sym = section.comdat_si.get(coff); + const comdat_name = if (comdat_sym.gmi != .none) + comdat_sym.gmi.name(coff).toSlice(coff) + else + comdat_sym.extra.isli.name(coff).toSlice(coff); + + err.addNote("referenced by input COMDAT section '{s}={s}' '{f}{f}'", .{ + section_name, + comdat_name, + other_ioi.path(coff).fmtEscapeString(), + fmtMemberNameString(other_ioi.memberName(coff)), + }); + } else { + err.addNote("referenced by input section '{s}' '{f}{f}'", .{ + section_name, + other_ioi.path(coff).fmtEscapeString(), + fmtMemberNameString(other_ioi.memberName(coff)), + }); + } + } else { + err.addNote("referenced by input symbol '{s}' from '{f}{f}'", .{ + loc_sym.gmi.name(coff).toSlice(coff), + other_ioi.path(coff).fmtEscapeString(), + fmtMemberNameString(other_ioi.memberName(coff)), + }); + } + }, + .import_thunk => |gmi| err.addNote("referenced by import thunk for '{s}'", .{ + gmi.name(coff).toSlice(coff), + }), + inline .nav, + .uav, + .lazy_code, + .lazy_const_data, + => |val, tag| { + err.addNote("referenced by '{f}'", .{ + format: switch (tag) { + .nav => { + const ip = &comp.zcu.?.intern_pool; + break :format ip.getNav(val.navIndex(coff)).fqn.fmt(ip); + }, + .uav => Value.fromInterned(val.uavValue(coff)).fmtValue(.{ + .zcu = coff.base.comp.zcu.?, + .tid = tid, + }), + inline .lazy_code, .lazy_const_data => Type.fromInterned(val.lazySymbol(coff).ty).fmt(.{ + .zcu = coff.base.comp.zcu.?, + .tid = tid, + }), + else => unreachable, + }, + }); + }, + else => unreachable, + } + } + + if (num_unique_references > max_notes) + err.addNote("referenced {d} more times", .{num_unique_references - max_notes}); + } else if (i != start_i and + coff.relocs.items[undef_indices.items[i - 1]].loc != coff.relocs.items[undef_indices.items[i]].loc) + { + num_unique_references += 1; + } + } + + return error.AlreadyReported; +} + pub fn flush( coff: *Coff, arena: std.mem.Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, -) !void { +) link.Error!void { _ = arena; _ = prog_node; - while (try coff.idle(tid)) {} - - // hack for stage2_x86_64 + coff const comp = coff.base.comp; - if (comp.compiler_rt_dyn_lib) |crt_file| { - const gpa = comp.gpa; - const io = comp.io; - const compiler_rt_sub_path = try std.fs.path.join(gpa, &.{ - std.fs.path.dirname(coff.base.emit.sub_path) orelse "", - std.fs.path.basename(crt_file.full_object_path.sub_path), - }); - defer gpa.free(compiler_rt_sub_path); - std.Io.Dir.copyFile( - crt_file.full_object_path.root_dir.handle, - crt_file.full_object_path.sub_path, - coff.base.emit.root_dir.handle, - compiler_rt_sub_path, - io, - .{}, - ) catch |err| return comp.link_diags.fail("copy '{s}' failed: {t}", .{ compiler_rt_sub_path, err }); + + // TODO: When https://github.com/ziglang/zig/issues/23617 is in, + // this should be set after updateExports instead + coff.exports_complete = true; + + while (try coff.resolve(tid)) {} + while (try coff.idle(tid)) {} + + // This has to occur after all other flushMoved / flushResized have resolved, + // but it will also generate one more set of resizes and moves. + if (coff.symbol_table.pending_shrink) { + coff.symbol_table.pending_shrink = false; + + const number_of_symbols = coff.targetLoad(&coff.headerPtr().number_of_symbols); + coff.symbol_table.ni.shrink( + &coff.mf, + comp.gpa, + number_of_symbols * std.coff.Symbol.sizeOf(), + true, + ) catch |err| return comp.link_diags.fail( + "linker failed to compact symbol table: {t}", + .{err}, + ); } + while (try coff.idle(tid)) {} + + if (coff.isImage()) + try coff.reportUndefs(tid); + + if (comp.emit_implib) |implib_file| + coff.flushImplib(implib_file) catch |err| + return comp.link_diags.fail("flushing implib '{s}' failed: {t}", .{ implib_file, err }); + + coff.mf.flush() catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return comp.link_diags.fail("flush write failed: {t}", .{e}), + }; + + if (coff.options.enable_link_snapshots) + coff.dumpStderr(tid) catch |err| + return comp.link_diags.fail("dumping link snapshot failed: {t}", .{err}); } -pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { +/// Runs a single "resolution" task. +/// These are tasks that need to modify the node structure in some way. +/// They must run in a defined order with respect to linker tasks. +fn resolve(coff: *Coff, tid: Zcu.PerThread.Id) !bool { const comp = coff.base.comp; task: { + while (coff.section_merge_pending_index < coff.section_merges.count()) { + defer coff.section_merge_pending_index += 1; + const sub_prog_node = coff.synth_prog_node.start( + coff.section_merges.keys()[coff.section_merge_pending_index].toSlice(coff), + 0, + ); + defer sub_prog_node.end(); + coff.flushSectionMerge(coff.section_merge_pending_index) catch |err| switch (err) { + //error.OutOfMemory => |e| return e, + else => |e| return comp.link_diags.fail( + "linker failed to merge section {s} into {s}: {t}", + .{ + coff.section_merges.keys()[coff.section_merge_pending_index].toSlice(coff), + coff.section_merges.values()[coff.section_merge_pending_index].toSlice(coff), + e, + }, + ), + }; + break :task; + } while (coff.pending_uavs.pop()) |pending_uav| { const sub_prog_node = coff.idleProgNode(tid, coff.const_prog_node, .{ .uav = pending_uav.key }); defer sub_prog_node.end(); @@ -1779,22 +5973,52 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { }; break :task; } - if (coff.global_pending_index < coff.globals.count()) { - const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; - const gmi: Node.GlobalMapIndex = @enumFromInt(coff.global_pending_index); - coff.global_pending_index += 1; + if (coff.pending_input) |pending_iami| { + const name_slice = pending_iami.member(coff).name.toSlice(coff); + const sub_prog_node = coff.input_prog_node.start( + name_slice, + 0, + ); + defer sub_prog_node.end(); + coff.pending_input = null; + coff.flushInputMember(pending_iami) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return comp.link_diags.fail( + "linker failed to load archive member '{f}{f}': {t}", + .{ + pending_iami.member(coff).iai.path(coff), + fmtMemberNameString(name_slice), + e, + }, + ), + }; + break :task; + } + if (coff.exports_complete and coff.global_pending_index < coff.globals.count()) { + const gmi: Node.GlobalMapIndex = .wrap(coff.global_pending_index); const sub_prog_node = coff.synth_prog_node.start( - gmi.globalName(coff).name.toSlice(coff), + gmi.name(coff).toSlice(coff), 0, ); defer sub_prog_node.end(); - coff.flushGlobal(pt, gmi) catch |err| switch (err) { + if (coff.flushGlobal(gmi) catch |err| switch (err) { else => |e| return e, error.MappedFileIo => return comp.link_diags.fail( "linker failed to lower constant: {t}", .{coff.mf.io_err.?}, ), - }; + }) coff.global_pending_index += 1; + break :task; + } + if (coff.exports_complete and coff.pending_special_symbol != .none) { + coff.pending_special_symbol = coff.flushSpecialSymbol(coff.pending_special_symbol) catch |err| + switch (err) { + error.OutOfMemory => |e| return e, + else => |e| return comp.link_diags.fail( + "linker failed to flush special symbols: {t}", + .{e}, + ), + }; break :task; } var lazy_it = coff.lazy.iterator(); @@ -1824,6 +6048,73 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { }; break :task; }; + if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) { + defer coff.symbol_table.pending_symbol_index += 1; + const si = coff.symbol_table.symbols.keys()[coff.symbol_table.pending_symbol_index]; + const sym = si.get(coff); + const sub_prog_node = coff.idleProgNode( + tid, + coff.symbol_prog_node, + if (sym.ni != .none) + coff.getNode(sym.ni) + else + .{ .import_thunk = sym.gmi }, + ); + defer sub_prog_node.end(); + coff.flushSymbolTableEntry( + coff.symbol_table.pending_symbol_index, + .{ .zcu = comp.zcu.?, .tid = tid }, + ) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return comp.link_diags.fail( + "linker failed to flush symbol table entry: {t}", + .{e}, + ), + }; + break :task; + } + } + + if (coff.section_merge_pending_index < coff.section_merges.count()) return true; + if (coff.pending_uavs.count() > 0) return true; + if (coff.pending_input != null) return true; + if (coff.exports_complete and coff.globals.count() > coff.global_pending_index) return true; + assert(!coff.exports_complete or coff.inputs_complete); + if (coff.exports_complete and coff.pending_special_symbol != .none) return true; + for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; + if (coff.symbol_table.pending_symbol_index < coff.symbol_table.symbols.count()) return true; + return false; +} + +pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { + // Idle tasks should not modify create / modify nodes, otherwise the output is not reproducible. + coff.mf.nodes_lock.lock(); + defer coff.mf.nodes_lock.unlock(); + + const comp = coff.base.comp; + task: { + // TODO: Idle task for flushing obj into lib + if (coff.input_section_pending_index < coff.input_sections.items.len) { + const isi: Node.InputSection.Index = @enumFromInt(coff.input_section_pending_index); + coff.input_section_pending_index += 1; + const sub_prog_node = coff.idleProgNode(tid, coff.input_prog_node, coff.getNode(isi.symbol(coff).node(coff))); + defer sub_prog_node.end(); + coff.flushInputSection(isi) catch |err| switch (err) { + else => |e| { + const ioi = isi.input(coff); + return comp.link_diags.fail( + "linker failed to read input section '{s}' from \"{f}{f}\": {t}", + .{ + isi.symbol(coff).get(coff).section_number.name(coff).toSlice(coff), + ioi.path(coff).fmtEscapeString(), + fmtMemberNameString(ioi.memberName(coff)), + e, + }, + ); + }, + }; + break :task; + } while (coff.mf.updates.pop()) |ni| { const clean_moved = ni.cleanMoved(&coff.mf); const clean_resized = ni.cleanResized(&coff.mf); @@ -1836,11 +6127,33 @@ pub fn idle(coff: *Coff, tid: Zcu.PerThread.Id) !bool { break :task; } else coff.mf.update_prog_node.completeOne(); } + while (coff.pending_members.pop()) |pending_mi| { + const sub_prog_node = coff.idleProgNode( + tid, + coff.symbol_prog_node, + coff.getNode(pending_mi.key.get(coff).content_ni), + ); + defer sub_prog_node.end(); + try coff.flushMember(pending_mi.key); + break :task; + } + if (coff.exports_complete and coff.export_table.pending_sort) { + defer coff.export_table.pending_sort = false; + const sub_prog_node = coff.idleProgNode( + tid, + coff.synth_prog_node, + coff.getNode(coff.export_table.ni), + ); + defer sub_prog_node.end(); + + coff.flushExportsSort(); + break :task; + } } - if (coff.pending_uavs.count() > 0) return true; - if (coff.globals.count() > coff.global_pending_index) return true; - for (&coff.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; + if (coff.input_sections.items.len > coff.input_section_pending_index) return true; if (coff.mf.updates.items.len > 0) return true; + if (coff.pending_members.count() > 0) return true; + if (coff.exports_complete and coff.export_table.pending_sort) return true; return false; } @@ -1855,7 +6168,15 @@ fn idleProgNode( else => |tag| @tagName(tag), .image_section => |si| std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), inline .pseudo_section, .object_section => |smi| smi.name(coff).toSlice(coff), - .global => |gmi| gmi.globalName(coff).name.toSlice(coff), + .input_section => |isi| { + const ioi = isi.input(coff); + break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ + ioi.path(coff).fmtEscapeString(), + fmtMemberNameString(ioi.memberName(coff)), + coff.getNode(isi.symbol(coff).node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff), + }) catch &name; + }, + .import_thunk => |gmi| gmi.name(coff).toSlice(coff), .nav => |nmi| { const ip = &coff.base.comp.zcu.?.intern_pool; break :name ip.getNav(nmi.navIndex(coff)).fqn.toSlice(ip); @@ -1866,6 +6187,7 @@ fn idleProgNode( .tid = tid, }), }) catch &name, + .archive_member => |mi| &mi.get(coff).headerPtr(coff).name, }, 0); } @@ -1886,9 +6208,10 @@ fn flushUav( const sec_si = (try coff.objectSectionMapIndex( .@".rdata", coff.mf.flags.block_size, - .{ .read = true }, + .{ .read = true, .initialized = true }, )).symbol(coff); try coff.nodes.ensureUnusedCapacity(gpa, 1); + if (!isImage(coff)) try coff.symbol_table.symbols.ensureUnusedCapacity(gpa, 1); const sym = si.get(coff); const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{ .alignment = uav_align.toStdMem(), @@ -1907,6 +6230,9 @@ fn flushUav( const sym = si.get(coff); assert(sym.loc_relocs == .none); sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + if (!isImage(coff) and sym.target_relocs != .none) + try coff.pendingSymbolTableEntry(si); + break :ni sym.ni; }; @@ -1923,173 +6249,561 @@ fn flushUav( error.WriteFailed => return nw.err.?, else => |e| return e, }; - si.get(coff).size = @intCast(nw.interface.end); - si.applyLocationRelocs(coff); + si.get(coff).extra.size = @intCast(nw.interface.end); + try si.applyLocationRelocs(coff); } -fn flushGlobal(coff: *Coff, pt: Zcu.PerThread, gmi: Node.GlobalMapIndex) !void { - const zcu = pt.zcu; - const comp = zcu.comp; - const gpa = zcu.gpa; - const gn = gmi.globalName(coff); - if (gn.lib_name.toSlice(coff)) |lib_name| { - const name = gn.name.toSlice(coff); - try coff.nodes.ensureUnusedCapacity(gpa, 4); - try coff.symbol_table.ensureUnusedCapacity(gpa, 1); +fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !void { + const si = gmi.symbol(coff); + const sym = si.get(coff); + const alias_sym = alias_si.get(coff); + assert(sym.section_number == .UNDEFINED); + assert(sym.loc_relocs == .none); - const target_endian = coff.targetEndian(); - const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); - const addr_size: u64, const addr_align: std.mem.Alignment = switch (magic) { - _ => unreachable, - .PE32 => .{ 4, .@"4" }, - .@"PE32+" => .{ 8, .@"8" }, - }; + log.debug("aliasGlobal({s}, {?s}) {d}->{d} ({?s})", .{ + gmi.name(coff).toSlice(coff), + gmi.libName(coff).toSlice(coff), + si, + alias_si, + if (alias_sym.gmi != .none) alias_sym.gmi.name(coff).toSlice(coff) else null, + }); - const gop = try coff.import_table.entries.getOrPutAdapted( - gpa, - lib_name, - ImportTable.Adapter{ .coff = coff }, - ); - const import_hint_name_align: std.mem.Alignment = .@"2"; - if (!gop.found_existing) { - errdefer _ = coff.import_table.entries.pop(); - try coff.import_table.ni.resize( - &coff.mf, - gpa, - @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2), + var ri = sym.target_relocs; + while (ri != .none) { + const reloc = ri.get(coff); + assert(reloc.target == si); + reloc.target = alias_si; + if (reloc.next == .none) { + reloc.next = alias_sym.target_relocs; + if (alias_sym.target_relocs != .none) + alias_sym.target_relocs.get(coff).prev = ri; + break; + } + ri = reloc.next; + } + + const prev_target_relocs = alias_sym.target_relocs; + if (sym.target_relocs != .none) + alias_sym.target_relocs = sym.target_relocs; + sym.target_relocs = .none; + sym.gmi = alias_sym.gmi; + coff.globals.values()[gmi.unwrap().?].si = alias_si; + // Only apply the new relocs + try alias_si.applyTargetRelocs(coff, prev_target_relocs); +} + +fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool { + const comp = coff.base.comp; + const gpa = comp.gpa; + const name = gmi.name(coff); + const si = gmi.symbol(coff); + + log.debug( + "flushGlobal({s}, {?s}) = n{d} {d}@{d}", + .{ + name.toSlice(coff), + gmi.libName(coff).toSlice(coff), + si.get(coff).ni, + si, + si.get(coff).section_number, + }, + ); + + if (!coff.isImage()) { + try coff.pendingSymbolTableEntry(si); + if (coff.isArchive() and si.get(coff).ni != .none) + try coff.ensureMemberSymbol( + coff.getNode(Node.known.zcu_member).archive_member, + name, ); - const import_hint_name_table_len = - import_hint_name_align.forward(lib_name.len + ".dll".len + 1); - const idata_section_ni = coff.import_table.ni.parent(&coff.mf); - const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ - .size = addr_size * 2, - .alignment = addr_align, - .moved = true, - }); - const import_address_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ - .size = addr_size * 2, - .alignment = addr_align, - .moved = true, - }); - const import_address_table_si = coff.addSymbolAssumeCapacity(); - { - const import_address_table_sym = import_address_table_si.get(coff); - import_address_table_sym.ni = import_address_table_ni; - assert(import_address_table_sym.loc_relocs == .none); - import_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); - import_address_table_sym.section_number = - coff.getNode(idata_section_ni).object_section.symbol(coff).get(coff).section_number; + + return true; + } + + if (si.get(coff).ni != .none) + return true; + + const Import = struct { + lib_name: String, + name: String.Optional, + ordinal_hint: u16, + kind: enum { + iat_ptr, + thunk, + }, + }; + + const import: Import = import: { + const sym = si.get(coff); + const name_slice = name.toSlice(coff); + const imp_match = std.mem.startsWith(u8, name_slice, imp_prefix); + + // Globals may have the __imp_ prefix already if they are undef externals from another input. + assert(sym.flags.dll_storage_class != .dllexport); + const search_name, const is_imp = if (imp_match or sym.flags.dll_storage_class != .dllimport) + .{ name, imp_match } + else name: { + try coff.ensureUnusedStringCapacity(imp_prefix.len + name_slice.len); + const imp_name = try std.fmt.allocPrint(gpa, imp_prefix ++ "{s}", .{name_slice}); + defer gpa.free(imp_name); + break :name .{ coff.getOrPutStringAssumeCapacity(imp_name), true }; + }; + + const opt_alt_search_name = coff.alternate_names.get(search_name); + const search_libs = switch (sym.flags.value_tag) { + .weak_alias_si, .weak_alias_name => switch (sym.flags.weak_external_strat) { + .none => unreachable, + .no_library => false, + .library, + .alias, + => true, + .anti_dependency => return comp.link_diags.fail( + // TODO: Figure out what the purpose of this is + "TODO support anti_dependency weak external: {s}", + .{name.toSlice(coff)}, + ), + }, + else => true, + }; + + const opt_indices_lists: []const ?InputArchive.SearchList = if (search_libs) &.{ + coff.input_archive_symbol_indices.get(search_name), + if (opt_alt_search_name) |alt| coff.input_archive_symbol_indices.get(alt) else null, + } else &.{}; + + for (opt_indices_lists) |opt_indices_list| { + const indices_list = opt_indices_list orelse continue; + var iter: InputArchive.Member.Symbol.Index = indices_list.first; + while (true) { + const archive_sym = &coff.input_archive_symbols.items[@intFromEnum(iter)]; + const member = &coff.input_archive_members.items[@intFromEnum(archive_sym.iami)]; + member: switch (member.content) { + .object => if (!member.flags.is_loaded) { + if (gmi.libName(coff).unwrap()) |lib_name| + if (!std.ascii.eqlIgnoreCase( + lib_name.toSlice(coff), + member.iai.path(coff).stem(), + )) break :member; + + // Try loading the input member and then retry. + // This could still be a member containing imports + // that use the older non-IMPORT_HEADER method. + coff.pending_input = archive_sym.iami; + return false; + }, + .import => |import| { + if (gmi.libName(coff).unwrap()) |lib_name| + if (!std.ascii.eqlIgnoreCase( + import.lib_name.toSlice(coff), + lib_name.toSlice(coff), + )) break :member; + + const imp_name: String.Optional = name: switch (import.name_type) { + .NAME, + .NAME_NOPREFIX, + .NAME_UNDECORATE, + => |tag| { + const symbol_name: []const u8 = import.symbol_name.toSlice(coff); + const end_match = std.mem.endsWith(u8, name_slice, symbol_name); + const len_delta = name_slice.len -% symbol_name.len; + if (!end_match or + (!imp_match and len_delta != 0) or + (imp_match and len_delta != imp_prefix.len)) + return comp.link_diags.fail( + "global '{s}' has mismatched symbol name in import header: '{s}'", + .{ + name.toSlice(coff), + import.symbol_name.toSlice(coff), + }, + ); + + const imp_name = if (tag == .NAME) import.symbol_name else undecorated: { + var imp_name = std.mem.trimStart(u8, symbol_name, "?@_"); + if (tag == .NAME_UNDECORATE) + imp_name = std.mem.sliceTo(imp_name, '@'); + + try coff.ensureUnusedStringCapacity(imp_name.len); + break :undecorated coff.getOrPutStringAssumeCapacity(imp_name); + }; + + break :name imp_name.toOptional(); + }, + .ORDINAL => break :name .none, + else => |t| return comp.link_diags.fail("TODO handle name_type {t}", .{t}), + }; + + break :import .{ + .lib_name = import.lib_name, + .name = imp_name, + .ordinal_hint = import.import_ordinal_hint, + .kind = if (import.type == .CODE and !is_imp) .thunk else .iat_ptr, + }; + }, + } + + if (archive_sym.next == iter) break; + iter = archive_sym.next; } - const import_hint_name_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ - .size = import_hint_name_table_len, - .alignment = import_hint_name_align, - .moved = true, - }); - gop.value_ptr.* = .{ - .import_lookup_table_ni = import_lookup_table_ni, - .import_address_table_si = import_address_table_si, - .import_hint_name_table_ni = import_hint_name_table_ni, - .len = 0, - .hint_name_len = @intCast(import_hint_name_table_len), + } + + switch (sym.flags.value_tag) { + .weak_alias_si => { + try coff.aliasGlobal(gmi, sym.value.weak_alias_si); + return true; + }, + .weak_alias_name => { + // Convert an unresolved weak external that itself refers to an undef external + // into a (possibly new) global, so it can be resolved separately. + const alias_gop = try coff.getOrPutGlobalSymbol(.{ + .name = sym.value.weak_alias_name.toSlice(coff), + }); + try coff.aliasGlobal(gmi, alias_gop.value_ptr.si); + return true; + }, + else => {}, + } + + // If there was an object that had the alternate name, we've attempted to load it + if (opt_alt_search_name) |alt_search_name| { + if (coff.globals.get(alt_search_name)) |alias_global| { + try coff.aliasGlobal(gmi, alias_global.si); + return true; + } + } + + // Allow importing symbols with no implib entry, if a lib_name was specified. + // This is necessary for certain ntdll symbols, such as LdrRegisterDllNotification, + // which are not in the implib. + if (sym.flags.type != .unknown) { + if (gmi.libName(coff).unwrap()) |lib_name| break :import .{ + .lib_name = lib_name, + .name = name.toOptional(), + .ordinal_hint = 0, + .kind = if (sym.flags.type == .code) .thunk else .iat_ptr, }; - const import_hint_name_slice = import_hint_name_table_ni.slice(&coff.mf); - @memcpy(import_hint_name_slice[0..lib_name.len], lib_name); - @memcpy(import_hint_name_slice[lib_name.len..][0..".dll".len], ".dll"); - @memset(import_hint_name_slice[lib_name.len + ".dll".len ..], 0); - coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @enumFromInt(gop.index) }); - coff.nodes.appendAssumeCapacity(.{ .import_address_table = @enumFromInt(gop.index) }); - coff.nodes.appendAssumeCapacity(.{ .import_hint_name_table = @enumFromInt(gop.index) }); + } + + return true; + }; + + try coff.nodes.ensureUnusedCapacity(gpa, 4); + try coff.symbols.ensureUnusedCapacity(gpa, 2); - const import_directory_entries = coff.importDirectoryTableSlice()[gop.index..][0..2]; - import_directory_entries.* = .{ .{ - .import_lookup_table_rva = coff.computeNodeRva(import_lookup_table_ni), - .time_date_stamp = 0, - .forwarder_chain = 0, - .name_rva = coff.computeNodeRva(import_hint_name_table_ni), - .import_address_table_rva = coff.computeNodeRva(import_address_table_ni), - }, .{ - .import_lookup_table_rva = 0, - .time_date_stamp = 0, - .forwarder_chain = 0, - .name_rva = 0, - .import_address_table_rva = 0, - } }; - if (target_endian != native_endian) - std.mem.byteSwapAllFields([2]std.coff.ImportDirectoryEntry, import_directory_entries); + const target_endian = coff.targetEndian(); + const addr_info = coff.targetAddrInfo(); + const lib_name = import.lib_name.toSlice(coff); + const gop = try coff.import_table.entries.getOrPutAdapted( + gpa, + lib_name, + ImportTable.Adapter{ .coff = coff }, + ); + const import_hint_name_align: std.mem.Alignment = .@"2"; + if (!gop.found_existing) { + errdefer _ = coff.import_table.entries.pop(); + try coff.import_table.ni.resize( + &coff.mf, + gpa, + @sizeOf(std.coff.ImportDirectoryEntry) * (gop.index + 2), + ); + const import_hint_name_table_len = + import_hint_name_align.forward(lib_name.len + ".dll".len + 1); + const idata_section_ni = coff.import_table.ni.parent(&coff.mf); + const import_lookup_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ + .size = addr_info.size * 2, + .alignment = addr_info.alignment, + .moved = true, + }); + const import_address_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ + .size = addr_info.size * 2, + .alignment = addr_info.alignment, + .moved = true, + }); + const import_address_table_si = coff.addSymbolAssumeCapacity(); + { + const import_address_table_sym = import_address_table_si.get(coff); + import_address_table_sym.ni = import_address_table_ni; + assert(import_address_table_sym.loc_relocs == .none); + import_address_table_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + import_address_table_sym.section_number = + coff.getNode(idata_section_ni).object_section.symbol(coff).get(coff).section_number; } + const import_hint_name_table_ni = try coff.mf.addLastChildNode(gpa, idata_section_ni, .{ + .size = import_hint_name_table_len, + .alignment = import_hint_name_align, + .moved = true, + }); + gop.value_ptr.* = .{ + .import_lookup_table_ni = import_lookup_table_ni, + .import_address_table_si = import_address_table_si, + .import_hint_name_table_ni = import_hint_name_table_ni, + .import_address_table_symbols = .empty, + .len = 0, + .hint_name_len = @intCast(import_hint_name_table_len), + }; + const import_hint_name_slice = import_hint_name_table_ni.slice(&coff.mf); + @memcpy(import_hint_name_slice[0..lib_name.len], lib_name); + @memcpy(import_hint_name_slice[lib_name.len..][0..".dll".len], ".dll"); + @memset(import_hint_name_slice[lib_name.len + ".dll".len ..], 0); + coff.nodes.appendAssumeCapacity(.{ .import_lookup_table = @enumFromInt(gop.index) }); + coff.nodes.appendAssumeCapacity(.{ .import_address_table = @enumFromInt(gop.index) }); + coff.nodes.appendAssumeCapacity(.{ .import_hint_name_table = @enumFromInt(gop.index) }); + + const import_directory_entries = coff.importDirectoryTableSlice()[gop.index..][0..2]; + import_directory_entries.* = .{ .{ + .import_lookup_table_rva = coff.computeNodeRva(import_lookup_table_ni), + .time_date_stamp = 0, + .forwarder_chain = 0, + .name_rva = coff.computeNodeRva(import_hint_name_table_ni), + .import_address_table_rva = coff.computeNodeRva(import_address_table_ni), + }, .{ + .import_lookup_table_rva = 0, + .time_date_stamp = 0, + .forwarder_chain = 0, + .name_rva = 0, + .import_address_table_rva = 0, + } }; + if (target_endian != native_endian) + std.mem.byteSwapAllFields([2]std.coff.ImportDirectoryEntry, import_directory_entries); + } + + log.debug( + "flushGlobalImport({s}, {?s}, {d}, {s})", + .{ name.toSlice(coff), import.name.toSlice(coff), import.ordinal_hint, lib_name }, + ); + + const iat_symbol_gop = try coff.import_table.iat_symbol_indices.getOrPut(gpa, .{ + .iti = @enumFromInt(gop.index), + .name = import.name, + .ordinal_hint = import.ordinal_hint, + }); + if (!iat_symbol_gop.found_existing) { const import_symbol_index = gop.value_ptr.len; + iat_symbol_gop.value_ptr.* = import_symbol_index; + gop.value_ptr.len = import_symbol_index + 1; - const new_symbol_table_size = addr_size * (import_symbol_index + 2); - const import_hint_name_index = gop.value_ptr.hint_name_len; - gop.value_ptr.hint_name_len = @intCast( - import_hint_name_align.forward(import_hint_name_index + 2 + name.len + 1), - ); + const new_symbol_table_size = addr_info.size * (import_symbol_index + 2); + try gop.value_ptr.import_lookup_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); const import_address_table_ni = gop.value_ptr.import_address_table_si.node(coff); try import_address_table_ni.resize(&coff.mf, gpa, new_symbol_table_size); - try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); + + const opt_imp_name = import.name.toSlice(coff); + const opt_import_hint_name_index = if (opt_imp_name) |imp_name| blk: { + const import_hint_name_index = gop.value_ptr.hint_name_len; + gop.value_ptr.hint_name_len = @intCast( + import_hint_name_align.forward(import_hint_name_index + 2 + imp_name.len + 1), + ); + try gop.value_ptr.import_hint_name_table_ni.resize(&coff.mf, gpa, gop.value_ptr.hint_name_len); + break :blk import_hint_name_index; + } else null; + + const import_hint_name_rva = if (opt_import_hint_name_index) |import_hint_name_index| blk: { + const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); + const ordinal_hint: *u16 = @ptrCast(@alignCast(import_hint_name_slice[import_hint_name_index..][0..2])); + ordinal_hint.* = std.mem.nativeTo(u16, import.ordinal_hint, target_endian); + @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..opt_imp_name.?.len], opt_imp_name.?); + @memset(import_hint_name_slice[import_hint_name_index + 2 + opt_imp_name.?.len ..], 0); + break :blk coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; + } else 0; + const import_lookup_slice = gop.value_ptr.import_lookup_table_ni.slice(&coff.mf); const import_address_slice = import_address_table_ni.slice(&coff.mf); - const import_hint_name_slice = gop.value_ptr.import_hint_name_table_ni.slice(&coff.mf); - @memset(import_hint_name_slice[import_hint_name_index..][0..2], 0); - @memcpy(import_hint_name_slice[import_hint_name_index + 2 ..][0..name.len], name); - @memset(import_hint_name_slice[import_hint_name_index + 2 + name.len ..], 0); - const import_hint_name_rva = - coff.computeNodeRva(gop.value_ptr.import_hint_name_table_ni) + import_hint_name_index; - switch (magic) { + switch (addr_info.magic) { _ => unreachable, inline .PE32, .@"PE32+" => |ct_magic| { - const Addr = switch (ct_magic) { - _ => comptime unreachable, - .PE32 => u32, - .@"PE32+" => u64, - }; - const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); - const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); - const import_hint_name_rvas: [2]Addr = .{ - std.mem.nativeTo(Addr, @intCast(import_hint_name_rva), target_endian), - std.mem.nativeTo(Addr, 0, target_endian), + const Entry = std.coff.ImportLookupTableEntry(ct_magic); + const import_lookup_table: []Entry = @ptrCast(@alignCast(import_lookup_slice)); + const import_address_table: []Entry = @ptrCast(@alignCast(import_address_slice)); + var import_hint_name_rvas: [2]Entry = .{ + .{ + .payload = if (import.name == .none) + .{ .ordinal = .{ .ordinal = import.ordinal_hint } } + else + .{ .hint_name_rva = @intCast(import_hint_name_rva) }, + .is_ordinal = import.name == .none, + }, + @bitCast(@as(@typeInfo(Entry).@"struct".backing_integer.?, 0)), }; + if (native_endian != target_endian) + for (&import_hint_name_rvas) |*v| std.mem.byteSwapAllFields(Entry, v); + import_lookup_table[import_symbol_index..][0..2].* = import_hint_name_rvas; import_address_table[import_symbol_index..][0..2].* = import_hint_name_rvas; }, } - const si = gmi.symbol(coff); - const sym = si.get(coff); - sym.section_number = Symbol.Index.text.get(coff).section_number; - assert(sym.loc_relocs == .none); - sym.loc_relocs = @enumFromInt(coff.relocs.items.len); - switch (coff.targetLoad(&coff.headerPtr().machine)) { - else => |tag| @panic(@tagName(tag)), - .AMD64 => { - const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; - const target = &comp.root_mod.resolved_target.result; - const ni = try coff.mf.addLastChildNode(gpa, Symbol.Index.text.node(coff), .{ - .alignment = switch (comp.root_mod.optimize_mode) { - .Debug, - .ReleaseSafe, - .ReleaseFast, - => target_util.defaultFunctionAlignment(target), - .ReleaseSmall => target_util.minFunctionAlignment(target), - }.toStdMem(), - .size = init.len, - }); - @memcpy(ni.slice(&coff.mf)[0..init.len], &init); - sym.ni = ni; - sym.size = init.len; + } + + const sym = si.get(coff); + assert(sym.loc_relocs == .none); + const iat_offset: u32 = @intCast(addr_info.size * iat_symbol_gop.value_ptr.*); + switch (import.kind) { + .iat_ptr => { + const iat_sym = gop.value_ptr.import_address_table_si.get(coff); + sym.section_number = iat_sym.section_number; + sym.ni = iat_sym.ni; + sym.setValue(.{ .node_offset = iat_offset }); + (try gop.value_ptr.import_address_table_symbols.addOne(gpa)).* = si; + }, + .thunk => { + sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + + const target = &comp.root_mod.resolved_target.result; + const alignment = switch (comp.root_mod.optimize_mode) { + .Debug, + .ReleaseSafe, + .ReleaseFast, + => target_util.defaultFunctionAlignment(target), + .ReleaseSmall => target_util.minFunctionAlignment(target), + }.toStdMem(); + const parent_si = (try coff.pseudoSectionMapIndex( + .@".thunks", + alignment, + .{ .execute = true, .read = true }, + )).symbol(coff); + + const parent_sym = parent_si.get(coff); + sym.section_number = parent_sym.section_number; + + switch (coff.targetLoad(&coff.headerPtr().machine)) { + else => |tag| @panic(@tagName(tag)), + .AMD64 => { + const init = [_]u8{ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 }; + const ni = try coff.mf.addLastChildNode(gpa, parent_sym.ni, .{ + .alignment = alignment, + .size = init.len, + }); + @memcpy(ni.slice(&coff.mf)[0..init.len], &init); + sym.ni = ni; + sym.extra.size = init.len; + try coff.addReloc( + si, + init.len - 4, + gop.value_ptr.import_address_table_si, + .{ .known = iat_offset }, + .{ .AMD64 = .REL32 }, + ); + }, + } + coff.nodes.appendAssumeCapacity(.{ .import_thunk = gmi }); + }, + } + + try si.flushMoved(coff); + return true; +} + +fn flushSpecialSymbol(coff: *Coff, pending: SpecialSymbol) !SpecialSymbol { + const comp = coff.base.comp; + + if (!coff.isImage()) return .none; + const gpa = comp.gpa; + const machine = coff.targetLoad(&coff.headerPtr().machine); + const target = &comp.root_mod.resolved_target.result; + + return next: switch (pending) { + .entry => { + // TODO: Use explicitly specified entry if set, add err if not found + const entries: []const struct { ?[]const u8, []const u8 } = if (coff.isExe()) + if (comp.config.link_libc) switch (coff.optionalHeaderField(.subsystem)) { + .WINDOWS_CUI => &.{ + .{ "main", "mainCRTStartup" }, + .{ "wmain", "wmainCRTStartup" }, + }, + .WINDOWS_GUI => &.{ + .{ "WinMain", "WinMainCRTStartup" }, + .{ "wWinMain", "wWinMainCRTStartup" }, + }, + else => unreachable, + } else &.{ + .{ "wWinMainCRTStartup", "wWinMainCRTStartup" }, + } + else + &.{.{ null, if (target.abi.isGnu()) "DllMainCRTStartup" else "_DllMainCRTStartup" }}; + + const entry_si = for (entries) |entry| { + if (entry[0]) |required_name| + if (coff.getDefinedGlobal(required_name) == .null) continue; + + break try coff.globalSymbol(.{ .name = entry[1], .type = .code }); + } else .null; + + if (entry_si != .null) { + log.debug( + "entry({s}, {d})", + .{ entry_si.get(coff).gmi.name(coff).toSlice(coff), entry_si }, + ); + + try coff.symbols.ensureUnusedCapacity(gpa, 1); + const optional_hdr_si = coff.addSymbolAssumeCapacity(); + const optional_hdr_sym = optional_hdr_si.get(coff); + optional_hdr_sym.ni = Node.known.optional_header; + assert(optional_hdr_sym.loc_relocs == .none); + optional_hdr_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + + const optional_hdr = coff.optionalHeaderStandardPtr(); + optional_hdr.address_of_entry_point = std.mem.nativeTo( + u32, + entry_si.get(coff).rva, + coff.targetEndian(), + ); + try coff.addReloc( - si, - init.len - 4, - gop.value_ptr.import_address_table_si, - @intCast(addr_size * import_symbol_index), - .{ .AMD64 = .REL32 }, + optional_hdr_si, + @intFromPtr(&optional_hdr.address_of_entry_point) - @intFromPtr(optional_hdr), + entry_si, + .{ .known = 0 }, + switch (machine) { + else => |tag| @panic(@tagName(tag)), + .AMD64 => .{ .AMD64 = .ADDR32NB }, + .I386 => .{ .I386 = .DIR32NB }, + }, ); - }, - } - coff.nodes.appendAssumeCapacity(.{ .global = gmi }); - sym.rva = coff.computeNodeRva(sym.ni); - si.applyLocationRelocs(coff); - } + } + + // Referencing the startup functions may trigger loading the object containing them, + // we need to wait until that is done before looking for further symbols. + break :next .tls; + }, + .tls => { + if (coff.getDefinedGlobal("_tls_used").unwrap()) |tls_used_si| { + log.debug("tlsDir({d})", .{tls_used_si}); + + const tls_directory = coff.dataDirectoryPtr(.TLS); + tls_directory.* = .{ + .virtual_address = tls_used_si.get(coff).rva, + .size = switch (coff.targetLoad(&coff.optionalHeaderStandardPtr().magic)) { + _ => unreachable, + .PE32 => 24, + .@"PE32+" => 40, + }, + }; + if (coff.targetEndian() != native_endian) + std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); + + try coff.symbols.ensureUnusedCapacity(gpa, 1); + const data_dir_si = coff.addSymbolAssumeCapacity(); + const data_dir_sym = data_dir_si.get(coff); + data_dir_sym.ni = Node.known.data_directories; + assert(data_dir_sym.loc_relocs == .none); + data_dir_sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + + try coff.addReloc( + data_dir_si, + @intFromPtr(&tls_directory.virtual_address) - @intFromPtr(coff.dataDirectorySlice().ptr), + tls_used_si, + .{ .known = 0 }, + switch (machine) { + else => |tag| @panic(@tagName(tag)), + .AMD64 => .{ .AMD64 = .ADDR32NB }, + .I386 => .{ .I386 = .DIR32NB }, + }, + ); + } + + break :next .none; + }, + .none => unreachable, + }; } fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { @@ -2119,6 +6833,9 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { } assert(sym.loc_relocs == .none); sym.loc_relocs = @enumFromInt(coff.relocs.items.len); + if (!isImage(coff) and sym.target_relocs != .none) + try coff.pendingSymbolTableEntry(si); + break :ni sym.ni; }; @@ -2138,42 +6855,107 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { error.WriteFailed => return nw.err.?, else => |e| return e, }; - si.get(coff).size = @intCast(nw.interface.end); - si.applyLocationRelocs(coff); + si.get(coff).extra.size = @intCast(nw.interface.end); + try si.applyLocationRelocs(coff); } fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { + log.debug("flushMoved({s}, n{d})", .{ @tagName(coff.getNode(ni)), ni }); switch (coff.getNode(ni)) { .file, .header, .signature, + => unreachable, .coff_header, .optional_header, .data_directories, .section_table, - => unreachable, - .image_section => |si| return coff.targetStore( - &si.get(coff).section_number.header(coff).pointer_to_raw_data, - @intCast(ni.fileLocation(&coff.mf, false).offset), - ), - .import_directory_table => coff.targetStore( - &coff.dataDirectoryPtr(.IMPORT).virtual_address, - coff.computeNodeRva(ni), - ), + .placeholder, + => assert(!coff.isImage()), + .symbol_table, + .string_table, + => |_, tag| { + if (tag == .symbol_table) + coff.targetStore( + &coff.headerPtr().pointer_to_symbol_table, + @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]), + ); + + if (!coff.symbol_table.pending_shrink) { + const symbol_table_loc, const symbol_table_size = coff.symbol_table.ni.location(&coff.mf).resolve(&coff.mf); + const string_table_offset, _ = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf); + coff.symbol_table.pending_shrink = string_table_offset - (symbol_table_loc + symbol_table_size) > 0; + } + }, + .relocation_table => |sn| { + coff.targetStore( + &sn.header(coff).pointer_to_relocations, + @intCast(ni.location(&coff.mf).resolve(&coff.mf)[0]), + ); + }, + .relocation_table_entry => {}, + .archive_member_header => |mi| { + const member = mi.get(coff); + switch (member.kind) { + .first_linker, .second_linker, .longnames => {}, + else => coff.targetStore( + &coff.secondLinkerMemberOffsetsSlice()[@intFromEnum(mi) - Member.Index.known_count], + @intCast(ni.fileLocation(&coff.mf, false).offset), + ), + } + + if (member.kind == .coff) + try coff.pending_members.put(coff.base.comp.gpa, mi, {}); + }, + .archive_member, + => {}, + .image_section => |si| { + const sym = si.get(coff); + const flags = coff.targetLoad(&sym.section_number.header(coff).flags); + if (!flags.CNT_UNINITIALIZED_DATA) { + const file_offset = if (isArchive(coff)) + sym.ni.location(&coff.mf).resolve(&coff.mf)[0] + else + ni.fileLocation(&coff.mf, false).offset; + + return coff.targetStore( + &sym.section_number.header(coff).pointer_to_raw_data, + @intCast(file_offset), + ); + } + }, + .input_section => |isi| { + try isi.symbol(coff).flushMoved(coff); + for (coff.input_symbols.items[@intFromEnum(isi.firstSymbol(coff))..]) |input_symbol| { + if (input_symbol.si.get(coff).ni != ni) break; + try input_symbol.si.flushMoved(coff); + } + }, + .import_directory_table => { + _, const size = ni.location(&coff.mf).resolve(&coff.mf); + if (size > 0) + coff.targetStore( + &coff.dataDirectoryPtr(.IMPORT).virtual_address, + coff.computeNodeRva(ni), + ); + }, .import_lookup_table => |import_index| coff.targetStore( &coff.importDirectoryEntryPtr(import_index).import_lookup_table_rva, coff.computeNodeRva(ni), ), .import_address_table => |import_index| { - const import_address_table_si = import_index.get(coff).import_address_table_si; - import_address_table_si.flushMoved(coff); + const entry = import_index.get(coff); + const import_address_table_si = entry.import_address_table_si; + try import_address_table_si.flushMoved(coff); coff.targetStore( &coff.importDirectoryEntryPtr(import_index).import_address_table_rva, import_address_table_si.get(coff).rva, ); + + for (entry.import_address_table_symbols.items) |iat_ptr_si| + try iat_ptr_si.flushMoved(coff); }, .import_hint_name_table => |import_index| { - const target_endian = coff.targetEndian(); const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic); const import_hint_name_rva = coff.computeNodeRva(ni); coff.targetStore( @@ -2186,78 +6968,173 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void { import_entry.import_address_table_si.node(coff).slice(&coff.mf); const import_hint_name_slice = ni.slice(&coff.mf); const import_hint_name_align = ni.alignment(&coff.mf); + var import_hint_name_index: u32 = 0; for (0..import_entry.len) |import_symbol_index| { - import_hint_name_index = @intCast(import_hint_name_align.forward( - std.mem.indexOfScalarPos( - u8, - import_hint_name_slice, - import_hint_name_index, - 0, - ).? + 1, - )); switch (magic) { _ => unreachable, inline .PE32, .@"PE32+" => |ct_magic| { - const Addr = switch (ct_magic) { - _ => comptime unreachable, - .PE32 => u32, - .@"PE32+" => u64, - }; - const import_lookup_table: []Addr = @ptrCast(@alignCast(import_lookup_slice)); - const import_address_table: []Addr = @ptrCast(@alignCast(import_address_slice)); - const rva = std.mem.nativeTo( - Addr, - import_hint_name_rva + import_hint_name_index, - target_endian, - ); - import_lookup_table[import_symbol_index] = rva; - import_address_table[import_symbol_index] = rva; + const Entry = std.coff.ImportLookupTableEntry(ct_magic); + const import_lookup_table: []Entry = @ptrCast(@alignCast(import_lookup_slice)); + const import_address_table: []Entry = @ptrCast(@alignCast(import_address_slice)); + + var entry = coff.targetLoad(&import_lookup_table[import_symbol_index]); + if (entry.is_ordinal) + continue; + + import_hint_name_index = @intCast(import_hint_name_align.forward( + std.mem.indexOfScalarPos( + u8, + import_hint_name_slice, + import_hint_name_index, + 0, + ).? + 1, + )); + + entry.payload.hint_name_rva = @intCast(import_hint_name_rva + import_hint_name_index); + import_hint_name_index += 2; + + coff.targetStore(&import_lookup_table[import_symbol_index], entry); + coff.targetStore(&import_address_table[import_symbol_index], entry); }, } - import_hint_name_index += 2; + } + }, + .export_directory_table => { + const rva = coff.computeNodeRva(ni); + coff.targetStore(&coff.dataDirectoryPtr(.EXPORT).virtual_address, rva); + coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable)); + }, + .export_address_table => { + try coff.export_table.export_address_table_si.flushMoved(coff); + + // These relocs are applied directly here instead of via the above flushMoved call as + // they are non-contiguous, and not tracked under export_address_table_si. + for (coff.export_table.entries.values()) |entry| + try entry.export_address_table_ri.get(coff).apply(coff); + + coff.targetStore( + &coff.exportDirectoryTable().export_address_table_rva, + coff.computeNodeRva(ni), + ); + }, + .export_name_pointer_table => coff.targetStore( + &coff.exportDirectoryTable().name_pointer_table_rva, + coff.computeNodeRva(ni), + ), + .export_ordinal_table => coff.targetStore( + &coff.exportDirectoryTable().ordinal_table_rva, + coff.computeNodeRva(ni), + ), + .export_name_table => { + const name_table_rva = coff.computeNodeRva(coff.export_table.name_table_ni); + for ( + coff.exportNamePointerTableSlice(), + coff.exportOrdinalTableSlice(), + ) |*np, target_ord| { + const ord: ExportTable.Ordinal = @enumFromInt(coff.targetLoad(&target_ord.unbiased_ordinal)); + const entry = ord.get(coff); + coff.targetStore( + &np.name_rva, + @intCast(name_table_rva + entry.name_index), + ); } }, inline .pseudo_section, .object_section, - .global, + .import_thunk, .nav, .uav, .lazy_code, .lazy_const_data, - => |mi| mi.symbol(coff).flushMoved(coff), + => |mi| try mi.symbol(coff).flushMoved(coff), + .builtin => |si| try si.flushMoved(coff), } try ni.childrenMoved(coff.base.comp.gpa, &coff.mf); } fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { - _, const size = ni.location(&coff.mf).resolve(&coff.mf); + const offset, const size = ni.location(&coff.mf).resolve(&coff.mf); + log.debug("flushResized({s}, n{d}, 0x{x})", .{ @tagName(coff.getNode(ni)), ni, size }); + switch (coff.getNode(ni)) { - .file => {}, + .file => { + if (coff.isArchive() and coff.members.items.len > 0) { + const last_member = coff.members.items[coff.members.items.len - 1]; + // See .archive_member branch for reasoning + assert(Node.known.file.reverseChildren(&coff.mf).ni == last_member.content_ni); + try coff.flushResized(last_member.content_ni); + } + }, .header => { - switch (coff.optionalHeaderPtr()) { - inline else => |optional_header| coff.targetStore( - &optional_header.size_of_headers, - @intCast(size), - ), + if (coff.isImage()) { + switch (coff.optionalHeaderPtr()) { + inline else => |optional_header| coff.targetStore( + &optional_header.size_of_headers, + @intCast(size), + ), + } + + if (size > coff.section_table.values()[0].si.get(coff).rva) try coff.virtualSlide( + 0, + std.mem.alignForward( + u32, + @intCast(size * 4), + coff.optionalHeaderField(.section_alignment), + ), + ); } - if (size > coff.image_section_table.items[0].get(coff).rva) try coff.virtualSlide( - 0, - std.mem.alignForward( - u32, - @intCast(size * 4), - coff.optionalHeaderField(.section_alignment), - ), - ); }, - .signature, .coff_header, .optional_header, .data_directories => unreachable, + .signature, + .archive_member_header, + => unreachable, + .archive_member => |mi| { + const content_ni = mi.get(coff).content_ni; + const next_ni = content_ni.next(&coff.mf); + const content_offset, _ = content_ni.location(&coff.mf).resolve(&coff.mf); + const next_offset = switch (next_ni) { + .none => offset: { + assert(content_ni.parent(&coff.mf) == Node.known.file); + // This must take into account the final file size. If there are trailing + // bytes, they will be expected to contain another valid member header + break :offset coff.mf.memory_map.memory.len; + }, + else => offset: { + assert(coff.getNode(next_ni) == .archive_member_header); + break :offset next_ni.location(&coff.mf).resolve(&coff.mf)[0]; + }, + }; + + // Not inserting IMAGE_ARCHIVE_PAD `\n` byte here, because we are expanding to full size + Member.storeHeaderDecimalStr(&mi.get(coff).headerPtr(coff).size, next_offset - content_offset); + }, + .coff_header, + .optional_header, + .data_directories, + => unreachable, .section_table => {}, + .symbol_table => { + assert(!coff.isImage()); + if (!coff.symbol_table.pending_shrink) { + const string_table_offset, _ = coff.symbol_table.strings_ni.location(&coff.mf).resolve(&coff.mf); + coff.symbol_table.pending_shrink = + size > coff.targetLoad(&coff.headerPtr().number_of_symbols) * std.coff.Symbol.sizeOf() or + string_table_offset - (offset + size) > 0; + } + }, + .string_table => { + assert(!coff.isImage()); + coff.targetStore(coff.symbolTableStringLenPtr(), @intCast(size)); + }, + .relocation_table, + .relocation_table_entry, + => assert(!coff.isImage()), .image_section => |si| { const sym = si.get(coff); const section_index = sym.section_number.toIndex(); const section = &coff.sectionTableSlice()[section_index]; coff.targetStore(§ion.size_of_raw_data, @intCast(size)); - if (size > coff.targetLoad(§ion.virtual_size)) { + if (coff.isImage() and size > coff.targetLoad(§ion.virtual_size)) { const virtual_size = std.mem.alignForward( u32, @intCast(size * 4), @@ -2266,29 +7143,221 @@ fn flushResized(coff: *Coff, ni: MappedFile.Node.Index) !void { coff.targetStore(§ion.virtual_size, virtual_size); try coff.virtualSlide(section_index + 1, sym.rva + virtual_size); } + + if (!coff.isImage()) { + if (coff.symbolTableSectionAuxEntryPtr(si.sti(coff))) |aux_ptr| + coff.targetStore(&aux_ptr.length, @intCast(size)); + } }, - .import_directory_table => coff.targetStore( - &coff.dataDirectoryPtr(.IMPORT).size, - @intCast(size), - ), - .import_lookup_table, .import_address_table, .import_hint_name_table => {}, + .input_section => {}, + .import_directory_table => { + const prev_size = coff.targetLoad(&coff.dataDirectoryPtr(.IMPORT).size); + coff.targetStore( + &coff.dataDirectoryPtr(.IMPORT).size, + @intCast(size), + ); + if (prev_size == 0) try coff.flushMoved(ni); + }, + .import_lookup_table, + .import_address_table, + .import_hint_name_table, + => {}, + .export_directory_table => unreachable, + .export_address_table, + .export_name_pointer_table, + .export_ordinal_table, + .export_name_table, + => {}, inline .pseudo_section, .object_section, - => |smi| smi.symbol(coff).get(coff).size = @intCast(size), - .global, .nav, .uav, .lazy_code, .lazy_const_data => {}, + => |smi, tag| { + if (tag == .pseudo_section and smi.name(coff) == .@".edata") { + coff.targetStore( + &coff.dataDirectoryPtr(.EXPORT).size, + @intCast(size), + ); + } + + var sym = smi.symbol(coff).get(coff); + while (sym.flags.extra_tag == .next_alias_si) + sym = sym.extra.next_alias_si.get(coff); + + sym.extra.size = @intCast(size); + }, + .import_thunk, + .nav, + .uav, + .lazy_code, + .lazy_const_data, + .builtin, + => {}, + .placeholder, + => unreachable, } } + +fn flushMember(coff: *Coff, mi: Member.Index) !void { + const member = mi.get(coff); + switch (member.kind) { + .first_linker, + .longnames, + .import, + => unreachable, + .second_linker => { + const Context = struct { + coff: *Coff, + indices: []u16, + strings: []String, + + pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool { + return std.mem.lessThan( + u8, + ctx.strings[lhs].toSlice(ctx.coff), + ctx.strings[rhs].toSlice(ctx.coff), + ); + } + + pub fn swap(ctx: @This(), lhs: usize, rhs: usize) void { + std.mem.swap(u16, &ctx.indices[lhs], &ctx.indices[rhs]); + std.mem.swap(String, &ctx.strings[lhs], &ctx.strings[rhs]); + } + }; + + // TODO: Does this sort need to also sort by linker input order (if names equal)? + std.sort.pdqContext(0, coff.lib_string_table.items.len, Context{ + .coff = coff, + .indices = coff.secondLinkerMemberIndicesSlice(), + .strings = coff.lib_string_table.items, + }); + + var offset: usize = 0; + var string_table = coff.secondLinkerMemberStringsSlice(); + for (coff.lib_string_table.items) |string| { + const str = string.toSlice(coff); + @memcpy(string_table[offset..][0..str.len], str); + string_table[offset + str.len] = 0; + offset += str.len + 1; + } + }, + .coff => { + const file_offset: u32 = @intCast(member.header_ni.fileLocation(&coff.mf, false).offset); + const first_linker_offsets = coff.firstLinkerMemberOffsetsSlice(); + for (member.first_linker_indices.values()) |mfli| + first_linker_offsets[@intFromEnum(mfli)] = std.mem.nativeTo(u32, file_offset, .big); + }, + } +} + +fn flushExportsSort(coff: *Coff) void { + const Context = struct { + coff: *Coff, + np: []std.coff.ExportNamePointerTableEntry, + ord: []std.coff.ExportOrdinalTableEntry, + entries: []ExportTable.Entry, + nt: []const u8, + + pub fn lessThan(ctx: *const @This(), lhs: usize, rhs: usize) bool { + const lhs_entry = &ctx.entries[ctx.coff.targetLoad(&ctx.ord[lhs].unbiased_ordinal)]; + const rhs_entry = &ctx.entries[ctx.coff.targetLoad(&ctx.ord[rhs].unbiased_ordinal)]; + return std.mem.lessThan( + u8, + ctx.nt[lhs_entry.name_index..][0..lhs_entry.name_len], + ctx.nt[rhs_entry.name_index..][0..rhs_entry.name_len], + ); + } + + pub fn swap(ctx: @This(), lhs: usize, rhs: usize) void { + std.mem.swap(std.coff.ExportNamePointerTableEntry, &ctx.np[lhs], &ctx.np[rhs]); + std.mem.swap(std.coff.ExportOrdinalTableEntry, &ctx.ord[lhs], &ctx.ord[rhs]); + } + }; + + std.sort.pdqContext(0, coff.export_table.entries.count(), &Context{ + .coff = coff, + .np = coff.exportNamePointerTableSlice(), + .ord = coff.exportOrdinalTableSlice(), + .entries = coff.export_table.entries.values(), + .nt = coff.export_table.name_table_ni.slice(&coff.mf), + }); +} + +fn flushSectionMerges(coff: *Coff) !void { + while (coff.section_merge_pending_index < coff.section_merges.count()) : (coff.section_merge_pending_index += 1) + try coff.flushSectionMerge(coff.section_merge_pending_index); +} + +fn flushSectionMerge(coff: *Coff, index: u32) !void { + assert(coff.isImage()); + const from = coff.section_merges.keys()[index]; + const to = coff.section_merges.values()[index]; + assert(from != to); + + log.debug("flushSectionMerge({s}->{s})", .{ from.toSlice(coff), to.toSlice(coff) }); + + const opt_to_sec = coff.section_table.getPtr(to); + if (coff.section_table.getPtr(from)) |from_sec| { + const from_sym = from_sec.si.get(coff); + if (opt_to_sec) |to_sec| { + const to_sym = to_sec.si.get(coff); + + // TODO: Create a pseudo-section named `from` in `to`, copy `from_sec` ni into that pseudo section + // TODO: Update .section_number for all contained syms + // TODO: Remove `from_sec` from section table (set size = 0 and can do it in flushResized?). + // This is non-trivial as we can't leave holes in the section table. + // TODO: Merge section flags + _ = to_sym; + return coff.base.comp.link_diags.fail("TODO implement section to section merge", .{}); + } else if (coff.pseudo_section_table.get(to)) |to_ps_si| { + const to_sym = to_ps_si.get(coff); + if (from_sym.section_number == to_sym.section_number) + return; + + // TODO: Same as above, except place `from` into a node in `to_psmi`'s parent + return coff.base.comp.link_diags.fail("TODO implement section to pseudosection merge", .{}); + } + + // If `to` doesn't exist, /MERGE is defined as renaming `from` to `to`. + // No other path will create image-level sections, so we can safely rename this now + const from_name = &from_sec.si.get(coff).section_number.header(coff).name; + const to_slice = to.toSlice(coff); + @memcpy(from_name[0..to_slice.len], to_slice); + @memset(from_name[to_slice.len..], 0); + } else if (coff.pseudo_section_table.getIndex(from)) |from_index| { + const from_psmi: Node.PseudoSectionMapIndex = @enumFromInt(from_index); + const from_sym = from_psmi.symbol(coff).get(coff); + if (opt_to_sec) |to_sec| { + const to_sym = to_sec.si.get(coff); + if (from_sym.section_number == to_sym.section_number) + return; + + // TODO: Move from_psmi's node into to_sec + // TODO: Update .section_number for all contained syms + // TODO: Merge section flags + return coff.base.comp.link_diags.fail("TODO implement pseudosection to section merge", .{}); + } else if (coff.pseudo_section_table.get(to)) |to_ps_si| { + const to_sym = to_ps_si.get(coff); + if (from_sym.section_number == to_sym.section_number) + return; + + // TODO: Same as above, but move from_psmi's node after to_psmi's node in its parent + return coff.base.comp.link_diags.fail("TODO implement pseudosection to pseudosection merge", .{}); + } + + // Renaming pseudo-sections have no effect on the output, so this is a no-op. + } +} + fn virtualSlide(coff: *Coff, start_section_index: usize, start_rva: u32) !void { var rva = start_rva; for ( - coff.image_section_table.items[start_section_index..], + coff.section_table.values()[start_section_index..], coff.sectionTableSlice()[start_section_index..], - ) |section_si, *section| { - const section_sym = section_si.get(coff); + ) |*section, *header| { + const section_sym = section.si.get(coff); section_sym.rva = rva; - coff.targetStore(§ion.virtual_address, rva); + coff.targetStore(&header.virtual_address, rva); try section_sym.ni.childrenMoved(coff.base.comp.gpa, &coff.mf); - rva += coff.targetLoad(§ion.virtual_size); + rva += coff.targetLoad(&header.virtual_size); } switch (coff.optionalHeaderPtr()) { inline else => |optional_header| coff.targetStore( @@ -2303,19 +7372,27 @@ pub fn updateExports( pt: Zcu.PerThread, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, +) link.Error!void { + const diags = &coff.base.comp.link_diags; + return coff.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { + error.MappedFileIo => return diags.fail( + "failed to write output file: {t}", + .{coff.mf.io_err.?}, + ), + else => |e| return e, + }; +} +fn updateExportsInner( + coff: *Coff, + pt: Zcu.PerThread, + exported: Zcu.Exported, + export_indices: []const Zcu.Export.Index, ) !void { const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; - switch (exported) { - .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}), - .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{ - Type.fromInterned(ip.typeOf(uav)).fmt(pt), - Value.fromInterned(uav).fmtValue(pt), - }), - } - try coff.symbol_table.ensureUnusedCapacity(gpa, export_indices.len); + try coff.symbols.ensureUnusedCapacity(gpa, export_indices.len); const exported_si: Symbol.Index = switch (exported) { .nav => |nav| try coff.navSymbol(zcu, nav), .uav => |uav| @enumFromInt(@intFromEnum(try coff.lowerUav( @@ -2324,62 +7401,299 @@ pub fn updateExports( Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), ))), }; + switch (exported) { + .nav => |nav| log.debug("updateExports({f}) = {d}", .{ ip.getNav(nav).fqn.fmt(ip), exported_si }), + .uav => |uav| log.debug("updateExports(@as({f}, {f})) = {d}", .{ + Type.fromInterned(ip.typeOf(uav)).fmt(pt), + Value.fromInterned(uav).fmtValue(pt), + exported_si, + }), + } + while (try coff.resolve(pt.tid)) {} while (try coff.idle(pt.tid)) {} + + const machine = coff.targetLoad(&coff.headerPtr().machine); const exported_ni = exported_si.node(coff); const exported_sym = exported_si.get(coff); + var prev_alias_si = exported_si; + for (export_indices) |export_index| { const @"export" = export_index.ptr(zcu); - const export_si = try coff.globalSymbol(@"export".opts.name.toSlice(ip), null); + const name = @"export".opts.name.toSlice(ip); + + // TODO: add an errMsg if this conflicts with an existing symbol + const export_si = try coff.globalSymbol(.{ .name = name }); const export_sym = export_si.get(coff); export_sym.ni = exported_ni; export_sym.rva = exported_sym.rva; - export_sym.size = exported_sym.size; export_sym.section_number = exported_sym.section_number; - export_si.applyTargetRelocs(coff); - if (@"export".opts.name.eqlSlice("wWinMainCRTStartup", ip)) { - coff.optionalHeaderStandardPtr().address_of_entry_point = exported_sym.rva; - } else if (@"export".opts.name.eqlSlice("_tls_used", ip)) { - const tls_directory = coff.dataDirectoryPtr(.TLS); - tls_directory.* = .{ .virtual_address = exported_sym.rva, .size = exported_sym.size }; - if (coff.targetEndian() != native_endian) - std.mem.byteSwapAllFields(std.coff.ImageDataDirectory, tls_directory); + if (@"export".opts.linkage == .weak and !coff.isImage()) { + // exported_si needs to be ahead of export_si in the symbol table, + // so that its sti is known when creating the weak external aux entry + try coff.pendingSymbolTableEntry(exported_si); + export_sym.flags.weak_external_strat = .alias; + export_sym.setValue(.{ .weak_alias_si = exported_si }); + } + defer export_si.applyTargetRelocs(coff, .none) catch unreachable; + + // The last symbol in the alias list holds the size + const prev_alias_sym = prev_alias_si.get(coff); + switch (prev_alias_sym.flags.extra_tag) { + .size => export_sym.setExtra(.{ .size = prev_alias_sym.extra.size }), + // This export should have been deleted + .next_alias_si => assert(prev_alias_sym.extra.next_alias_si == export_si), + else => unreachable, + } + + prev_alias_sym.setExtra(.{ .next_alias_si = export_si }); + prev_alias_si = export_si; + + if (!coff.isImage()) continue; + + const entries_ctx = ExportTable.Adapter{ .coff = coff }; + const gop = try coff.export_table.entries.getOrPutAdapted( + gpa, + name, + entries_ctx, + ); + + if (!gop.found_existing) { + errdefer _ = coff.export_table.entries.pop(); + + const export_count = coff.export_table.entries.count(); + if (export_count > std.math.maxInt(@FieldType(std.coff.ExportDirectoryTable, "number_of_entries"))) + return coff.base.comp.link_diags.fail("exceeded maximum number of exports", .{}); + + const name_index: u32 = @intCast(coff.export_table.name_table_ni.location(&coff.mf).resolve(&coff.mf)[1]); + const new_name_table_size = name_index + name.len + 1; + if (new_name_table_size > std.math.maxInt(@FieldType(ExportTable.Entry, "name_index"))) + return coff.base.comp.link_diags.fail("exports name table limit reached", .{}); + + try coff.export_table.name_table_ni.resize(&coff.mf, gpa, new_name_table_size); + + const name_table_slice = coff.export_table.name_table_ni.slice(&coff.mf); + @memcpy(name_table_slice[name_index..][0 .. name.len + 1], name[0 .. name.len + 1]); + + // If the new name sorts after the current tail of the sorted list, we don't need to re-sort + { + const ordinal_table_slice = coff.exportOrdinalTableSlice(); + if (ordinal_table_slice.len > 0 and !coff.export_table.pending_sort) { + const tail_index: ExportTable.Ordinal = + @enumFromInt(ordinal_table_slice[ordinal_table_slice.len - 1].unbiased_ordinal); + const tail_entry = tail_index.get(coff); + const tail_name = name_table_slice[tail_entry.name_index..][0..tail_entry.name_len]; + coff.export_table.pending_sort = std.mem.lessThan(u8, name, tail_name); + } + } + + const edt = coff.exportDirectoryTable(); + coff.targetStore(&edt.number_of_names, @intCast(export_count)); + edt.number_of_entries = edt.number_of_names; + + // TODO: These should all be resized ahead of time to fit all exports + // after https://github.com/ziglang/zig/issues/23616 + try coff.export_table.export_address_table_si.node(coff).resize( + &coff.mf, + gpa, + export_count * @sizeOf(std.coff.ExportAddressTableEntry), + ); + + try coff.export_table.name_pointer_table_ni.resize( + &coff.mf, + gpa, + export_count * @sizeOf(std.coff.ExportNamePointerTableEntry), + ); + + try coff.export_table.ordinal_table_ni.resize( + &coff.mf, + gpa, + export_count * @sizeOf(std.coff.ExportOrdinalTableEntry), + ); + + coff.targetStore( + &coff.exportNamePointerTableSlice()[gop.index].name_rva, + @intCast(coff.computeNodeRva(coff.export_table.name_table_ni) + name_index), + ); + coff.targetStore( + &coff.exportOrdinalTableSlice()[gop.index].unbiased_ordinal, + @intCast(gop.index), + ); + + gop.value_ptr.* = .{ + .si = export_si, + .name_index = @intCast(name_index), + .name_len = @intCast(name.len), + .export_address_table_ri = @enumFromInt(coff.relocs.items.len), + }; + + try coff.addReloc( + coff.export_table.export_address_table_si, + @intCast(@sizeOf(std.coff.ExportAddressTableEntry) * gop.index), + export_si, + .{ .known = 0 }, + switch (machine) { + else => |tag| @panic(@tagName(tag)), + .AMD64 => .{ .AMD64 = .ADDR32NB }, + .I386 => .{ .I386 = .DIR32NB }, + }, + ); + } else { + gop.value_ptr.si = export_si; + const reloc = gop.value_ptr.*.export_address_table_ri.get(coff); + reloc.target = export_si; } } } -pub fn deleteExport(coff: *Coff, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void { - _ = coff; - _ = exported; - _ = name; +pub fn deleteExport( + coff: *Coff, + exported: Zcu.Exported, + name: InternPool.NullTerminatedString, +) void { + const zcu = coff.base.comp.zcu.?; + const ip = &zcu.intern_pool; + + const exported_si: Symbol.Index = switch (exported) { + .nav => |nav| coff.navs.get(nav).?, + .uav => |uav| coff.uavs.get(uav).?, + }; + + const name_slice = name.toSlice(ip); + log.debug("deleteExport({s}, {d})", .{ name_slice, exported_si }); + + // TODO: Delete from first / second linker member table + // TODO: Delete from symbol table inside section } -pub fn dump(coff: *Coff, tid: Zcu.PerThread.Id) Io.Cancelable!void { +fn dumpStderr(coff: *Coff, tid: Zcu.PerThread.Id) !void { const comp = coff.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; - coff.printNode(tid, w, .root, 0) catch |err| switch (err) { - error.WriteFailed => return stderr.err.?, - }; + _ = try coff.dump(w, tid); } -pub fn printNode( +pub fn dump(coff: *Coff, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpResult { + if (coff.options.enable_link_snapshots) { + try coff.printNode(tid, w, .root, 0); + try w.writeAll("Section table:\n"); + for (coff.section_table.keys(), coff.section_table.values()) |name, sec| + try coff.printSection(w, name, sec.si); + try w.writeAll("Symbol table:\n"); + for (1..coff.symbols.items.len) |si| + try coff.printSymbol(w, tid, @enumFromInt(si)); + + return .enabled; + } + return .disabled; +} + +fn printSection(coff: *Coff, w: *Io.Writer, name: String, si: Symbol.Index) !void { + const sym = si.get(coff); + try w.print("{d:0>6}@{d:0>2} {x:08} n{d:0>8} | {s}\n", .{ + si, + sym.section_number, + if (sym.flags.extra_tag == .size) sym.extra.size else 0, + sym.ni, + name.toSlice(coff), + }); +} + +fn printSymbol( coff: *Coff, + w: *Io.Writer, tid: Zcu.PerThread.Id, + si: Symbol.Index, +) !void { + const sym = si.get(coff); + const node = coff.getNode(sym.ni); + try w.print("{d:0>6}@{d:0>2} {x:08} {s} {s} {s} n{d:0>8}+{x:08}:{t: <26} | {x:08} ", .{ + si, + sym.section_number, + if (sym.flags.extra_tag == .size) + @as(u64, sym.extra.size) + else if (sym.ni != .none) + sym.ni.location(&coff.mf).resolve(&coff.mf)[1] + else + 0, + switch (sym.flags.value_tag) { + .none => "xx", + .weak_alias_name => "an", + .weak_alias_si => "as", + .node_offset => "no", + }, + switch (sym.flags.extra_tag) { + .size => "sz", + .isli => "li", + .next_alias_si => "na", + }, + switch (sym.flags.type) { + .unknown => "u", + .code => "c", + .data => "d", + }, + sym.ni, + if (sym.flags.value_tag == .node_offset) sym.value.node_offset else 0, + node, + sym.rva, + }); + + if (sym.gmi != .none) { + try w.print("G {f}\n", .{fmtGlobalName(coff, sym.gmi)}); + } else { + try w.writeAll("| "); + try coff.printNodeName(w, tid, node); + if (sym.flags.extra_tag == .isli) + try w.print(" | {s}", .{sym.extra.isli.name(coff).toSlice(coff)}); + try w.writeByte('\n'); + } +} + +const FmtGlobalName = struct { coff: *Coff, gmi: Node.GlobalMapIndex }; + +fn fmtGlobalName(coff: *Coff, gmi: Node.GlobalMapIndex) std.fmt.Alt(FmtGlobalName, globalNameEscape) { + return .{ .data = .{ .coff = coff, .gmi = gmi } }; +} + +fn globalNameEscape(data: FmtGlobalName, w: *std.Io.Writer) std.Io.Writer.Error!void { + if (data.gmi == .none) return; + try w.writeAll(data.gmi.name(data.coff).toSlice(data.coff)); + if (data.gmi.libName(data.coff).unwrap()) |lib_name| + try w.print("({s})", .{lib_name.toSlice(data.coff)}); +} + +fn printNodeName( + coff: *Coff, w: *std.Io.Writer, - ni: MappedFile.Node.Index, - indent: usize, + tid: Zcu.PerThread.Id, + node: Node, ) !void { - const node = coff.getNode(ni); - try w.splatByteAll(' ', indent); - try w.writeAll(@tagName(node)); switch (node) { else => {}, .image_section => |si| try w.print("({s})", .{ std.mem.sliceTo(&si.get(coff).section_number.header(coff).name, 0), }), + .input_section => |isi| { + const ioi = isi.input(coff); + const is = isi.inputSection(coff); + try w.print("({f}{f}, {s}", .{ + ioi.path(coff).fmtEscapeString(), + fmtMemberNameString(ioi.memberName(coff)), + coff.getNode(is.si.node(coff).parent(&coff.mf)).object_section.name(coff).toSlice(coff), + }); + if (is.comdat_si != .null) { + const comdat_sym = is.comdat_si.get(coff); + const comdat_name = if (comdat_sym.gmi != .none) + comdat_sym.gmi.name(coff).toSlice(coff) + else + coff.input_symbols.items[@intFromEnum(comdat_sym.extra.isli)].name.toSlice(coff); + + try w.print("={s}", .{comdat_name}); + } + try w.writeAll(")"); + }, .import_lookup_table, .import_address_table, .import_hint_name_table, @@ -2389,18 +7703,18 @@ pub fn printNode( inline .pseudo_section, .object_section => |smi| try w.print("({s})", .{ smi.name(coff).toSlice(coff), }), - .global => |gmi| { - const gn = gmi.globalName(coff); + .import_thunk, + => |gmi| { try w.writeByte('('); - if (gn.lib_name.toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); - try w.print("{s})", .{gn.name.toSlice(coff)}); + if (gmi.libName(coff).toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); + try w.print("{s})", .{gmi.name(coff).toSlice(coff)}); }, .nav => |nmi| { const zcu = coff.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(nmi.navIndex(coff)); try w.print("({f}, {f})", .{ - Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), + Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }), nav.fqn.fmt(ip), }); }, @@ -2418,7 +7732,28 @@ pub fn printNode( .tid = tid, }), }), + .builtin => |si| { + const sym = si.get(coff); + if (sym.gmi != .none) { + try w.writeByte('('); + if (sym.gmi.libName(coff).toSlice(coff)) |lib_name| try w.print("{s}.dll, ", .{lib_name}); + try w.print("{s})", .{sym.gmi.name(coff).toSlice(coff)}); + } + }, } +} + +pub fn printNode( + coff: *Coff, + tid: Zcu.PerThread.Id, + w: *Io.Writer, + ni: MappedFile.Node.Index, + indent: usize, +) !void { + const node = coff.getNode(ni); + try w.splatByteAll(' ', indent); + try w.writeAll(@tagName(node)); + try coff.printNodeName(w, tid, node); { const mf_node = &coff.mf.nodes.items[@intFromEnum(ni)]; const off, const size = mf_node.location().resolve(&coff.mf); @@ -2446,7 +7781,7 @@ pub fn printNode( const line_len = 0x10; var line_it = std.mem.window( u8, - coff.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], + coff.mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], line_len, line_len, ); diff --git a/src/link/ConstPool.zig b/src/link/ConstPool.zig index 1282ad67c4b5fc49bac914bfeede2da46301ee91..3ff2d9a540e1d47d2da7e5e3d9b441ff70effa6b 100644 --- a/src/link/ConstPool.zig +++ b/src/link/ConstPool.zig @@ -15,10 +15,10 @@ /// * ensure that any `get` call is eventually followed by a `flushPending` call const ConstPool = @This(); -values: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), +values: std.array_hash_map.Auto(InternPool.Index, void), pending: std.ArrayList(Index), -complete_containers: std.AutoArrayHashMapUnmanaged(InternPool.Index, void), -container_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, ContainerDepEntry.Index), +complete_containers: std.array_hash_map.Auto(InternPool.Index, void), +container_deps: std.array_hash_map.Auto(InternPool.Index, ContainerDepEntry.Index), container_dep_entries: std.ArrayList(ContainerDepEntry), pub const empty: ConstPool = .{ @@ -196,6 +196,7 @@ fn checkType(pool: *const ConstPool, ty: Type, zcu: *const Zcu) bool { .null, .error_set, .@"opaque", + .spirv, .frame, .@"anyframe", .enum_literal, @@ -241,6 +242,7 @@ fn registerTypeDeps(pool: *ConstPool, root: Index, ty: Type, zcu: *const Zcu) Al .null, .error_set, .@"opaque", + .spirv, .frame, .@"anyframe", .enum_literal, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 0142b0a91969f2f9632a77d9b57cb4ff44a3a09e..96fb3d10c9191de8a2acaf7acaf799f5b9832fc5 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -27,11 +27,11 @@ address_size: AddressSize, const_pool: link.ConstPool, -mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo), +mods: std.array_hash_map.Auto(*Module, ModInfo), /// Indices are `link.ConstPool.Index`. values: std.ArrayList(struct { Unit.Index, Entry.Index }), -navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index), -decls: std.AutoArrayHashMapUnmanaged(InternPool.TrackedInst.Index, Entry.Index), +navs: std.array_hash_map.Auto(InternPool.Nav.Index, Entry.Index), +decls: std.array_hash_map.Auto(InternPool.TrackedInst.Index, Entry.Index), debug_abbrev: DebugAbbrev, debug_aranges: DebugAranges, @@ -69,8 +69,8 @@ pub const AddressSize = enum(u8) { const ModInfo = struct { root_dir_path: Entry.Index, - dirs: std.AutoArrayHashMapUnmanaged(Unit.Index, void), - files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void), + dirs: std.array_hash_map.Auto(Unit.Index, void), + files: std.array_hash_map.Auto(Zcu.File.Index, void), fn deinit(mod_info: *ModInfo, gpa: Allocator) void { mod_info.dirs.deinit(gpa); @@ -236,7 +236,7 @@ const DebugRngLists = struct { const StringSection = struct { contents: std.ArrayList(u8), - map: std.AutoArrayHashMapUnmanaged(void, void), + map: std.array_hash_map.Auto(void, void), section: Section, const unit: Unit.Index = @enumFromInt(0); @@ -3047,6 +3047,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo .func_type, .error_set_type, .inferred_error_set_type, + .spirv_type, => .alias, .struct_type => tag: { @@ -3533,6 +3534,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co switch (value_ip_key) { .func => unreachable, // handled above .@"extern" => unreachable, // handled above + .spirv_type => unreachable, .int_type => |int_type| { try wip_nav.abbrevCode(.numeric_type); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 4c50caf8f2b6d363a37c3f6189b0975b8bdd1451..d64d429bb0bc7d03f3e152615cbf81434e67515e 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2,7 +2,7 @@ pub const Atom = @import("Elf/Atom.zig"); base: link.File, zig_object: ?*ZigObject, -rpath_table: std.StringArrayHashMapUnmanaged(void), +rpath_table: std.array_hash_map.String(void), image_base: u64, z_nodelete: bool, z_notext: bool, @@ -30,7 +30,7 @@ file_handles: std.ArrayList(File.Handle) = .empty, zig_object_index: ?File.Index = null, linker_defined_index: ?File.Index = null, objects: std.ArrayList(File.Index) = .empty, -shared_objects: std.StringArrayHashMapUnmanaged(File.Index) = .empty, +shared_objects: std.array_hash_map.String(File.Index) = .empty, /// List of all output sections and their associated metadata. sections: std.MultiArrayList(Section) = .{}, @@ -249,7 +249,7 @@ pub fn createEmpty( const is_dyn_lib = output_mode == .Lib and link_mode == .dynamic; const default_sym_version: elf.Versym = if (is_dyn_lib or comp.config.rdynamic) .GLOBAL else .LOCAL; - var rpath_table: std.StringArrayHashMapUnmanaged(void) = .empty; + var rpath_table: std.array_hash_map.String(void) = .empty; try rpath_table.entries.resize(arena, options.rpath_list.len); @memcpy(rpath_table.entries.items(.key), options.rpath_list); try rpath_table.reIndex(arena); @@ -1112,7 +1112,7 @@ fn parseDso( io: Io, diags: *Diags, dso: link.Input.Dso, - shared_objects: *std.StringArrayHashMapUnmanaged(File.Index), + shared_objects: *std.array_hash_map.String(File.Index), files: *std.MultiArrayList(File.Entry), target: *const std.Target, ) !void { @@ -4153,7 +4153,7 @@ pub const Ref = struct { pub const SymbolResolver = struct { keys: std.ArrayList(Key) = .empty, values: std.ArrayList(Ref) = .empty, - table: std.AutoArrayHashMapUnmanaged(void, void) = .empty, + table: std.array_hash_map.Auto(void, void) = .empty, const Result = struct { found_existing: bool, diff --git a/src/link/Elf/AtomList.zig b/src/link/Elf/AtomList.zig index 9350f1a276b16382a297a471ae8214b1bcc1be29..245c00bf6ee359e452826363c428144d45371202 100644 --- a/src/link/Elf/AtomList.zig +++ b/src/link/Elf/AtomList.zig @@ -3,7 +3,7 @@ size: u64 = 0, alignment: Atom.Alignment = .@"1", output_section_index: u32 = 0, // atoms: std.ArrayList(Elf.Ref) = .empty, -atoms: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .empty, +atoms: std.array_hash_map.Auto(Elf.Ref, void) = .empty, dirty: bool = true, diff --git a/src/link/Elf/Thunk.zig b/src/link/Elf/Thunk.zig index 1700bb8276dd4e534629e6ff30eaa9220ada8a5d..69af9707bc9e8d41c2b81952c32b5cc981ccfdbd 100644 --- a/src/link/Elf/Thunk.zig +++ b/src/link/Elf/Thunk.zig @@ -1,6 +1,6 @@ value: i64 = 0, output_section_index: u32 = 0, -symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .empty, +symbols: std.array_hash_map.Auto(Elf.Ref, void) = .empty, output_symtab_ctx: Elf.SymtabCtx = .{}, pub fn deinit(thunk: *Thunk, allocator: Allocator) void { diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index d57a77a3ab4759d283c465b2850f7a713726c4d4..3f4a85ece7a40dbed094b587df82cc0e1293cbd6 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -267,8 +267,9 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { // Handle any lazy symbols that were emitted by incremental compilation. if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| { - const pt: Zcu.PerThread = .activate(elf_file.base.comp.zcu.?, tid); - defer pt.deactivate(); + const active = elf_file.base.comp.zcu.?.activate(tid); + defer active.deactivate(); + const pt = active.pt; // Most lazy symbols can be updated on first use, but // anyerror needs to wait for everything to be flushed. @@ -291,20 +292,22 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { } if (build_options.enable_logging) { - const pt: Zcu.PerThread = .activate(elf_file.base.comp.zcu.?, tid); - defer pt.deactivate(); + const active = elf_file.base.comp.zcu.?.activate(tid); + defer active.deactivate(); for (self.navs.keys(), self.navs.values()) |nav_index, meta| { - checkNavAllocated(pt, nav_index, meta); + checkNavAllocated(active.pt, nav_index, meta); } for (self.uavs.keys(), self.uavs.values()) |uav_index, meta| { - checkUavAllocated(pt, uav_index, meta); + checkUavAllocated(active.pt, uav_index, meta); } } if (self.dwarf) |*dwarf| { - const pt: Zcu.PerThread = .activate(elf_file.base.comp.zcu.?, tid); - defer pt.deactivate(); - try dwarf.flush(pt); + { + const active = elf_file.base.comp.zcu.?.activate(tid); + defer active.deactivate(); + try dwarf.flush(active.pt); + } const gpa = elf_file.base.comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; @@ -2405,10 +2408,10 @@ const TlsVariable = struct { }; const AtomList = std.ArrayList(Atom.Index); -const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); -const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata); -const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); -const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, void); +const NavTable = std.array_hash_map.Auto(InternPool.Nav.Index, AvMetadata); +const UavTable = std.array_hash_map.Auto(InternPool.Index, AvMetadata); +const LazySymbolTable = std.array_hash_map.Auto(InternPool.Index, LazySymbolMetadata); +const TlsTable = std.array_hash_map.Auto(Atom.Index, void); const x86_64 = struct { fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 { diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index b16e726d21213f6ba5ccd2c6aa6c22c4690ef914..372e32ed297687542379d5419b41165b32ef7133 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -112,7 +112,7 @@ plt_first_symbol_reloc: SymbolReloc.Index, /// The `.dynamic` section contains zero or more symbol relocations starting at this index. dynamic_first_symbol_reloc: SymbolReloc.Index, -needed: std.AutoArrayHashMapUnmanaged(String(.dynstr), void), +needed: std.array_hash_map.Auto(String(.dynstr), void), inputs: std.ArrayList(struct { path: std.Build.Cache.Path, member: ?[]const u8, @@ -120,21 +120,21 @@ inputs: std.ArrayList(struct { }), input_sections: std.ArrayList(InputSection), input_section_pending_index: u32, -navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, struct { +navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct { lsi: Symbol.LocalIndex, /// The start index of the contiguous sequence of symbol relocations in this NAV. first_symbol_reloc: SymbolReloc.Index, /// The start index of the contiguous sequence of GOT relocations in this NAV. first_got_reloc: GotReloc.Index, }), -uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { +uavs: std.array_hash_map.Auto(InternPool.Index, struct { lsi: Symbol.LocalIndex, /// The start index of the contiguous sequence of symbol relocations in this UAV. first_symbol_reloc: SymbolReloc.Index, // No `first_got_reloc` field because a UAV never contains GOT relocations. }), lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { - map: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { + map: std.array_hash_map.Auto(InternPool.Index, struct { lsi: Symbol.LocalIndex, /// The start index of the contiguous sequence of symbol relocations in this lazy code/data. first_symbol_reloc: SymbolReloc.Index, @@ -749,6 +749,14 @@ const GotReloc = struct { offset32, rel64, rel32, + + rel32_hi20, + rel64_lo20, + rel64_hi12, + abs32_lo12, + abs32_hi20, + abs64_lo20, + abs64_hi12, }; const Index = enum(u32) { @@ -817,6 +825,41 @@ const GotReloc = struct { @intCast(@as(i64, @bitCast(got_vaddr +% got_offset +% addend -% dest_vaddr))), target_endian, ), + .rel32_hi20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_value = got_vaddr +% got_offset +% addend; + link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr)); + }, + .rel64_lo20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_value = got_vaddr +% got_offset +% addend; + link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr)); + }, + .rel64_hi12 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_value = got_vaddr +% got_offset +% addend; + link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr)); + }, + .abs32_lo12 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_value = got_vaddr +% got_offset +% addend; + link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value)); + }, + .abs32_hi20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_value = got_vaddr +% got_offset +% addend; + link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12)); + }, + .abs64_lo20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_value = got_vaddr +% got_offset +% addend; + link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32)); + }, + .abs64_hi12 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_value = got_vaddr +% got_offset +% addend; + link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52)); + }, } } }; @@ -824,6 +867,7 @@ const GotReloc = struct { pub const MachineRelocType = union { X86_64: std.elf.R_X86_64, AARCH64: std.elf.R_AARCH64, + LOONGARCH: std.elf.R_LARCH, RISCV: std.elf.R_RISCV, PPC64: std.elf.R_PPC64, @@ -831,6 +875,7 @@ pub const MachineRelocType = union { return switch (elf.ehdrField(.machine)) { else => unreachable, .AARCH64 => .{ .AARCH64 = .NONE }, + .LOONGARCH => .{ .LOONGARCH = .NONE }, .PPC64 => .{ .PPC64 = .NONE }, .RISCV => .{ .RISCV = .NONE }, .X86_64 => .{ .X86_64 = .NONE }, @@ -840,6 +885,7 @@ pub const MachineRelocType = union { return switch (elf.ehdrField(.machine)) { else => unreachable, .AARCH64 => .{ .AARCH64 = .COPY }, + .LOONGARCH => .{ .LOONGARCH = .COPY }, .PPC64 => .{ .PPC64 = .COPY }, .RISCV => .{ .RISCV = .COPY }, .X86_64 => .{ .X86_64 = .COPY }, @@ -849,24 +895,28 @@ pub const MachineRelocType = union { return switch (elf.ehdrField(.machine)) { else => unreachable, .X86_64 => .{ .X86_64 = .JUMP_SLOT }, + .LOONGARCH => .{ .LOONGARCH = .JUMP_SLOT }, }; } pub fn globDat(elf: *Elf) MachineRelocType { return switch (elf.ehdrField(.machine)) { else => unreachable, .X86_64 => .{ .X86_64 = .GLOB_DAT }, + .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, }; } pub fn dtpOffAddr(elf: *Elf) MachineRelocType { return switch (elf.ehdrField(.machine)) { else => unreachable, .X86_64 => .{ .X86_64 = .DTPOFF64 }, + .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 }, }; } pub fn absAddr(elf: *Elf) MachineRelocType { return switch (elf.ehdrField(.machine)) { else => unreachable, .AARCH64 => .{ .AARCH64 = .ABS64 }, + .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, .PPC64 => .{ .PPC64 = .ADDR64 }, .RISCV => .{ .RISCV = .@"64" }, .X86_64 => .{ .X86_64 = .@"64" }, @@ -883,6 +933,7 @@ pub const MachineRelocType = union { return switch (elf.ehdrField(.machine)) { else => unreachable, inline .AARCH64, + .LOONGARCH, .PPC64, .RISCV, .X86_64, @@ -893,6 +944,7 @@ pub const MachineRelocType = union { return switch (elf.ehdrField(.machine)) { else => unreachable, inline .AARCH64, + .LOONGARCH, .PPC64, .RISCV, .X86_64, @@ -984,9 +1036,23 @@ const SymbolReloc = struct { size64, size32, + abs32_lo12, + rel32_hi20, + rel64_lo20, + rel64_hi12, + branch_rel18, + branch_rel23, + branch_rel28, + call_rel38, + tpoff32_lo12, + tpoff32_hi20, + tpoff64_lo20, + tpoff64_hi12, + fn dependsOnTlsSize(t: SymbolReloc.Type) bool { return switch (t) { .tpoff32, .tpoff64 => true, + .tpoff32_lo12, .tpoff32_hi20, .tpoff64_lo20, .tpoff64_hi12 => true, else => false, }; } @@ -1145,6 +1211,67 @@ const SymbolReloc = struct { target_endian, ); }, + .abs32_lo12 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value)); + }, + .rel32_hi20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcalaHi20(target_value, dest_vaddr)); + }, + .rel64_lo20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeJ20(dest_slice[0..4], link.loongarch.toPcala64Lo20(target_value, dest_vaddr)); + }, + .rel64_hi12 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeK12(dest_slice[0..4], link.loongarch.toPcala64Hi12(target_value, dest_vaddr)); + }, + // TODO: handle bad alignment and overflow gracefully + .branch_rel18 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_rel: i64 = @bitCast(target_value -% dest_vaddr); + const slot_target: i16 = @intCast(@shrExact(target_rel, 2)); + link.loongarch.writeK16(dest_slice[0..4], @bitCast(slot_target)); + }, + .branch_rel23 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_rel: i64 = @bitCast(target_value -% dest_vaddr); + const slot_target: i21 = @intCast(@shrExact(target_rel, 2)); + link.loongarch.writeD5K16(dest_slice[0..4], @bitCast(slot_target)); + }, + .branch_rel28 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_rel: i64 = @bitCast(target_value -% dest_vaddr); + const slot_target: i26 = @intCast(@shrExact(target_rel, 2)); + link.loongarch.writeD10K16(dest_slice[0..4], @bitCast(slot_target)); + }, + .call_rel38 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + const target_rel: i64 = @bitCast(target_value -% dest_vaddr); + // We use i64 instead of i36 here because the allowed range is + // [PC - 128 GiB - 0x20000, PC + 128GiB - 0x20000 - 4]. + // The intCast in writeJ20 will do the final check. + const slot_target: i64 = @intCast(@shrExact(target_rel, 2)); + link.loongarch.writeJ20(dest_slice[0..4], @bitCast(@as(i20, @intCast((slot_target +% 0x8000) >> 16)))); + link.loongarch.writeK16(dest_slice[4..8], @bitCast(@as(i16, @truncate(slot_target)))); + }, + .tpoff32_lo12 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value)); + }, + .tpoff32_hi20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 12)); + }, + .tpoff64_lo20 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeJ20(dest_slice[0..4], @truncate(target_value >> 32)); + }, + .tpoff64_hi12 => { + assert(elf.ehdrField(.machine) == .LOONGARCH); + link.loongarch.writeK12(dest_slice[0..4], @truncate(target_value >> 52)); + }, } } @@ -1259,6 +1386,18 @@ fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { const plt_sec_need_size: usize = 16 * need_plt_capacity; try elf.ensureNodeSize(elf.shndx.plt_sec.get(elf).ni, plt_sec_need_size); }, + .LOONGARCH => { + // Ensure the `.plt` section's node is big enough + const plt_need_size: usize = 32 + 16 * need_plt_capacity; + try elf.ensureNodeSize(elf.shndx.plt.get(elf).ni, plt_need_size); + + // Ensure the `.got.plt` section's node is big enough + const got_plt_need_size: usize = switch (elf.identClass()) { + .NONE, _ => unreachable, + inline else => |class| @sizeOf(class.ElfN().Addr) * (2 + need_plt_capacity), + }; + try elf.ensureNodeSize(elf.shndx.got_plt.get(elf).ni, got_plt_need_size); + }, } } /// Given an index into the PLT, returns whether that PLT entry is dead, meaning it may be reused at @@ -1874,12 +2013,18 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void .addend = 0, })); + const reserved_got_plt_entries: u32 = switch (elf.ehdrField(.machine)) { + else => |machine| @panic(@tagName(machine)), + .X86_64 => 3, + .LOONGARCH => 2, + }; + // Now that we know the index, we can set the relocation's offset. const got_plt_addr = switch (elf.shdrPtr(elf.shndx.got_plt)) { inline else => |shdr, class| got_plt_addr: { const ent_size = @sizeOf(class.ElfN().Addr); assert(elf.targetLoad(&shdr.entsize) == ent_size); - const offset = ent_size * @as(u64, 3 + plt_index); + const offset = ent_size * @as(u64, reserved_got_plt_entries + plt_index); assert(offset <= elf.targetLoad(&shdr.size)); break :got_plt_addr elf.targetLoad(&shdr.addr) + offset; }, @@ -1961,6 +2106,55 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void }, } }, + .LOONGARCH => { + // add a .PLT entry, writing the template + const plt_ni = elf.shndx.plt.get(elf).ni; + const plt_addr, const plt_slice = plt_entry: switch (elf.shdrPtr(elf.shndx.plt)) { + inline else => |shdr| { + const old_size = 16 * (1 + plt_index); + assert(elf.targetLoad(&shdr.size) == old_size); + elf.targetStore(&shdr.size, old_size + 16); + const plt_slice = plt_ni.slice(&elf.mf)[old_size..][0..16]; + @memcpy(plt_slice, source: switch (elf.identClass()) { + .NONE, _ => unreachable, + inline .@"32", .@"64" => |elf_class| { + const ld_byte = if (elf_class == .@"64") 0xc0 else 0x80; + break :source &[16]u8{ + 0x1a, 0x00, 0x00, 0x0f, // pcalau12i $t3, %pc_hi20(func@.got.plt) + 0x28, ld_byte, 0x01, 0xef, // ld.w/d $t3, $t3, %lo12(func@.got.plt) + 0x4c, 0x00, 0x01, 0xed, // jirl $t1, $t3, 0 + 0x00, 0x2a, 0x00, 0x00, // break + }; + }, + }); + break :plt_entry .{ elf.targetLoad(&shdr.addr) + old_size, plt_slice }; + }, + }; + + // add a .GOT.PLT entry, writing the address of the corresponding .PLT entry + const got_plt_ni = elf.shndx.got_plt.get(elf).ni; + switch (elf.shdrPtr(elf.shndx.got_plt)) { + inline else => |shdr, class| { + const ent_size = @sizeOf(class.ElfN().Addr); + const old_size = ent_size * (2 + plt_index); + assert(elf.targetLoad(&shdr.size) == old_size); + elf.targetStore(&shdr.size, old_size + ent_size); + std.mem.writeInt( + class.ElfN().Addr, + got_plt_ni.slice(&elf.mf)[old_size..][0..ent_size], + @intCast(plt_addr), + target_endian, + ); + assert(got_plt_addr == (elf.targetLoad(&shdr.addr) + old_size)); + }, + } + + // relocate the PLT entry to point to the .GOT.PLT entry + const got_plt_abs: u64 = @as(u64, got_plt_addr); + // TODO: handle overflow gracefully + link.loongarch.writeJ20(plt_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr)); + link.loongarch.writeK12(plt_slice[4..8], @truncate(got_plt_abs)); + }, } } @@ -2715,6 +2909,12 @@ fn initHeaders( const relro_phndx = phnum; phnum += 1; + const init_plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = + switch (machine) { + else => @panic(@tagName(machine)), + .X86_64 => .{ 16, .@"16", true }, + .LOONGARCH => .{ 32, .@"4", false }, + }; const expected_nodes_len = expected_nodes_len: switch (@"type") { .NONE, .CORE, _ => unreachable, .REL => { @@ -2722,9 +2922,10 @@ fn initHeaders( defer phnum = 0; break :expected_nodes_len 5 + phnum; }, - .EXEC, .DYN => break :expected_nodes_len 10 + + .EXEC, .DYN => break :expected_nodes_len 9 + phnum * 2 - 1 + // each phdr also has a matching shdr, except for the PT_PHDR phdr - @as(usize, 4) * @intFromBool(have_dynamic_section), // .dynstr, .dynsym, .rela.dyn, .rela.plt + @as(usize, 4) * @intFromBool(have_dynamic_section) + // .dynstr, .dynsym, .rela.dyn, .rela.plt + @intFromBool(plt_sec), }; try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); try elf.shdrs.ensureTotalCapacity(gpa, shnum); @@ -2757,7 +2958,24 @@ fn initHeaders( ehdr.entry = 0; ehdr.phoff = 0; ehdr.shoff = 0; - ehdr.flags = 0; + ehdr.flags = switch (machine) { + .X86_64 => 0, + .LOONGARCH => e_flags: { + const target_cpu = &elf.base.comp.getTarget().cpu; + const e_flags: std.elf.loongarch.EFlags = .{ + .base_abi_modifier = if (target_cpu.has(.loongarch, .d)) + .d + else if (target_cpu.has(.loongarch, .f)) + .f + else + .s, + .abi_extension = .base, + .abi_version = 1, + }; + break :e_flags @bitCast(e_flags); + }, + else => @panic(@tagName(machine)), + }; ehdr.ehsize = @sizeOf(ElfN.Ehdr); ehdr.phentsize = @sizeOf(ElfN.Phdr); ehdr.phnum = @min(phnum, std.elf.PN_XNUM); @@ -3051,6 +3269,7 @@ fn initHeaders( .size = switch (machine) { else => @panic(@tagName(machine)), .X86_64 => 3 * 8, + .LOONGARCH => if (elf.identClass() == .@"64") 8 else 4, }, .flags = .{ .WRITE = true, .ALLOC = true }, .addralign = addr_align, @@ -3066,21 +3285,17 @@ fn initHeaders( else => @panic(@tagName(machine)), .@"386" => 3 * 4, .X86_64 => 3 * 8, + .LOONGARCH => if (elf.identClass() == .@"64") 2 * 8 else 2 * 4, }, .addralign = addr_align, .entsize = @intCast(addr_align.toByteUnits()), }, ); - const plt_size: std.elf.Xword, const plt_align: std.mem.Alignment, const plt_sec = - switch (machine) { - else => @panic(@tagName(machine)), - .X86_64 => .{ 16, .@"16", true }, - }; elf.shndx.plt = try elf.addSection(elf.ni.text, .{ .name = ".plt", .type = .PROGBITS, .flags = .{ .ALLOC = true, .EXECINSTR = true }, - .size = plt_size, + .size = init_plt_size, .addralign = plt_align, .node_align = elf.mf.flags.block_size, }); @@ -3218,6 +3433,38 @@ fn initHeaders( .{ .X86_64 = .PC32 }, ); }, + .LOONGARCH => { + const plt_ni = elf.shndx.plt.get(elf).ni; + const got_plt_sym: Symbol.Id = .local(elf.shndx.got_plt.get(elf).lsi); + @memcpy(plt_ni.slice(&elf.mf)[0..32], switch (class) { + .NONE, _ => unreachable, + .@"32" => &[32]u8{ + 0x1a, 0x00, 0x00, 0x0e, // pcalau12i $t2, %pc_hi20(.got.plt) + 0x00, 0x11, 0x3d, 0xad, // sub.w $t1, $t1, $t3 + 0x28, 0x80, 0x01, 0xcf, // ld.w $t3, $t2, %lo12(.got.plt) # _dl_runtime_resolve + 0x02, 0xbf, 0x51, 0xad, // addi.w $t1, $t1, -44 # .plt entry + 0x02, 0x80, 0x01, 0xcc, // addi.w $t0, $t2, %lo12(.got.plt) # &.got.plt + 0x00, 0x44, 0x89, 0xad, // srli.w $t1, $t1, 2 # .plt entry offset + 0x28, 0x80, 0x11, 0x8c, // ld.w $t0, $t0, 4 # link map + 0x4c, 0x00, 0x01, 0xe0, // jr $t3 + }, + .@"64" => &[32]u8{ + 0x1a, 0x00, 0x00, 0x0e, // pcalau12i $t2, %pc_hi20(.got.plt) + 0x00, 0x11, 0xbd, 0xad, // sub.d $t1, $t1, $t3 + 0x28, 0xc0, 0x01, 0xcf, // ld.d $t3, $t2, %lo12(.got.plt) # _dl_runtime_resolve + 0x02, 0xff, 0x51, 0xad, // addi.d $t1, $t1, -44 # .plt entry + 0x02, 0xc0, 0x01, 0xcc, // addi.d $t0, $t2, %lo12(.got.plt) # &.got.plt + 0x00, 0x45, 0x05, 0xad, // srli.d $t1, $t1, 1 # .plt entry offset + 0x28, 0xc0, 0x21, 0x8c, // ld.d $t0, $t0, 8 # link map + 0x4c, 0x00, 0x01, 0xe0, // jr $t3 + }, + }); + elf.plt_first_symbol_reloc = @enumFromInt(elf.symbol_relocs.items.len); + try elf.ensureUnusedRelocCapacity(plt_ni, 3); + try elf.addRelocAssumeCapacity(plt_ni, 0, got_plt_sym, 0, .{ .LOONGARCH = .PCALA_HI20 }); + try elf.addRelocAssumeCapacity(plt_ni, 8, got_plt_sym, 0, .{ .LOONGARCH = .PCALA_LO12 }); + try elf.addRelocAssumeCapacity(plt_ni, 16, got_plt_sym, 0, .{ .LOONGARCH = .PCALA_LO12 }); + }, } } if (comp.config.any_non_single_threaded) { @@ -3242,6 +3489,13 @@ fn initHeaders( elf.got.putAssumeCapacityNoClobber(.{ .reserved = 1 }, .none); elf.got.putAssumeCapacityNoClobber(.{ .reserved = 2 }, .none); }, + .LOONGARCH => { + try elf.got.ensureUnusedCapacity(gpa, 1); + elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) { + true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) }, + false => .{ .reserved = 0 }, + }, .none); + }, } switch (elf.shdrPtr(elf.shndx.got)) { inline else => |shdr, ct_class| { @@ -3254,7 +3508,7 @@ fn initHeaders( // `FINI_ARRAY`/`PREINIT_ARRAY` sections are instead created by `createInitFiniArraySection` // when needed (it seems to be legal to leave those undefined if the section doesn't exist). - try elf.ensureUnusedSymbolCapacity(4, .maybe_global); + try elf.ensureUnusedSymbolCapacity(10, .maybe_global); // Despite the name, `__dso_handle` is necessary even in static binaries. _ = elf.addGlobalSymbolAssumeCapacity(.{ .node = Section.Index.text.get(elf).ni, @@ -3262,7 +3516,7 @@ fn initHeaders( .value = Section.Index.text.vaddr(elf), .size = 0, .type = .NOTYPE, - .bind = .strong, + .bind = .weak, .visibility = .HIDDEN, .shndx = .text, }) catch |err| switch (err) { @@ -3292,6 +3546,78 @@ fn initHeaders( }) catch |err| switch (err) { error.MultipleDefinitions => unreachable, // no inputs are processed yet }; + _ = elf.addGlobalSymbolAssumeCapacity(.{ + .node = .none, + .name = try .string(elf, "__init_array_start"), + .value = 0, + .size = 0, + .type = .NOTYPE, + .bind = .strong, + .visibility = .HIDDEN, + .shndx = .ABS, + }) catch |err| switch (err) { + error.MultipleDefinitions => unreachable, // no inputs are processed yet + }; + _ = elf.addGlobalSymbolAssumeCapacity(.{ + .node = .none, + .name = try .string(elf, "__init_array_end"), + .value = 0, + .size = 0, + .type = .NOTYPE, + .bind = .strong, + .visibility = .HIDDEN, + .shndx = .ABS, + }) catch |err| switch (err) { + error.MultipleDefinitions => unreachable, // no inputs are processed yet + }; + _ = elf.addGlobalSymbolAssumeCapacity(.{ + .node = .none, + .name = try .string(elf, "__fini_array_start"), + .value = 0, + .size = 0, + .type = .NOTYPE, + .bind = .strong, + .visibility = .HIDDEN, + .shndx = .ABS, + }) catch |err| switch (err) { + error.MultipleDefinitions => unreachable, // no inputs are processed yet + }; + _ = elf.addGlobalSymbolAssumeCapacity(.{ + .node = .none, + .name = try .string(elf, "__fini_array_end"), + .value = 0, + .size = 0, + .type = .NOTYPE, + .bind = .strong, + .visibility = .HIDDEN, + .shndx = .ABS, + }) catch |err| switch (err) { + error.MultipleDefinitions => unreachable, // no inputs are processed yet + }; + _ = elf.addGlobalSymbolAssumeCapacity(.{ + .node = .none, + .name = try .string(elf, "__preinit_array_start"), + .value = 0, + .size = 0, + .type = .NOTYPE, + .bind = .strong, + .visibility = .HIDDEN, + .shndx = .ABS, + }) catch |err| switch (err) { + error.MultipleDefinitions => unreachable, // no inputs are processed yet + }; + _ = elf.addGlobalSymbolAssumeCapacity(.{ + .node = .none, + .name = try .string(elf, "__preinit_array_end"), + .value = 0, + .size = 0, + .type = .NOTYPE, + .bind = .strong, + .visibility = .HIDDEN, + .shndx = .ABS, + }) catch |err| switch (err) { + error.MultipleDefinitions => unreachable, // no inputs are processed yet + }; if (have_dynamic_section) { _ = elf.addGlobalSymbolAssumeCapacity(.{ .node = elf.shndx.dynamic.get(elf).ni, @@ -3713,7 +4039,7 @@ fn mapInputSection(elf: *Elf, opts: struct { const new_alignment: std.mem.Alignment = .fromByteUnits( std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)), ); - try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment); + try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{ .set_alignment = true }); } // ...and update the shdr as needed. switch (elf.shdrPtr(existing_shndx)) { @@ -3876,7 +4202,7 @@ fn uavMapIndex( } else { const node = uav_gop.value_ptr.lsi.index().ptr(elf).node; if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) { - try node.realign(&elf.mf, gpa, resolved_align.toStdMem()); + try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{ .set_alignment = true }); } } return umi; @@ -4605,7 +4931,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars // We have a copy relocation for this global, but the amount of space we // reserved for it could be too small or underaligned! try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size); - try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment); + try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{ .set_alignment = true }); const global_ptr = elf.globalByName(name).?; switch (elf.symPtr(global_ptr.symtab_index)) { inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)), @@ -4759,36 +5085,24 @@ fn createInitFiniArraySection( }); elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {}); try elf.ensureUnusedSymbolCapacity(2, .maybe_global); - _ = elf.addGlobalSymbolAssumeCapacity(.{ + // These symbols definitely already have strong definitions, because we added them alongside the + // other linker-defined symbols, all the way back in `initHeaders`. + const start_sym_name = try elf.string(.strtab, "__" ++ name ++ "_start"); + const end_sym_name = try elf.string(.strtab, "__" ++ name ++ "_end"); + elf.setGlobalSymbolValue(start_sym_name, elf.globals.strong_def.getPtr(start_sym_name).?, .{ .node = shndx.get(elf).ni, - .name = try .string(elf, "__" ++ name ++ "_start"), .value = shndx.vaddr(elf), .size = 0, .type = .NOTYPE, - .bind = .strong, - .visibility = .HIDDEN, .shndx = shndx.*, - }) catch |err| switch (err) { - error.MultipleDefinitions => return elf.base.comp.link_diags.fail( - "multiple definitions of '{s}'", - .{"__" ++ name ++ "_start"}, - ), - }; - _ = elf.addGlobalSymbolAssumeCapacity(.{ + }); + elf.setGlobalSymbolValue(end_sym_name, elf.globals.strong_def.getPtr(end_sym_name).?, .{ .node = shndx.get(elf).ni, - .name = try .string(elf, "__" ++ name ++ "_end"), .value = shndx.vaddr(elf), .size = 0, .type = .NOTYPE, - .bind = .strong, - .visibility = .HIDDEN, .shndx = shndx.*, - }) catch |err| switch (err) { - error.MultipleDefinitions => return elf.base.comp.link_diags.fail( - "multiple definitions of '{s}'", - .{"__" ++ name ++ "_end"}, - ), - }; + }); } fn updateInitFiniArraySectionSize( elf: *Elf, @@ -5315,6 +5629,52 @@ fn addRelocAssumeCapacity( .TLSLD => elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .rel32), .GOTTPOFF => elf.addGotRelocAssumeCapacity(node, offset, .{ .tpoff = target }, addend, .rel32), }, + .LOONGARCH => switch (@"type".LOONGARCH) { + else => std.debug.panic("TODO: unsupported input relocation, {t}", .{@"type".LOONGARCH}), + _, + .NONE, + .COPY, + .JUMP_SLOT, + .RELATIVE, + .IRELATIVE, + => std.debug.panic("TODO: error for illegal or unsupported input relocation, {t}", .{@"type".LOONGARCH}), + + .RELAX => {}, // TODO: relaxation is not yet implemented + + // Relocations targeting a symbol + .@"64" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs64), + .@"32" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32), + .@"64_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64), + .@"32_PCREL" => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32), + + .PCALA_LO12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .abs32_lo12), + .PCALA_HI20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel32_hi20), + .PCALA64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_hi12), + .PCALA64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .rel64_lo20), + + .B16 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel18), + .B21 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel23), + .B26 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .branch_rel28), + .CALL36 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .call_rel38), + + // Relocations targeting a TLS symbol + .TLS_LE_LO12, .TLS_LE_LO12_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_lo12), + .TLS_LE_HI20, .TLS_LE_HI20_R => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff32_hi20), + .TLS_LE64_LO20 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_lo20), + .TLS_LE64_HI12 => try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .tpoff64_hi12), + .TLS_LE_ADD_R => {}, // TODO: relaxation is not yet implemented + + // Relocations targeting a GOT entry + .GOT_PC_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12), + .GOT_PC_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel32_hi20), + .GOT64_PC_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_lo20), + .GOT64_PC_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .rel64_hi12), + + .GOT_LO12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_lo12), + .GOT_HI20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs32_hi20), + .GOT64_LO20 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_lo20), + .GOT64_HI12 => elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .abs64_hi12), + }, }, } } @@ -5352,7 +5712,47 @@ fn addSymbolRelocAssumeCapacity( .tpoff32 => .TPOFF32, .size64 => .SIZE64, .size32 => .SIZE32, + .abs32_lo12, + .rel32_hi20, + .rel64_lo20, + .rel64_hi12, + .branch_rel18, + .branch_rel23, + .branch_rel28, + .call_rel38, + .tpoff32_lo12, + .tpoff32_hi20, + .tpoff64_lo20, + .tpoff64_hi12, + => unreachable, } }, + .LOONGARCH => .{ + .LOONGARCH = switch (@"type") { + .write_rela => unreachable, + .abs64 => .@"64", + .abs32 => .@"32", + .abs32s, .size64, .size32 => unreachable, + .rel64 => .@"64_PCREL", + .rel32 => .@"32_PCREL", + .pltrel64, .pltrel32 => break :r .none, + .dtpoff64 => .TLS_DTPREL64, + .dtpoff32 => .TLS_DTPREL32, + .tpoff64 => .TLS_TPREL64, + .tpoff32 => .TLS_TPREL32, + .abs32_lo12 => .PCALA_LO12, + .rel32_hi20 => .PCALA_HI20, + .rel64_lo20 => .PCALA64_LO20, + .rel64_hi12 => .PCALA64_HI12, + .branch_rel18 => .B16, + .branch_rel23 => .B21, + .branch_rel28 => .B26, + .call_rel38 => .CALL36, + .tpoff32_lo12 => .TLS_LE_LO12, + .tpoff32_hi20 => .TLS_LE_HI20, + .tpoff64_lo20 => .TLS_LE64_LO20, + .tpoff64_hi12 => .TLS_LE64_HI12, + }, + }, }; // TODO: even if the symbol is locally defined, preemption/interposition is a // possibility, which this condition does not currently consider! @@ -5523,6 +5923,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { .type = switch (elf.ehdrField(.machine)) { else => |machine| @panic(@tagName(machine)), .X86_64 => .{ .X86_64 = .TPOFF64 }, + .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 }, }, .dynsym_index = switch (sym_id.unwrap()) { .global => |name| elf.globalByName(name).?.dynsym_index, @@ -5579,7 +5980,11 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { .UNDEF => .{ .unsigned = 1 }, // TLS module ID for exexcutable else => .{ .reloc = .{ - .type = .{ .X86_64 = .DTPMOD64 }, + .type = switch (elf.ehdrField(.machine)) { + else => |machine| @panic(@tagName(machine)), + .X86_64 => .{ .X86_64 = .DTPMOD64 }, + .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 }, + }, .dynsym_index = switch (sym.unwrap()) { .local => 0, .global => |name| dsi: { @@ -5611,7 +6016,11 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void { .tlsld0 => switch (elf.shndx.dynamic) { .UNDEF => .{ .unsigned = 1 }, // TLS module ID for exexcutable else => .{ .reloc = .{ - .type = .{ .X86_64 = .DTPMOD64 }, + .type = switch (elf.ehdrField(.machine)) { + else => |machine| @panic(@tagName(machine)), + .X86_64 => .{ .X86_64 = .DTPMOD64 }, + .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 }, + }, .dynsym_index = 0, } }, }, @@ -6558,6 +6967,55 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad }, } }, + .LOONGARCH => { + switch (which) { + .plt => { + // We also need to update all of the references from `.plt` to `.got.plt`. + // However, if there's also a flush pending for `.got.plt`, don't bother doing + // this now, because we'll do it when `.got.plt` is flushed anyway. + if (elf.shndx.got_plt.get(elf).ni.hasMoved(&elf.mf)) { + return; + } + // Exit this `switch` to update those references. + }, + .plt_sec => unreachable, + .got_plt => { + // Update the offsets of the relocation entries in `.rela.plt`. + const rela_plt_shndx = elf.shndx.rela_plt; + for (0..elf.plt.count()) |plt_index| { + if (elf.pltEntryIsDead(plt_index)) continue; + rela_plt_shndx.relaAdjustOffset(elf, @enumFromInt(plt_index), old_addr, addr); + } + // We also need to update all of the references from `.plt` to `.got.plt`. + // However, if there's also a flush pending for `.plt`, don't bother doing + // this now, because we'll do it when `.plt` is flushed anyway. + if (elf.shndx.plt.get(elf).ni.hasMoved(&elf.mf)) { + return; + } + // Exit this `switch` to update those references. + }, + } + // We are updating the references from `.plt` to `.got.plt`. + const got_plt_addr = elf.shndx.got_plt.vaddr(elf); + const plt_addr = elf.shndx.plt.vaddr(elf); + const plt_slice = elf.shndx.plt.get(elf).ni.slice(&elf.mf); + switch (elf.identClass()) { + .NONE, _ => unreachable, + inline else => |class| { + const Addr = class.ElfN().Addr; + for (0..elf.plt.count()) |plt_index| { + const plt_offset = 16 * plt_index; + const got_plt_offset = @sizeOf(Addr) * (2 + plt_index); + const target_slice = plt_slice[plt_offset..]; + + const got_plt_abs: u64 = got_plt_addr + got_plt_offset; + // TODO: handle overflow gracefully + link.loongarch.writeJ20(target_slice[0..4], link.loongarch.toPcalaHi20(got_plt_abs, plt_addr + plt_offset)); + link.loongarch.writeK12(target_slice[4..8], @truncate(got_plt_abs)); + } + }, + } + }, } } @@ -6651,16 +7109,12 @@ pub fn deleteExport(elf: *Elf, exported: Zcu.Exported, name: InternPool.NullTerm _ = name; } -pub fn dump(elf: *Elf, tid: Zcu.PerThread.Id) Io.Cancelable!void { - const comp = elf.base.comp; - const io = comp.io; - var buffer: [512]u8 = undefined; - const stderr = try io.lockStderr(&buffer, null); - defer io.lockStderr(); - const w = &stderr.file_writer.interface; - elf.printNode(tid, w, .root, 0) catch |err| switch (err) { - error.WriteFailed => return stderr.err.?, - }; +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); + return .enabled; + } + return .disabled; } pub fn printNode( @@ -6704,13 +7158,13 @@ pub fn printNode( elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf), }); }, - .copied_global => |name| try w.print("(copy:{s})", .{name}), + .copied_global => |name| try w.print("(copy:{s})", .{name.slice(elf)}), .nav => |nmi| { const zcu = elf.base.comp.zcu.?; const ip = &zcu.intern_pool; const nav = ip.getNav(nmi.navIndex(elf)); try w.print("({f}, {f})", .{ - Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), + Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }), nav.fqn.fmt(ip), }); }, diff --git a/src/link/Lld.zig b/src/link/Lld.zig index 3f20d15ebd7e8c9890b2fab69d57dc5779715579..c4c4e0fb3d721cc134473db4b348ee65a048d08e 100644 --- a/src/link/Lld.zig +++ b/src/link/Lld.zig @@ -304,23 +304,25 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void { // insight as to what's going on here you can read that function body which is more // well-commented. - const link_inputs = comp.link_inputs; - var object_files: std.ArrayList([*:0]const u8) = .empty; - try object_files.ensureUnusedCapacity(arena, link_inputs.len); - for (link_inputs) |input| { - object_files.appendAssumeCapacity(try input.path().?.toStringZ(arena)); - } + 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 => { + const path = try input.path().?.toStringZ(arena); + object_files.appendAssumeCapacity(path); + }, + }; - try object_files.ensureUnusedCapacity(arena, comp.c_object_table.count() + - comp.win32_resource_table.count() + 2); + try object_files.ensureUnusedCapacity(arena, comp.c_objects.items.len + + comp.win32_resources.items.len + 2); - for (comp.c_object_table.keys()) |key| { - object_files.appendAssumeCapacity(try key.status.success.object_path.toStringZ(arena)); + for (comp.c_objects.items) |c_object| { + object_files.appendAssumeCapacity(try c_object.status.success.object_path.toStringZ(arena)); } - for (comp.win32_resource_table.keys()) |key| { - object_files.appendAssumeCapacity(try arena.dupeSentinel(u8, key.status.success.res_path, 0)); + for (comp.win32_resources.items) |win32_resource| { + object_files.appendAssumeCapacity(try arena.dupeSentinel(u8, win32_resource.status.success.res_path, 0)); } if (zcu_obj_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); if (compiler_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena)); @@ -395,8 +397,8 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { const the_object_path = blk: { if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; + if (comp.c_objects.items.len != 0) + break :blk comp.c_objects.items[0].status.success.object_path; if (zcu_obj_path) |p| break :blk p; @@ -546,12 +548,12 @@ fn coffLink(lld: *Lld, arena: Allocator) !void { }, }; - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } - for (comp.win32_resource_table.keys()) |key| { - try argv.append(key.status.success.res_path); + for (comp.win32_resources.items) |win32_resource| { + try argv.append(win32_resource.status.success.res_path); } if (zcu_obj_path) |p| { @@ -805,8 +807,8 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { const the_object_path = blk: { if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; + if (comp.c_objects.items.len != 0) + break :blk comp.c_objects.items[0].status.success.object_path; if (zcu_obj_path) |p| break :blk p; @@ -1099,8 +1101,8 @@ fn elfLink(lld: *Lld, arena: Allocator) !void { whole_archive = false; } - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { @@ -1295,21 +1297,21 @@ fn getLDMOption(target: *const std.Target) ?[]const u8 { }, .mips64 => switch (target.os.tag) { .freebsd => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32btsmipn32_fbsd", + .gnuabin32, .muslabin32, .abin32 => "elf32btsmipn32_fbsd", else => "elf64btsmip_fbsd", }, else => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32btsmipn32", + .gnuabin32, .muslabin32, .abin32 => "elf32btsmipn32", else => "elf64btsmip", }, }, .mips64el => switch (target.os.tag) { .freebsd => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32ltsmipn32_fbsd", + .gnuabin32, .muslabin32, .abin32 => "elf32ltsmipn32_fbsd", else => "elf64ltsmip_fbsd", }, else => switch (target.abi) { - .gnuabin32, .muslabin32 => "elf32ltsmipn32", + .gnuabin32, .muslabin32, .abin32 => "elf32ltsmipn32", else => "elf64ltsmip", }, }, @@ -1336,7 +1338,7 @@ fn getLDMOption(target: *const std.Target) ?[]const u8 { else => "elf_i386", }, .x86_64 => switch (target.abi) { - .gnux32, .muslx32 => "elf32_x86_64", + .gnux32, .muslx32, .x32 => "elf32_x86_64", else => "elf_x86_64", }, else => null, @@ -1381,8 +1383,8 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { const the_object_path = blk: { if (link.firstObjectInput(comp.link_inputs)) |obj| break :blk obj.path; - if (comp.c_object_table.count() != 0) - break :blk comp.c_object_table.keys()[0].status.success.object_path; + if (comp.c_objects.items.len != 0) + break :blk comp.c_objects.items[0].status.success.object_path; if (zcu_obj_path) |p| break :blk p; @@ -1566,8 +1568,8 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void { whole_archive = false; } - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { try argv.append(try p.toString(arena)); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 8783781a4ced69514353f2696587a9f9a1516b23..125db2983f2fa8a550b218d2d4be6d41153c1c8b 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -28,9 +28,9 @@ sections: std.MultiArrayList(Section) = .{}, resolver: SymbolResolver = .{}, /// This table will be populated after `scanRelocs` has run. /// Key is symbol index. -undefs: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, UndefRefs) = .empty, +undefs: std.array_hash_map.Auto(SymbolResolver.Index, UndefRefs) = .empty, undefs_mutex: std.Io.Mutex = .init, -dupes: std.AutoArrayHashMapUnmanaged(SymbolResolver.Index, std.ArrayList(File.Index)) = .empty, +dupes: std.array_hash_map.Auto(SymbolResolver.Index, std.ArrayList(File.Index)) = .empty, dupes_mutex: std.Io.Mutex = .init, dyld_info_cmd: macho.dyld_info_command = .{}, @@ -377,9 +377,9 @@ pub fn flush( // This is a set of object files emitted by clang in a single `build-exe` invocation. // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up // in this set. - try positionals.ensureUnusedCapacity(comp.c_object_table.keys().len); - for (comp.c_object_table.keys()) |key| { - positionals.appendAssumeCapacity(try link.openObjectInput(io, diags, key.status.success.object_path)); + try positionals.ensureUnusedCapacity(comp.c_objects.items.len); + for (comp.c_objects.items) |c_object| { + positionals.appendAssumeCapacity(try link.openObjectInput(io, diags, c_object.status.success.object_path)); } if (zcu_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); @@ -657,8 +657,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }), }; - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { @@ -749,8 +749,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }), }; - for (comp.c_object_table.keys()) |key| { - try argv.append(try key.status.success.object_path.toString(arena)); + for (comp.c_objects.items) |c_object| { + try argv.append(try c_object.status.success.object_path.toString(arena)); } if (zcu_obj_path) |p| { @@ -4102,7 +4102,7 @@ const Section = struct { }; pub const LiteralPool = struct { - table: std.AutoArrayHashMapUnmanaged(void, void) = .empty, + table: std.array_hash_map.Auto(void, void) = .empty, keys: std.ArrayList(Key) = .empty, values: std.ArrayList(MachO.Ref) = .empty, data: std.ArrayList(u8) = .empty, @@ -4541,7 +4541,7 @@ pub const Ref = struct { pub const SymbolResolver = struct { keys: std.ArrayList(Key) = .empty, values: std.ArrayList(Ref) = .empty, - table: std.AutoArrayHashMapUnmanaged(void, void) = .empty, + table: std.array_hash_map.Auto(void, void) = .empty, const Result = struct { found_existing: bool, diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig index d1f79b5ab73e7efd293858116a2031453d57c8de..3125cd538d01636f3c181c48282c354de53f388a 100644 --- a/src/link/MachO/Dylib.zig +++ b/src/link/MachO/Dylib.zig @@ -14,7 +14,7 @@ symbols: std.ArrayList(Symbol) = .empty, symbols_extra: std.ArrayList(u32) = .empty, globals: std.ArrayList(MachO.SymbolResolver.Index) = .empty, dependents: std.ArrayList(Id) = .empty, -rpaths: std.StringArrayHashMapUnmanaged(void) = .empty, +rpaths: std.array_hash_map.String(void) = .empty, umbrella: File.Index, platform: ?MachO.Platform = null, diff --git a/src/link/MachO/Thunk.zig b/src/link/MachO/Thunk.zig index cdb9eb649af4a0aeb340d96cad81716cc66ecbde..d71cf29aea5c331a08028cf99eb78fd7a7f8f511 100644 --- a/src/link/MachO/Thunk.zig +++ b/src/link/MachO/Thunk.zig @@ -1,6 +1,6 @@ value: u64 = 0, out_n_sect: u8 = 0, -symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .empty, +symbols: std.array_hash_map.Auto(MachO.Ref, void) = .empty, output_symtab_ctx: MachO.SymtabCtx = .{}, pub fn deinit(thunk: *Thunk, allocator: Allocator) void { diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 5f2309dbfee59c24df7d3f6e90a3d8264913b1a4..fc2500867f7d90d619c91fd0b2ad48bc3c59f9d1 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -560,14 +560,14 @@ pub fn flush(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.E // Handle any lazy symbols that were emitted by incremental compilation. if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| { - const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid); - defer pt.deactivate(); + const active = macho_file.base.comp.zcu.?.activate(tid); + defer active.deactivate(); // Most lazy symbols can be updated on first use, but // anyerror needs to wait for everything to be flushed. if (metadata.text_state != .unused) self.updateLazySymbol( macho_file, - pt, + active.pt, .{ .kind = .code, .ty = .anyerror_type }, metadata.text_symbol_index, ) catch |err| switch (err) { @@ -576,7 +576,7 @@ pub fn flush(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.E }; if (metadata.const_state != .unused) self.updateLazySymbol( macho_file, - pt, + active.pt, .{ .kind = .const_data, .ty = .anyerror_type }, metadata.const_symbol_index, ) catch |err| switch (err) { @@ -590,9 +590,9 @@ pub fn flush(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.E } if (self.dwarf) |*dwarf| { - const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid); - defer pt.deactivate(); - dwarf.flush(pt) catch |err| switch (err) { + const active = macho_file.base.comp.zcu.?.activate(tid); + defer active.deactivate(); + dwarf.flush(active.pt) catch |err| switch (err) { error.OutOfMemory => |e| return e, else => |e| return diags.fail("failed to flush dwarf module: {s}", .{@errorName(e)}), }; @@ -1750,11 +1750,11 @@ const TlvInitializer = struct { } }; -const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); -const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata); -const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); +const NavTable = std.array_hash_map.Auto(InternPool.Nav.Index, AvMetadata); +const UavTable = std.array_hash_map.Auto(InternPool.Index, AvMetadata); +const LazySymbolTable = std.array_hash_map.Auto(InternPool.Index, LazySymbolMetadata); const RelocationTable = std.ArrayList(std.ArrayList(Relocation)); -const TlvInitializerTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlvInitializer); +const TlvInitializerTable = std.array_hash_map.Auto(Atom.Index, TlvInitializer); const x86_64 = struct { fn writeTrampolineCode(source_addr: u64, target_addr: u64, buf: *[max_trampoline_len]u8) ![]u8 { diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index be36cfc045b7bb4abe4ff8fde43b62b7299511e6..b864ee66ca42394529dd6c58556e5cb10801e413 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -9,8 +9,8 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat try positionals.ensureUnusedCapacity(comp.link_inputs.len); positionals.appendSliceAssumeCapacity(comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - try positionals.append(try link.openObjectInput(io, diags, key.status.success.object_path)); + for (comp.c_objects.items) |c_object| { + try positionals.append(try link.openObjectInput(io, diags, c_object.status.success.object_path)); } if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); @@ -86,8 +86,8 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? try positionals.ensureUnusedCapacity(comp.link_inputs.len); positionals.appendSliceAssumeCapacity(comp.link_inputs); - for (comp.c_object_table.keys()) |key| { - try positionals.append(try link.openObjectInput(io, diags, key.status.success.object_path)); + for (comp.c_objects.items) |c_object| { + try positionals.append(try link.openObjectInput(io, diags, c_object.status.success.object_path)); } if (module_obj_path) |path| try positionals.append(try link.openObjectInput(io, diags, path)); diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig index 9c317aff744d99f6570654851bb253670d35f8e8..74c1ce432999043d8fe5ad0331d8ba4128973abd 100644 --- a/src/link/MappedFile.zig +++ b/src/link/MappedFile.zig @@ -26,6 +26,9 @@ updates: std.ArrayList(Node.Index), update_prog_node: std.Progress.Node, writers: std.SinglyLinkedList, io_err: ?IoError, +/// If locked, modifying the node layout is not allowed. +/// Modifying node content is always allowed. +nodes_lock: std.debug.SafetyLock = .{}, pub const growth_factor = 4; @@ -188,6 +191,10 @@ pub const Node = extern struct { return ni.get(mf).parent; } + pub fn next(ni: Node.Index, mf: *const MappedFile) Node.Index { + return ni.get(mf).next; + } + pub fn ChildIterator(comptime direction: enum { prev, next }) type { return struct { mf: *const MappedFile, @@ -330,6 +337,7 @@ pub const Node = extern struct { } pub fn resize(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, size: u64) Error!void { + defer if (std.debug.runtime_safety) mf.verify(); mf.resizeNode(gpa, ni, size) catch |err| switch (err) { error.OutOfMemory, error.Canceled, @@ -346,16 +354,23 @@ pub const Node = extern struct { } } + pub const RealignNodeOptions = struct { + /// Shift the node backwards if possible + try_backwards: bool = true, + /// If `set, persists `new_alignment` as the node's alignment for future operations. + set_alignment: bool = true, + }; + /// Moves and expands a node such that its offset and size are aligned to `new_alignment`. - /// /// Asserts that `ni` is not `Node.Index.root`. pub fn realign( ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, new_alignment: std.mem.Alignment, + opts: RealignNodeOptions, ) Error!void { - mf.realignNode(gpa, ni, new_alignment) catch |err| switch (err) { + mf.realignNode(gpa, ni, new_alignment, opts) catch |err| switch (err) { error.OutOfMemory, error.Canceled, => |e| return e, @@ -371,6 +386,26 @@ pub const Node = extern struct { } } + /// Shrink a node to `size`, exactly. + /// Asserts that the new size can contain all the children. + /// If `shift_next` is set, then the following node is shifted backwards into + /// the free space as much as alignment allows. + /// Asserts that `size` is >= the end of the last child node. + pub fn shrink( + ni: Node.Index, + mf: *MappedFile, + gpa: std.mem.Allocator, + size: u64, + shift_next: bool, + ) Error!void { + try mf.shrinkNode(gpa, ni, size, shift_next); + var writers_it = mf.writers.first; + while (writers_it) |writer_node| : (writers_it = writer_node.next) { + const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); + w.interface.buffer = w.ni.slice(mf); + } + } + pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { w.* = .{ .gpa = gpa, @@ -530,7 +565,26 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { add_node: AddNodeOptions, }) Error!Node.Index { if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); + mf.nodes_lock.assertUnlocked(); const offset = opts.add_node.alignment.forward(@intCast(opts.offset)); + if (opts.parent != .none) { + const new_end = offset + opts.add_node.size; + switch (opts.next) { + .none => { + _, const parent_size = opts.parent.location(mf).resolve(mf); + if (new_end > parent_size) + try opts.parent.resize(mf, gpa, new_end); + }, + else => |next_ni| { + const next_offset, _ = next_ni.location(mf).resolve(mf); + if (new_end > next_offset) + try next_ni.realign(mf, gpa, opts.add_node.alignment, .{ + .try_backwards = false, + .set_alignment = false, + }); + }, + } + } const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{ .small = .{ .offset = small_offset, .size = 0 }, @@ -572,14 +626,12 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { }, .location_payload = location_payload, }; + { - defer { - free_node.flags.moved = false; - free_node.flags.resized = false; - } - _, const parent_size = opts.parent.location(mf).resolve(mf); - if (offset > parent_size) try opts.parent.resize(mf, gpa, offset); try free_ni.resize(mf, gpa, 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); @@ -666,11 +718,63 @@ pub fn addNodeAfter( }); } -fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) (Allocator.Error || Io.Cancelable || IoError)!void { +fn shrinkNode( + mf: *MappedFile, + gpa: std.mem.Allocator, + ni: Node.Index, + size: u64, + shift_next: bool, +) !void { + mf.nodes_lock.assertUnlocked(); + const node = ni.get(mf); + const old_offset, _ = node.location().resolve(mf); + + // This would require unmapping first + assert(ni != Node.Index.root); + defer if (std.debug.runtime_safety) mf.verify(); + + if (node.last != .none) { + const last = node.last.get(mf); + const last_offset, const last_size = last.location().resolve(mf); + assert(last_offset + last_size > size); + } + + try mf.large.ensureUnusedCapacity(gpa, 4); + try mf.updates.ensureUnusedCapacity(gpa, 2); + + ni.setLocationAssumeCapacity(mf, old_offset, size); + if (!shift_next or node.next == .none) return; + + const next = node.next.get(mf); + const old_next_offset, const next_size = next.location().resolve(mf); + const padding = old_next_offset - (old_offset + size); + const new_next_offset = next.flags.alignment.forward(@intCast(old_next_offset - padding)); + + if (next.flags.has_content and new_next_offset < old_next_offset) { + const old_file_offset = node.next.fileLocation(mf, false).offset; + const new_file_offset = (old_file_offset - old_next_offset) + new_next_offset; + @memmove( + mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(next_size)], + mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(next_size)], + ); + @memset(mf.memory_map.memory[@intCast(new_file_offset + next_size)..@intCast(old_file_offset + next_size)], 0); + } + + node.next.setLocationAssumeCapacity(mf, new_next_offset, next_size); +} + +fn resizeNode( + mf: *MappedFile, + gpa: std.mem.Allocator, + ni: Node.Index, + requested_size: u64, +) (Allocator.Error || Io.Cancelable || IoError)!void { + mf.nodes_lock.assertUnlocked(); const io = mf.io; const node = ni.get(mf); const old_offset, const old_size = node.location().resolve(mf); const new_size = node.flags.alignment.forward(@intCast(requested_size)); + // Resize the entire file if (ni == Node.Index.root) { try mf.ensureCapacityForSetLocation(gpa); @@ -703,19 +807,26 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested if (is_linux and !mf.flags.fallocate_insert_range_unsupported and node.flags.alignment.order(mf.flags.block_size).compare(.gte)) insert_range: { - mf.memory_map.write(io) catch |err| switch (err) { - error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking - error.NotOpenForWriting => return error.Unexpected, // we definitely opened the file for writing - else => |e| return e, - }; - // Ask the filesystem driver to insert extents into the file without copying any data - const last_offset, const last_size = parent.last.location(mf).resolve(mf); - const last_end = last_offset + last_size; - assert(last_end <= old_parent_size); const range_file_offset = ni.fileLocation(mf, false).offset + old_size; const range_size = node.flags.alignment.forward( @intCast(requested_size +| requested_size / growth_factor), ) - old_size; + + // If this node is being realigned, its current state might not + // meet the requirements for fallocate + if (!mf.flags.block_size.check(@intCast(range_file_offset)) or + !mf.flags.block_size.check(@intCast(range_size))) + break :insert_range; + + mf.memory_map.write(io) catch |err| switch (err) { + error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking + error.NotOpenForWriting => return error.Unexpected, // we definitely opened the file for writing + else => |e| return e, + }; + // Ask the filesystem driver to insert extents into the file without copying any data + const last_offset, const last_size = parent.last.location(mf).resolve(mf); + const last_end = last_offset + last_size; + assert(last_end <= old_parent_size); _, const file_size = Node.Index.root.location(mf).resolve(mf); while (true) switch (linux.errno(switch (std.math.order(range_file_offset, file_size)) { .lt => linux.fallocate( @@ -814,6 +925,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested var last_fixed_ni = ni; var first_floating_ni = node.next; var shift = new_size - old_size; + var max_shift_align: std.mem.Alignment = .@"1"; var direction: enum { forward, reverse } = .forward; while (true) { assert(last_fixed_ni != .none); @@ -830,10 +942,12 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested if (new_last_fixed_offset + last_fixed_size <= old_first_floating_offset) break :make_space; assert(direction == .forward); + max_shift_align = max_shift_align.max(first_floating.flags.alignment.max(last_fixed.flags.alignment)); if (first_floating.flags.fixed) { - shift = first_floating.flags.alignment.forward(@intCast( + shift = max_shift_align.forward(@intCast( @max(shift, first_floating_size), )); + // Not enough space, try the next node last_fixed_ni = first_floating_ni; first_floating_ni = first_floating.next; @@ -842,7 +956,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested // Move the found floating node to make space for preceding fixed nodes const last = parent.last.get(mf); const last_offset, const last_size = last.location().resolve(mf); - const new_first_floating_offset = first_floating.flags.alignment.forward( + const new_first_floating_offset = max_shift_align.forward( @intCast(@max(new_last_fixed_offset + last_fixed_size, last_offset + last_size)), ); const new_parent_size = new_first_floating_offset + first_floating_size; @@ -903,7 +1017,7 @@ fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested last_fixed_ni.setLocationAssumeCapacity( mf, old_last_fixed_offset, - last_fixed_size + shift, + new_size, ); return; } @@ -929,8 +1043,10 @@ fn realignNode( gpa: std.mem.Allocator, ni: Node.Index, new_alignment: std.mem.Alignment, + opts: Node.Index.RealignNodeOptions, ) (Allocator.Error || Io.Cancelable || IoError)!void { assert(ni != Node.Index.root); // currently unsupported + mf.nodes_lock.assertUnlocked(); const node = ni.get(mf); const old_offset, const size = node.location().resolve(mf); @@ -939,7 +1055,12 @@ fn realignNode( defer if (std.debug.runtime_safety) mf.verify(); + const prev_alignment = node.flags.alignment; node.flags.alignment = new_alignment; + defer { + // alignment needs to be temporarily set for the resizes below + if (!opts.set_alignment) node.flags.alignment = prev_alignment; + } const new_size = node.flags.alignment.forward(@intCast(size)); if (new_alignment.check(@intCast(old_offset))) { @@ -956,6 +1077,37 @@ fn realignNode( }, }; + if (opts.try_backwards) { + const backward_offset = new_alignment.backward(@intCast(old_offset)); + const prev_end = if (node.prev == .none) 0 else prev: { + const prev_offset, const prev_size = node.prev.location(mf).resolve(mf); + break :prev prev_offset + prev_size; + }; + + if (backward_offset >= prev_end) { + try mf.ensureCapacityForSetLocation(gpa); + + if (node.flags.has_content) { + const old_file_offset = ni.fileLocation(mf, false).offset; + const new_file_offset = (old_file_offset - old_offset) + backward_offset; + @memmove( + mf.memory_map.memory[@intCast(new_file_offset)..][0..@intCast(size)], + mf.memory_map.memory[@intCast(old_file_offset)..][0..@intCast(size)], + ); + @memset(mf.memory_map.memory[@intCast(new_file_offset + size)..@intCast(old_file_offset + size)], 0); + } + + if (backward_offset + new_size <= trailing_end) { + ni.setLocationAssumeCapacity(mf, backward_offset, new_size); + } else { + ni.setLocationAssumeCapacity(mf, backward_offset, size); + try mf.resizeNode(gpa, ni, new_size); + } + + return; + } + } + const forward_offset = new_alignment.forward(@intCast(old_offset)); if (forward_offset + new_size <= trailing_end) { // Shift into the free space if possible @@ -1135,6 +1287,12 @@ fn ensureTotalCapacityPreciseInner(mf: *MappedFile, new_capacity: usize) (Alloca error.OperationUnsupported => {}, else => |e| return e, } + + mf.memory_map.write(io) catch |err| switch (err) { + error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking + error.NotOpenForWriting => return error.Unexpected, // we definitely opened the file for writing + else => |e| return e, + }; unmap(mf); } @@ -1156,11 +1314,12 @@ pub fn unmap(mf: *MappedFile) void { } pub fn flush(mf: *MappedFile) (Io.Cancelable || error{MappedFileIo})!void { - mf.memory_map.write(mf.io) catch |err| switch (err) { + mf.flushInner() catch |err| switch (err) { error.Canceled => |e| return e, error.WouldBlock, // file was not opened as non-blocking error.NotOpenForWriting, // we definitely opened the file for writing + error.ReadOnlyFileSystem, => { mf.io_err = error.Unexpected; return error.MappedFileIo; @@ -1173,6 +1332,11 @@ pub fn flush(mf: *MappedFile) (Io.Cancelable || error{MappedFileIo})!void { }; } +fn flushInner(mf: *MappedFile) (Io.File.WritePositionalError || Io.File.SetTimestampsError)!void { + try mf.memory_map.write(mf.io); + if (is_windows) try mf.memory_map.file.setTimestampsNow(mf.io); +} + fn verify(mf: *MappedFile) void { const root = Node.Index.root.get(mf); assert(root.parent == .none); @@ -1207,3 +1371,184 @@ fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void { ni = node.next; } } + +const testing = std.testing; +fn testVerifyContent(mf: *@This(), ni: Node.Index, value: u8, init_len: usize) !void { + // Not using std.mem.allEqual, so we can get useful output + const slice = ni.slice(mf); + var buf: [256]u8 = undefined; + @memset(buf[0..init_len], value); + @memset(buf[init_len..], 0); + try testing.expectEqualSlices(u8, buf[0..slice.len], slice); +} + +test { + const gpa = testing.allocator; + + var tmp_dir = testing.tmpDir(.{}); + defer tmp_dir.cleanup(); + + var file = try tmp_dir.dir.createFile(testing.io, "test.mf", .{ .read = true }); + defer file.close(testing.io); + + var mf = try init(file, gpa, testing.io); + defer mf.deinit(gpa); + + const a = try mf.addFirstChildNode(gpa, .root, .{ .fixed = true, .alignment = .@"4" }); + const c = try mf.addLastChildNode(gpa, .root, .{ .fixed = true, .alignment = .@"4" }); + const b = try mf.addNodeAfter(gpa, a, .{ .fixed = true, .alignment = .@"16" }); + const d = try mf.addNodeAfter(gpa, b, .{ .alignment = .@"4" }); + + const a_init_size = 8; + const b_init_size = 16; + const c_init_size = 24; + const d_init_size = 28; + + // Resize without content + { + // Verify size is aligned forward + try d.resize(&mf, gpa, d_init_size - 1); + try a.resize(&mf, gpa, a_init_size - 2); + try c.resize(&mf, gpa, c_init_size); + try b.resize(&mf, gpa, b_init_size); + mf.verify(); + + const a_loc, const a_size = a.location(&mf).resolve(&mf); + const b_loc, const b_size = b.location(&mf).resolve(&mf); + const c_loc, const c_size = c.location(&mf).resolve(&mf); + _, const d_size = d.location(&mf).resolve(&mf); + try testing.expect(a_size >= a_init_size); + try testing.expect(b_size >= b_init_size); + try testing.expect(c_size >= c_init_size); + try testing.expect(d_size >= d_init_size); + try testing.expect(b_loc >= a_loc + a_size); + try testing.expect(c_loc >= b_loc + b_size); + } + + const a_exp_size = 24; + const b_exp_size = 28; + const c_exp_size = 48; + const d_exp_size = 32; + + // Resize with content + { + @memset(a.slice(&mf)[0..a_init_size], 0xaa); + @memset(b.slice(&mf)[0..b_init_size], 0xbb); + @memset(c.slice(&mf)[0..c_init_size], 0xcc); + @memset(d.slice(&mf)[0..d_init_size], 0xdd); + + try a.resize(&mf, gpa, a_exp_size); + try b.resize(&mf, gpa, b_exp_size); + try c.resize(&mf, gpa, c_exp_size); + try d.resize(&mf, gpa, d_exp_size); + mf.verify(); + + const a_loc, const a_size = a.location(&mf).resolve(&mf); + const b_loc, const b_size = b.location(&mf).resolve(&mf); + const c_loc, const c_size = c.location(&mf).resolve(&mf); + _, const d_size = d.location(&mf).resolve(&mf); + try testing.expect(a_size >= a_exp_size); + try testing.expect(b_size >= b_exp_size); + try testing.expect(c_size >= c_exp_size); + try testing.expect(d_size >= d_exp_size); + try testing.expect(b_loc >= a_loc + a_size); + try testing.expect(c_loc >= b_loc + b_size); + + try testVerifyContent(&mf, a, 0xaa, a_init_size); + try testVerifyContent(&mf, b, 0xbb, b_init_size); + try testVerifyContent(&mf, c, 0xcc, c_init_size); + try testVerifyContent(&mf, d, 0xdd, d_init_size); + } + + const child_init: []const struct { std.mem.Alignment, usize } = &.{ + .{ .@"16", 16 }, + .{ .@"1", 1 }, + .{ .@"1", 19 }, + .{ .@"1", 3 }, + .{ .@"8", 30 }, + .{ .@"2", 5 }, + .{ .@"1", 60 }, + .{ .@"2", 2 }, + .{ .@"16", 32 }, + }; + + var children: [child_init.len]Node.Index = undefined; + + // Differently-aligned fixed sibling nodes + { + for (children[0 .. children.len - 1], child_init[0 .. children.len - 1], 0..) |*ni, opts, i| { + ni.* = try mf.addLastChildNode(gpa, b, .{ + .alignment = opts.@"0", + .size = opts.@"1", + .fixed = true, + }); + + @memset(ni.slice(&mf)[0..opts.@"1"], @intCast(i + 1)); + } + // Shift differently-aligned nodes by inserting a node + children[children.len - 1] = try mf.addNodeAfter(gpa, children[3], .{ + .alignment = child_init[children.len - 1].@"0", + .size = child_init[children.len - 1].@"1", + .fixed = true, + }); + @memset(children[children.len - 1].slice(&mf), @intCast(children.len)); + + mf.verify(); + for (children, child_init, 0..) |ni, opts, i| { + try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); + } + } + + // Shifting child nodes forward due via resize of parent.prev + { + try testing.expect(a.location(&mf).resolve(&mf)[1] < 64); + try a.resize(&mf, gpa, 64); + + try testVerifyContent(&mf, a, 0xaa, a_init_size); + try testVerifyContent(&mf, c, 0xcc, c_init_size); + try testVerifyContent(&mf, d, 0xdd, d_init_size); + for (children, child_init, 0..) |ni, opts, i| { + try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); + } + } + + // Re-align last node into trailing free space within parent + { + try b.resize(&mf, gpa, b.location(&mf).resolve(&mf)[1] + 64); + + const last = children[children.len - 2]; + try last.realign(&mf, gpa, .@"4", true); + mf.verify(); + + for (children, child_init, 0..) |ni, opts, i| + try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); + try testVerifyContent(&mf, c, 0xcc, c_init_size); + } + + // Re-align, shifting sibling nodes + { + try children[1].realign(&mf, gpa, .@"8", true); + mf.verify(); + + for (children, child_init, 0..) |ni, opts, i| + try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); + try testVerifyContent(&mf, c, 0xcc, c_init_size); + } + + // Shrink and shift start of trailing node into free space + { + try mf.shrinkNode(gpa, a, 16, true); + mf.verify(); + + const a_loc, const a_size = a.location(&mf).resolve(&mf); + const b_loc, _ = b.location(&mf).resolve(&mf); + try testing.expectEqual(b_loc, a_loc + a_size); + + try testVerifyContent(&mf, a, 0xaa, a_init_size); + try testVerifyContent(&mf, c, 0xcc, c_init_size); + try testVerifyContent(&mf, d, 0xdd, d_init_size); + for (children, child_init, 0..) |ni, opts, i| { + try testVerifyContent(&mf, ni, @intCast(i + 1), opts.@"1"); + } + } +} diff --git a/src/link/Queue.zig b/src/link/Queue.zig index 9e05b0b99ef870fb90f800d091124269c0f39ca0..2057245f012e32d25bd3005ec8f466430230d9bd 100644 --- a/src/link/Queue.zig +++ b/src/link/Queue.zig @@ -101,8 +101,6 @@ pub fn enqueueZcu( ) Io.Cancelable!void { const io = comp.io; - assert(tid == .main); - if (q.future != null) { if (q.zcu_queue.putOne(io, task)) |_| { return; diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 5095e2e8c51e2d0f3dbc5bb89ce5856a36eaf4b6..e6cdabd133e641406bfd0ef96328e9fe8e07469a 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -3,28 +3,43 @@ const Allocator = std.mem.Allocator; const Path = std.Build.Cache.Path; const assert = std.debug.assert; const log = std.log.scoped(.link); - +const zig_version = @import("builtin").zig_version; const Zcu = @import("../Zcu.zig"); const InternPool = @import("../InternPool.zig"); const Compilation = @import("../Compilation.zig"); const link = @import("../link.zig"); const Air = @import("../Air.zig"); const Type = @import("../Type.zig"); +const codegen = @import("../codegen.zig"); const CodeGen = @import("../codegen/spirv/CodeGen.zig"); -const Module = @import("../codegen/spirv/Module.zig"); -const trace = @import("../tracy.zig").trace; const BinaryModule = @import("SpirV/BinaryModule.zig"); const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig"); - +const dedup_types = @import("SpirV/dedup_types.zig"); +const prune_unused = @import("SpirV/prune_unused.zig"); const spec = @import("../codegen/spirv/spec.zig"); +const Section = @import("../codegen/spirv/Section.zig"); const Id = spec.Id; const Word = spec.Word; +const Mir = @import("../codegen/spirv/Mir.zig"); const Linker = @This(); base: link.File, -module: Module, -cg: CodeGen, +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, + +const EntryPointDecl = struct { + nav: InternPool.Nav.Index, + name: []const u8, + cc: std.builtin.CallingConvention, +}; + +const ExternalObject = struct { + instructions: []const Word, + id_bound: u32, +}; pub fn createEmpty( arena: Allocator, @@ -32,7 +47,6 @@ pub fn createEmpty( emit: Path, options: link.File.OpenOptions, ) !*Linker { - const gpa = comp.gpa; const io = comp.io; const target = &comp.root_mod.resolved_target.result; @@ -61,21 +75,6 @@ pub fn createEmpty( .file = null, .build_id = options.build_id, }, - .module = .{ - .gpa = gpa, - .arena = arena, - .zcu = comp.zcu.?, - }, - .cg = .{ - // These fields are populated in generate() - .pt = undefined, - .air = undefined, - .liveness = undefined, - .owner_nav = undefined, - .module = undefined, - .control_flow = .{ .structured = .{} }, - .base_line = undefined, - }, }; errdefer linker.deinit(); @@ -97,70 +96,124 @@ pub fn open( } pub fn deinit(linker: *Linker) void { - linker.cg.deinit(); - linker.module.deinit(); + const gpa = linker.base.comp.gpa; + for (linker.fragments.values()) |*mir| { + mir.deinit(gpa); + } + linker.fragments.deinit(gpa); + linker.pending_navs.deinit(gpa); + linker.entry_points.deinit(gpa); + for (linker.external_objects.items) |obj| { + gpa.free(obj.instructions); + } + linker.external_objects.deinit(gpa); } -fn generate( - linker: *Linker, - pt: Zcu.PerThread, - nav_index: InternPool.Nav.Index, - air: Air, - liveness: Air.Liveness, - do_codegen: bool, -) !void { - const zcu = pt.zcu; - const gpa = zcu.gpa; - const structured_cfg = zcu.navFileScope(nav_index).mod.?.structured_cfg; - - linker.cg.control_flow.deinit(gpa); - linker.cg.args.clearRetainingCapacity(); - linker.cg.inst_results.clearRetainingCapacity(); - linker.cg.id_scratch.clearRetainingCapacity(); - linker.cg.prologue.reset(); - linker.cg.body.reset(); - - linker.cg = .{ - .pt = pt, - .air = air, - .liveness = liveness, - .owner_nav = nav_index, - .module = &linker.module, - .control_flow = switch (structured_cfg) { - true => .{ .structured = .{} }, - false => .{ .unstructured = .{} }, +pub fn loadInput(linker: *Linker, input: link.Input) !void { + switch (input) { + .object => |obj| { + const comp = linker.base.comp; + const gpa = comp.gpa; + const io = comp.io; + const diags = &comp.link_diags; + + const stat = obj.file.stat(io) catch |err| + return diags.fail("failed to stat SPIR-V object '{f}': {t}", .{ obj.path, err }); + const file_size = std.math.cast(usize, stat.size) orelse + return diags.fail("SPIR-V object '{f}' is too large", .{obj.path}); + if (file_size < 5 * @sizeOf(Word)) + return diags.fail("SPIR-V object '{f}' is too small to contain a valid header", .{obj.path}); + if (file_size % @sizeOf(Word) != 0) + return diags.fail("SPIR-V object '{f}' size is not a multiple of the word size", .{obj.path}); + + const word_count = file_size / @sizeOf(Word); + const all_words = try gpa.alloc(Word, word_count); + defer gpa.free(all_words); + + const bytes = std.mem.sliceAsBytes(all_words); + const n_read = obj.file.readPositionalAll(io, bytes, 0) catch |err| + return diags.fail("failed to read SPIR-V object '{f}': {t}", .{ obj.path, err }); + if (n_read != bytes.len) + return diags.fail("SPIR-V object '{f}': incomplete read", .{obj.path}); + + const needs_swap = all_words[0] == @byteSwap(spec.magic_number); + if (needs_swap) { + for (all_words) |*w| w.* = @byteSwap(w.*); + } + + if (all_words[0] != spec.magic_number) + return diags.fail("SPIR-V object '{f}': invalid magic number", .{obj.path}); + + const id_bound = all_words[3]; + const instructions = try gpa.dupe(Word, all_words[5..]); + errdefer gpa.free(instructions); + + // OpCapability instructions appear at the top of the module + // so we can stop scanning as soon as we hit anything else. + var it: BinaryModule.Instruction.Iterator = .init(instructions, 0); + const has_linkage = while (it.next()) |inst| switch (inst.opcode) { + .OpCapability => { + const cap: spec.Capability = @enumFromInt(inst.operands[0]); + if (cap == .linkage) break true; + }, + else => break false, + } else false; + if (!has_linkage) { + return diags.fail("SPIR-V object '{f}' is missing the Linkage capability and cannot be linked", .{obj.path}); + } + + try linker.external_objects.append(gpa, .{ + .instructions = instructions, + .id_bound = id_bound, + }); + }, + else => { + const diags = &linker.base.comp.link_diags; + return diags.fail("unsupported link input for SPIR-V target", .{}); }, - .base_line = zcu.navSrcLine(nav_index), - - .args = linker.cg.args, - .inst_results = linker.cg.inst_results, - .id_scratch = linker.cg.id_scratch, - .prologue = linker.cg.prologue, - .body = linker.cg.body, - }; - - linker.cg.genNav(do_codegen) catch |err| switch (err) { - error.AlreadyReported => return, - else => |e| return e, - }; + } } pub fn updateFunc( linker: *Linker, pt: Zcu.PerThread, func_index: InternPool.Index, - air: *const Air, - liveness: *const ?Air.Liveness, + mir: *codegen.AnyMir, ) !void { + const gpa = linker.base.comp.gpa; const nav = pt.zcu.funcInfo(func_index).owner_nav; - // TODO: Separate types for generating decls and functions? - try linker.generate(pt, nav, air.*, liveness.*.?, true); + + if (linker.fragments.getPtr(nav)) |existing| { + existing.deinit(gpa); + } + + try linker.fragments.put(gpa, nav, mir.spirv); + mir.spirv = .{ + .extended_instruction_set = &.{}, + .globals = &.{}, + .functions = &.{}, + .annotations = &.{}, + .debug_names = &.{}, + .debug_strings = &.{}, + .execution_modes = &.{}, + .id_bound = 0, + .owner_nav = mir.spirv.owner_nav, + .kind = mir.spirv.kind, + .decl_result_id = .none, + .nav_refs = &.{}, + .uav_refs = &.{}, + .decl_deps = &.{}, + .internal_globals = &.{}, + .entry_points = &.{}, + }; } pub fn updateNav(linker: *Linker, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.Error!void { const ip = &pt.zcu.intern_pool; - log.debug("lowering nav {f}({d})", .{ ip.getNav(nav).fqn.fmt(ip), nav }); - try linker.generate(pt, nav, undefined, undefined, false); + log.debug("deferring nav {f}({d}) to flush", .{ ip.getNav(nav).fqn.fmt(ip), nav }); + + const gpa = linker.base.comp.gpa; + linker.pending_navs.append(gpa, nav) catch return error.OutOfMemory; } pub fn updateExports( @@ -171,6 +224,7 @@ pub fn updateExports( ) !void { const zcu = pt.zcu; const ip = &zcu.intern_pool; + const gpa = linker.base.comp.gpa; const nav_index = switch (exported) { .nav => |nav| nav, .uav => |uav| { @@ -179,40 +233,17 @@ pub fn updateExports( }, }; const nav_ty = ip.getNav(nav_index).resolved.?.type; - const target = zcu.getTarget(); if (ip.isFunctionType(nav_ty)) { - const spv_decl_index = try linker.module.resolveNav(ip, nav_index); const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu); - const exec_model: spec.ExecutionModel = switch (target.os.tag) { - .vulkan, .opengl => switch (cc) { - .spirv_vertex => .vertex, - .spirv_fragment => .fragment, - .spirv_kernel => .gl_compute, - // TODO: We should integrate with the Linkage capability and export this function - .spirv_device => return, - else => unreachable, - }, - .opencl => switch (cc) { - .spirv_kernel => .kernel, - // TODO: We should integrate with the Linkage capability and export this function - .spirv_device => return, - else => unreachable, - }, - else => unreachable, - }; - for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); - try linker.module.declareEntryPoint( - spv_decl_index, - exp.opts.name.toSlice(ip), - exec_model, - null, - ); + try linker.entry_points.append(gpa, .{ + .nav = nav_index, + .name = exp.opts.name.toSlice(ip), + .cc = cc, + }); } } - - // TODO: Export regular functions, variables, etc using Linkage attributes. } pub fn flush( @@ -221,14 +252,6 @@ pub fn flush( tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.Error!void { - // The goal is to never use this because it's only needed if we need to - // write to InternPool, but flush is too late to be writing to the - // InternPool. - _ = tid; - - const tracy = trace(@src()); - defer tracy.end(); - const sub_prog_node = prog_node.start("Flush Module", 0); defer sub_prog_node.end(); @@ -237,19 +260,519 @@ pub fn flush( const gpa = comp.gpa; const io = comp.io; - // We need to export the list of error names somewhere so that we can pretty-print them in the - // executor. This is not really an important thing though, so we can just dump it in any old - // nonsemantic instruction. For now, just put it in OpSourceExtension with a special name. - var error_info: std.Io.Writer.Allocating = .init(linker.module.gpa); + if (comp.zcu) |zcu| { + const active = zcu.activate(tid); + defer active.deactivate(); + const pt = active.pt; + for (linker.pending_navs.items) |nav| { + if (linker.fragments.contains(nav)) continue; + + const mir = CodeGen.generateNav(pt, nav) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AlreadyReported => continue, + error.Canceled => return error.Canceled, + }; + + linker.fragments.put(gpa, nav, mir) catch return error.OutOfMemory; + } + linker.pending_navs.clearRetainingCapacity(); + } + + const merged = mergeFragments(linker, gpa, arena) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + }; + + var binary = linkModule(arena, merged.words, merged.id_bound, sub_prog_node) catch |err| switch (err) { + error.OutOfMemory => |e| return e, + else => |other| { + return diags.fail("error while linking: {s}", .{@errorName(other)}); + }, + }; + defer binary.deinit(arena); + + const header = [_]Word{ + spec.magic_number, + merged.version.toWord(), + merged.generator_id, + binary.id_bound, + 0, + }; + + var file_writer = linker.base.file.?.writer(io, &.{}); + file_writer.interface.writeSliceEndian(Word, &header, .little) catch |err| switch (err) { + error.WriteFailed => return diags.fail("failed to write: {t}", .{file_writer.err.?}), + }; + file_writer.interface.writeSliceEndian(Word, binary.instructions, .little) catch |err| switch (err) { + error.WriteFailed => return diags.fail("failed to write: {t}", .{file_writer.err.?}), + }; + file_writer.end() catch |err| switch (err) { + error.WriteFailed => return diags.fail("failed to write: {t}", .{file_writer.err.?}), + else => |e| return diags.fail("failed to write: {t}", .{e}), + }; +} + +fn linkModule(arena: Allocator, words: []const Word, id_bound: u32, progress: std.Progress.Node) !BinaryModule { + var parser = try BinaryModule.Parser.init(arena); + defer parser.deinit(); + var binary = try parser.initFromWords(words, id_bound); + try prune_unused.run(&parser, &binary); + try dedup_types.run(&parser, &binary); + try lower_invocation_globals.run(&parser, &binary, progress); + return binary; +} + +fn mergeFragments(linker: *Linker, gpa: Allocator, arena: Allocator) error{OutOfMemory}!MergedModule { + const comp = linker.base.comp; + const target = &comp.root_mod.resolved_target.result; + const maybe_ip: ?*InternPool = if (comp.zcu) |zcu| &zcu.intern_pool else null; + const is_obj = comp.config.output_mode == .Obj; + + var next_id: Word = 1; + + var nav_final_ids: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Id) = .empty; + defer nav_final_ids.deinit(gpa); + + var uav_final_ids: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Id) = .empty; + defer uav_final_ids.deinit(gpa); + + var frag_infos: std.ArrayList(FragmentInfo) = .empty; + defer frag_infos.deinit(gpa); + try frag_infos.ensureTotalCapacity(gpa, @intCast(linker.fragments.count())); + + for (linker.fragments.keys(), linker.fragments.values()) |nav, *mir| { + const id_offset = next_id - 1; + frag_infos.appendAssumeCapacity(.{ .id_offset = id_offset }); + if (mir.decl_result_id != .none) { + try nav_final_ids.put(gpa, nav, @enumFromInt(@intFromEnum(mir.decl_result_id) + id_offset)); + } + next_id += mir.id_bound - 1; + } + + for (linker.fragments.values(), frag_infos.items) |*mir, frag_info| { + for (mir.nav_refs) |ref| { + if (!nav_final_ids.contains(ref.nav)) { + try nav_final_ids.put(gpa, ref.nav, @enumFromInt(@intFromEnum(ref.local_id) + frag_info.id_offset)); + } + } + for (mir.uav_refs) |ref| { + const key = .{ ref.val, ref.storage_class }; + if (!uav_final_ids.contains(key)) { + try uav_final_ids.put(gpa, key, @enumFromInt(@intFromEnum(ref.local_id) + frag_info.id_offset)); + } + } + } + + // Resolve Zig extern navs against external objects. + var ext_id_offsets: std.ArrayListUnmanaged(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; + defer resolved_ids.deinit(gpa); + + if (maybe_ip) |ip| { + var extern_name_map: std.StringArrayHashMapUnmanaged(InternPool.Nav.Index) = .empty; + defer extern_name_map.deinit(gpa); + + var nav_it = nav_final_ids.iterator(); + while (nav_it.next()) |entry| { + const nav = ip.getNav(entry.key_ptr.*); + if (!nav.resolved.?.is_extern_decl) continue; + const name = if (nav.getExtern(ip)) |e| e.name.toSlice(ip) else nav.fqn.toSlice(ip); + try extern_name_map.put(gpa, name, entry.key_ptr.*); + } + + for (linker.external_objects.items) |ext_obj| { + const id_offset = next_id - 1; + ext_id_offsets.appendAssumeCapacity(id_offset); + + var it: BinaryModule.Instruction.Iterator = .init(ext_obj.instructions, 0); + while (it.next()) |inst| { + const ld = LinkageDecoration.parse(inst) orelse continue; + if (ld.linkage_type != .@"export") continue; + const remapped_id: Id = @enumFromInt(@intFromEnum(ld.target_id) + id_offset); + + if (extern_name_map.get(ld.name)) |nav_index| { + log.debug("extern resolve: '{s}' -> ext_fn_id={d}", .{ ld.name, @intFromEnum(remapped_id) }); + nav_final_ids.getPtr(nav_index).?.* = remapped_id; + _ = extern_name_map.swapRemove(ld.name); + try resolved_ids.put(gpa, remapped_id, {}); + } + } + next_id += ext_obj.id_bound - 1; + } + + unresolved_extern_count = @intCast(extern_name_map.count()); + } else { + for (linker.external_objects.items) |ext_obj| { + ext_id_offsets.appendAssumeCapacity(next_id - 1); + next_id += ext_obj.id_bound - 1; + } + } + + var parser = BinaryModule.Parser.init(gpa) catch return error.OutOfMemory; + defer parser.deinit(); + var sections: Sections = .{}; + defer sections.deinit(gpa); + + try mergeZigFragments(linker, gpa, &parser, §ions, frag_infos.items, &nav_final_ids, &uav_final_ids, &resolved_ids, maybe_ip); + + var has_linkage = false; + try appendExternalObjects(linker, gpa, &parser, ext_id_offsets.items, §ions, &has_linkage, linker.fragments.count() == 0, is_obj, &resolved_ids); + + if (is_obj) { + for (linker.entry_points.items) |ep| { + if (ep.cc != .spirv_device) continue; + const final_id = nav_final_ids.get(ep.nav) orelse continue; + try sections.annotations.emit(gpa, .OpDecorate, .{ + .target = final_id, + .decoration = .{ .linkage_attributes = .{ .name = ep.name, .linkage_type = .@"export" } }, + }); + has_linkage = true; + } + if (unresolved_extern_count > 0) has_linkage = true; + } + + var capabilities_section = Section{}; + defer capabilities_section.deinit(gpa); + var extensions_section = Section{}; + defer extensions_section.deinit(gpa); + var memory_model_section = Section{}; + defer memory_model_section.deinit(gpa); + + try emitPreamble( + gpa, + target, + has_linkage, + &capabilities_section, + &extensions_section, + &memory_model_section, + ); + try emitEntryPoints( + linker, + gpa, + target, + §ions.entry_points, + §ions.execution_modes, + &nav_final_ids, + &uav_final_ids, + &frag_infos, + ); + + const zig_packed_version = (zig_version.major << 12) | (zig_version.minor << 7) | zig_version.patch; + if (maybe_ip) |ip| { + try emitSourceInfo(gpa, ip, zig_packed_version, §ions.debug_strings); + } + + const version: spec.Version = .{ + .major = 1, + .minor = blk: { + if (target.cpu.has(.spirv, .v1_6)) break :blk 6; + if (target.cpu.has(.spirv, .v1_5)) break :blk 5; + if (target.cpu.has(.spirv, .v1_4)) break :blk 4; + if (target.cpu.has(.spirv, .v1_3)) break :blk 3; + if (target.cpu.has(.spirv, .v1_2)) break :blk 2; + if (target.cpu.has(.spirv, .v1_1)) break :blk 1; + break :blk 0; + }, + }; + + const buffers = &[_][]const Word{ + capabilities_section.toWords(), + extensions_section.toWords(), + sections.ext_inst.toWords(), + memory_model_section.toWords(), + sections.entry_points.toWords(), + sections.execution_modes.toWords(), + sections.debug_strings.toWords(), + sections.debug_names.toWords(), + sections.annotations.toWords(), + sections.globals.toWords(), + sections.functions.toWords(), + }; + + var total_size: usize = 0; + for (buffers) |buffer| total_size += buffer.len; + const result = try arena.alloc(Word, total_size); + + var offset: usize = 0; + for (buffers) |buffer| { + @memcpy(result[offset..][0..buffer.len], buffer); + offset += buffer.len; + } + + return .{ + .words = result, + .id_bound = next_id, + .version = version, + .generator_id = (spec.zig_generator_id << 16) | zig_packed_version, + }; +} + +fn mergeZigFragments( + linker: *Linker, + gpa: Allocator, + parser: *BinaryModule.Parser, + sections: *Sections, + 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), + 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; + defer resolved_local_ids.deinit(gpa); + + for (mir.nav_refs) |ref| { + if (nav_final_ids.get(ref.nav)) |final_id| { + try id_remap.put(gpa, ref.local_id, final_id); + if (maybe_ip) |ip| { + const nav = ip.getNav(ref.nav); + if (nav.resolved.?.is_extern_decl and resolved_ids.contains(final_id)) { + try resolved_local_ids.put(gpa, ref.local_id, {}); + } + } + } + } + for (mir.uav_refs) |ref| { + if (uav_final_ids.get(.{ ref.val, ref.storage_class })) |final_id| { + try id_remap.put(gpa, ref.local_id, final_id); + } + } + + try remapAndAppend(gpa, §ions.ext_inst, mir.extended_instruction_set, frag_info.id_offset, &id_remap, parser); + try remapAndAppend(gpa, §ions.globals, mir.globals, frag_info.id_offset, &id_remap, parser); + + try remapFilteredInsts(gpa, §ions.functions, mir.functions, frag_info.id_offset, &id_remap, parser, &resolved_local_ids, .skip_functions); + try remapFilteredInsts(gpa, §ions.annotations, mir.annotations, frag_info.id_offset, &id_remap, parser, &resolved_local_ids, .skip_linkage); + try remapFilteredInsts(gpa, §ions.debug_names, mir.debug_names, frag_info.id_offset, &id_remap, parser, &resolved_local_ids, .skip_names); + try remapAndAppend(gpa, §ions.debug_strings, mir.debug_strings, frag_info.id_offset, &id_remap, parser); + try remapAndAppend(gpa, §ions.execution_modes, mir.execution_modes, frag_info.id_offset, &id_remap, parser); + + for (mir.entry_points) |ep| { + try linker.entry_points.append(gpa, .{ .nav = mir.owner_nav, .name = ep.name, .cc = ep.cc }); + } + } +} + +const FilterMode = enum { skip_functions, skip_linkage, skip_names }; + +fn remapFilteredInsts( + gpa: Allocator, + dest: *Section, + words: []const Word, + id_offset: Word, + id_remap: *const std.AutoHashMapUnmanaged(Id, Id), + parser: *BinaryModule.Parser, + skip_ids: *const std.AutoArrayHashMapUnmanaged(Id, void), + mode: FilterMode, +) error{OutOfMemory}!void { + if (words.len == 0) return; + var it: BinaryModule.Instruction.Iterator = .init(words, 0); + var skip_function = false; + while (it.next()) |inst| { + switch (mode) { + .skip_functions => { + if (inst.opcode == .OpFunction) { + skip_function = skip_ids.contains(@enumFromInt(inst.operands[1])); + } + if (skip_function) { + if (inst.opcode == .OpFunctionEnd) skip_function = false; + continue; + } + }, + .skip_linkage => { + if (LinkageDecoration.parse(inst)) |ld| { + if (skip_ids.contains(ld.target_id)) continue; + } + }, + .skip_names => { + if (inst.opcode == .OpName and inst.operands.len >= 1) { + if (skip_ids.contains(@enumFromInt(inst.operands[0]))) continue; + } + }, + } + try remapAndAppendInst(gpa, dest, words, inst, id_offset, id_remap, parser); + } +} + +fn emitPreamble( + gpa: Allocator, + target: *const std.Target, + has_linkage: bool, + capabilities: *Section, + extensions: *Section, + memory_model: *Section, +) !void { + var caps: std.EnumSet(spec.Capability) = .empty; + var exts: std.StringHashMapUnmanaged(void) = .empty; + defer exts.deinit(gpa); + + switch (target.os.tag) { + .opengl, .vulkan => caps.insert(.shader), + .opencl, .amdhsa => { + caps.insert(.kernel); + caps.insert(.addresses); + }, + else => unreachable, + } + if (target.os.tag == .vulkan and target.cpu.arch == .spirv64) { + caps.insert(.physical_storage_buffer_addresses); + try exts.put(gpa, "SPV_KHR_physical_storage_buffer", {}); + } + if (has_linkage) caps.insert(.linkage); + + inline for (@typeInfo(spec.Capability).@"enum".field_names) |cap_name| { + if (target.cpu.has(.spirv, @field(std.Target.spirv.Feature, cap_name))) + caps.insert(@field(spec.Capability, cap_name)); + } + inline for (@typeInfo(spec.Extension).@"enum".field_names) |ext_name| { + switch (@field(spec.Extension, ext_name)) { + .v1_0, .v1_1, .v1_2, .v1_3, .v1_4, .v1_5, .v1_6 => {}, + else => if (target.cpu.has(.spirv, @field(std.Target.spirv.Feature, ext_name))) + try exts.put(gpa, ext_name, {}), + } + } + + var cit = caps.iterator(); + while (cit.next()) |cap| try capabilities.emit(gpa, .OpCapability, .{ .capability = cap }); + var eit = exts.iterator(); + while (eit.next()) |e| try extensions.emit(gpa, .OpExtension, .{ .name = e.key_ptr.* }); + + const addressing_model: spec.AddressingModel = switch (target.os.tag) { + .opengl => .logical, + .vulkan => switch (target.cpu.arch) { + .spirv32 => .logical, + .spirv64 => .physical_storage_buffer64, + else => unreachable, + }, + .opencl => switch (target.cpu.arch) { + .spirv32 => .physical32, + .spirv64 => .physical64, + else => unreachable, + }, + .amdhsa => .physical64, + else => unreachable, + }; + try memory_model.emit(gpa, .OpMemoryModel, .{ + .addressing_model = addressing_model, + .memory_model = switch (target.os.tag) { + .opencl => .open_cl, + .vulkan, .opengl => .glsl450, + .amdhsa => unreachable, // TODO + else => unreachable, + }, + }); +} + +fn emitEntryPoints( + linker: *Linker, + gpa: Allocator, + target: *const std.Target, + entry_points_section: *Section, + execution_modes_section: *Section, + nav_final_ids: *const std.AutoHashMapUnmanaged(InternPool.Nav.Index, Id), + uav_final_ids: *const std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Id), + frag_infos: *const std.ArrayList(FragmentInfo), +) error{OutOfMemory}!void { + for (linker.entry_points.items) |ep| { + const final_id = nav_final_ids.get(ep.nav) orelse continue; + + var interface: std.ArrayList(Id) = .empty; + defer interface.deinit(gpa); + var visited: std.AutoHashMapUnmanaged(InternPool.Nav.Index, void) = .empty; + defer visited.deinit(gpa); + try collectEntryPointInterface(linker, ep.nav, &interface, &visited, nav_final_ids, uav_final_ids, frag_infos, gpa); + + const exec_model: spec.ExecutionModel = switch (target.os.tag) { + .vulkan, .opengl => switch (ep.cc) { + .spirv_vertex => .vertex, + .spirv_fragment => .fragment, + .spirv_kernel => .gl_compute, + .spirv_task => .task_ext, + .spirv_mesh => .mesh_ext, + .spirv_device => continue, + else => unreachable, + }, + .opencl => switch (ep.cc) { + .spirv_kernel => .kernel, + .spirv_device => continue, + else => unreachable, + }, + else => unreachable, + }; + + try entry_points_section.emit(gpa, .OpEntryPoint, .{ + .execution_model = exec_model, + .entry_point = final_id, + .name = ep.name, + .interface = interface.items, + }); + + switch (ep.cc) { + .spirv_kernel, .spirv_task => |kernel| { + try execution_modes_section.emit(gpa, .OpExecutionMode, .{ + .entry_point = final_id, + .mode = .{ .local_size = .{ .x_size = kernel.x, .y_size = kernel.y, .z_size = kernel.z } }, + }); + }, + .spirv_fragment => |fragment| { + try execution_modes_section.emit(gpa, .OpExecutionMode, .{ + .entry_point = final_id, + .mode = if (target.os.tag == .vulkan) .origin_upper_left else .origin_lower_left, + }); + if (fragment.pixel_centered_integer) { + try execution_modes_section.emit(gpa, .OpExecutionMode, .{ + .entry_point = final_id, + .mode = .pixel_center_integer, + }); + } + const exec_mode: ?spec.ExecutionMode.Extended = switch (fragment.depth_assumption) { + .none => null, + .greater => .depth_greater, + .less => .depth_less, + .unchanged => .depth_unchanged, + }; + if (exec_mode) |mode| { + try execution_modes_section.emit(gpa, .OpExecutionMode, .{ + .entry_point = final_id, + .mode = mode, + }); + } + }, + .spirv_mesh => |mesh| { + try execution_modes_section.emit(gpa, .OpExecutionMode, .{ + .entry_point = final_id, + .mode = .{ .output_vertices = .{ .vertex_count = mesh.max_vertices } }, + }); + try execution_modes_section.emit(gpa, .OpExecutionMode, .{ + .entry_point = final_id, + .mode = .{ .output_primitives_ext = .{ .primitive_count = mesh.max_primitives } }, + }); + try execution_modes_section.emit(gpa, .OpExecutionMode, .{ + .entry_point = final_id, + .mode = switch (mesh.stage_output) { + .output_points => .output_points, + .output_lines => .output_lines_ext, + .output_triangles => .output_triangles_ext, + }, + }); + }, + else => {}, + } + } +} + +fn emitSourceInfo(gpa: Allocator, ip: *InternPool, version: u32, debug_strings: *Section) error{OutOfMemory}!void { + var error_info: std.Io.Writer.Allocating = .init(gpa); defer error_info.deinit(); - error_info.writer.writeAll("zig_errors:") catch return error.OutOfMemory; - const ip = &linker.base.comp.zcu.?.intern_pool; for (ip.global_error_set.getNamesFromMainThread()) |name| { - // Errors can contain pretty much any character - to encode them in a string we must escape - // them somehow. Easiest here is to use some established scheme, one which also preseves the - // name if it contains no strange characters is nice for debugging. URI encoding fits the bill. - // We're using : as separator, which is a reserved character. error_info.writer.writeByte(':') catch return error.OutOfMemory; std.Uri.Component.percentEncode( &error_info.writer, @@ -264,27 +787,423 @@ pub fn flush( }.isValidChar, ) catch return error.OutOfMemory; } - try linker.module.sections.debug_strings.emit(gpa, .OpSourceExtension, .{ - .extension = error_info.written(), - }); + try debug_strings.emit(gpa, .OpSourceExtension, .{ .extension = error_info.written() }); + try debug_strings.emit(gpa, .OpSource, .{ .source_language = .zig, .version = version, .file = null, .source = null }); +} - const module = try linker.module.finalize(arena); - errdefer arena.free(module); +const MergedModule = struct { + words: []const Word, + id_bound: Word, + version: spec.Version, + generator_id: u32, +}; - const linked_module = linkModule(arena, module, sub_prog_node) catch |err| switch (err) { - error.OutOfMemory => |e| return e, - else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}), +const FragmentInfo = struct { + id_offset: Word, +}; + +const LinkageDecoration = struct { + target_id: Id, + name: []const u8, + linkage_type: spec.LinkageType, + + fn parse(inst: BinaryModule.Instruction) ?LinkageDecoration { + if (inst.opcode != .OpDecorate) return null; + if (inst.operands.len < 3) return null; + if (inst.operands[1] != @intFromEnum(spec.Decoration.linkage_attributes)) return null; + return .{ + .target_id = @enumFromInt(inst.operands[0]), + .name = std.mem.sliceTo(std.mem.sliceAsBytes(inst.operands[2 .. inst.operands.len - 1]), 0), + .linkage_type = @enumFromInt(inst.operands[inst.operands.len - 1]), + }; + } +}; + +const Sections = struct { + ext_inst: Section = .{}, + globals: Section = .{}, + functions: Section = .{}, + annotations: Section = .{}, + debug_names: Section = .{}, + debug_strings: Section = .{}, + entry_points: Section = .{}, + execution_modes: Section = .{}, + + fn deinit(self: *Sections, gpa: Allocator) void { + self.ext_inst.deinit(gpa); + self.globals.deinit(gpa); + self.functions.deinit(gpa); + self.annotations.deinit(gpa); + self.debug_names.deinit(gpa); + self.debug_strings.deinit(gpa); + self.entry_points.deinit(gpa); + self.execution_modes.deinit(gpa); + } + + const SectionClass = enum { ext_inst, debug_name, debug_string, annotation, global }; + + fn classifyPreambleInst(opcode: spec.Opcode) SectionClass { + return switch (opcode) { + .OpExtInstImport => .ext_inst, + .OpName, .OpMemberName => .debug_name, + .OpString => .debug_string, + .OpDecorate, + .OpMemberDecorate, + .OpGroupDecorate, + .OpGroupMemberDecorate, + .OpDecorationGroup, + .OpDecorateId, + .OpDecorateString, + .OpMemberDecorateString, + => .annotation, + else => .global, + }; + } + + fn getSection(self: *Sections, class: SectionClass) *Section { + return switch (class) { + .ext_inst => &self.ext_inst, + .debug_name => &self.debug_names, + .debug_string => &self.debug_strings, + .annotation => &self.annotations, + .global => &self.globals, + }; + } +}; + +fn appendExternalObjects( + linker: *Linker, + gpa: Allocator, + parser: *BinaryModule.Parser, + ext_id_offsets: []const Word, + sections: *Sections, + has_linkage: *bool, + keep_entry_points: bool, + is_obj: bool, + resolved_ids: *const std.AutoArrayHashMapUnmanaged(Id, void), +) error{OutOfMemory}!void { + var export_map: std.StringArrayHashMapUnmanaged(Id) = .empty; + defer export_map.deinit(gpa); + + for (linker.external_objects.items, ext_id_offsets) |ext_obj, id_offset| { + var it: BinaryModule.Instruction.Iterator = .init(ext_obj.instructions, 0); + while (it.next()) |inst| { + const ld = LinkageDecoration.parse(inst) orelse continue; + if (ld.linkage_type != .@"export") continue; + try export_map.put(gpa, ld.name, @enumFromInt(@intFromEnum(ld.target_id) + id_offset)); + } + } + + var per_obj_remaps = try gpa.alloc(std.AutoHashMapUnmanaged(Id, Id), linker.external_objects.items.len); + defer { + for (per_obj_remaps) |*m| m.deinit(gpa); + gpa.free(per_obj_remaps); + } + for (per_obj_remaps) |*m| m.* = .empty; + + var resolved_linkage_ids: std.AutoArrayHashMapUnmanaged(Id, void) = .empty; + defer resolved_linkage_ids.deinit(gpa); + + for (resolved_ids.keys()) |id| { + try resolved_linkage_ids.put(gpa, id, {}); + } + + for (linker.external_objects.items, ext_id_offsets, 0..) |ext_obj, id_offset, obj_idx| { + var it: BinaryModule.Instruction.Iterator = .init(ext_obj.instructions, 0); + while (it.next()) |inst| { + const ld = LinkageDecoration.parse(inst) orelse continue; + if (ld.linkage_type != .import) continue; + const remapped_import: Id = @enumFromInt(@intFromEnum(ld.target_id) + id_offset); + + if (export_map.get(ld.name)) |export_id| { + try per_obj_remaps[obj_idx].put(gpa, ld.target_id, export_id); + try resolved_linkage_ids.put(gpa, remapped_import, {}); + try resolved_linkage_ids.put(gpa, export_id, {}); + log.debug("cross-object resolve: '{s}' import={d} -> export={d}", .{ + ld.name, @intFromEnum(remapped_import), @intFromEnum(export_id), + }); + } else { + has_linkage.* = true; + } + } + } + + for (linker.external_objects.items, ext_id_offsets, 0..) |ext_obj, id_offset, obj_idx| { + var binary = parser.initFromWords(ext_obj.instructions, ext_obj.id_bound) catch + return error.OutOfMemory; + defer binary.deinit(gpa); + + const id_remap = &per_obj_remaps[obj_idx]; + + var preamble_it: BinaryModule.Instruction.Iterator = .init(ext_obj.instructions, 0); + while (preamble_it.next()) |inst| { + if (inst.offset >= binary.functions_start) break; + + switch (inst.opcode) { + .OpCapability, + .OpExtension, + .OpMemoryModel, + .OpSource, + .OpSourceExtension, + .OpSourceContinued, + => continue, + .OpEntryPoint => { + if (keep_entry_points) + try remapAndAppendInst(gpa, §ions.entry_points, ext_obj.instructions, inst, id_offset, id_remap, parser); + continue; + }, + .OpExecutionMode, .OpExecutionModeId => { + if (keep_entry_points) + try remapAndAppendInst(gpa, §ions.execution_modes, ext_obj.instructions, inst, id_offset, id_remap, parser); + continue; + }, + else => {}, + } + + if (LinkageDecoration.parse(inst)) |ld| { + const remapped: Id = @enumFromInt(@intFromEnum(ld.target_id) + id_offset); + if (resolved_linkage_ids.contains(remapped)) { + if (ld.linkage_type == .@"export" and is_obj) { + has_linkage.* = true; + } else { + continue; + } + } + } + + if (inst.opcode == .OpName and inst.operands.len >= 1) { + if (id_remap.contains(@enumFromInt(inst.operands[0]))) continue; + } + + const dest = sections.getSection(Sections.classifyPreambleInst(inst.opcode)); + try remapAndAppendInst(gpa, dest, ext_obj.instructions, inst, id_offset, id_remap, parser); + } + + var fn_it: BinaryModule.Instruction.Iterator = .init(ext_obj.instructions, binary.functions_start); + var skip_function = false; + while (fn_it.next()) |inst| { + if (inst.opcode == .OpFunction) { + skip_function = id_remap.contains(@enumFromInt(inst.operands[1])); + } + if (!skip_function) { + try remapAndAppendInst(gpa, §ions.functions, ext_obj.instructions, inst, id_offset, id_remap, parser); + } + if (inst.opcode == .OpFunctionEnd) { + skip_function = false; + } + } + } +} + +fn collectEntryPointInterface( + linker: *Linker, + nav: InternPool.Nav.Index, + interface: *std.ArrayList(Id), + visited: *std.AutoHashMapUnmanaged(InternPool.Nav.Index, void), + nav_final_ids: *const std.AutoHashMapUnmanaged(InternPool.Nav.Index, Id), + uav_final_ids: *const std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Id), + frag_infos: *const std.ArrayList(FragmentInfo), + gpa: Allocator, +) error{OutOfMemory}!void { + const visited_gop = try visited.getOrPut(gpa, nav); + if (visited_gop.found_existing) return; + + const frag_index = linker.fragments.getIndex(nav) orelse return; + const mir = &linker.fragments.values()[frag_index]; + const id_offset = frag_infos.items[frag_index].id_offset; + + if (mir.kind == .global) { + if (nav_final_ids.get(nav)) |final_id| { + try interface.append(gpa, final_id); + } + } + + for (mir.uav_refs) |ref| { + if (ref.kind == .global) { + if (uav_final_ids.get(.{ ref.val, ref.storage_class })) |final_id| { + try interface.append(gpa, final_id); + } + } + } + + for (mir.internal_globals) |local_id| { + const global_id: Id = @enumFromInt(@intFromEnum(local_id) + id_offset); + try interface.append(gpa, global_id); + } + + for (mir.decl_deps) |dep| { + try collectEntryPointInterface(linker, dep.nav, interface, visited, nav_final_ids, uav_final_ids, frag_infos, gpa); + } +} + +fn remapAndAppend( + gpa: Allocator, + dest: *Section, + words: []const Word, + id_offset: Word, + id_remap: *const std.AutoHashMapUnmanaged(Id, Id), + parser: *BinaryModule.Parser, +) error{OutOfMemory}!void { + if (words.len == 0) return; + + try dest.instructions.ensureUnusedCapacity(gpa, words.len); + + var it: BinaryModule.Instruction.Iterator = .init(words, 0); + while (it.next()) |inst| { + try remapAndAppendInst(gpa, dest, words, inst, id_offset, id_remap, parser); + } +} + +fn remapAndAppendInst( + gpa: Allocator, + dest: *Section, + words: []const Word, + inst: BinaryModule.Instruction, + id_offset: Word, + id_remap: *const std.AutoHashMapUnmanaged(Id, Id), + parser: *BinaryModule.Parser, +) error{OutOfMemory}!void { + const inst_words = words[inst.offset..][0..((words[inst.offset] >> 16))]; + try dest.instructions.ensureUnusedCapacity(gpa, inst_words.len); + const dest_start = dest.instructions.items.len; + dest.instructions.appendSliceAssumeCapacity(inst_words); + const inst_slice = dest.instructions.items[dest_start..][0..inst_words.len]; + + const inst_spec = parser.getInstSpec(inst.opcode) orelse return; + var offset: usize = 0; + for (inst_spec.operands) |operand| { + const cat = operand.kind.category(); + switch (operand.quantifier) { + .required, .optional => { + if (offset >= inst.operands.len) break; + offset += remapOperand(operand.kind, cat, inst, inst_slice, offset, id_offset, id_remap); + }, + .variadic => { + while (offset < inst.operands.len) { + offset += remapOperand(operand.kind, cat, inst, inst_slice, offset, id_offset, id_remap); + } + }, + } + } +} + +fn remapOperand( + kind: spec.OperandKind, + cat: spec.OperandCategory, + inst: BinaryModule.Instruction, + inst_slice: []Word, + offset: usize, + id_offset: Word, + id_remap: *const std.AutoHashMapUnmanaged(Id, Id), +) usize { + switch (cat) { + .id => { + remapSingleId(&inst_slice[1 + offset], id_offset, id_remap); + return 1; + }, + .literal => return operandLiteralWordCount(kind, inst, offset), + .composite => { + remapCompositeOperand(kind, inst_slice, offset, id_offset, id_remap); + return 2; + }, + .bit_enum => { + const mask = inst_slice[1 + offset]; + var consumed: usize = 1; + for (kind.enumerants()) |e| { + if ((mask & e.value) == 0) continue; + for (e.parameters) |param_kind| { + if (offset + consumed >= inst.operands.len) return consumed; + consumed += remapOperand( + param_kind, + param_kind.category(), + inst, + inst_slice, + offset + consumed, + id_offset, + id_remap, + ); + } + } + return consumed; + }, + .value_enum => { + const value = inst_slice[1 + offset]; + var consumed: usize = 1; + for (kind.enumerants()) |e| { + if (e.value != value) continue; + for (e.parameters) |param_kind| { + if (offset + consumed >= inst.operands.len) return consumed; + consumed += remapOperand( + param_kind, + param_kind.category(), + inst, + inst_slice, + offset + consumed, + id_offset, + id_remap, + ); + } + break; + } + return consumed; + }, + } +} + +fn remapCompositeOperand( + kind: spec.OperandKind, + inst_slice: []Word, + offset: usize, + id_offset: Word, + id_remap: *const std.AutoHashMapUnmanaged(Id, Id), +) void { + switch (kind) { + .pair_literal_integer_id_ref => { + remapSingleId(&inst_slice[1 + offset + 1], id_offset, id_remap); + }, + .pair_id_ref_literal_integer => { + remapSingleId(&inst_slice[1 + offset], id_offset, id_remap); + }, + .pair_id_ref_id_ref => { + remapSingleId(&inst_slice[1 + offset], id_offset, id_remap); + remapSingleId(&inst_slice[1 + offset + 1], id_offset, id_remap); + }, + else => {}, + } +} + +fn operandLiteralWordCount(kind: spec.OperandKind, inst: BinaryModule.Instruction, offset: usize) usize { + return switch (kind) { + .literal_integer, .literal_float => 1, + .literal_string => blk: { + var count: usize = 0; + var off = offset; + while (off < inst.operands.len) { + const word = inst.operands[off]; + count += 1; + off += 1; + if (word & 0xFF000000 == 0 or + word & 0x00FF0000 == 0 or + word & 0x0000FF00 == 0 or + word & 0x000000FF == 0) + { + break; + } + } + break :blk count; + }, + .literal_context_dependent_number => inst.operands.len - offset, + .literal_ext_inst_integer => 1, + else => 1, }; - - // TODO endianness bug. use file writer and call writeSliceEndian instead - linker.base.file.?.writeStreamingAll(io, @ptrCast(linked_module)) catch |err| - return diags.fail("failed to write: {t}", .{err}); } -fn linkModule(arena: Allocator, module: []Word, progress: std.Progress.Node) ![]Word { - var parser = try BinaryModule.Parser.init(arena); - defer parser.deinit(); - var binary = try parser.parse(module); - try lower_invocation_globals.run(&parser, &binary, progress); - return binary.finalize(arena); +fn remapSingleId(word: *Word, id_offset: Word, id_remap: *const std.AutoHashMapUnmanaged(Id, Id)) void { + const id: Id = @enumFromInt(word.*); + if (id == .none) return; + if (id_remap.get(id)) |final_id| { + word.* = @intFromEnum(final_id); + } else { + word.* = @intFromEnum(id) + id_offset; + } } diff --git a/src/link/SpirV/BinaryModule.zig b/src/link/SpirV/BinaryModule.zig index e639994f33b7df39e90814768983803cbb898d17..55604fc194d6e70df9fbd54eb417b6e55426eea5 100644 --- a/src/link/SpirV/BinaryModule.zig +++ b/src/link/SpirV/BinaryModule.zig @@ -11,278 +11,161 @@ const ResultId = spec.Id; const BinaryModule = @This(); -pub const header_words = 5; - -/// The module SPIR-V version. -version: spec.Version, - -/// The generator magic number. -generator_magic: u32, - /// The result-id bound of this SPIR-V module. id_bound: u32, -/// The instructions of this module. This does not contain the header. +/// The instructions of this module (no header). instructions: []const Word, /// Maps OpExtInstImport result-ids to their InstructionSet. ext_inst_map: std.AutoHashMapUnmanaged(ResultId, InstructionSet), -/// This map contains the width of arithmetic types (OpTypeInt and -/// OpTypeFloat). We need this information to correctly parse the operands -/// of Op(Spec)Constant and OpSwitch. +/// Width of arithmetic types (OpTypeInt/OpTypeFloat). Needed to correctly +/// parse operands of Op(Spec)Constant and OpSwitch. arith_type_width: std.AutoHashMapUnmanaged(ResultId, u16), -/// The starting offsets of some sections -sections: struct { - functions: usize, -}, +functions_start: usize, -pub fn deinit(self: *BinaryModule, a: Allocator) void { - self.ext_inst_map.deinit(a); - self.arith_type_width.deinit(a); - self.* = undefined; +pub fn deinit(bm: *BinaryModule, gpa: Allocator) void { + bm.ext_inst_map.deinit(gpa); + bm.arith_type_width.deinit(gpa); + bm.* = undefined; } -pub fn iterateInstructions(self: BinaryModule) Instruction.Iterator { - return Instruction.Iterator.init(self.instructions, 0); +pub fn iterateInstructions(bm: BinaryModule) Instruction.Iterator { + return Instruction.Iterator.init(bm.instructions, 0); } -pub fn iterateInstructionsFrom(self: BinaryModule, offset: usize) Instruction.Iterator { - return Instruction.Iterator.init(self.instructions, offset); +pub fn iterateInstructionsFrom(bm: BinaryModule, offset: usize) Instruction.Iterator { + return Instruction.Iterator.init(bm.instructions, offset); } -pub fn instructionAt(self: BinaryModule, offset: usize) Instruction { - var it = self.iterateInstructionsFrom(offset); - return it.next().?; -} - -pub fn finalize(self: BinaryModule, a: Allocator) ![]Word { - const result = try a.alloc(Word, 5 + self.instructions.len); - errdefer a.free(result); - - result[0] = spec.magic_number; - result[1] = @bitCast(self.version); - result[2] = @bitCast(self.generator_magic); - result[3] = self.id_bound; - result[4] = 0; // Schema - - @memcpy(result[5..], self.instructions); - return result; -} - -/// Errors that can be raised when the module is not correct. -/// Note that the parser doesn't validate SPIR-V modules by a -/// long shot. It only yields errors that critically prevent -/// further analysis of the module. -pub const ParseError = error{ - /// Raised when the module doesn't start with the SPIR-V magic. - /// This usually means that the module isn't actually SPIR-V. - InvalidMagic, - /// Raised when the module has an invalid "physical" format: - /// For example when the header is incomplete, or an instruction - /// has an illegal format. - InvalidPhysicalFormat, - /// OpExtInstImport was used with an unknown extension string. - InvalidExtInstImport, - /// The module had an instruction with an invalid (unknown) opcode. - InvalidOpcode, - /// An instruction's operands did not conform to the SPIR-V specification - /// for that instruction. - InvalidOperands, - /// A result-id was declared more than once. - DuplicateId, - /// Some ID did not resolve. - InvalidId, - /// This opcode or instruction is not supported yet. - UnsupportedOperation, - /// Parser ran out of memory. - OutOfMemory, -}; - pub const Instruction = struct { pub const Iterator = struct { words: []const Word, - index: usize = 0, offset: usize = 0, pub fn init(words: []const Word, start_offset: usize) Iterator { return .{ .words = words, .offset = start_offset }; } - pub fn next(self: *Iterator) ?Instruction { - if (self.offset >= self.words.len) return null; + pub fn next(it: *Iterator) ?Instruction { + if (it.offset >= it.words.len) return null; - const instruction_len = self.words[self.offset] >> 16; - defer self.offset += instruction_len; - defer self.index += 1; + const instruction_len = it.words[it.offset] >> 16; + defer it.offset += instruction_len; assert(instruction_len != 0); - assert(self.offset < self.words.len); + assert(it.offset < it.words.len); return Instruction{ - .opcode = @enumFromInt(self.words[self.offset] & 0xFFFF), - .index = self.index, - .offset = self.offset, - .operands = self.words[self.offset..][1..instruction_len], + .opcode = @enumFromInt(it.words[it.offset] & 0xFFFF), + .offset = it.offset, + .operands = it.words[it.offset..][1..instruction_len], }; } }; - /// The opcode for this instruction. opcode: Opcode, - /// The instruction's index. - index: usize, - /// The instruction's word offset in the module. offset: usize, - /// The raw (unparsed) operands for this instruction. operands: []const Word, }; -/// This parser contains information (acceleration tables) -/// that can be persisted across different modules. This is -/// used to initialize the module, and is also used when -/// further analyzing it. pub const Parser = struct { - /// The allocator used to allocate this parser's structures, - /// and also the structures of any parsed module. - a: Allocator, - - /// Maps (instruction set, opcode) => instruction index (for instruction set) + gpa: Allocator, opcode_table: std.AutoHashMapUnmanaged(u32, u16) = .empty, - pub fn init(a: Allocator) !Parser { - var self = Parser{ - .a = a, - }; - errdefer self.deinit(); + pub fn init(gpa: Allocator) !Parser { + var parser = Parser{ .gpa = gpa }; + errdefer parser.deinit(); inline for (std.meta.tags(InstructionSet)) |set| { const instructions = set.instructions(); - try self.opcode_table.ensureUnusedCapacity(a, @intCast(instructions.len)); + try parser.opcode_table.ensureUnusedCapacity(gpa, @intCast(instructions.len)); for (instructions, 0..) |inst, i| { - // Note: Some instructions may alias another. In this case we don't really care - // which one is first: they all (should) have the same operands anyway. Just pick - // the first, which is usually the core, KHR or EXT variant. - const entry = self.opcode_table.getOrPutAssumeCapacity(mapSetAndOpcode(set, @intCast(inst.opcode))); + const entry = parser.opcode_table.getOrPutAssumeCapacity(mapSetAndOpcode(set, @intCast(inst.opcode))); if (!entry.found_existing) { entry.value_ptr.* = @intCast(i); } } } - return self; + return parser; } - pub fn deinit(self: *Parser) void { - self.opcode_table.deinit(self.a); + pub fn deinit(parser: *Parser) void { + parser.opcode_table.deinit(parser.gpa); } fn mapSetAndOpcode(set: InstructionSet, opcode: u16) u32 { return (@as(u32, @intFromEnum(set)) << 16) | opcode; } - pub fn getInstSpec(self: Parser, opcode: Opcode) ?spec.Instruction { - const index = self.opcode_table.get(mapSetAndOpcode(.core, @intFromEnum(opcode))) orelse return null; + pub fn getInstSpec(parser: Parser, opcode: Opcode) ?spec.Instruction { + const index = parser.opcode_table.get(mapSetAndOpcode(.core, @intFromEnum(opcode))) orelse return null; return InstructionSet.core.instructions()[index]; } - pub fn parse(self: *Parser, module: []const u32) ParseError!BinaryModule { - if (module[0] != spec.magic_number) { - return error.InvalidMagic; - } else if (module.len < header_words) { - log.err("module only has {}/{} header words", .{ module.len, header_words }); - return error.InvalidPhysicalFormat; - } - + /// Build a BinaryModule from raw instruction words (no header). + /// Scans for ext_inst_map, arith_type_width, and the functions section offset. + pub fn initFromWords(parser: *Parser, words: []const Word, id_bound: u32) !BinaryModule { var binary = BinaryModule{ - .version = @bitCast(module[1]), - .generator_magic = @bitCast(module[2]), - .id_bound = module[3], - .instructions = module[header_words..], + .id_bound = id_bound, + .instructions = words, .ext_inst_map = .{}, .arith_type_width = .{}, - .sections = undefined, + .functions_start = undefined, }; var maybe_function_section: ?usize = null; + var it = binary.iterateInstructions(); + while (it.next()) |inst| { + const inst_spec = parser.getInstSpec(inst.opcode) orelse continue; + const operands = inst.operands; - // First pass through the module to verify basic structure and - // to gather some initial stuff for more detailed analysis. - // We want to check some stuff that Instruction.Iterator is no good for, - // so just iterate manually. - var offset: usize = 0; - while (offset < binary.instructions.len) { - const len = binary.instructions[offset] >> 16; - if (len == 0 or len + offset > binary.instructions.len) { - log.err("invalid instruction format: len={}, end={}, module len={}", .{ len, len + offset, binary.instructions.len }); - return error.InvalidPhysicalFormat; - } - defer offset += len; - - // We can't really efficiently use non-exhaustive enums here, because we would - // need to manually write out all valid cases. Since we have this map anyway, just - // use that. - const opcode: Opcode = @enumFromInt(@as(u16, @truncate(binary.instructions[offset]))); - const inst_spec = self.getInstSpec(opcode) orelse { - log.err("invalid opcode for core set: {}", .{@intFromEnum(opcode)}); - return error.InvalidOpcode; - }; - - const operands = binary.instructions[offset..][1..len]; - switch (opcode) { + switch (inst.opcode) { .OpExtInstImport => { const set_name = std.mem.sliceTo(std.mem.sliceAsBytes(operands[1..]), 0); - const set = std.meta.stringToEnum(InstructionSet, set_name) orelse { - log.err("invalid instruction set '{s}'", .{set_name}); - return error.InvalidExtInstImport; - }; - if (set == .core) return error.InvalidExtInstImport; - try binary.ext_inst_map.put(self.a, @enumFromInt(operands[0]), set); + const set = std.meta.stringToEnum(InstructionSet, set_name) orelse continue; + if (set == .core) continue; + try binary.ext_inst_map.put(parser.gpa, @enumFromInt(operands[0]), set); }, .OpTypeInt, .OpTypeFloat => { - const entry = try binary.arith_type_width.getOrPut(self.a, @enumFromInt(operands[0])); - if (entry.found_existing) return error.DuplicateId; - entry.value_ptr.* = std.math.cast(u16, operands[1]) orelse return error.InvalidOperands; + try binary.arith_type_width.put(parser.gpa, @enumFromInt(operands[0]), @intCast(operands[1])); }, .OpFunction => if (maybe_function_section == null) { - maybe_function_section = offset; + maybe_function_section = inst.offset; }, else => {}, } - // OpSwitch takes a value as argument, not an OpType... hence we need to populate arith_type_width - // with ALL operations that return an int or float. + // propagate arith type widths through instructions that return int/float const spec_operands = inst_spec.operands; if (spec_operands.len >= 2 and spec_operands[0].kind == .id_result_type and spec_operands[1].kind == .id_result) { - if (operands.len < 2) return error.InvalidOperands; - if (binary.arith_type_width.get(@enumFromInt(operands[0]))) |width| { - const entry = try binary.arith_type_width.getOrPut(self.a, @enumFromInt(operands[1])); - if (entry.found_existing) return error.DuplicateId; - entry.value_ptr.* = width; + if (operands.len >= 2) { + if (binary.arith_type_width.get(@enumFromInt(operands[0]))) |width| { + try binary.arith_type_width.put(parser.gpa, @enumFromInt(operands[1]), width); + } } } } - binary.sections = .{ - .functions = maybe_function_section orelse binary.instructions.len, - }; + binary.functions_start = maybe_function_section orelse binary.instructions.len; return binary; } /// Parse offsets in the instruction that contain result-ids. /// Returned offsets are relative to inst.operands. - /// Returns in an arraylist to armortize allocations. pub fn parseInstructionResultIds( - self: *Parser, + parser: *Parser, binary: BinaryModule, inst: Instruction, - offsets: *std.array_list.Managed(u16), + offsets: *std.ArrayList(u16), ) !void { - const index = self.opcode_table.get(mapSetAndOpcode(.core, @intFromEnum(inst.opcode))).?; + const index = parser.opcode_table.get(mapSetAndOpcode(.core, @intFromEnum(inst.opcode))).?; const operands = InstructionSet.core.instructions()[index].operands; var offset: usize = 0; @@ -290,37 +173,37 @@ pub const Parser = struct { .OpSpecConstantOp => { assert(operands[0].kind == .id_result_type); assert(operands[1].kind == .id_result); - offset = try self.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets); + offset = try parser.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets); if (offset >= inst.operands.len) return error.InvalidPhysicalFormat; const spec_opcode = std.math.cast(u16, inst.operands[offset]) orelse return error.InvalidPhysicalFormat; - const spec_index = self.opcode_table.get(mapSetAndOpcode(.core, spec_opcode)) orelse + const spec_index = parser.opcode_table.get(mapSetAndOpcode(.core, spec_opcode)) orelse return error.InvalidPhysicalFormat; const spec_operands = InstructionSet.core.instructions()[spec_index].operands; assert(spec_operands[0].kind == .id_result_type); assert(spec_operands[1].kind == .id_result); - offset = try self.parseOperandsResultIds(binary, inst, spec_operands[2..], offset + 1, offsets); + offset = try parser.parseOperandsResultIds(binary, inst, spec_operands[2..], offset + 1, offsets); }, .OpExtInst => { assert(operands[0].kind == .id_result_type); assert(operands[1].kind == .id_result); - offset = try self.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets); + offset = try parser.parseOperandsResultIds(binary, inst, operands[0..2], offset, offsets); if (offset + 1 >= inst.operands.len) return error.InvalidPhysicalFormat; const set_id: ResultId = @enumFromInt(inst.operands[offset]); - try offsets.append(@intCast(offset)); + try offsets.append(parser.gpa, @intCast(offset)); const set = binary.ext_inst_map.get(set_id) orelse { log.err("invalid instruction set {}", .{@intFromEnum(set_id)}); return error.InvalidId; }; const ext_opcode = std.math.cast(u16, inst.operands[offset + 1]) orelse return error.InvalidPhysicalFormat; - const ext_index = self.opcode_table.get(mapSetAndOpcode(set, ext_opcode)) orelse + const ext_index = parser.opcode_table.get(mapSetAndOpcode(set, ext_opcode)) orelse return error.InvalidPhysicalFormat; const ext_operands = set.instructions()[ext_index].operands; - offset = try self.parseOperandsResultIds(binary, inst, ext_operands, offset + 2, offsets); + offset = try parser.parseOperandsResultIds(binary, inst, ext_operands, offset + 2, offsets); }, else => { - offset = try self.parseOperandsResultIds(binary, inst, operands, offset, offsets); + offset = try parser.parseOperandsResultIds(binary, inst, operands, offset, offsets); }, } @@ -328,50 +211,50 @@ pub const Parser = struct { } fn parseOperandsResultIds( - self: *Parser, + parser: *Parser, binary: BinaryModule, inst: Instruction, operands: []const spec.Operand, start_offset: usize, - offsets: *std.array_list.Managed(u16), + offsets: *std.ArrayList(u16), ) !usize { var offset = start_offset; for (operands) |operand| { - offset = try self.parseOperandResultIds(binary, inst, operand, offset, offsets); + offset = try parser.parseOperandResultIds(binary, inst, operand, offset, offsets); } return offset; } fn parseOperandResultIds( - self: *Parser, + parser: *Parser, binary: BinaryModule, inst: Instruction, operand: spec.Operand, start_offset: usize, - offsets: *std.array_list.Managed(u16), + offsets: *std.ArrayList(u16), ) !usize { var offset = start_offset; switch (operand.quantifier) { .variadic => while (offset < inst.operands.len) { - offset = try self.parseOperandKindResultIds(binary, inst, operand.kind, offset, offsets); + offset = try parser.parseOperandKindResultIds(binary, inst, operand.kind, offset, offsets); }, .optional => if (offset < inst.operands.len) { - offset = try self.parseOperandKindResultIds(binary, inst, operand.kind, offset, offsets); + offset = try parser.parseOperandKindResultIds(binary, inst, operand.kind, offset, offsets); }, .required => { - offset = try self.parseOperandKindResultIds(binary, inst, operand.kind, offset, offsets); + offset = try parser.parseOperandKindResultIds(binary, inst, operand.kind, offset, offsets); }, } return offset; } fn parseOperandKindResultIds( - self: *Parser, + parser: *Parser, binary: BinaryModule, inst: Instruction, kind: spec.OperandKind, start_offset: usize, - offsets: *std.array_list.Managed(u16), + offsets: *std.ArrayList(u16), ) !usize { var offset = start_offset; if (offset >= inst.operands.len) return error.InvalidPhysicalFormat; @@ -383,7 +266,7 @@ pub const Parser = struct { for (kind.enumerants()) |enumerant| { if ((mask & enumerant.value) != 0) { for (enumerant.parameters) |param_kind| { - offset = try self.parseOperandKindResultIds(binary, inst, param_kind, offset, offsets); + offset = try parser.parseOperandKindResultIds(binary, inst, param_kind, offset, offsets); } } } @@ -394,14 +277,14 @@ pub const Parser = struct { for (kind.enumerants()) |enumerant| { if (value == enumerant.value) { for (enumerant.parameters) |param_kind| { - offset = try self.parseOperandKindResultIds(binary, inst, param_kind, offset, offsets); + offset = try parser.parseOperandKindResultIds(binary, inst, param_kind, offset, offsets); } break; } } }, .id => { - try offsets.append(@intCast(offset)); + try offsets.append(parser.gpa, @intCast(offset)); offset += 1; }, else => switch (kind) { @@ -433,7 +316,7 @@ pub const Parser = struct { }, .literal_ext_inst_integer => unreachable, .literal_spec_constant_op_integer => unreachable, - .pair_literal_integer_id_ref => { // Switch case + .pair_literal_integer_id_ref => { assert(inst.opcode == .OpSwitch); const bit_width = binary.arith_type_width.get(@enumFromInt(inst.operands[0])) orelse { log.err("invalid OpSwitch type {}", .{inst.operands[0]}); @@ -444,16 +327,16 @@ pub const Parser = struct { 33...64 => 2, else => unreachable, }; - try offsets.append(@intCast(offset)); + try offsets.append(parser.gpa, @intCast(offset)); offset += 1; }, .pair_id_ref_literal_integer => { - try offsets.append(@intCast(offset)); + try offsets.append(parser.gpa, @intCast(offset)); offset += 2; }, .pair_id_ref_id_ref => { - try offsets.append(@intCast(offset)); - try offsets.append(@intCast(offset + 1)); + try offsets.append(parser.gpa, @intCast(offset)); + try offsets.append(parser.gpa, @intCast(offset + 1)); offset += 2; }, else => unreachable, diff --git a/src/link/SpirV/dedup_types.zig b/src/link/SpirV/dedup_types.zig new file mode 100644 index 0000000000000000000000000000000000000000..338258e17ef40eff1d9557163395689a33cb22db --- /dev/null +++ b/src/link/SpirV/dedup_types.zig @@ -0,0 +1,244 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const BinaryModule = @import("BinaryModule.zig"); + +const spec = @import("../../codegen/spirv/spec.zig"); +const Word = spec.Word; +const Id = spec.Id; +const Opcode = spec.Opcode; +const Instruction = BinaryModule.Instruction; + +/// Deduplicate types and constants in a SPIR-V binary module. +/// +/// The SPIR-V spec requires that non-aggregate types be unique. +/// When merging fragments from parallel codegen, duplicate type definitions +/// may exist. This pass identifies structurally identical types/constants, +/// keeps one canonical instance, and remaps all references to duplicates. +pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void { + const gpa = parser.gpa; + + const Decoration = struct { offset: usize, len: usize }; + var decorations_by_id: std.array_hash_map.Auto(Id, std.ArrayList(Decoration)) = .empty; + defer { + for (decorations_by_id.values()) |*list| list.deinit(gpa); + decorations_by_id.deinit(gpa); + } + + var it = binary.iterateInstructions(); + while (it.next()) |inst| { + if (inst.offset >= binary.functions_start) break; + switch (inst.opcode) { + .OpName, .OpMemberName => continue, + else => switch (inst.opcode.class()) { + .annotation => {}, + else => continue, + }, + } + if (inst.operands.len == 0) continue; + const target_id: Id = @enumFromInt(inst.operands[0]); + + const gop = try decorations_by_id.getOrPut(gpa, target_id); + if (!gop.found_existing) gop.value_ptr.* = .empty; + try gop.value_ptr.append(gpa, .{ + .offset = inst.offset, + .len = 1 + inst.operands.len, + }); + } + + var canonical_map: std.array_hash_map.Custom(TypeKey, Id, TypeKey.HashContext, true) = .empty; + defer { + for (canonical_map.keys()) |key| gpa.free(key.words); + canonical_map.deinit(gpa); + } + + var id_remap: std.AutoHashMapUnmanaged(Id, Id) = .empty; + defer id_remap.deinit(gpa); + + var id_offsets: std.ArrayList(u16) = .empty; + defer id_offsets.deinit(gpa); + + var key_words: std.ArrayList(Word) = .empty; + defer key_words.deinit(gpa); + + var dec_hashes: std.ArrayList(u64) = .empty; + defer dec_hashes.deinit(gpa); + + // first pass: build canonical map, identify duplicates + it = binary.iterateInstructions(); + while (it.next()) |inst| { + if (inst.offset >= binary.functions_start) break; + if (!canDeduplicate(inst.opcode)) continue; + + const result_id_index: usize = switch (inst.opcode.class()) { + .type_declaration, .extension => 0, + .constant_creation => 1, + else => continue, + }; + if (result_id_index >= inst.operands.len) continue; + const result_id: Id = @enumFromInt(inst.operands[result_id_index]); + + key_words.items.len = 0; + try key_words.append(gpa, @intFromEnum(inst.opcode)); + + id_offsets.items.len = 0; + parser.parseInstructionResultIds(binary.*, inst, &id_offsets) catch continue; + + for (inst.operands, 0..) |word, i| { + if (i == result_id_index) continue; + if (std.mem.indexOfScalar(u16, id_offsets.items, @intCast(i)) != null) { + const canonical = id_remap.get(@enumFromInt(word)) orelse @as(Id, @enumFromInt(word)); + try key_words.append(gpa, @intFromEnum(canonical)); + } else { + try key_words.append(gpa, word); + } + } + + if (decorations_by_id.getPtr(result_id)) |dec_list| { + dec_hashes.items.len = 0; + for (dec_list.items) |dec| { + const dec_words = binary.instructions[dec.offset..][0..dec.len]; + var hasher = std.hash.Wyhash.init(0); + hasher.update(std.mem.asBytes(&dec_words[0])); + for (dec_words[2..]) |w| { + const w_val = if (id_remap.get(@enumFromInt(w))) |c| @intFromEnum(c) else w; + hasher.update(std.mem.asBytes(&w_val)); + } + try dec_hashes.append(gpa, hasher.final()); + } + std.mem.sort(u64, dec_hashes.items, {}, std.sort.asc(u64)); + var prev: u64 = 0; + for (dec_hashes.items) |h| { + if (h == prev) continue; + prev = h; + try key_words.append(gpa, @truncate(h)); + try key_words.append(gpa, @truncate(h >> 32)); + } + } + + const key = TypeKey{ .words = try gpa.dupe(Word, key_words.items) }; + const gop = try canonical_map.getOrPut(gpa, key); + if (gop.found_existing) { + try id_remap.put(gpa, result_id, gop.value_ptr.*); + gpa.free(key.words); + } else { + gop.value_ptr.* = result_id; + } + } + + if (id_remap.count() == 0) return; + + // second pass: rewrite id references, remove duplicates and redundant annotations + var new_words: std.ArrayList(Word) = .empty; + defer new_words.deinit(gpa); + try new_words.ensureTotalCapacity(gpa, binary.instructions.len); + + var emitted_annotations: std.AutoHashMapUnmanaged(u64, void) = .empty; + defer emitted_annotations.deinit(gpa); + + var new_functions_offset: ?usize = null; + var max_id: Word = 0; + + it = binary.iterateInstructions(); + while (it.next()) |inst| { + if (new_functions_offset == null and inst.offset >= binary.functions_start) { + new_functions_offset = new_words.items.len; + } + + if (canDeduplicate(inst.opcode)) { + const result_id_index: usize = switch (inst.opcode.class()) { + .type_declaration, .extension => 0, + .constant_creation => 1, + else => unreachable, + }; + if (result_id_index < inst.operands.len) { + const result_id: Id = @enumFromInt(inst.operands[result_id_index]); + if (id_remap.contains(result_id)) continue; + } + } + + switch (inst.opcode.class()) { + .annotation, .debug => { + if (inst.operands.len > 0) { + const target: Id = @enumFromInt(inst.operands[0]); + if (id_remap.contains(target)) continue; + } + }, + else => {}, + } + + const inst_start = new_words.items.len; + new_words.appendAssumeCapacity(binary.instructions[inst.offset]); + new_words.appendSliceAssumeCapacity(inst.operands); + const inst_slice = new_words.items[inst_start + 1 ..]; + + id_offsets.items.len = 0; + parser.parseInstructionResultIds(binary.*, inst, &id_offsets) catch continue; + + const inst_spec = parser.getInstSpec(inst.opcode); + const maybe_result_id_index: ?usize = if (inst_spec) |ispec| blk: { + break :blk for (0..@min(2, ispec.operands.len)) |i| { + if (ispec.operands[i].kind == .id_result) break @intCast(i); + } else null; + } else null; + + for (inst_slice, 0..) |*word, i| { + if (std.mem.indexOfScalar(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; + + if (id_remap.get(@enumFromInt(word.*))) |canonical| { + word.* = @intFromEnum(canonical); + max_id = @max(max_id, word.*); + } + } + + switch (inst.opcode.class()) { + .annotation, .debug => { + const ann_words = new_words.items[inst_start..]; + const ann_hash = std.hash.Wyhash.hash(0, std.mem.sliceAsBytes(ann_words)); + const gop = try emitted_annotations.getOrPut(gpa, ann_hash); + if (gop.found_existing) { + new_words.items.len = inst_start; + continue; + } + }, + else => {}, + } + } + + var remap_it = id_remap.iterator(); + while (remap_it.next()) |entry| { + _ = binary.ext_inst_map.remove(entry.key_ptr.*); + _ = binary.arith_type_width.remove(entry.key_ptr.*); + } + + binary.instructions = try gpa.dupe(Word, new_words.items); + binary.functions_start = new_functions_offset orelse new_words.items.len; + binary.id_bound = max_id + 1; +} + +fn canDeduplicate(opcode: Opcode) bool { + return switch (opcode) { + .OpTypeForwardPointer => false, + .OpGroupDecorate, .OpGroupMemberDecorate => false, + else => switch (opcode.class()) { + .type_declaration, .constant_creation => true, + .extension => opcode == .OpExtInstImport, + else => false, + }, + }; +} + +const TypeKey = struct { + words: []const Word, + + const HashContext = struct { + pub fn hash(_: @This(), key: TypeKey) u32 { + return @truncate(std.hash.Wyhash.hash(0, std.mem.sliceAsBytes(key.words))); + } + + pub fn eql(_: @This(), a: TypeKey, b: TypeKey, _: usize) bool { + return std.mem.eql(Word, a.words, b.words); + } + }; +}; diff --git a/src/link/SpirV/lower_invocation_globals.zig b/src/link/SpirV/lower_invocation_globals.zig index e2db1b33e5ca64c772082db596ceae64592c3bb9..7cc9604d049908c09fa63599ac2d0b61359331ef 100644 --- a/src/link/SpirV/lower_invocation_globals.zig +++ b/src/link/SpirV/lower_invocation_globals.zig @@ -23,14 +23,14 @@ const ModuleInfo = struct { /// The set of (result-id's of) invocation globals that are accessed /// in this function, or after resolution, that are accessed in this /// function or any of it's callees. - invocation_globals: std.AutoArrayHashMapUnmanaged(ResultId, void), + invocation_globals: std.array_hash_map.Auto(ResultId, void), }; /// Information about a particular invocation global const InvocationGlobal = struct { /// The list of invocation globals that this invocation global /// depends on. - dependencies: std.AutoArrayHashMapUnmanaged(ResultId, void), + dependencies: std.array_hash_map.Auto(ResultId, void), /// The invocation global's type ty: ResultId, /// Initializer function. May be `none`. @@ -39,13 +39,18 @@ const ModuleInfo = struct { }; /// Maps function result-id -> Fn information structure. - functions: std.AutoArrayHashMapUnmanaged(ResultId, Fn), + functions: std.array_hash_map.Auto(ResultId, Fn), /// Set of OpFunction result-ids in this module. - entry_points: std.AutoArrayHashMapUnmanaged(ResultId, void), + entry_points: std.array_hash_map.Auto(ResultId, void), /// For each function, a list of function result-ids that it calls. callee_store: []const ResultId, /// Maps each invocation global result-id to a type-id. - invocation_globals: std.AutoArrayHashMapUnmanaged(ResultId, InvocationGlobal), + invocation_globals: std.array_hash_map.Auto(ResultId, InvocationGlobal), + /// Subset of `invocation_globals` reachable from any entry point. + live_invocation_globals: std.array_hash_map.Auto(ResultId, void), + /// Initializer functions of unreachable invocation globals. Their + /// OpFunction...OpFunctionEnd ranges are skipped during rewriteFunctions. + dead_initializers: std.array_hash_map.Auto(ResultId, void), /// Fetch the list of callees per function. Guaranteed to contain only unique IDs. fn callees(self: ModuleInfo, fn_id: ResultId) []const ResultId { @@ -66,7 +71,7 @@ const ModuleInfo = struct { arena: Allocator, parser: *BinaryModule.Parser, binary: BinaryModule, - ) BinaryModule.ParseError!ModuleInfo { + ) !ModuleInfo { var entry_points: std.array_hash_map.Auto(ResultId, void) = .empty; var functions: std.array_hash_map.Auto(ResultId, Fn) = .empty; var fn_types = std.AutoHashMap(ResultId, struct { @@ -74,9 +79,9 @@ const ModuleInfo = struct { param_types: []const ResultId, }).init(arena); var calls: std.array_hash_map.Auto(ResultId, void) = .empty; - var callee_store = std.array_list.Managed(ResultId).init(arena); + var callee_store: std.ArrayList(ResultId) = .empty; var function_invocation_globals: std.array_hash_map.Auto(ResultId, void) = .empty; - var result_id_offsets = std.array_list.Managed(u16).init(arena); + var result_id_offsets: std.ArrayList(u16) = .empty; var invocation_globals: std.array_hash_map.Auto(ResultId, InvocationGlobal) = .empty; var maybe_current_function: ?ResultId = null; @@ -159,7 +164,7 @@ const ModuleInfo = struct { } const first_callee = callee_store.items.len; - try callee_store.appendSlice(calls.keys()); + try callee_store.appendSlice(arena, calls.keys()); const fn_type = fn_types.get(fn_ty_id) orelse { log.err("Function {f} has invalid OpFunction type", .{current_function}); @@ -196,6 +201,8 @@ const ModuleInfo = struct { .entry_points = entry_points, .callee_store = callee_store.items, .invocation_globals = invocation_globals, + .live_invocation_globals = .empty, + .dead_initializers = .empty, }; } @@ -203,6 +210,25 @@ const ModuleInfo = struct { fn resolve(self: *ModuleInfo, arena: Allocator) !void { try self.resolveInvocationGlobalUsage(arena); try self.resolveInvocationGlobalDependencies(arena); + try self.resolveLiveSet(arena); + } + + fn resolveLiveSet(self: *ModuleInfo, arena: Allocator) !void { + for (self.entry_points.keys()) |ep_id| { + const ep_info = self.functions.get(ep_id) orelse continue; + for (ep_info.invocation_globals.keys()) |g| { + try self.live_invocation_globals.put(arena, g, {}); + const g_info = self.invocation_globals.get(g).?; + for (g_info.dependencies.keys()) |dep| { + try self.live_invocation_globals.put(arena, dep, {}); + } + } + } + for (self.invocation_globals.keys(), self.invocation_globals.values()) |g, info| { + if (info.initializer == .none) continue; + if (self.live_invocation_globals.contains(g)) continue; + try self.dead_initializers.put(arena, info.initializer, {}); + } } /// For each function, extend the list of `invocation_globals` with the @@ -340,11 +366,13 @@ const ModuleBuilder = struct { /// The first ID of the new entry points. Entry points are allocated from /// here according to their index in `info.entry_points`. entry_point_new_id_base: u32, + /// OpName operands saved for invocation globals to re-emit. + global_names: std.array_hash_map.Auto(ResultId, []const Word) = .empty, /// A set of all function types in the new program. SPIR-V mandates that these are unique, /// and until a general type deduplication pass is programmed, we just handle it here via this. - function_types: std.ArrayHashMapUnmanaged(FunctionType, ResultId, FunctionType.Context, true) = .empty, + function_types: std.array_hash_map.Custom(FunctionType, ResultId, FunctionType.Context, true) = .empty, /// Maps functions to new information required for creating the module - function_new_info: std.AutoArrayHashMapUnmanaged(ResultId, FunctionNewInfo) = .empty, + function_new_info: std.array_hash_map.Auto(ResultId, FunctionNewInfo) = .empty, /// Offset of the functions section in the new binary. new_functions_section: ?usize, @@ -369,22 +397,50 @@ const ModuleBuilder = struct { return @enumFromInt(self.id_bound); } - fn finalize(self: *ModuleBuilder, a: Allocator, binary: *BinaryModule) !void { + fn finalize(self: *ModuleBuilder, arena: Allocator, binary: *BinaryModule) !void { binary.id_bound = self.id_bound; - binary.instructions = try a.dupe(Word, self.section.instructions.items); + binary.instructions = try arena.dupe(Word, self.section.instructions.items); // Nothing is removed in this pass so we don't need to change any of the maps, // just make sure the section is updated. - binary.sections.functions = self.new_functions_section orelse binary.instructions.len; + binary.functions_start = self.new_functions_section orelse binary.instructions.len; + } + + fn emitGlobalNames(self: *ModuleBuilder, info: ModuleInfo) !void { + for (info.functions.keys(), info.functions.values()) |func, fn_info| { + if (info.dead_initializers.contains(func)) continue; + const new_info = self.function_new_info.get(func) orelse continue; + for (fn_info.invocation_globals.keys(), 0..) |global, i| { + if (!info.live_invocation_globals.contains(global)) continue; + const name_words = self.global_names.get(global) orelse continue; + const id = new_info.invocationGlobalId(i); + try self.section.emitRaw(self.arena, .OpName, 1 + name_words.len); + self.section.writeOperand(ResultId, id); + self.section.writeWords(name_words); + } + } } /// Process everything from `binary` up to the first function and emit it into the builder. fn processPreamble(self: *ModuleBuilder, binary: BinaryModule, info: ModuleInfo) !void { + var emitted_global_names = false; var it = binary.iterateInstructions(); while (it.next()) |inst| { + if (!emitted_global_names) switch (inst.opcode.class()) { + .annotation, .type_declaration, .constant_creation => { + try self.emitGlobalNames(info); + emitted_global_names = true; + }, + else => {}, + }; + switch (inst.opcode) { .OpName => { const id: ResultId = @enumFromInt(inst.operands[0]); - if (info.invocation_globals.contains(id)) continue; + if (info.invocation_globals.contains(id)) { + try self.global_names.put(self.arena, id, inst.operands[1..]); + continue; + } + if (info.dead_initializers.contains(id)) continue; }, .OpExtInstImport => { const set_id: ResultId = @enumFromInt(inst.operands[0]); @@ -401,29 +457,34 @@ const ModuleBuilder = struct { }, .OpEntryPoint => { const original_id: ResultId = @enumFromInt(inst.operands[1]); - const new_id_index = info.entry_points.getIndex(original_id).?; - const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index); - try self.section.emitRaw(self.arena, .OpEntryPoint, inst.operands.len); - self.section.writeWord(inst.operands[0]); - self.section.writeOperand(ResultId, new_id); - self.section.writeWords(inst.operands[2..]); + const fn_info = info.functions.get(original_id).?; + if (fn_info.invocation_globals.count() > 0) { + const new_id_index = info.entry_points.getIndex(original_id).?; + const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index); + try self.section.emitRaw(self.arena, .OpEntryPoint, inst.operands.len); + self.section.writeWord(inst.operands[0]); + self.section.writeOperand(ResultId, new_id); + self.section.writeWords(inst.operands[2..]); + } else { + try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands); + } continue; }, .OpExecutionMode, .OpExecutionModeId => { const original_id: ResultId = @enumFromInt(inst.operands[0]); - const new_id_index = info.entry_points.getIndex(original_id).?; - const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index); - try self.section.emitRaw(self.arena, inst.opcode, inst.operands.len); - self.section.writeOperand(ResultId, new_id); - self.section.writeWords(inst.operands[1..]); + const fn_info = info.functions.get(original_id).?; + if (fn_info.invocation_globals.count() > 0) { + const new_id_index = info.entry_points.getIndex(original_id).?; + const new_id: ResultId = @enumFromInt(self.entry_point_new_id_base + new_id_index); + try self.section.emitRaw(self.arena, inst.opcode, inst.operands.len); + self.section.writeOperand(ResultId, new_id); + self.section.writeWords(inst.operands[1..]); + } else { + try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands); + } continue; }, .OpTypeFunction => { - // Re-emitted in `emitFunctionTypes()`. We can do this because - // OpTypeFunction's may not currently be used anywhere that is not - // directly with an OpFunction. For now we ignore Intels function - // pointers extension, that is not a problem with a generalized - // pass anyway. continue; }, .OpFunction => break, @@ -432,6 +493,10 @@ const ModuleBuilder = struct { try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands); } + + if (!emitted_global_names) { + try self.emitGlobalNames(info); + } } /// Derive new information required for further emitting this module, @@ -498,18 +563,23 @@ const ModuleBuilder = struct { binary: BinaryModule, info: ModuleInfo, ) !void { - var result_id_offsets = std.array_list.Managed(u16).init(self.arena); - var operands = std.array_list.Managed(u32).init(self.arena); + var result_id_offsets: std.ArrayList(u16) = .empty; + var operands: std.ArrayList(u32) = .empty; var maybe_current_function: ?ResultId = null; - var it = binary.iterateInstructionsFrom(binary.sections.functions); + var skip_until_end: bool = false; + var it = binary.iterateInstructionsFrom(binary.functions_start); self.new_functions_section = self.section.instructions.items.len; while (it.next()) |inst| { + if (skip_until_end) { + if (inst.opcode == .OpFunctionEnd) skip_until_end = false; + continue; + } result_id_offsets.items.len = 0; try parser.parseInstructionResultIds(binary, inst, &result_id_offsets); operands.items.len = 0; - try operands.appendSlice(inst.operands); + try operands.appendSlice(self.arena, inst.operands); // Replace the result-ids with the global's new result-id if required. for (result_id_offsets.items) |off| { @@ -527,6 +597,10 @@ const ModuleBuilder = struct { .OpFunction => { // Re-declare the function with the new parameters. const func: ResultId = @enumFromInt(operands.items[1]); + if (info.dead_initializers.contains(func)) { + skip_until_end = true; + continue; + } const fn_info = info.functions.get(func).?; const new_info = self.function_new_info.get(func).?; @@ -588,6 +662,7 @@ const ModuleBuilder = struct { for (info.entry_points.keys(), 0..) |func, entry_point_index| { const fn_info = info.functions.get(func).?; + if (fn_info.invocation_globals.count() == 0) continue; const ep_id: ResultId = @enumFromInt(self.entry_point_new_id_base + @as(u32, @intCast(entry_point_index))); const fn_type = self.function_types.get(.{ .return_type = fn_info.return_type, @@ -705,14 +780,14 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Pr const sub_node = progress.start("Lower invocation globals", 6); defer sub_node.end(); - var arena = std.heap.ArenaAllocator.init(parser.a); - defer arena.deinit(); - const a = arena.allocator(); + var arena_state = std.heap.ArenaAllocator.init(parser.gpa); + defer arena_state.deinit(); + const arena = arena_state.allocator(); - var info = try ModuleInfo.parse(a, parser, binary.*); - try info.resolve(a); + var info = try ModuleInfo.parse(arena, parser, binary.*); + try info.resolve(arena); - var builder = try ModuleBuilder.init(a, binary.*, info); + var builder = try ModuleBuilder.init(arena, binary.*, info); sub_node.completeOne(); try builder.deriveNewFnInfo(info); sub_node.completeOne(); @@ -724,5 +799,5 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Pr sub_node.completeOne(); try builder.emitNewEntryPoints(info); sub_node.completeOne(); - try builder.finalize(parser.a, binary); + try builder.finalize(parser.gpa, binary); } diff --git a/src/link/SpirV/prune_unused.zig b/src/link/SpirV/prune_unused.zig new file mode 100644 index 0000000000000000000000000000000000000000..356da14952784938ade741ba08e5ed52fd859df3 --- /dev/null +++ b/src/link/SpirV/prune_unused.zig @@ -0,0 +1,257 @@ +const std = @import("std"); +const BinaryModule = @import("BinaryModule.zig"); +const spec = @import("../../codegen/spirv/spec.zig"); +const Opcode = spec.Opcode; +const ResultId = spec.Id; +const Word = spec.Word; + +pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void { + const gpa = parser.gpa; + + // map result-id → index in id_offsets for preamble instructions and function headers + var id_to_index: std.AutoHashMapUnmanaged(ResultId, u32) = .empty; + defer id_to_index.deinit(gpa); + + // for each indexed instruction, its offset in the binary + var code_offsets: std.ArrayList(usize) = .empty; + defer code_offsets.deinit(gpa); + + var it = binary.iterateInstructions(); + while (it.next()) |inst| { + const inst_spec = parser.getInstSpec(inst.opcode) orelse continue; + const result_id = getResultId(inst, inst_spec) orelse continue; + + // only index preamble instructions and function headers + if (inst.offset < binary.functions_start or inst.opcode == .OpFunction) { + const index: u32 = @intCast(code_offsets.items.len); + try id_to_index.put(gpa, result_id, index); + try code_offsets.append(gpa, inst.offset); + } + } + + var alive: std.bit_set.Dynamic = try .initEmpty(gpa, code_offsets.items.len); + defer alive.deinit(gpa); + + var id_offset_buf: std.ArrayList(u16) = .empty; + defer id_offset_buf.deinit(gpa); + + // Mark non-prunable preamble instructions alive + // OpExtInst in the preamble is metadata (e.g. Zig error info) that references + // functions. skip it here so it doesn't root dead functions alive. + // These instructions are handled as prunable during the rewrite phase. + it = binary.iterateInstructions(); + while (it.next()) |inst| { + if (inst.offset >= binary.functions_start) break; + if (canPrune(inst.opcode) or inst.opcode == .OpExtInst) continue; + try markAlive( + parser, + binary.*, + inst, + &alive, + &id_to_index, + &code_offsets, + &id_offset_buf, + ); + } + + // mark functions with LinkageAttributes Export alive + it = binary.iterateInstructions(); + while (it.next()) |inst| { + if (inst.offset >= binary.functions_start) break; + if (inst.opcode == .OpDecorate and inst.operands.len >= 2 and + inst.operands[1] == @intFromEnum(spec.Decoration.linkage_attributes)) + { + // Last word after the string is the linkage type; Export = 0. + if (inst.operands[inst.operands.len - 1] == @intFromEnum(spec.LinkageType.@"export")) { + const target: ResultId = @enumFromInt(inst.operands[0]); + if (id_to_index.get(target)) |index| { + alive.set(index); + } + } + } + } + + // mark alive functions' contents alive + it = binary.iterateInstructionsFrom(binary.functions_start); + while (it.next()) |inst| { + if (inst.opcode == .OpFunction) { + const inst_spec = parser.getInstSpec(inst.opcode) orelse continue; + const result_id = getResultId(inst, inst_spec) orelse continue; + const index = id_to_index.get(result_id) orelse continue; + if (!alive.isSet(index)) { + // skip dead function + while (it.next()) |inner| { + if (inner.opcode == .OpFunctionEnd) break; + } + continue; + } + + // mark the function's type operands alive + try markAlive(parser, binary.*, inst, &alive, &id_to_index, &code_offsets, &id_offset_buf); + continue; + } + + // mark operands of alive function contents + try markAlive(parser, binary.*, inst, &alive, &id_to_index, &code_offsets, &id_offset_buf); + } + + // rewrite + var new_words: std.ArrayList(Word) = .empty; + defer new_words.deinit(gpa); + try new_words.ensureTotalCapacity(gpa, binary.instructions.len); + + var new_functions_start: ?usize = null; + + it = binary.iterateInstructions(); + while (it.next()) |inst| { + if (inst.offset >= binary.functions_start and inst.opcode == .OpFunction) { + const inst_spec = parser.getInstSpec(inst.opcode) orelse continue; + const result_id = getResultId(inst, inst_spec) orelse continue; + const index = id_to_index.get(result_id) orelse continue; + if (!alive.isSet(index)) { + while (it.next()) |inner| { + if (inner.opcode == .OpFunctionEnd) break; + } + continue; + } + } + + const is_prunable = canPrune(inst.opcode) or + (inst.opcode == .OpExtInst and inst.offset < binary.functions_start); + if (is_prunable) { + const inst_spec = parser.getInstSpec(inst.opcode) orelse { + appendInst(&new_words, binary, inst, &new_functions_start); + continue; + }; + + if (getResultId(inst, inst_spec)) |result_id| { + const index = id_to_index.get(result_id) orelse { + appendInst(&new_words, binary, inst, &new_functions_start); + continue; + }; + if (!alive.isSet(index)) continue; + } else { + // annotation-style: emit only if the target id is alive + if (inst.operands.len > 0) { + const target: ResultId = @enumFromInt(inst.operands[0]); + if (id_to_index.get(target)) |idx| { + if (!alive.isSet(idx)) continue; + } else continue; + } + } + } + + appendInst(&new_words, binary, inst, &new_functions_start); + } + + { + var to_remove: std.ArrayList(ResultId) = .empty; + defer to_remove.deinit(gpa); + + var ext_it = binary.ext_inst_map.iterator(); + while (ext_it.next()) |entry| { + if (id_to_index.get(entry.key_ptr.*)) |index| { + if (!alive.isSet(index)) try to_remove.append(gpa, entry.key_ptr.*); + } + } + for (to_remove.items) |id| _ = binary.ext_inst_map.remove(id); + + to_remove.items.len = 0; + var arith_it = binary.arith_type_width.iterator(); + while (arith_it.next()) |entry| { + if (id_to_index.get(entry.key_ptr.*)) |index| { + if (!alive.isSet(index)) try to_remove.append(gpa, entry.key_ptr.*); + } + } + for (to_remove.items) |id| _ = binary.arith_type_width.remove(id); + } + + binary.instructions = try gpa.dupe(Word, new_words.items); + binary.functions_start = new_functions_start orelse new_words.items.len; +} + +fn appendInst( + new_words: *std.ArrayList(Word), + binary: *const BinaryModule, + inst: BinaryModule.Instruction, + new_functions_start: *?usize, +) void { + if (new_functions_start.* == null and inst.offset >= binary.functions_start) { + new_functions_start.* = new_words.items.len; + } + const len = @as(usize, binary.instructions[inst.offset] >> 16); + new_words.appendSliceAssumeCapacity(binary.instructions[inst.offset..][0..len]); +} + +fn markAlive( + parser: *BinaryModule.Parser, + binary: BinaryModule, + inst: BinaryModule.Instruction, + alive: *std.DynamicBitSetUnmanaged, + id_to_index: *const std.AutoHashMapUnmanaged(ResultId, u32), + code_offsets: *const std.ArrayList(usize), + id_offset_buf: *std.ArrayList(u16), +) !void { + const start = id_offset_buf.items.len; + try parser.parseInstructionResultIds(binary, inst, id_offset_buf); + const end = id_offset_buf.items.len; + + var i = start; + while (i < end) : (i += 1) { + const off = id_offset_buf.items[i]; + const id: ResultId = @enumFromInt(inst.operands[off]); + const index = id_to_index.get(id) orelse continue; + if (alive.isSet(index)) continue; + alive.set(index); + + const offset = code_offsets.items[index]; + const ref_inst = BinaryModule.Instruction{ + .opcode = @enumFromInt(binary.instructions[offset] & 0xFFFF), + .offset = offset, + .operands = blk: { + const l = binary.instructions[offset] >> 16; + break :blk binary.instructions[offset..][1..l]; + }, + }; + + if (ref_inst.opcode == .OpFunction) { + var fn_it = binary.iterateInstructionsFrom(ref_inst.offset); + _ = fn_it.next(); + while (fn_it.next()) |fn_inst| { + if (fn_inst.opcode == .OpFunctionEnd) break; + try markAlive(parser, binary, fn_inst, alive, id_to_index, code_offsets, id_offset_buf); + } + try markAlive(parser, binary, ref_inst, alive, id_to_index, code_offsets, id_offset_buf); + } else { + try markAlive(parser, binary, ref_inst, alive, id_to_index, code_offsets, id_offset_buf); + } + } +} + +fn getResultId(inst: BinaryModule.Instruction, inst_spec: spec.Instruction) ?ResultId { + for (0..@min(2, inst_spec.operands.len)) |i| { + if (inst_spec.operands[i].kind == .id_result) { + if (i < inst.operands.len) return @enumFromInt(inst.operands[i]); + } + } + return null; +} + +fn canPrune(op: Opcode) bool { + return switch (op.class()) { + .type_declaration, + .constant_creation, + .annotation, + => true, + else => switch (op) { + .OpFunction, + .OpUndef, + .OpString, + .OpName, + .OpMemberName, + .OpVariable, + => true, + else => false, + }, + }; +} diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 88502d8329e81c37e3dd3a7f8c48b7cd7bfd29a9..fd18419bab38858a538154f459cb683e2a345d2c 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -80,27 +80,27 @@ name: []const u8, /// List of relocatable files to be linked into the final binary. objects: std.ArrayList(Object) = .empty, -func_types: std.AutoArrayHashMapUnmanaged(FunctionType, void) = .empty, +func_types: std.array_hash_map.Auto(FunctionType, void) = .empty, /// Provides a mapping of both imports and provided functions to symbol name. /// Local functions may be unnamed. /// Key is symbol name, however the `FunctionImport` may have an name override for the import name. -object_function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImport) = .empty, +object_function_imports: std.array_hash_map.Auto(String, FunctionImport) = .empty, /// All functions for all objects. object_functions: std.ArrayList(ObjectFunction) = .empty, /// Provides a mapping of both imports and provided globals to symbol name. /// Local globals may be unnamed. -object_global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImport) = .empty, +object_global_imports: std.array_hash_map.Auto(String, GlobalImport) = .empty, /// All globals for all objects. object_globals: std.ArrayList(ObjectGlobal) = .empty, /// All table imports for all objects. -object_table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport) = .empty, +object_table_imports: std.array_hash_map.Auto(String, TableImport) = .empty, /// All parsed table sections for all objects. object_tables: std.ArrayList(Table) = .empty, /// All memory imports for all objects. -object_memory_imports: std.AutoArrayHashMapUnmanaged(String, MemoryImport) = .empty, +object_memory_imports: std.array_hash_map.Auto(String, MemoryImport) = .empty, /// All parsed memory sections for all objects. object_memories: std.ArrayList(ObjectMemory) = .empty, @@ -119,15 +119,15 @@ object_data_segments: std.ArrayList(ObjectDataSegment) = .empty, /// Each segment has many data symbols, which correspond logically to global /// constants. object_datas: std.ArrayList(ObjectData) = .empty, -object_data_imports: std.AutoArrayHashMapUnmanaged(String, ObjectDataImport) = .empty, +object_data_imports: std.array_hash_map.Auto(String, ObjectDataImport) = .empty, /// Non-synthetic section that can essentially be mem-cpy'd into place after performing relocations. -object_custom_segments: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, CustomSegment) = .empty, +object_custom_segments: std.array_hash_map.Auto(ObjectSectionIndex, CustomSegment) = .empty, /// All comdat information for all objects. object_comdats: std.ArrayList(Comdat) = .empty, /// A table that maps the relocations to be performed where the key represents /// the section (across all objects) that the slice of relocations applies to. -object_relocations_table: std.AutoArrayHashMapUnmanaged(ObjectSectionIndex, ObjectRelocation.Slice) = .empty, +object_relocations_table: std.array_hash_map.Auto(ObjectSectionIndex, ObjectRelocation.Slice) = .empty, /// Incremented across all objects in order to enable calculation of `ObjectSectionIndex` values. object_total_sections: u32 = 0, /// All comdat symbols from all objects concatenated. @@ -150,7 +150,7 @@ nav_fixups: std.ArrayList(NavFixup) = .empty, 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.AutoArrayHashMapUnmanaged(String, void) = .empty, +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. @@ -174,24 +174,24 @@ preloaded_strings: PreloadedStrings, /// This field is used when emitting an object; `navs_exe` used otherwise. /// Does not include externs since that data lives elsewhere. -navs_obj: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ZcuDataObj) = .empty, +navs_obj: std.array_hash_map.Auto(InternPool.Nav.Index, ZcuDataObj) = .empty, /// This field is unused when emitting an object; `navs_obj` used otherwise. /// Does not include externs since that data lives elsewhere. -navs_exe: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, ZcuDataExe) = .empty, +navs_exe: std.array_hash_map.Auto(InternPool.Nav.Index, ZcuDataExe) = .empty, /// Tracks all InternPool values referenced by codegen. Needed for outputting /// the data segment. This one does not track ref count because object files /// require using max LEB encoding for these references anyway. -uavs_obj: std.AutoArrayHashMapUnmanaged(InternPool.Index, ZcuDataObj) = .empty, +uavs_obj: std.array_hash_map.Auto(InternPool.Index, ZcuDataObj) = .empty, /// Tracks ref count to optimize LEB encodings for UAV references. -uavs_exe: std.AutoArrayHashMapUnmanaged(InternPool.Index, ZcuDataExe) = .empty, +uavs_exe: std.array_hash_map.Auto(InternPool.Index, ZcuDataExe) = .empty, /// Sparse table of uavs that need to be emitted with greater alignment than /// the default for the type. -overaligned_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .empty, +overaligned_uavs: std.array_hash_map.Auto(InternPool.Index, Alignment) = .empty, /// When the key is an enum type, this represents a `@tagName` function. -zcu_funcs: std.AutoArrayHashMapUnmanaged(InternPool.Index, ZcuFunc) = .empty, -nav_exports: std.AutoArrayHashMapUnmanaged(NavExport, Zcu.Export.Index) = .empty, -uav_exports: std.AutoArrayHashMapUnmanaged(UavExport, Zcu.Export.Index) = .empty, -imports: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, +zcu_funcs: std.array_hash_map.Auto(InternPool.Index, ZcuFunc) = .empty, +nav_exports: std.array_hash_map.Auto(NavExport, Zcu.Export.Index) = .empty, +uav_exports: std.array_hash_map.Auto(UavExport, Zcu.Export.Index) = .empty, +imports: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty, dwarf: ?Dwarf = null, @@ -200,19 +200,19 @@ flush_buffer: Flush = .{}, /// Empty until `prelink`. There it is populated based on object files. /// Next, it is copied into `Flush.missing_exports` just before `flush` /// and that data is used during `flush`. -missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty, +missing_exports: std.array_hash_map.Auto(String, void) = .empty, entry_resolution: FunctionImport.Resolution = .unresolved, /// Empty when outputting an object. -function_exports: std.AutoArrayHashMapUnmanaged(String, FunctionIndex) = .empty, -hidden_function_exports: std.AutoArrayHashMapUnmanaged(String, FunctionIndex) = .empty, +function_exports: std.array_hash_map.Auto(String, FunctionIndex) = .empty, +hidden_function_exports: std.array_hash_map.Auto(String, FunctionIndex) = .empty, global_exports: std.ArrayList(GlobalExport) = .empty, /// Tracks the value at the end of prelink. global_exports_len: u32 = 0, /// Ordered list of non-import functions that will appear in the final binary. /// Empty until prelink. -functions: std.AutoArrayHashMapUnmanaged(FunctionImport.Resolution, void) = .empty, +functions: std.array_hash_map.Auto(FunctionImport.Resolution, void) = .empty, /// Tracks the value at the end of prelink, at which point `functions` /// contains only object file functions, and nothing from the Zcu yet. functions_end_prelink: u32 = 0, @@ -230,7 +230,7 @@ data_imports_len_prelink: u32 = 0, /// `flush` gets a copy of this table, and then Zcu exports are applied to /// remove elements from the table, and the remainder are either undefined /// symbol errors, or import section entries depending on the output mode. -function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty, +function_imports: std.array_hash_map.Auto(String, FunctionImportId) = .empty, /// At the end of prelink, this is populated with data symbols needed by /// objects. @@ -243,29 +243,29 @@ function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .emp /// `flush` gets a copy of this table, and then Zcu exports are applied to /// 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.AutoArrayHashMapUnmanaged(String, DataImportId) = .empty, +data_imports: std.array_hash_map.Auto(String, DataImportId) = .empty, /// Set of data symbols that will appear in the final binary. Used to populate /// `Flush.data_segments` before sorting. -data_segments: std.AutoArrayHashMapUnmanaged(DataSegmentId, void) = .empty, +data_segments: std.array_hash_map.Auto(DataSegmentId, void) = .empty, /// Ordered list of non-import globals that will appear in the final binary. /// Empty until prelink. -globals: std.AutoArrayHashMapUnmanaged(GlobalImport.Resolution, void) = .empty, +globals: std.array_hash_map.Auto(GlobalImport.Resolution, void) = .empty, /// Tracks the value at the end of prelink, at which point `globals` /// contains only object file globals, and nothing from the Zcu yet. globals_end_prelink: u32 = 0, -global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty, +global_imports: std.array_hash_map.Auto(String, GlobalImportId) = .empty, /// Ordered list of non-import tables that will appear in the final binary. /// Empty until prelink. -tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty, -table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport.Index) = .empty, +tables: std.array_hash_map.Auto(TableImport.Resolution, void) = .empty, +table_imports: std.array_hash_map.Auto(String, TableImport.Index) = .empty, /// All functions that have had their address taken and therefore might be /// called via a `call_indirect` function. -zcu_indirect_function_set: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, -object_indirect_function_import_set: std.AutoArrayHashMapUnmanaged(String, void) = .empty, -object_indirect_function_set: std.AutoArrayHashMapUnmanaged(ObjectFunctionIndex, void) = .empty, +zcu_indirect_function_set: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty, +object_indirect_function_import_set: std.array_hash_map.Auto(String, void) = .empty, +object_indirect_function_set: std.array_hash_map.Auto(ObjectFunctionIndex, void) = .empty, error_name_table_ref_count: u32 = 0, tag_name_table_ref_count: u32 = 0, diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig index 9424eeabf41db56a8fab5fc55464bdeaba49d857..65a1ee313b8c6bc5e8710728cd877284c47b544f 100644 --- a/src/link/Wasm/Archive.zig +++ b/src/link/Wasm/Archive.zig @@ -12,7 +12,7 @@ toc: Toc, /// Key points into `LazyArchive` `file_contents`. /// Value is allocated with gpa. -const Toc = std.StringArrayHashMapUnmanaged(std.ArrayList(u32)); +const Toc = std.array_hash_map.String(std.ArrayList(u32)); const ARMAG = std.elf.ARMAG; const ARFMAG = std.elf.ARFMAG; diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 95bc18070facb84f8a5e5d5ab3286b2a6df8bc20..56b07cd158f0ab2b6fa79cc87daa15b76bbdb62f 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -24,22 +24,22 @@ const ArrayList = std.ArrayList; /// Ordered list of data segments that will appear in the final binary. /// When sorted, to-be-merged segments will be made adjacent. /// Values are virtual address. -data_segments: std.AutoArrayHashMapUnmanaged(Wasm.DataSegmentId, u32) = .empty, +data_segments: std.array_hash_map.Auto(Wasm.DataSegmentId, u32) = .empty, /// Each time a `data_segment` offset equals zero it indicates a new group, and /// the next element in this array will contain the total merged segment size. /// Value is the virtual memory address of the end of the segment. data_segment_groups: ArrayList(DataSegmentGroup) = .empty, binary_bytes: ArrayList(u8) = .empty, -missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty, -function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty, -global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty, -data_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.DataImportId) = .empty, +missing_exports: std.array_hash_map.Auto(String, void) = .empty, +function_imports: std.array_hash_map.Auto(String, Wasm.FunctionImportId) = .empty, +global_imports: std.array_hash_map.Auto(String, Wasm.GlobalImportId) = .empty, +data_imports: std.array_hash_map.Auto(String, Wasm.DataImportId) = .empty, -indirect_function_table: std.AutoArrayHashMapUnmanaged(Wasm.OutputFunctionIndex, void) = .empty, +indirect_function_table: std.array_hash_map.Auto(Wasm.OutputFunctionIndex, void) = .empty, /// A subset of the full interned function type list created only during flush. -func_types: std.AutoArrayHashMapUnmanaged(Wasm.FunctionType.Index, void) = .empty, +func_types: std.array_hash_map.Auto(Wasm.FunctionType.Index, void) = .empty, /// For debug purposes only. memory_layout_finished: bool = false, diff --git a/src/link/loongarch.zig b/src/link/loongarch.zig new file mode 100644 index 0000000000000000000000000000000000000000..be460a0c19e7f49094324c004bdd912b56474cea --- /dev/null +++ b/src/link/loongarch.zig @@ -0,0 +1,55 @@ +const std = @import("std"); +const mem = std.mem; + +pub fn writeK12(code: *[4]u8, target_value: u12) void { + var inst = std.mem.readInt(u32, code, .little); + inst &= 0b11111111110000000000001111111111; + inst |= (@as(u32, target_value) << 10); + std.mem.writeInt(u32, code, inst, .little); +} + +pub fn writeK16(code: *[4]u8, target_value: u16) void { + var inst = std.mem.readInt(u32, code, .little); + inst &= 0b11111100000000000000001111111111; + inst |= (@as(u32, target_value) << 10); + std.mem.writeInt(u32, code, inst, .little); +} + +pub fn writeJ20(code: *[4]u8, target_value: u20) void { + var inst = std.mem.readInt(u32, code, .little); + inst &= 0b11111110000000000000000000011111; + inst |= (@as(u32, target_value) << 5); + std.mem.writeInt(u32, code, inst, .little); +} + +pub fn writeD5K16(code: *[4]u8, target_value: u21) void { + var inst = std.mem.readInt(u32, code, .little); + inst &= 0b11111100000000000000001111100000; + inst |= @as(u32, target_value >> 16); + inst |= (@as(u32, target_value << 5) << 5); + std.mem.writeInt(u32, code, inst, .little); +} + +pub fn writeD10K16(code: *[4]u8, target_value: u26) void { + var inst = std.mem.readInt(u32, code, .little); + inst &= 0b11111100000000000000000000000000; + inst |= @as(u32, target_value >> 16); + inst |= @as(u32, target_value << 10); + std.mem.writeInt(u32, code, inst, .little); +} + +pub fn toPcalaHi20(target: u64, pc: u64) u20 { + return @truncate(((target +% 0x800) >> 12) -% (pc >> 12)); +} + +pub fn toPcala64Lo20(target: u64, pc: u64) u20 { + const fixup = if (target & 0x800 != 0) (@as(u64, 0x1000) -% @as(u64, 0x100000000)) else 0; + const hi32 = (((target +% 0x80000000 +% fixup) >> 12) -% ((pc -% 8) >> 12)) >> 20; + return @truncate(hi32); +} + +pub fn toPcala64Hi12(target: u64, pc: u64) u12 { + const fixup = if (target & 0x800 != 0) (@as(u64, 0x1000) -% @as(u64, 0x100000000)) else 0; + const hi32 = (((target +% 0x80000000 +% fixup) >> 12) -% ((pc -% 12) >> 12)) >> 20; + return @truncate(hi32 >> 20); +} diff --git a/src/main.zig b/src/main.zig index 142d5facb6dddffaa242d3e94081f2d549eb7a5c..4dd56dd3b0623c7836ce04604c9066b562a223a4 100644 --- a/src/main.zig +++ b/src/main.zig @@ -295,7 +295,7 @@ fn mainArgs( // However it's possible Zig is installed as *that* C compiler as well, which is // why we have this additional environment variable here to check. - const inf_loop_env_key: EnvVar = .ZIG_IS_TRYING_TO_NOT_CALL_ITSELF; + const inf_loop_env_key: EnvVar = .ZIG_IS_AVOIDING_CALLING_ITSELF; if (inf_loop_env_key.isSet(environ_map)) { fatal("{s}", .{ "The compilation links against libc, but Zig is unable to provide a libc " ++ @@ -887,6 +887,7 @@ const CliModule = struct { inherited: Package.Module.CreateOptions.Inherited, target_arch_os_abi: ?[]const u8, target_mcpu: ?[]const u8, + dynamic_linker: ?[]const u8, deps: []const Dep, resolved: ?*Package.Module, @@ -943,6 +944,7 @@ fn buildOutputType( var emit_implib_arg_provided = false; var target_arch_os_abi: ?[]const u8 = null; var target_mcpu: ?[]const u8 = null; + var dynamic_linker: ?[]const u8 = null; var emit_h: Emit = .no; var soname: SOName = undefined; var want_compiler_rt: ?bool = null; @@ -987,7 +989,7 @@ fn buildOutputType( var test_no_exec = false; var test_execve = false; var entry: Compilation.CreateOptions.Entry = .default; - var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .empty; + var force_undefined_symbols: std.array_hash_map.String(void) = .empty; var stack_size: ?u64 = null; var image_base: ?u64 = null; var link_eh_frame_hdr = false; @@ -1024,7 +1026,7 @@ fn buildOutputType( // These are before resolving sysroot. var extra_cflags: std.ArrayList([]const u8) = .empty; var extra_rcflags: std.ArrayList([]const u8) = .empty; - var symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .empty; + var symbol_wrap_set: std.array_hash_map.String(void) = .empty; var rc_includes: std.zig.RcIncludes = .any; var manifest_file: ?[]const u8 = null; var linker_export_symbol_names: std.ArrayList([]const u8) = .empty; @@ -1059,7 +1061,6 @@ fn buildOutputType( // Populated just before the call to `createModule`. .dirs = undefined, .object_format = null, - .dynamic_linker = null, .modules = .empty, .opts = .{ .is_test = switch (arg_mode) { @@ -1179,6 +1180,7 @@ fn buildOutputType( &cc_argv, &target_arch_os_abi, &target_mcpu, + &dynamic_linker, &deps, &c_source_files_owner_index, &rc_source_files_owner_index, @@ -1397,9 +1399,9 @@ fn buildOutputType( } else if (mem.cutPrefix(u8, arg, "-O")) |rest| { mod_opts.optimize_mode = parseOptimizeMode(rest); } else if (mem.eql(u8, arg, "--dynamic-linker")) { - create_module.dynamic_linker = args_iter.nextOrFatal(); + dynamic_linker = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--no-dynamic-linker")) { - create_module.dynamic_linker = ""; + dynamic_linker = ""; } else if (mem.eql(u8, arg, "--sysroot")) { const next_arg = args_iter.nextOrFatal(); create_module.sysroot = next_arg; @@ -1438,8 +1440,8 @@ fn buildOutputType( dev.check(.stdio_listen); listen = .stdio; } else if (mem.eql(u8, arg, "--debug-link-snapshot")) { - if (!build_options.enable_link_snapshots) { - warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{}); + if (!build_options.enable_debug_extensions) { + warn("Zig was compiled without debug extensions. --debug-link-snapshot has no effect.", .{}); } else { enable_link_snapshots = true; } @@ -1846,7 +1848,7 @@ fn buildOutputType( const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest; if (mem.eql(u8, lang, "none")) { file_ext = null; - } else if (Compilation.LangToExt.get(lang)) |got_ext| { + } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| { file_ext = got_ext; } else { fatal("language not recognized: {s}", .{lang}); @@ -1983,7 +1985,7 @@ fn buildOutputType( const lang = mem.sliceTo(it.only_arg, 0); if (mem.eql(u8, lang, "none")) { file_ext = null; - } else if (Compilation.LangToExt.get(lang)) |got_ext| { + } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| { file_ext = got_ext; } else { fatal("language not recognized: {q}", .{lang}); @@ -2610,12 +2612,11 @@ fn buildOutputType( mem.eql(u8, arg, "--dynamic-linker") or mem.eql(u8, arg, "-dynamic-linker")) { - create_module.dynamic_linker = linker_args_it.nextOrFatal(); - } else if (mem.eql(u8, arg, "-I") or - mem.eql(u8, arg, "--no-dynamic-linker") or + dynamic_linker = linker_args_it.nextOrFatal(); + } else if (mem.eql(u8, arg, "--no-dynamic-linker") or mem.eql(u8, arg, "-no-dynamic-linker")) { - create_module.dynamic_linker = ""; + dynamic_linker = ""; } else if (mem.eql(u8, arg, "-E") or mem.eql(u8, arg, "--export-dynamic") or mem.eql(u8, arg, "-export-dynamic")) @@ -3184,6 +3185,7 @@ fn buildOutputType( .inherited = mod_opts, .target_arch_os_abi = target_arch_os_abi, .target_mcpu = target_mcpu, + .dynamic_linker = dynamic_linker, .deps = try deps.toOwnedSlice(arena), .resolved = null, .c_source_files_start = c_source_files_owner_index, @@ -3592,7 +3594,7 @@ fn buildOutputType( defer file_system_inputs.deinit(gpa); // Deduplicate rpath entries - var rpath_dedup = std.StringArrayHashMapUnmanaged(void){}; + var rpath_dedup = std.array_hash_map.String(void){}; for (create_module.rpath_list.items) |rpath| { try rpath_dedup.put(arena, rpath, {}); } @@ -3842,10 +3844,59 @@ fn buildOutputType( if (test_exec_args.items.len == 0 and target.ofmt == .c and emit_bin_resolved != .no) { // Default to using `zig run` to execute the produced .c code from `zig test`. try test_exec_args.appendSlice(arena, &.{ self_exe_path, "run" }); - if (dirs.zig_lib.path) |p| { - try test_exec_args.appendSlice(arena, &.{ "-I", p }); + // Skip passing `-ofmt`, we want the default for the target, not `.c` anymore. + + 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; + } + 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; + if (prev_has_cflags or cflags_len > 0) { + try test_exec_args.ensureUnusedCapacity(arena, 1 + cflags_len + 1); + test_exec_args.appendAssumeCapacity("-cflags"); + for (c_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); + for (c_source_file.cache_exempt_flags) |cache_exempt_flag| test_exec_args.appendAssumeCapacity(cache_exempt_flag); + test_exec_args.appendAssumeCapacity("--"); + } + prev_has_cflags = cflags_len > 0; + if (c_source_file.ext) |ext| try test_exec_args.appendSlice(arena, &.{ "-x", ext.toLang() }); + try test_exec_args.append(arena, c_source_file.src_path); + if (c_source_file.ext) |_| try test_exec_args.appendSlice(arena, &.{ "-x", "none" }); + } + for (create_module.rc_source_files.items[mod.rc_source_files_start..mod.rc_source_files_end]) |rc_source_file| { + const rcflags_len = rc_source_file.extra_flags.len; + if (prev_has_rcflags or rcflags_len > 0) { + try test_exec_args.ensureUnusedCapacity(arena, 1 + rcflags_len + 1); + test_exec_args.appendAssumeCapacity("-rcflags"); + for (rc_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag); + test_exec_args.appendAssumeCapacity("--"); + } + prev_has_rcflags = rcflags_len > 0; + try test_exec_args.append(arena, rc_source_file.src_path); + } + if (mod.target_arch_os_abi) |triple| try test_exec_args.appendSlice(arena, &.{ "-target", triple }); + if (mod.target_mcpu) |mcpu| try test_exec_args.appendSlice(arena, &.{ "-mcpu", mcpu }); + if (mod.dynamic_linker) |dl| if (dl.len > 0) + try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }) + else + try test_exec_args.append(arena, "--no-dynamic-linker"); + try test_exec_args.ensureUnusedCapacity(arena, mod.cc_argv.len); + for (mod.cc_argv) |cc_arg| test_exec_args.appendAssumeCapacity(cc_arg); + for (mod.deps) |dep| try test_exec_args.appendSlice(arena, &.{ + "--dep", + if (std.mem.eql(u8, dep.key, dep.value)) dep.value else try std.fmt.allocPrint(arena, "{s}={s}", .{ dep.key, dep.value }), + }); + try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-M{s}", .{mod_name})); } + try test_exec_args.ensureUnusedCapacity(arena, comp.global_cc_argv.len); + for (comp.global_cc_argv) |global_cc_arg| test_exec_args.appendAssumeCapacity(global_cc_arg); + if (create_module.resolved_options.link_libcpp) try test_exec_args.append(arena, "-lc++"); if (create_module.resolved_options.link_libc) { try test_exec_args.append(arena, "-lc"); } else if (target.os.tag == .windows) { @@ -3855,21 +3906,10 @@ fn buildOutputType( }); } - const first_cli_mod = create_module.modules.values()[0]; - if (first_cli_mod.target_arch_os_abi) |triple| { - try test_exec_args.appendSlice(arena, &.{ "-target", triple }); - } - if (first_cli_mod.target_mcpu) |mcpu| { - try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu})); - } - if (create_module.dynamic_linker) |dl| { - if (dl.len > 0) { - try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }); - } else { - try test_exec_args.append(arena, "--no-dynamic-linker"); - } - } - try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file + try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); + for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); + if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); + if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc"); } try runOrTest( @@ -3896,9 +3936,8 @@ fn buildOutputType( const CreateModule = struct { dirs: Compilation.Directories, - modules: std.StringArrayHashMapUnmanaged(CliModule), + modules: std.array_hash_map.String(CliModule), opts: Compilation.Config.Options, - dynamic_linker: ?[]const u8, object_format: ?[]const u8, /// undefined until createModule() for the root module is called. resolved_options: Compilation.Config, @@ -3908,7 +3947,7 @@ const CreateModule = struct { /// link_libcpp, and then the libraries are filtered into /// `unresolved_link_inputs` and `windows_libs`. cli_link_inputs: std.ArrayList(link.UnresolvedInput), - windows_libs: std.StringArrayHashMapUnmanaged(void), + windows_libs: std.array_hash_map.String(void), /// The local variable `unresolved_link_inputs` is fed into library /// resolution, mutating the input array, and producing this data as /// output. Allocated with gpa. @@ -3926,7 +3965,7 @@ const CreateModule = struct { lib_dir_args: std.ArrayList([]const u8), libc_installation: ?LibCInstallation, want_native_include_dirs: bool, - frameworks: std.StringArrayHashMapUnmanaged(Framework), + frameworks: std.array_hash_map.String(Framework), native_system_include_paths: []const []const u8, framework_dirs: std.ArrayList([]const u8), rpath_list: std.ArrayList([]const u8), @@ -3960,7 +3999,7 @@ fn createModule( var target_parse_options: std.Target.Query.ParseOptions = .{ .arch_os_abi = cli_mod.target_arch_os_abi orelse "native", .cpu_features = cli_mod.target_mcpu, - .dynamic_linker = create_module.dynamic_linker, + .dynamic_linker = cli_mod.dynamic_linker, .object_format = create_module.object_format, }; @@ -4419,7 +4458,7 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void { var file_name_bytes: std.ArrayList(u8) = .empty; defer file_name_bytes.deinit(gpa); - var files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void) = .empty; + var files: std.array_hash_map.Auto(Zcu.File.Index, void) = .empty; defer files.deinit(gpa); var decl_data: std.ArrayList(u8) = .empty; defer decl_data.deinit(gpa); @@ -7844,6 +7883,7 @@ fn handleModArg( cc_argv: *std.ArrayList([]const u8), target_arch_os_abi: *?[]const u8, target_mcpu: *?[]const u8, + dynamic_linker: *?[]const u8, deps: *std.ArrayList(CliModule.Dep), c_source_files_owner_index: *usize, rc_source_files_owner_index: *usize, @@ -7892,6 +7932,7 @@ fn handleModArg( .inherited = mod_opts.*, .target_arch_os_abi = target_arch_os_abi.*, .target_mcpu = target_mcpu.*, + .dynamic_linker = dynamic_linker.*, .deps = try deps.toOwnedSlice(arena), .resolved = null, .c_source_files_start = c_source_files_owner_index.*, @@ -7903,6 +7944,7 @@ fn handleModArg( mod_opts.* = .{}; target_arch_os_abi.* = null; target_mcpu.* = null; + dynamic_linker.* = null; c_source_files_owner_index.* = create_module.c_source_files.items.len; rc_source_files_owner_index.* = create_module.rc_source_files.items.len; } diff --git a/src/print_value.zig b/src/print_value.zig index be363a76b707723432ad01c7d8955d5d64459bbe..54d81d50d26abba08d8bde2d60820c8b652f02f9 100644 --- a/src/print_value.zig +++ b/src/print_value.zig @@ -60,6 +60,7 @@ pub fn print( .union_type, .opaque_type, .enum_type, + .spirv_type, .func_type, .error_set_type, .inferred_error_set_type, diff --git a/src/print_zir.zig b/src/print_zir.zig index 596c6d504091089638d35af7901f45091227ad9c..64703fbd60052209854fc733570fa008ec5b201e 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -204,6 +204,8 @@ const Writer = struct { .ensure_result_used, .ensure_result_non_error, .ensure_err_union_payload_void, + .deref, + .ref_deref, .ret_node, .ret_load, .resolve_inferred_alloc, @@ -260,7 +262,6 @@ const Writer = struct { .bit_reverse, .@"resume", .make_ptr_const, - .validate_deref, .validate_const, .check_comptime_control_flow, .opt_eu_base_ptr_init, @@ -685,6 +686,16 @@ const Writer = struct { defer self.parent_decl_node = prev_parent_decl_node; try self.writeSrcNode(stream, .zero); }, + .reify_spirv_type => { + const extra = self.code.extraData(Zir.Inst.ReifySpirvType, extended.operand).data; + try stream.print("line({d}), ", .{extra.src_line}); + try self.writeInstRef(stream, extra.operand); + try stream.writeAll(")) "); + const prev_parent_decl_node = self.parent_decl_node; + self.parent_decl_node = extra.node; + defer self.parent_decl_node = prev_parent_decl_node; + try self.writeSrcNode(stream, .zero); + }, .cmpxchg => try self.writeCmpxchg(stream, extended), .ptr_cast_full => try self.writePtrCastFull(stream, extended), diff --git a/src/target.zig b/src/target.zig index 997dbb89453bf30bcbc5cb172000684c27d75ba6..200591c68ebae9abba03633ec3ece7fbc88906bf 100644 --- a/src/target.zig +++ b/src/target.zig @@ -164,7 +164,10 @@ pub fn hasValgrindSupport(target: *const std.Target, backend: std.lang.CompilerB else => false, }, .x86_64 => switch (target.os.tag) { - .linux => target.abi != .gnux32 and target.abi != .muslx32, + .linux => switch (target.abi) { + .gnux32, .muslx32, .x32 => false, + else => true, + }, .freebsd, .illumos => true, .windows => !ofmt_c_msvc, else => false, @@ -700,7 +703,7 @@ pub fn llvmMachineAbi(target: *const std.Target) ?[:0]const u8 { }, .mips, .mipsel => "o32", .mips64, .mips64el => switch (target.abi) { - .gnuabin32, .muslabin32 => "n32", + .gnuabin32, .muslabin32, .abin32 => "n32", else => "n64", }, .powerpc64 => if (target.os.tag == .ps3) "elfv1" else "elfv2", @@ -950,9 +953,6 @@ pub inline fn backendSupportsFeature(backend: std.lang.CompilerBackend, comptime // threads because they would all just be locking the same mutex to // protect Builder. .stage2_llvm => false, - // Same problem. Frontend needs to allow this backend to run in the - // linker thread. - .stage2_spirv => false, // Please do not make any more exceptions. Backends must support // being run in a separate thread from now on. else => true, diff --git a/stage1/zig.h b/stage1/zig.h index f2faed0b376201db96a464f6c1394f2fc26f8aa8..34b56286a508b2707f4498f49612d9d625ee7c86 100644 --- a/stage1/zig.h +++ b/stage1/zig.h @@ -11,8 +11,6 @@ #elif defined(__GNUC__) #define zig_gcc #define zig_gnuc -#elif defined(__IBMC__) -#define zig_xlc #elif defined(__TINYC__) #define zig_tinyc #elif defined(__slimcc__) @@ -28,8 +26,18 @@ #define zig_arm #elif defined(__arm__) #define zig_arm +#elif defined(__arc__) +#define zig_arc +#elif defined(__csky__) +#define zig_csky #elif defined(__hexagon__) #define zig_hexagon +#elif defined(__hppa__) && defined(_LP64) +#define zig_hppa64 +#define zig_hppa +#elif defined(__hppa__) +#define zig_hppa32 +#define zig_hppa #elif defined(__kvx__) #define zig_kvx #elif defined(__loongarch32) @@ -42,6 +50,8 @@ #define zig_m68k #elif defined(__m88k__) #define zig_m88k +#elif defined(__microblaze__) +#define zig_microblaze #elif defined(__mips64) #define zig_mips64 #define zig_mips @@ -64,6 +74,8 @@ #define zig_riscv #elif defined(__s390x__) #define zig_s390x +#elif defined(__sh__) +#define zig_sh #elif defined(__sparc__) && defined(__arch64__) #define zig_sparc64 #define zig_sparc @@ -100,32 +112,30 @@ #define zig_big_endian 1 #endif -#if defined(__MACH__) +#if defined(__APPLE__) #define zig_darwin #elif defined(__DragonFly__) #define zig_dragonfly -#define zig_bsd #elif defined(__EMSCRIPTEN__) #define zig_emscripten #elif defined(__FreeBSD__) #define zig_freebsd -#define zig_bsd #elif defined(__Fuchsia__) #define zig_fuchsia #elif defined(__HAIKU__) #define zig_haiku #elif defined(__gnu_hurd__) #define zig_hurd +#elif defined(__illumos__) +#define zig_illumos #elif defined(__linux__) #define zig_linux #elif defined(__NetBSD__) #define zig_netbsd -#define zig_bsd #elif defined(__OpenBSD__) #define zig_openbsd -#define zig_bsd -#elif defined(__SVR4) -#define zig_solaris +#elif defined(__serenity__) +#define zig_serenity #elif defined(__wasi__) #define zig_wasi #elif defined(_WIN32) @@ -404,14 +414,22 @@ #define zig_trap() __asm__ volatile("udf #0xfe") #elif defined(zig_arm) || defined(zig_aarch64) #define zig_trap() __asm__ volatile("udf #0xfdee") +#elif defined(zig_arc) +#define zig_trap() __asm__ volatile("unimp_s") +#elif defined(zig_csky) +#define zig_trap() __asm__ volatile(".word 0x3fff") #elif defined(zig_hexagon) #define zig_trap() __asm__ volatile("r27:26 = memd(#0xbadc0fee)") +#elif defined(zig_hppa) +#define zig_trap() __asm__ volatile("iitlbp %r0, (%sr0, %r0)") #elif defined(zig_kvx) || defined(zig_loongarch) || defined(zig_powerpc) #define zig_trap() __asm__ volatile(".word 0x0") #elif defined(zig_m68k) #define zig_trap() __asm__ volatile("illegal") #elif defined(zig_m88k) #define zig_trap() __asm__ volatile("tb0 0, %%r0, 511") +#elif defined(zig_microblaze) +#define zig_trap() __asm__ volatile("getd r0, r0") #elif defined(zig_mips) #define zig_trap() __asm__ volatile(".word 0x3d") #elif defined(zig_or1k) @@ -420,6 +438,8 @@ #define zig_trap() __asm__ volatile("unimp") #elif defined(zig_s390x) #define zig_trap() __asm__ volatile("j 0x2") +#elif defined(zig_sh) +#define zig_trap() __asm__ volatile(".word 0x0001") #elif defined(zig_sparc) #define zig_trap() __asm__ volatile("illtrap") #elif defined(zig_x86_16) @@ -446,16 +466,22 @@ #if defined(zig_alpha) #define zig_breakpoint() __asm__ volatile("call_pal 0x000080") -#elif defined(zig_arm) +#elif defined(zig_arm) || defined(zig_csky) #define zig_breakpoint() __asm__ volatile("bkpt #0x0") #elif defined(zig_aarch64) #define zig_breakpoint() __asm__ volatile("brk #0xf000") +#elif defined(zig_arc) +#define zig_breakpoint() __asm__ volatile("brk_s") #elif defined(zig_hexagon) #define zig_breakpoint() __asm__ volatile("brkpt") +#elif defined(zig_hppa) +#define zig_breakpoint() __asm__ volatile("break 0x04, 0x0008") #elif defined(zig_kvx) || defined(zig_loongarch) #define zig_breakpoint() __asm__ volatile("break 0x0") #elif defined(zig_m88k) #define zig_breakpoint() __asm__ volatile("illop1") +#elif defined(zig_microblaze) +#define zig_breakpoint() __asm__ volatile("brki r16, 0x0018") #elif defined(zig_mips) #define zig_breakpoint() __asm__ volatile("break") #elif defined(zig_or1k) @@ -466,6 +492,8 @@ #define zig_breakpoint() __asm__ volatile("ebreak") #elif defined(zig_s390x) #define zig_breakpoint() __asm__ volatile("j 0x6") +#elif defined(zig_sh) +#define zig_breakpoint() __asm__ volatile("trapa #0xc3") #elif defined(zig_sparc) #define zig_breakpoint() __asm__ volatile("ta 0x1") #elif defined(zig_x86) @@ -4529,9 +4557,12 @@ static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 a #include #endif +static inline void* zig_e_zig_windows_teb(void) zig_mangled(zig_e_zig_windows_teb, "zig_windows_teb"); +static inline void* zig_e_zig_windows_peb(void) zig_mangled(zig_e_zig_windows_peb, "zig_windows_peb"); + #if defined(zig_thumb) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); @@ -4543,7 +4574,7 @@ static inline void* zig_windows_teb(void) { #elif defined(zig_aarch64) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readx18qword(0x0); @@ -4555,7 +4586,7 @@ static inline void* zig_windows_teb(void) { #elif defined(zig_x86_32) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readfsdword(0x18); @@ -4565,7 +4596,7 @@ static inline void* zig_windows_teb(void) { return teb; } -static inline void* zig_windows_peb(void) { +static inline void* zig_e_zig_windows_peb(void) { void* peb = 0; #if defined(zig_msvc) peb = (void*)__readfsdword(0x30); @@ -4577,7 +4608,7 @@ static inline void* zig_windows_peb(void) { #elif defined(zig_x86_64) -static inline void* zig_windows_teb(void) { +static inline void* zig_e_zig_windows_teb(void) { void* teb = 0; #if defined(zig_msvc) teb = (void*)__readgsqword(0x30); @@ -4587,7 +4618,7 @@ static inline void* zig_windows_teb(void) { return teb; } -static inline void* zig_windows_peb(void) { +static inline void* zig_e_zig_windows_peb(void) { void* peb = 0; #if defined(zig_msvc) peb = (void*)__readgsqword(0x60); @@ -4601,7 +4632,9 @@ static inline void* zig_windows_peb(void) { #if defined(zig_loongarch) -static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { +static inline void zig_e_zig_loongarch_cpucfg(uint32_t word, uint32_t* result) zig_mangled(zig_e_zig_loongarch_cpucfg, "zig_loongarch_cpucfg"); + +static inline void zig_e_zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { #if defined(zig_gnuc_asm) __asm__("cpucfg %[result], %[word]" : [result] "=r" (result) : [word] "r" (word)); #else @@ -4611,7 +4644,10 @@ static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) { #elif defined(zig_x86) && !defined(zig_x86_16) -static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { +static inline void zig_e_zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) zig_mangled(zig_e_zig_x86_cpuid, "zig_x86_cpuid"); +static inline uint32_t zig_e_zig_x86_get_xcr0(void) zig_mangled(zig_e_zig_x86_get_xcr0, "zig_x86_get_xcr0"); + +static inline void zig_e_zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { #if defined(zig_msvc) int cpu_info[4]; __cpuidex(cpu_info, leaf_id, subid); @@ -4629,7 +4665,7 @@ static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax #endif } -static inline uint32_t zig_x86_get_xcr0(void) { +static inline uint32_t zig_e_zig_x86_get_xcr0(void) { #if defined(zig_msvc) return (uint32_t)_xgetbv(0); #elif defined(zig_gnuc_asm) diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm index 10afc539bc2588e4bc10cb6f074094a403f80e1d..1a985c43006c7abfd1e82ead3ac9b656a5b753ab 100644 Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ diff --git a/test/behavior.zig b/test/behavior.zig index c9c06e934230692c95d07b96d911fb09a80d3bdf..32be1951bcd7359632884683ca6b2108bd18a717 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -112,6 +112,10 @@ test { _ = @import("behavior/wasm.zig"); } + if (builtin.zig_backend == .stage2_spirv) { + _ = @import("behavior/spirv.zig"); + } + if (builtin.zig_backend != .stage2_spirv and builtin.os.tag != .wasi) { _ = @import("behavior/asm.zig"); } diff --git a/test/behavior/abs.zig b/test/behavior/abs.zig index 55c7ebf6a7b0704fa88c83e7afec14584eb00d55..895f9bbf8d956e61bdf5455084cd4d58ebd2b1e9 100644 --- a/test/behavior/abs.zig +++ b/test/behavior/abs.zig @@ -7,7 +7,6 @@ test "@abs integers" { 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; try comptime testAbsIntegers(); try testAbsIntegers(); @@ -145,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_spirv) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try comptime testAbsSignedBigInt(); diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 3de3dd090670331c27e4856e90246483546a2432..06c12eaea14622bbeaaa0aa85cede2fda9feb504 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -7,6 +7,8 @@ const assert = std.debug.assert; var foo: u8 align(4) = 100; test "global variable alignment" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + comptime assert(@typeInfo(@TypeOf(&foo)).pointer.attrs.@"align" == 4); comptime assert(@TypeOf(&foo) == *align(4) u8); { @@ -16,6 +18,8 @@ test "global variable alignment" { } test "large abi alignment of global" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { var global: @This() = undefined; x: u64 align(64), @@ -51,6 +55,8 @@ test "slicing array of length 1 can not assume runtime index is always zero" { } test "implicitly-aligned pointer is coercible to equivalent explicitly-aligned pointer" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const A = *u32; const B = *align(@alignOf(u32)) u32; @@ -83,6 +89,8 @@ test "implicitly-aligned pointer is coercible to equivalent explicitly-aligned p } test "implicitly decreasing pointer alignment" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const a: u32 align(4) = 3; const b: u32 align(8) = 4; try expect(addUnaligned(&a, &b) == 7); @@ -93,8 +101,6 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 { } test "@alignCast pointers" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - var x: u32 align(4) = 1; expectsOnly1(&x); try expect(x == 2); @@ -125,6 +131,20 @@ test "alignment and size of structs with 128-bit fields" { y: u8, }; const expected = switch (builtin.cpu.arch) { + .s390x, + => .{ + .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, @@ -137,7 +157,6 @@ test "alignment and size of structs with 128-bit fields" { .powerpc, .powerpcle, .riscv32, - .s390x, => .{ .a_align = 8, .a_size = 16, @@ -183,7 +202,7 @@ test "alignment and size of structs with 128-bit fields" { else => return error.SkipZigTest, }; - const min_struct_align = if (builtin.zig_backend == .stage2_c) 16 else 0; + 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(@sizeOf(A) == expected.a_size); @@ -202,7 +221,6 @@ test "alignment and size of structs with 128-bit fields" { test "implicitly decreasing slice alignment" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const a: u32 align(4) = 3; const b: u32 align(8) = 4; try expect(addUnalignedSlice(@as(*const [1]u32, &a)[0..], @as(*const [1]u32, &b)[0..]) == 7); @@ -244,8 +262,6 @@ test "return error union with 128-bit integer" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO 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; - try expect(3 == try give()); } fn give() anyerror!u128 { @@ -257,7 +273,6 @@ test "page aligned array on stack" { 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; - // Large alignment value to make it hard to accidentally pass. var array align(0x1000) = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; var number1: u8 align(16) = 42; @@ -616,3 +631,30 @@ test "function pointer align mask" { const aligned: *align(16) const fn () callconv(.c) void = @alignCast(unaligned); try expect(@intFromPtr(aligned) == int); } + +test "align expression is implicitly comptime" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = struct { + fn alignment() usize { + return 4; + } + + var global: [3]u8 align(alignment()) = @splat(0); + fn check() !void { + try std.testing.expect(@intFromPtr(&global) % alignment() == 0); + var local: [3]u8 align(alignment()) = @splat(0); + try std.testing.expect(@intFromPtr(&local) % alignment() == 0); + var de: [3]u8 align(alignment()), var structure: [3]u8 align(alignment()) = .{ @splat(0), @splat(0) }; + try std.testing.expect(@intFromPtr(&de) % alignment() == 0); + try std.testing.expect(@intFromPtr(&structure) % alignment() == 0); + var @"struct": struct { field: [3]u8 align(alignment()) } = .{ .field = @splat(0) }; + try std.testing.expect(@intFromPtr(&@"struct".field) % alignment() == 0); + var @"union": union { field: [3]u8 align(alignment()) } = .{ .field = @splat(0) }; + try std.testing.expect(@intFromPtr(&@"union".field) % alignment() == 0); + const ptr: *align(alignment()) [3]u8 = &global; + try std.testing.expect(@intFromPtr(ptr) % alignment() == 0); + } + }; + try S.check(); +} diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 04e014b5157ef2e15bfc3ae10ff10c4d5e2f9c32..f7e179034a9a2f16807a6682f8ee7f1f50ba97e8 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -7,6 +7,7 @@ const expect = testing.expect; const expectEqual = testing.expectEqual; test "array to slice" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const a: u32 align(4) = 3; const b: u32 align(8) = 4; const a_slice: []align(1) const u32 = @as(*const [1]u32, &a)[0..]; @@ -21,7 +22,6 @@ test "array to slice" { test "arrays" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - var array: [5]u32 = undefined; var i: u32 = 0; @@ -49,7 +49,6 @@ test "runtime array concat with comptime slice" { 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; - var a: [1]u8 = .{1}; const b = (comptime @as([]const u8, &.{0})) ++ &a; const c = &a ++ (comptime @as([]const u8, &.{0})); @@ -96,6 +95,24 @@ test "array concat with tuple" { } } +test "array concat with undefined tuple" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + { + const array: [2]u64 = .{ 1, 2 }; + var seq = array ++ @as(struct { u32, u16 }, undefined); + seq[2] = 3; + seq[3] = 4; + try std.testing.expectEqualSlices(u64, &.{ 1, 2, 3, 4 }, &seq); + } + { + const array: [2]u64 = undefined; + var seq = @as(struct { u32, u16 }, undefined) ++ array; + for (&seq, 1..) |*s, i| s.* = i; + try std.testing.expectEqualSlices(u64, &.{ 1, 2, 3, 4 }, &seq); + } +} + test "array init with concat" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -259,6 +276,7 @@ fn doSomeMangling(array: *[4]u8) void { test "implicit cast zero sized array ptr to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; { var b = "".*; @@ -636,6 +654,8 @@ test "array of array agregate init" { } test "pointer to array has ptr field" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const arr: *const [5]u32 = &.{ 10, 20, 30, 40, 50 }; try std.testing.expect(arr.ptr == @as([*]const u32, arr)); try std.testing.expect(arr.ptr[0] == 10); @@ -969,6 +989,7 @@ test "runtime index of array of zero-bit values" { } test "@splat array" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1036,11 +1057,15 @@ test "@splat zero-length array" { } test "initialize slice with reference to empty array initializer" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const a: []const u8 = &.{}; comptime assert(a.len == 0); } test "initialize many-pointer with reference to empty array initializer" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const a: [*]const u8 = &.{}; _ = a; // nothing meaningful to test; points to zero bits } @@ -1052,6 +1077,7 @@ test "initialize sentinel-terminated slice with reference to empty array initial } test "initialize sentinel-terminated many-pointer with reference to empty array initializer" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const a: [*:0]const u8 = &.{}; comptime assert(a[0] == 0); } @@ -1124,3 +1150,30 @@ test "resist alias of explicit copy of array passed as arg" { try expect(buf_b[0] == 1234); } + +test "access element through reference" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = struct { + fn doTheTest(x: u8) !void { + { + var val: [1]u8 = .{x}; + const single_ptr: *[1]u8 = &val; + try expect(single_ptr.*[0] == x); + const elem_ptr = &single_ptr.*[0]; + comptime assert(@TypeOf(elem_ptr) == *u8); + try expect(elem_ptr.* == x); + } + { + var val: [1]u8 = .{x}; + const c_ptr: [*c][1]u8 = &val; + try expect(c_ptr.*[0] == x); + const elem_ptr = &c_ptr.*[0]; + comptime assert(@TypeOf(elem_ptr) == *u8); + try expect(elem_ptr.* == x); + } + } + }; + try comptime S.doTheTest(123); + try S.doTheTest(123); +} diff --git a/test/behavior/asm.zig b/test/behavior/asm.zig index 8d7f3bcbca2566d2669a577a958a720d21d0d83b..ac2178044584884d536295a336765e21517c4e6f 100644 --- a/test/behavior/asm.zig +++ b/test/behavior/asm.zig @@ -82,7 +82,6 @@ test "sized integer/float in asm input" { 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly @@ -210,42 +209,6 @@ test "packed output types (x86_64)" { } } -test "extern output types (x86_64)" { - if (builtin.target.cpu.arch != .x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly - if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/31531 - - const S = extern struct { x: u32 }; - { - const s: S = asm volatile ("mov $123, %[ret]" - : [ret] "=r" (-> S), - ); - try expect(s.x == 123); - } - { - var s: S = undefined; - asm volatile ("mov $123, %[ret]" - : [ret] "=r" (s), - ); - try expect(s.x == 123); - } - - const U = extern union { x: u32 }; - { - const u: U = asm volatile ("mov $123, %[ret]" - : [ret] "=r" (-> U), - ); - try expect(u.x == 123); - } - { - var u: U = undefined; - asm volatile ("mov $123, %[ret]" - : [ret] "=r" (u), - ); - try expect(u.x == 123); - } -} - test "abi register aliases as clobbers (RISC-V)" { if (!builtin.target.cpu.arch.isRISCV()) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index a8580904c5be15e8409eafaeac007ba38d00da75..e53a4c818fb7e1a911a6ecee4e171ba67b37cfe2 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -358,7 +358,6 @@ test "atomics with different types" { 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; - if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // #24282 try testAtomicsWithType(bool, true, false); diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 2c5e6ab9a9c65ca28d72d60b32c0f100e9a4824b..16fdfc8c15cbd9f5e9ad3cc11d72461092cf839c 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -24,7 +24,6 @@ fn testTruncate(x: u32) u8 { } test "truncate to non-power-of-two integers" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try testTrunc(u32, u1, 0b10101, 0b1); @@ -41,7 +40,6 @@ test "truncate to non-power-of-two integers" { test "truncate to non-power-of-two integers from 128-bit" { 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; try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010101, 0x01); try testTrunc(u128, u1, 0xffffffff_ffffffff_ffffffff_01010110, 0x00); @@ -299,7 +297,6 @@ const global_b: *const i32 = &global_a; const global_c: *const f32 = @as(*const f32, @ptrCast(global_b)); test "compile time global reinterpret" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const d = @as(*const i32, @ptrCast(global_c)); try expect(d.* == 1234); } @@ -376,7 +373,6 @@ fn fB() []const u8 { test "call function pointer in struct" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - try expect(mem.eql(u8, f3(true), "a")); try expect(mem.eql(u8, f3(false), "b")); } @@ -640,6 +636,7 @@ fn emptyFn() void {} const addr1 = @as(*const u8, @ptrCast(&emptyFn)); test "comptime cast fn to ptr" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const addr2 = @as(*const u8, @ptrCast(&emptyFn)); comptime assert(addr1 == addr2); } @@ -918,6 +915,7 @@ test "labeled block with runtime branch forwards its result location type to bre test "try in labeled block doesn't cast to wrong type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { a: u32, @@ -1142,7 +1140,7 @@ test "arrays and vectors with big integers" { if (builtin.zig_backend == .stage2_arm) 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.abi == .gnuabin32 or builtin.abi == .muslabin32)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23805 + if (builtin.zig_backend == .stage2_llvm and (builtin.abi == .gnuabin32 or builtin.abi == .muslabin32 or builtin.abi == .abin32)) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/23805 inline for (.{ u65528, u65529, u65535 }) |Int| { var a: [1]Int = undefined; @@ -1214,8 +1212,6 @@ fn testUnsignedCmp(comptime T: type) !void { } test "integer compare <= 64 bits" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - inline for (.{ u8, u16, u32, u64, usize, u10, u20, u30, u60 }) |T| { try testUnsignedCmp(T); try comptime testUnsignedCmp(T); @@ -1228,7 +1224,6 @@ test "integer compare <= 64 bits" { test "integer compare <= 128 bits" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; inline for (.{ u65, u96, u127, u128 }) |T| { try testUnsignedCmp(T); @@ -1242,7 +1237,6 @@ test "integer compare <= 128 bits" { test "integer compare > 128 bits" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; inline for (.{ u129, u255, u512, u800 }) |T| { try testUnsignedCmp(T); @@ -1278,6 +1272,7 @@ test "@Int returned from block" { } test "comptime variable initialized with addresses of literals" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; comptime var st = .{ .foo = &1, .bar = &2, @@ -1327,6 +1322,8 @@ test "proper value is returned from labeled block" { } test "const inferred array of slices" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const T = struct { v: bool }; const decls = [_][]const T{ @@ -1339,6 +1336,7 @@ test "const inferred array of slices" { test "var inferred array of slices" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const T = struct { v: bool }; @@ -1437,3 +1435,14 @@ test "loading array from struct is not optimized away" { var s = S{}; try s.doTheTest(); } + +test "local variable name begins with primitive integer type" { + const u032_ = 123; + comptime assert(u032_ == 123); + + const u0_ = 456; + comptime assert(u0_ == 456); + + const i0_ = 789; + comptime assert(i0_ == 789); +} diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index 28b45428d6b111a327561769781d5c045f49e17e..3b77d2c6023256829590cc98d9b8c217e6bbe660 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -23,8 +23,6 @@ test "@bitCast iX -> uX (8, 16, 128)" { if (builtin.zig_backend == .stage2_arm) 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_spirv) return error.SkipZigTest; - const bit_values = [_]usize{ 8, 16, 128 }; inline for (bit_values) |bits| { @@ -37,7 +35,6 @@ test "@bitCast iX -> uX exotic integers" { if (builtin.zig_backend == .stage2_aarch64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 }; @@ -77,55 +74,6 @@ fn conv_uN(comptime N: usize, x: @Int(.unsigned, N)) @Int(.signed, N) { return @as(@Int(.signed, N), @bitCast(x)); } -test "bitcast uX to bytes" { - if (builtin.zig_backend == .stage2_aarch64) 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; - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - - const bit_values = [_]usize{ 1, 48, 27, 512, 493, 293, 125, 204, 112 }; - inline for (bit_values) |bits| { - try testBitCast(bits); - try comptime testBitCast(bits); - } -} - -fn testBitCastuXToBytes(comptime N: usize) !void { - - // The location of padding bits in these layouts are technically not defined - // by LLVM, but we currently allow exotic integers to be cast (at comptime) - // to types that expose their padding bits anyway. - // - // This test at least makes sure those bits are matched by the runtime behavior - // on the platforms we target. If the above behavior is restricted after all, - // this test should be deleted. - - const T = @Int(.unsigned, N); - for ([_]T{ 0, ~@as(T, 0) }) |init_value| { - var x: T = init_value; - const bytes = std.mem.asBytes(&x); - - const byte_count = (N + 7) / 8; - switch (native_endian) { - .little => { - var byte_i = 0; - while (byte_i < (byte_count - 1)) : (byte_i += 1) { - try expect(bytes[byte_i] == 0xff); - } - try expect(((bytes[byte_i] ^ 0xff) << -%@as(u3, @truncate(N))) == 0); - }, - .big => { - var byte_i = byte_count - 1; - while (byte_i > 0) : (byte_i -= 1) { - try expect(bytes[byte_i] == 0xff); - } - try expect(((bytes[byte_i] ^ 0xff) << -%@as(u3, @truncate(N))) == 0); - }, - } - } -} - test "nested bitcast" { const S = struct { fn moo(x: isize) !void { @@ -162,6 +110,7 @@ test "@bitCast packed structs at runtime and comptime" { if (builtin.zig_backend == .stage2_aarch64) 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; const Full = packed struct { number: u16, @@ -185,43 +134,11 @@ test "@bitCast packed structs at runtime and comptime" { try comptime S.doTheTest(); } -test "@bitCast extern structs at runtime and comptime" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - - const Full = extern struct { - number: u16, - }; - const TwoHalves = extern struct { - half1: u8, - half2: u8, - }; - const S = struct { - fn doTheTest() !void { - var full = Full{ .number = 0x1234 }; - _ = &full; - const two_halves: TwoHalves = @bitCast(full); - switch (native_endian) { - .big => { - try expect(two_halves.half1 == 0x12); - try expect(two_halves.half2 == 0x34); - }, - .little => { - try expect(two_halves.half1 == 0x34); - try expect(two_halves.half2 == 0x12); - }, - } - } - }; - try S.doTheTest(); - try comptime S.doTheTest(); -} - test "bitcast packed struct to integer and back" { if (builtin.zig_backend == .stage2_aarch64) 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; const LevelUpMove = packed struct { move_id: u9, @@ -364,32 +281,12 @@ test "comptime @bitCast packed struct to int and back" { } } -test "comptime bitcast with fields following f80" { - if (true) { - // https://github.com/ziglang/zig/issues/19387 - return error.SkipZigTest; - } - - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - - const FloatT = extern struct { f: f80, x: u128 align(16) }; - const x: FloatT = .{ .f = 0.5, .x = 123 }; - var x_as_uint: u256 = comptime @as(u256, @bitCast(x)); - _ = &x_as_uint; - - try expect(x.f == @as(FloatT, @bitCast(x_as_uint)).f); - try expect(x.x == @as(FloatT, @bitCast(x_as_uint)).x); -} - 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; - if (builtin.cpu.arch.endian() == .big and builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; var vec: @Vector(16, bool) = @splat(true); vec[1] = false; @@ -525,73 +422,6 @@ test "@bitCast of packed struct of bools all false" { try expect(@as(u8, @as(u4, @bitCast(p))) == 0); } -test "@bitCast of extern struct containing pointer" { - 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 S = struct { - const A = extern struct { - ptr: *const u32, - }; - - const B = extern struct { - ptr: *const i32, - }; - - fn doTheTest() !void { - const x: u32 = 123; - var a: A = undefined; - a = .{ .ptr = &x }; - const b: B = @bitCast(a); - try expect(b.ptr.* == 123); - } - }; - - try S.doTheTest(); - try comptime S.doTheTest(); -} - -test "@bitCast of extern struct to float" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - - const S = struct { - const S = extern struct { - x: u16, - y: u16, - }; - fn doTheTest() !void { - var s: S = .{ .x = 0, .y = 0 }; - _ = &s; - const a: f32 = @bitCast(s); - try expect(a == 0); - } - }; - - try S.doTheTest(); - try comptime S.doTheTest(); -} - -test "@bitCast of float to extern struct" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - - const S = struct { - const S = extern struct { - x: u32, - }; - fn doTheTest() !void { - var a: f32 = -0.0; - _ = &a; - const s: S = @bitCast(a); - try expect(s.x == 0x80000000); - } - }; - - try S.doTheTest(); - try comptime S.doTheTest(); -} - test "@bitCast of packed struct with void field to integer" { const S = packed struct(u8) { v: void, @@ -607,3 +437,158 @@ test "@bitCast of packed struct with void field to integer" { try S.doTheTest(123); try comptime S.doTheTest(123); } + +test "@bitCast vector to array with different element size" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const static = struct { + fn doTheTest(v: @Vector(4, u5)) !void { + const result: [5]u4 = @bitCast(v); + // See the definition of `v` in the test proper for these values. + try expect(result[0] == 0b0010); + try expect(result[1] == 0b1110); + try expect(result[2] == 0b0101); + try expect(result[3] == 0b0110); + try expect(result[4] == 0b0000); + } + }; + // The strange digit groupings here are to indicate how this maps to `expected` above. + const v: @Vector(4, u5) = .{ + 0b0_0010, + 0b01_111, + 0b110_01, + 0b0000_0, + }; + try static.doTheTest(v); + try comptime static.doTheTest(v); +} + +test "@bitCast packed struct to array of bits" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = packed struct(u16) { + foo: u5, + bar: i7, + baz: u3, + qux: bool, + fn doTheTest(val: @This(), comptime Bits: type) !void { + const bits: Bits = @bitCast(val); + + // foo + try expect(bits[0] == 1); + try expect(bits[1] == 0); + try expect(bits[2] == 0); + try expect(bits[3] == 1); + try expect(bits[4] == 0); + // bar + try expect(bits[5] == 0); + try expect(bits[6] == 1); + try expect(bits[7] == 1); + try expect(bits[8] == 1); + try expect(bits[9] == 1); + try expect(bits[10] == 1); + try expect(bits[11] == 1); + // baz + try expect(bits[12] == 0); + try expect(bits[13] == 1); + try expect(bits[14] == 0); + // qux + try expect(bits[15] == 1); + } + }; + + const val: S = .{ + .foo = 0b01001, + .bar = -2, + .baz = 0b010, + .qux = true, + }; + + try val.doTheTest(@Vector(16, u1)); + try val.doTheTest([16]u1); + + try comptime val.doTheTest(@Vector(16, u1)); + try comptime val.doTheTest([16]u1); +} + +test "@bitCast nested arrays of vectors" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const Src = [2][2]@Vector(4, u5); + const Dest = [5]@Vector(2, u8); + + // The strange digit groupings here are to indicate how this maps to the output. + const src: Src = .{ .{ + .{ 0b00011, 0b00_100, 0b11100, 0b0010_1 }, + .{ 0b1_0110, 0b11011, 0b101_10, 0b10101 }, + }, .{ + .{ 0b10101, 0b00_001, 0b01011, 0b0001_0 }, + .{ 0b0_0001, 0b01111, 0b111_10, 0b00001 }, + } }; + + const expected: Dest = .{ + .{ 0b10000011, 0b11110000 }, + .{ 0b01100010, 0b10110111 }, + .{ 0b10101101, 0b00110101 }, + .{ 0b00101100, 0b00010001 }, + .{ 0b10011110, 0b00001111 }, + }; + + const static = struct { + fn doTheTest(src_arg: Src) !void { + const actual: Dest = @bitCast(src_arg); + for (actual, expected) |actual_vec, expected_vec| { + try expect(actual_vec[0] == expected_vec[0]); + try expect(actual_vec[1] == expected_vec[1]); + } + } + }; + + try static.doTheTest(src); + try comptime static.doTheTest(src); +} + +test "@bitCast nested arrays of bool to scalar" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const static = struct { + fn doTheTest(src: [4][4]bool) !void { + const result: u16 = @bitCast(src); + try expect(result == 0b1100_0101_1010_0011); + } + }; + const src: [4][4]bool = .{ + .{ true, true, false, false }, // 0b0011 + .{ false, true, false, true }, // 0b1010 + .{ true, false, true, false }, // 0b0101 + .{ false, false, true, true }, // 0b1100 + }; + try static.doTheTest(src); + try comptime static.doTheTest(src); +} + +test "@bitCast deeply nested arrays to scalar" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const static = struct { + fn doTheTest(src: [2][1][3][5]u4) !void { + const signed: i120 = @bitCast(src); + try expect(signed < 0); // top nibble is 0x8 so sign bit is 1 + const unsigned: u120 = @bitCast(src); + try expect(unsigned == 0x8873B_5BF6F_F4020_0E7AC_1EFED_40F51); + try expect(@as(i120, @bitCast(unsigned)) == signed); + try expect(@as(u120, @bitCast(signed)) == unsigned); + } + }; + const src: [2][1][3][5]u4 = .{ .{.{ + .{ 0x1, 0x5, 0xF, 0x0, 0x4 }, + .{ 0xD, 0xE, 0xF, 0xE, 0x1 }, + .{ 0xC, 0xA, 0x7, 0xE, 0x0 }, + }}, .{.{ + .{ 0x0, 0x2, 0x0, 0x4, 0xF }, + .{ 0xF, 0x6, 0xF, 0xB, 0x5 }, + .{ 0xB, 0x3, 0x7, 0x8, 0x8 }, + }} }; + try static.doTheTest(src); + try comptime static.doTheTest(src); +} diff --git a/test/behavior/bool.zig b/test/behavior/bool.zig index 7944c0903eba58efb24377b22d773f347a3674c6..72c1dff3362afc5960160776841f04a8b22ef2f9 100644 --- a/test/behavior/bool.zig +++ b/test/behavior/bool.zig @@ -10,7 +10,6 @@ test "bool literals" { test "cast bool to int" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const t = true; const f = false; diff --git a/test/behavior/call.zig b/test/behavior/call.zig index e1152ad910695f425c8de60894d7ecc92fe9d0f9..4846d475af9548e24a518ff035a6288aa64c7352 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -408,6 +408,7 @@ test "recursive inline call with comptime known argument" { test "inline while with @call" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn inc(a: *u32) void { @@ -735,6 +736,7 @@ test "tail call function pointer" { test "tail call with potentially extended types" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_llvm or builtin.zig_backend == .stage2_c) { if (builtin.cpu.arch.isMIPS() or builtin.cpu.arch.isPowerPC() or builtin.cpu.arch.isWasm()) { diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 2e5871d9dd2ae26b8f9b1739ce84a847b5a9f535..41b53fdbbb0f17e9f27264eeaebcf4e376a68cfc 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -131,6 +131,7 @@ fn testIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void { } 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; @@ -156,6 +157,7 @@ fn testFloatFromInt(comptime I: type, i: I, comptime F: type, expected: F) !void } 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; @@ -216,6 +218,8 @@ test "@floatFromInt(f80)" { } test "type coercion from int to float" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const check = struct { // Check that an integer value can be coerced to a float type and // then converted back to the original value without rounding issues. @@ -277,8 +281,6 @@ 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 - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - try testIntFromFloats(); try comptime testIntFromFloats(); } @@ -342,7 +344,6 @@ fn expectTruncCast(comptime F: type, f: F, comptime I: type, i: I) !void { test "implicitly cast indirect pointer to maybe-indirect pointer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { const Self = @This(); x: u8, @@ -505,7 +506,6 @@ test "array coercion to undefined at runtime" { var array = [4]u8{ 3, 4, 5, 6 }; var undefined_val = [4]u8{ 0xAA, 0xAA, 0xAA, 0xAA }; - try expect(std.mem.eql(u8, &array, &array)); array = undefined; try expect(std.mem.eql(u8, &array, &undefined_val)); @@ -539,6 +539,8 @@ test "return u8 coercing into ?u32 return type" { } test "cast from ?[*]T to ??[*]T" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const a: ??[*]u8 = @as(?[*]u8, null); try expect(a != null and a.? == null); } @@ -597,6 +599,7 @@ fn testPeerResolveArrayConstSlice(b: bool) !void { } test "implicitly cast from T to anyerror!?T" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -622,6 +625,7 @@ fn castToOptionalTypeError(z: i32) !void { } test "implicitly cast from [0]T to anyerror![]T" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try testCastZeroArrayToErrSliceMut(); @@ -1420,6 +1424,7 @@ test "comptime float casts" { } test "pointer reinterpret const float to int" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO // The hex representation is 0x3fe3333333333303. @@ -1613,6 +1618,7 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void { } test "implicit cast *[0]T to E![]const u8" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var x = @as(anyerror![]const u8, &[0]u8{}); @@ -1807,6 +1813,7 @@ test "cast compatible optional types" { } test "coerce undefined single-item pointer of array to error union of slice" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const a = @as([*]u8, undefined)[0..0]; @@ -1817,6 +1824,7 @@ test "coerce undefined single-item pointer of array to error union of slice" { } test "pointer to empty struct literal to mutable slice" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var x: []i32 = &.{}; @@ -1970,6 +1978,7 @@ test "peer type resolution forms error union" { } test "@constCast without a result location" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const x: i32 = 1234; const y = @constCast(&x); try expect(@TypeOf(y) == *i32); @@ -1977,6 +1986,7 @@ test "@constCast without a result location" { } test "@constCast optional" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const x: u8 = 10; const m: ?*const u8 = &x; const p = @constCast(m); @@ -2053,6 +2063,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" { } test "peer type resolution: float and runtime-known fixed-width integer" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -2163,6 +2174,7 @@ test "peer type resolution: array and vector with same child type" { } test "peer type resolution: array with smaller child type and vector with larger child type" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -2343,6 +2355,7 @@ test "peer type resolution: array and tuple" { } test "peer type resolution: vector and tuple" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -2541,7 +2554,7 @@ test "peer type resolution: many compatible pointers" { test "peer type resolution: tuples with comptime fields" { 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_spirv) return error.SkipZigTest; // TODO const a = .{ 1, 2 }; const b = .{ @as(u32, 3), @as(i16, 4) }; @@ -2734,6 +2747,7 @@ test "cast builtins can wrap result in optional" { } test "cast builtins can wrap result in error union" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -2809,6 +2823,7 @@ test "cast builtins can wrap result in error union and optional" { } test "@floatCast on vector" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -2897,6 +2912,7 @@ test "@intFromPtr on vector" { } test "@floatFromInt on vector" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -2916,6 +2932,7 @@ test "@floatFromInt on vector" { } test "@intFromFloat on vector" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -2935,6 +2952,7 @@ test "@intFromFloat on vector" { } test "@intFromBool on vector" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -3061,6 +3079,7 @@ test "peer type resolution: slice of sentinel-terminated array" { } test "@intFromFloat boundary cases" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -3092,6 +3111,7 @@ test "@intFromFloat boundary cases" { } test "@intFromFloat vector boundary cases" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index 841030a9e1a02fd23587b852bd73d2cdedfd5fdf..34adedf7267030379ee573cb519ce6dbe29c95e3 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -8,7 +8,6 @@ const minInt = std.math.minInt; test "@intCast i32 to u7" { 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_riscv64) return error.SkipZigTest; var x: u128 = maxInt(u128); @@ -144,7 +143,7 @@ fn testIntCast(comptime S: type, a: S, comptime D: type, expected: D) !void { test "@intCast <= 64 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testIntCast(i32, minInt(i32), i64, minInt(i32)); try testIntCast(i32, maxInt(i32), i64, maxInt(i32)); try testIntCast(u32, maxInt(u32), u64, maxInt(u32)); @@ -170,6 +169,7 @@ 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); try testIntCast(u64, 1 << 63, u140, 1 << 63); @@ -213,119 +213,3 @@ test "@intCast > 128 bits" { try testIntCast(u64, maxInt(u64), i255, maxInt(u64)); try testIntCast(u128, maxInt(u128), i255, maxInt(u128)); } - -const Piece = packed struct { - color: Color, - type: Type, - - const Type = enum(u3) { KING, QUEEN, BISHOP, KNIGHT, ROOK, PAWN }; - const Color = enum(u1) { WHITE, BLACK }; - - fn charToPiece(c: u8) !@This() { - return .{ - .type = try charToPieceType(c), - .color = if (std.ascii.isUpper(c)) Color.WHITE else Color.BLACK, - }; - } - - fn charToPieceType(c: u8) !Type { - return switch (std.ascii.toLower(c)) { - 'p' => .PAWN, - 'k' => .KING, - 'q' => .QUEEN, - 'b' => .BISHOP, - 'n' => .KNIGHT, - 'r' => .ROOK, - else => error.UnexpectedCharError, - }; - } -}; - -// Originally reported at https://github.com/ziglang/zig/issues/14200 -test "load non byte-sized optional value" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO - - // note: this bug is triggered by the == operator, expectEqual will hide it - const opt: ?Piece = try Piece.charToPiece('p'); - try expect(opt.?.type == .PAWN); - try expect(opt.?.color == .BLACK); - - var p: Piece = undefined; - @as(*u8, @ptrCast(&p)).* = 0b11111011; - try expect(p.type == .PAWN); - try expect(p.color == .BLACK); -} - -test "load non byte-sized value in struct" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO - - // note: this bug is triggered by the == operator, expectEqual will hide it - // using ptrCast not to depend on unitialised memory state - - var struct0: struct { - p: Piece, - int: u8, - } = undefined; - @as(*u8, @ptrCast(&struct0.p)).* = 0b11111011; - try expect(struct0.p.type == .PAWN); - try expect(struct0.p.color == .BLACK); - - var struct1: packed struct { - p0: Piece, - p1: Piece, - pad: u1, - p2: Piece, - } = undefined; - @as(*u8, @ptrCast(&struct1.p0)).* = 0b11111011; - struct1.p1 = try Piece.charToPiece('p'); - struct1.p2 = try Piece.charToPiece('p'); - try expect(struct1.p0.type == .PAWN); - try expect(struct1.p0.color == .BLACK); - try expect(struct1.p1.type == .PAWN); - try expect(struct1.p1.color == .BLACK); - try expect(struct1.p2.type == .PAWN); - try expect(struct1.p2.color == .BLACK); -} - -test "load non byte-sized value in union" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - - // note: this bug is triggered by the == operator, expectEqual will hide it - // using ptrCast not to depend on unitialised memory state - - var union0: packed union { - p: packed struct(u8) { - a: Piece, - b: u4, - }, - int: u8, - } = .{ .int = 0 }; - union0.int = 0b11111011; - try expect(union0.p.a.type == .PAWN); - try expect(union0.p.a.color == .BLACK); - - var union1: union { - p: packed struct(u8) { - a: Piece, - b: u4, - }, - int: u8, - } = .{ .p = .{ .a = .{ .color = .WHITE, .type = .KING }, .b = 0 } }; - @as(*u8, @ptrCast(&union1.p.a)).* = 0b11111011; - try expect(union1.p.a.type == .PAWN); - try expect(union1.p.a.color == .BLACK); - - var pieces: [3]Piece = undefined; - @as(*u8, @ptrCast(&pieces[1])).* = 0b11111011; - try expect(pieces[1].type == .PAWN); - try expect(pieces[1].color == .BLACK); -} diff --git a/test/behavior/comptime_memory.zig b/test/behavior/comptime_memory.zig index 769075aefff3c23691fa8474e16e62f1328d37a6..d11a7cb0165dca71e86447ec8a059257001d4cb4 100644 --- a/test/behavior/comptime_memory.zig +++ b/test/behavior/comptime_memory.zig @@ -516,7 +516,6 @@ fn fieldPtrTest() u32 { } test "pointer in aggregate field can mutate comptime state" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - try comptime std.testing.expect(fieldPtrTest() == 2); } @@ -553,6 +552,8 @@ test "comptime store of packed struct with void field into array" { } test "comptime store of reinterpreted zero-bit type" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { fn doTheTest(comptime T: type) void { comptime var buf: T = undefined; @@ -582,3 +583,21 @@ test "comptime store to extern struct reinterpreted as byte array" { comptime std.debug.assert(val.x == 0); } + +test "reinterpret sentinel-terminated array as packed struct" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = packed struct(u16) { lo: u8, hi: u8 }; + const data: [2:0]u8 = .{ 0x12, 0x34 }; + const ptr: *align(1) const S = @ptrCast(&data); + switch (endian) { + .little => { + try testing.expect(ptr.lo == 0x12); + try testing.expect(ptr.hi == 0x34); + }, + .big => { + try testing.expect(ptr.lo == 0x34); + try testing.expect(ptr.hi == 0x12); + }, + } +} diff --git a/test/behavior/decl_literals.zig b/test/behavior/decl_literals.zig index f96f46177179af58eee8e419648e5fdc7568a185..5d237778757f3c2f2a3faa160668f26debfee9f9 100644 --- a/test/behavior/decl_literals.zig +++ b/test/behavior/decl_literals.zig @@ -49,6 +49,8 @@ test "call decl literal with optional" { } test "call decl literal with pointer" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { x: u32, fn init() *const @This() { diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index c90df21fbca81fc441837057b74f26e227c17f9c..1a999c32c01a30dfe4c0cf98cdca5642c8b83511 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -109,7 +109,6 @@ test "mixing normal and error defers" { test "simple else prong doesn't emit an error for unreachable else prong" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn foo() error{Foo}!void { return error.Foo; diff --git a/test/behavior/duplicated_test_names.zig b/test/behavior/duplicated_test_names.zig index e7ee93776cb23e8731255818a1a38f485c243860..b16a7787d84b7f22c57376fee8cae225ced9b87f 100644 --- a/test/behavior/duplicated_test_names.zig +++ b/test/behavior/duplicated_test_names.zig @@ -15,7 +15,6 @@ comptime { test "thingy" {} test thingy { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (thingy(1, 2) != 3) unreachable; diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index 6557de08ca9dd687b2231436b3d48bf96e0dbbde..19a053e2c9192c63fd13929a39c73e1b9085f0bb 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -931,7 +931,6 @@ test "constant enum initialization with differing sizes" { 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; - try test3_1(test3_foo); try test3_2(test3_bar); } @@ -973,8 +972,8 @@ test "@tagName" { if (builtin.zig_backend == .stage2_aarch64) 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; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); @@ -1059,6 +1058,7 @@ test "tag name with signed enum values" { test "tag name with large enum values" { 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 Kdf = enum(u128) { aes_kdf = 0xea4f8ac1080d74bf60448a629af3d9c9, @@ -1078,6 +1078,7 @@ test "tag name with large enum values" { test "@tagName with exotic integer enum types" { 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 = struct { fn testEnumSigned(comptime T: type) !void { @@ -1280,6 +1281,7 @@ test "tag name functions are unique" { test "size of enum with only one tag which has explicit integer tag type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const E = enum(u8) { nope = 10 }; const S0 = struct { e: E }; @@ -1313,6 +1315,26 @@ test "switch on an extern enum with negative value" { } } +test "switch on an enum with small signed tag type" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const E = enum(i3) { + y = -2, + z = -1, + a = 0, + b = 1, + c = 2, + }; + + var runtime: E = .c; + _ = &runtime; + const result: u8 = switch (runtime) { + .y, .z, .a, .b => 0, + .c => 1, + }; + try expect(result == 1); +} + test "Non-exhaustive enum with nonstandard int size behaves correctly" { const E = enum(u15) { _ }; try expect(@sizeOf(E) == @sizeOf(u15)); diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 7a53776b36adecbaede5972f89e7ea19efed0375..725f52bfbee8ab78a3185caa5a20183b292944a3 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -145,6 +145,8 @@ test "implicit cast to optional to error union to return result loc" { } test "fn returning empty error set can be passed as fn returning any error" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + entry(); comptime entry(); } @@ -155,7 +157,6 @@ test "fn returning empty error set can be passed as fn returning any error - poi entryPtr(); comptime entryPtr(); } - fn entry() void { foo2(bar2); } @@ -509,7 +510,6 @@ test "function pointer with return type that is error union with payload which i const Foo = struct { fun: *const fn (a: i32) (anyerror!*Foo), }; - const Err = error{UnspecifiedErr}; fn bar(a: i32) anyerror!*Foo { @@ -526,6 +526,7 @@ test "function pointer with return type that is error union with payload which i } test "return result loc as peer result loc in inferred error set function" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -557,6 +558,7 @@ test "return result loc as peer result loc in inferred error set function" { } test "error payload type is correctly resolved" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -695,7 +697,6 @@ test "coerce error set to the current inferred error set" { test "error union payload is properly aligned" { 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_riscv64) return error.SkipZigTest; const S = struct { @@ -1111,6 +1112,7 @@ test "'if' ignores error via local while 'else' ignores error directly" { } test "@errorCast into own inferred error set" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const static = struct { fn foo(b: bool) !void { if (b) { diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index f644c4261eb79460e5045ce81914a1dbaf3e227e..6b60920e8560c6dfa7cd4381d8b6ede61706cd7e 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -456,7 +456,6 @@ test "binary math operator in partially inlined function" { test "comptime shl" { 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; const a: u128 = 3; const b: u7 = 63; @@ -883,6 +882,8 @@ test "debug variable type resolved through indirect zero-bit types" { } test "const local with comptime init through array init" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const E1 = enum { A, pub fn a() void {} @@ -1180,8 +1181,6 @@ test "lazy sizeof is resolved in division" { } test "lazy sizeof union tag size in compare" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const A = union(enum) { a: void, b: void, @@ -1194,7 +1193,6 @@ test "lazy value is resolved as slice operand" { 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 A = struct { a: u32 }; var a: [512]u64 = undefined; diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index 693656095332986f1062f0dd546acbe23c2bf8ff..2dbf47fff4d4632660d884e275b1da75420f3133 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -134,7 +134,6 @@ test "cmp f32" { } test "cmp f64" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try testCmp(f64); @@ -144,8 +143,8 @@ 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_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testCmp(f128); try comptime testCmp(f128); @@ -1546,6 +1545,7 @@ fn testNeg(comptime T: type) !void { test "negate f80" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var f: f80 = 0.0; const a: u80 = @bitCast(f); diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 52648140162843ecbceddf78165e201129bcc28c..7b22be363ca285bdbdcefa203086538292c05654 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -292,6 +292,7 @@ fn voidFun(a: i32, b: void, c: i32, d: void) !void { test "call function with empty string" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; acceptsString(""); } @@ -405,6 +406,7 @@ test "function with inferred error set but returning no error" { test "import passed byref to function in return type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn get() @import("std").ArrayList(i32) { @@ -440,6 +442,7 @@ test "implicit cast function to function ptr" { test "method call with optional and error union first param" { 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; const S = struct { x: i32 = 1234, @@ -744,6 +747,8 @@ test "coerce generic function making generic parameter concrete" { } test "return undefined pointer from function, directly and by expired local" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { var global: i32 = 1; diff --git a/test/behavior/for.zig b/test/behavior/for.zig index 3923029312f5c41115dcd202246eb434897e33f9..f4b2ea923f0e7407030b4dc661de7ebf154bfaec 100644 --- a/test/behavior/for.zig +++ b/test/behavior/for.zig @@ -521,6 +521,8 @@ test "return from inline for" { } test "for loop 0 length range" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const map: []const u8 = &.{}; for (map, 0..map.len) |i, j| { _ = i; @@ -545,3 +547,20 @@ test "labeled break from else" { try S.doTheTest(5); try comptime S.doTheTest(5); } + +test "value break from inline for" { + const S = struct { + fn doTheTest() !void { + const x = inline for (0..2) |_| { + if (true) { + var idx: u32 = 0; + idx += 1; + break idx; + } + }; + try expect(x == 1); + } + }; + try S.doTheTest(); + try comptime S.doTheTest(); +} diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 6f6c6d4707e29a2408c171f269ccba2bf46ca62a..1314925420c7b8a7c31c32fdaaa7e0fcac7bd9b0 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -486,8 +486,6 @@ test "union in struct captures argument" { test "function argument tuple used as struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn DeleagateWithContext(comptime Function: type) type { const ArgArgs = std.meta.ArgsTuple(Function); @@ -521,6 +519,7 @@ test "call generic function with from function called by the generic function" { if (builtin.zig_backend == .stage2_aarch64) 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; const GET = struct { key: []const u8, diff --git a/test/behavior/globals.zig b/test/behavior/globals.zig index 982ebc41f839ecbf7a28289be2fe38ab3c474acd..98ebedae41cf85ac2f7e6500e5d8cb380159a3d4 100644 --- a/test/behavior/globals.zig +++ b/test/behavior/globals.zig @@ -16,6 +16,7 @@ var vpos = @Vector(2, f32){ 0.0, 0.0 }; test "store to global vector" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(vpos[1] == 0.0); vpos = @Vector(2, f32){ 0.0, 1.0 }; @@ -42,6 +43,7 @@ test "slices pointing at the same address as global array." { } test "global loads can affect liveness" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; diff --git a/test/behavior/hasdecl.zig b/test/behavior/hasdecl.zig index 220a4afd491947c9a3906f80402ec197a8aff01a..71f9200b276e8bb02fdf5f53a7eb33c5c436e7d1 100644 --- a/test/behavior/hasdecl.zig +++ b/test/behavior/hasdecl.zig @@ -13,7 +13,6 @@ const Bar = struct { test "@hasDecl" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(@hasDecl(Foo, "public_thing")); try expect(!@hasDecl(Foo, "private_thing")); @@ -26,7 +25,6 @@ test "@hasDecl" { test "@hasDecl using a sliced string literal" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(@hasDecl(@This(), "std") == true); try expect(@hasDecl(@This(), "std"[0..0]) == false); diff --git a/test/behavior/import.zig b/test/behavior/import.zig index faa3a08141558864248a10bff2e5a60f7993fe42..7f1025a9156ef723d2733432f2e6511f3732c071 100644 --- a/test/behavior/import.zig +++ b/test/behavior/import.zig @@ -5,21 +5,18 @@ const expectEqual = std.testing.expectEqual; const a_namespace = @import("import/a_namespace.zig"); test "call fn via namespace lookup" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@as(i32, 1234) == a_namespace.foo()); } test "importing the same thing gives the same import" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@import("std") == @import("std")); } test "import empty file" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; _ = @import("import/empty.zig"); diff --git a/test/behavior/incomplete_struct_param_tld.zig b/test/behavior/incomplete_struct_param_tld.zig index 4edf974daba261157c5ecc355ff7355ce2a5bfe3..0dc585820f7220d4458e55ca7b3caf39c1c12580 100644 --- a/test/behavior/incomplete_struct_param_tld.zig +++ b/test/behavior/incomplete_struct_param_tld.zig @@ -23,6 +23,7 @@ fn foo(a: A) i32 { test "incomplete struct param top level declaration" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const a = A{ .b = B{ diff --git a/test/behavior/inline_switch.zig b/test/behavior/inline_switch.zig index a1efe7ab022e1de44dc0e0e0411d915348523999..2e35307167d7ec9ec3764da6cf349315d4c0e72d 100644 --- a/test/behavior/inline_switch.zig +++ b/test/behavior/inline_switch.zig @@ -4,6 +4,7 @@ const builtin = @import("builtin"); test "inline scalar prongs" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var x: usize = 0; switch (x) { @@ -18,6 +19,7 @@ test "inline scalar prongs" { test "inline prong ranges" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var x: usize = 0; _ = &x; @@ -32,7 +34,6 @@ test "inline prong ranges" { const E = enum { a, b, c, d }; test "inline switch enums" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - var x: E = .a; _ = &x; switch (x) { @@ -45,7 +46,7 @@ const U = union(E) { a: void, b: u2, c: u3, d: u4 }; test "inline switch unions" { 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; var x: U = .a; _ = &x; switch (x) { @@ -70,7 +71,6 @@ test "inline switch unions" { test "inline else bool" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - var a = true; _ = &a; switch (a) { @@ -81,7 +81,7 @@ test "inline else bool" { test "inline else error" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Err = error{ a, b, c }; var a = Err.a; _ = &a; @@ -93,6 +93,7 @@ test "inline else error" { test "inline else enum" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; var a: E2 = .a; @@ -123,6 +124,7 @@ test "inline else int with gaps" { test "inline else int all values" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var a: u2 = 0; _ = &a; @@ -138,6 +140,8 @@ test "inline else int all values" { } test "inline switch capture is set when switch operand is comptime known" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const U2 = union(enum) { a: u32, }; diff --git a/test/behavior/int128.zig b/test/behavior/int128.zig index eddf74097b78dc4d1a63521eee5bbc35e5833bb2..9687e3171497df8fb41e9c7fd3277829e81069e2 100644 --- a/test/behavior/int128.zig +++ b/test/behavior/int128.zig @@ -7,7 +7,6 @@ const builtin = @import("builtin"); test "uint128" { 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_riscv64) return error.SkipZigTest; var buff: u128 = maxInt(u128); @@ -45,7 +44,6 @@ test "undefined 128 bit int" { test "int128" { 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_riscv64) return error.SkipZigTest; var buff: i128 = -1; @@ -90,7 +88,6 @@ test "truncate int128" { test "shift int128" { 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_riscv64) return error.SkipZigTest; const types = .{ u128, i128 }; diff --git a/test/behavior/ir_block_deps.zig b/test/behavior/ir_block_deps.zig index 4708af87f4bd27060125a8e2c0e111e0996badab..d4218387ecd6987feaaa1c751947b2b27e8fb01f 100644 --- a/test/behavior/ir_block_deps.zig +++ b/test/behavior/ir_block_deps.zig @@ -19,6 +19,7 @@ fn getErrInt() anyerror!i32 { test "ir block deps" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try expect((foo(1) catch unreachable) == 0); diff --git a/test/behavior/math.zig b/test/behavior/math.zig index b7b383d358ea084ae2d340b0db8a97c8b44ec5d7..4f22fd04aef6e2dcb7db0c3387ef02df34409667 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -383,7 +383,6 @@ fn not(comptime T: type, a: T) T { test "binary not" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try expect(not(u0, 0) == 0); try expect(not(u1, 0) == 1); @@ -424,7 +423,6 @@ test "binary not" { test "binary not 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_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(not(u65, 1) == 0x1_FFFFFFFF_FFFFFFFE); @@ -458,8 +456,6 @@ test "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_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - try testIntDivision(); try comptime testIntDivision(); @@ -659,8 +655,6 @@ fn testSignedWrappingEval(x: i32) !void { } test "signed negation wrapping" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - try testSignedNegationWrappingEval(minInt(i16)); try comptime testSignedNegationWrappingEval(minInt(i16)); } @@ -763,7 +757,6 @@ fn should_not_be_zero(x: f128) !void { test "umax wrapped squaring" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; { var x: u4 = maxInt(u4); @@ -820,7 +813,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_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; @@ -873,7 +865,6 @@ test "@addWithOverflow <= 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; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO try testAddWithOverflow(u65, 4, 105, 109, 0); try testAddWithOverflow(u65, 1000, 100, 1100, 0); @@ -1000,7 +991,6 @@ test "extensive @mulWithOverflow" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testMulWithOverflow(u5, 3, 10, 30, 0); try testMulWithOverflow(u5, 3, 11, 1, 1); @@ -1114,6 +1104,7 @@ 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); try testMulWithOverflow(u140, 1, maxInt(u140), maxInt(u140), 0); @@ -1206,7 +1197,6 @@ test "@subWithOverflow <= 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; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO try testSubWithOverflow(u65, 4, 105, maxInt(u65) - 100, 1); try testSubWithOverflow(u65, 1000, 100, 900, 0); @@ -1340,6 +1330,7 @@ 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); try testShlWithOverflow(u140, 1 << 100, 40, 0, 1); @@ -1398,6 +1389,7 @@ 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; + if (builtin.zig_backend == .stage2_spirv) 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); @@ -1543,6 +1535,7 @@ 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); try testClz(u140, 1 << 139, 0); @@ -1572,6 +1565,7 @@ 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); try testCtz(u140, 1 << 139, 139); @@ -1601,6 +1595,7 @@ 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); try testPopCount(u140, maxInt(u140), 140); @@ -1630,6 +1625,7 @@ 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); try testBitReverse(u140, 1 << 70, 1 << 69); @@ -1659,6 +1655,7 @@ 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); try testByteSwap(u144, 1, 1 << 136); @@ -1688,6 +1685,7 @@ 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)); try testMax(u140, 1 << 139, 1 << 138, 1 << 139); @@ -1717,6 +1715,7 @@ 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); try testMin(u140, 1 << 139, 1 << 138, 1 << 138); @@ -1746,6 +1745,7 @@ 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; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testAbs(u140, 0, 0); try testAbs(u140, 1 << 139, 1 << 139); @@ -1770,6 +1770,7 @@ 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); try testRem(u140, maxInt(u140), maxInt(u140), 0); @@ -1797,6 +1798,7 @@ 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); try testMod(u140, maxInt(u140), maxInt(u140), 0); @@ -1824,6 +1826,7 @@ 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); try testDivFloor(u140, maxInt(u140), maxInt(u140), 1); @@ -1852,6 +1855,7 @@ 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); try testDivTrunc(u140, maxInt(u140), maxInt(u140), 1); @@ -2514,7 +2518,6 @@ test "partially-runtime integer vector division would be illegal if vector eleme 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; if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; var lhs: @Vector(2, i8) = .{ -128, 5 }; @@ -2542,7 +2545,6 @@ test "float vector division of comptime zero by runtime nan is nan" { 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 ct_zero: @Vector(1, f32) = .{0}; var rt_nan: @Vector(1, f32) = .{math.nan(f32)}; @@ -2559,7 +2561,6 @@ test "float vector multiplication of comptime zero by runtime nan is nan" { 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 ct_zero: @Vector(1, f32) = .{0}; var rt_nan: @Vector(1, f32) = .{math.nan(f32)}; @@ -2574,7 +2575,6 @@ test "comptime float vector division of zero by nan is nan" { 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 ct_zero: @Vector(1, f32) = .{0}; const ct_nan: @Vector(1, f32) = .{math.nan(f32)}; @@ -2588,7 +2588,6 @@ test "comptime float vector multiplication of zero by nan is nan" { 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 ct_zero: @Vector(1, f32) = .{0}; const ct_nan: @Vector(1, f32) = .{math.nan(f32)}; @@ -2598,6 +2597,8 @@ test "comptime float vector multiplication of zero by nan is nan" { } test "i96 operations" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + // This is coverage for some stuff used by std.Io timestamps, to catch // issues earlier than bootstrapping. const Op_i96 = union(enum) { diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index efe2a7f108b79fa7a589fa7e4e78671b6f091b0f..22db5a75502f8456ac0637ef134a137434d3da75 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -160,6 +160,7 @@ test "@min/@max more than two arguments" { } test "@min/@max more than two vector arguments" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -189,6 +190,7 @@ test "@min/@max notices bounds" { } test "@min/@max notices vector bounds" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -239,6 +241,7 @@ test "@min/@max notices bounds from types" { } test "@min/@max notices bounds from vector types" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -301,8 +304,6 @@ test "@min/@max notices bounds from vector types when element of comptime-known } test "@min/@max of signed and unsigned runtime integers" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - var x: i32 = -1; var y: u31 = 1; _ = .{ &x, &y }; @@ -348,6 +349,7 @@ test "@min/@max with runtime signed and unsigned integers of same size" { } test "@min/@max with runtime vectors of signed and unsigned integers of same size" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 diff --git a/test/behavior/memcpy.zig b/test/behavior/memcpy.zig index fd2cc8fe6a86c9fd8651b274a37eeecb506656f3..462ce44b1b4720971aa735230692a07165eabb73 100644 --- a/test/behavior/memcpy.zig +++ b/test/behavior/memcpy.zig @@ -168,8 +168,6 @@ test "@memcpy with sentinel" { } test "@memcpy no sentinel source into sentinel destination" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn doTheTest() void { const src: []const u8 = &.{ 1, 2, 3 }; diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 067f89c628a9b331ae57372b9d48cf3e566a6fe3..ed9df298ac0b327506efdbe68871044974ba75dc 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -179,6 +179,8 @@ test "@memset with zero-length array" { } test "@memset a global array" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { var buf: [1]u32 = .{123}; }; @@ -190,6 +192,8 @@ test "@memset a global array" { } test "@memset array of booleans" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { var x: bool = false; var y: [1]bool = undefined; diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 6a7e18d4102944513b91b9eb95331004ebf8467f..a6fddd62fe10a87ba72dd9b92e9fd72be46bca40 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -6,7 +6,6 @@ test "@mulAdd" { 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; try comptime testMulAdd(); try testMulAdd(); @@ -33,7 +32,6 @@ test "@mulAdd f16" { 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; try comptime testMulAdd16(); try testMulAdd16(); diff --git a/test/behavior/multiple_externs_with_conflicting_types.zig b/test/behavior/multiple_externs_with_conflicting_types.zig index 7fa72506aaa450ba24a3b48ddc13cf35a74bfacf..e0965665b697b61d10017da94ace744150ba7c91 100644 --- a/test/behavior/multiple_externs_with_conflicting_types.zig +++ b/test/behavior/multiple_externs_with_conflicting_types.zig @@ -5,7 +5,9 @@ const A = extern struct { extern fn issue529(?*A) void; comptime { - _ = @import("conflicting_externs/b.zig"); + if (builtin.zig_backend != .stage2_spirv) { + _ = @import("conflicting_externs/b.zig"); + } } const builtin = @import("builtin"); diff --git a/test/behavior/namespace_depends_on_compile_var.zig b/test/behavior/namespace_depends_on_compile_var.zig index 8cc7a9b85e01a37be83a8f82645a1c8114ea95b2..36c2b5ae666043d26317b63afcf71afd04e67275 100644 --- a/test/behavior/namespace_depends_on_compile_var.zig +++ b/test/behavior/namespace_depends_on_compile_var.zig @@ -3,7 +3,6 @@ const builtin = @import("builtin"); const expect = std.testing.expect; test "namespace depends on compile var" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (some_namespace.a_bool) { diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index ce104bf931b0e115812759e82cedefd51dad52ef..e812cd4c08b655cd2d21ad61cc8c4fd2fffd17d7 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -338,7 +338,6 @@ test "coerce an anon struct literal to optional struct" { test "0-bit child type coerced to optional return ptr result location" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - const S = struct { fn doTheTest() !void { var y = Foo{}; @@ -364,7 +363,6 @@ test "0-bit child type coerced to optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn doTheTest() !void { var it: Foo = .{ @@ -428,6 +426,7 @@ test "optional pointer to zero bit optional payload" { 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 B = struct { fn foo(_: *@This()) void {} @@ -655,6 +654,8 @@ test "result location initialization of optional with OPV payload" { } test "global comptime only optional" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { const @"null": ?*type = null; const @"void": ?*const type = &void; @@ -664,3 +665,14 @@ test "global comptime only optional" { assert(S.void.?.* == void); } } + +test "optional ptr payload alignment" { + const S = struct { + fn doTheTest(p: *align(1) ?u32) !void { + comptime assert(@TypeOf(&p.*.?) == *align(1) u32); + try expect(p.*.? == 10); + } + }; + var x: ?u32 = 10; + try S.doTheTest(&x); +} diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 1eb69ace532ea46cae3e12ca840663e31bbf4ceb..103d6a21775fdb3590e7ed873ccb07b5210907bd 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -227,7 +227,6 @@ test "nested packed structs" { test "regular in irregular packed struct" { 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_aarch64) return error.SkipZigTest; const Irregular = packed struct { @@ -248,7 +247,7 @@ test "nested packed struct unaligned" { if (builtin.zig_backend == .stage2_aarch64) 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; const S1 = packed struct { a: u4, b: u4, @@ -407,7 +406,6 @@ test "nested packed struct field pointers" { 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, p0: packed struct { @@ -816,6 +814,7 @@ test "packed struct passed to callconv(.c) function" { if (builtin.zig_backend == .stage2_arm) 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_spirv) return error.SkipZigTest; const S = struct { const Packed = packed struct(u64) { @@ -893,6 +892,7 @@ test "store undefined to packed result location" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var x: u4 = 0; _ = &x; diff --git a/test/behavior/packed-union.zig b/test/behavior/packed-union.zig index b0850392aa51efd60cac8af9403656bc07bae9a3..20732eab98a312ba077ffde4494e8deec179225d 100644 --- a/test/behavior/packed-union.zig +++ b/test/behavior/packed-union.zig @@ -201,6 +201,8 @@ test "packed union with explicit backing integer" { } test "packed union equality" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const Foo = packed union { a: u4, b: i4, diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index 357599bb449308f51f0779003b69146dce0e0a6e..9ac875fad4990e03554fc217fb38f42d0dfa6e62 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -144,7 +144,6 @@ test "initialize const optional C pointer to null" { test "assigning integer to C pointer" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - var x: i32 = 0; var y: i32 = 1; var ptr: [*c]u8 = 0; @@ -696,7 +695,6 @@ fn constant() !void { test "pointer-to-array constness for zero-size elements, var" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - try mutable(); try comptime mutable(); } @@ -720,6 +718,8 @@ test "cast pointers with zero sized elements" { } test "comptime pointer equality through distinct fields with well-defined layout" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const A = extern struct { x: u32, z: u16, @@ -744,6 +744,8 @@ test "comptime pointer equality through distinct fields with well-defined layout } test "comptime pointer equality through distinct elements with well-defined layout" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const buf: [2]u32 = .{ 123, 456 }; const ptr: *const [2]u32 = &buf; @@ -780,9 +782,11 @@ test "pointers to elements of many-ptr to zero-bit type" { } test "comptime C pointer to optional pointer" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const opt: ?*u8 = @ptrFromInt(0x1000); const outer_ptr: [*c]const ?*u8 = &opt; const inner_ptr = &outer_ptr.*.?; - comptime assert(@TypeOf(inner_ptr) == [*c]const *u8); + comptime assert(@TypeOf(inner_ptr) == *const *u8); comptime assert(@intFromPtr(inner_ptr.*) == 0x1000); } diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index b8b8fa32243871ad7a6faf48ff8517506eff4b0a..31de4f08b474620680a5d43252530124e12b736d 100644 --- a/test/behavior/ptrcast.zig +++ b/test/behavior/ptrcast.zig @@ -193,6 +193,7 @@ const Bytes = struct { test "ptrcast of const integer has the correct object size" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const is_value = ~@as(isize, @intCast(std.math.minInt(isize))); const is_bytes = @as([*]const u8, @ptrCast(&is_value))[0..@sizeOf(isize)]; @@ -279,6 +280,8 @@ test "@ptrCast undefined value at comptime" { } test "comptime @ptrCast with packed struct leaves value unmodified" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = packed struct { three: u3 }; const st: S = .{ .three = 6 }; try expect(st.three == 6); @@ -288,6 +291,8 @@ test "comptime @ptrCast with packed struct leaves value unmodified" { } test "@ptrCast restructures comptime-only array" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + { const a3a2: [3][2]comptime_int = .{ .{ 1, 2 }, @@ -330,6 +335,8 @@ test "@ptrCast restructures comptime-only array" { } test "@ptrCast restructures sliced comptime-only array" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const a3a2: [4][2]comptime_int = .{ .{ 1, 2 }, .{ 3, 4 }, @@ -552,6 +559,8 @@ test "@ptrCast single-item pointer to slice of bytes" { } test "@ptrCast array pointer removing sentinel" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 }; const out: []const i8 = @ptrCast(in); comptime assert(out.len == 4); @@ -562,6 +571,8 @@ test "@ptrCast array pointer removing sentinel" { } test "@ptrcast larger type to smaller one" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const T = packed struct { x: u17 }; const a: u32 = 0; const b: *const T = @ptrCast(&a); diff --git a/test/behavior/pub_enum.zig b/test/behavior/pub_enum.zig index 39ee14b9dc52151f0adecec02a4add23adfc3d72..fe397fdc640d2aa280050cfcd8ce95a40bd45328 100644 --- a/test/behavior/pub_enum.zig +++ b/test/behavior/pub_enum.zig @@ -3,7 +3,6 @@ const other = @import("pub_enum/other.zig"); const expect = @import("std").testing.expect; test "pub enum" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try pubEnumTest(other.APubEnum.Two); @@ -13,7 +12,6 @@ fn pubEnumTest(foo: other.APubEnum) !void { } test "cast with imported symbol" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; try expect(@as(other.size_t, 42) == 42); diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index 0e2978bd9b13819905cc1d29c705f33247dc3c7b..c434f014f36e40f2cfea9fc0c2508320d09c74a4 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -362,6 +362,7 @@ 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); try testSatAdd(u140, maxInt(u140), 1, maxInt(u140)); @@ -377,6 +378,7 @@ 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); try testSatSub(u140, maxInt(u140), maxInt(u140), 0); @@ -392,6 +394,7 @@ 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); try testSatMul(u140, 1 << 70, 1 << 69, 1 << 139); @@ -407,6 +410,7 @@ 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); try testSatShl(u140, 1 << 100, u8, 20, 1 << 120); diff --git a/test/behavior/shuffle.zig b/test/behavior/shuffle.zig index a3d899bc9ba41cf133e6e862af25f1d367aa9443..871852111025055a87858b65656ad15dc27062fe 100644 --- a/test/behavior/shuffle.zig +++ b/test/behavior/shuffle.zig @@ -54,8 +54,6 @@ test "@shuffle int strange sizes" { 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; - try comptime testShuffle(2, 2, 2); try testShuffle(2, 2, 2); try comptime testShuffle(4, 4, 4); @@ -136,7 +134,6 @@ test "@shuffle bool 1" { 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 x: @Vector(4, bool) = [4]bool{ false, true, false, true }; diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig index cb6c334cb7448bdd403c419baaad2eb9d92443d9..36288f2668777bfe0f2df7780531b2ebaf58c7c1 100644 --- a/test/behavior/sizeof_and_typeof.zig +++ b/test/behavior/sizeof_and_typeof.zig @@ -151,9 +151,6 @@ test "branching logic inside @TypeOf" { test "@bitSizeOf" { try expect(@bitSizeOf(u2) == 2); try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8); - try expect(@bitSizeOf(struct { - a: u2, - }) == 8); try expect(@bitSizeOf(packed struct { a: u2, }) == 2); @@ -211,8 +208,6 @@ test "@sizeOf comparison against zero" { } test "hardcoded address in typeof expression" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn func() @TypeOf(@as(*[]u8, @ptrFromInt(0x10)).*[0]) { return 0; @@ -283,14 +278,6 @@ test "@offsetOf zero-bit field" { try expect(@offsetOf(S, "b") == @offsetOf(S, "c")); } -test "@bitSizeOf on array of structs" { - const S = struct { - foo: u64, - }; - - try expectEqual(128, @bitSizeOf([2]S)); -} - test "lazy abi size used in comparison" { const S = struct { a: usize }; var rhs: i32 = 100; @@ -301,7 +288,6 @@ test "lazy abi size used in comparison" { test "peer type resolution with @TypeOf doesn't trigger dependency loop check" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const T = struct { next: @TypeOf(null, @as(*const @This(), undefined)), }; @@ -340,7 +326,7 @@ const exp = struct { } }; comptime { - _ = exp; + if (builtin.zig_backend != .stage2_spirv) _ = exp; } test "Extern function calls in @TypeOf" { @@ -426,3 +412,8 @@ test "@sizeOf struct is resolved when used as operand of slicing" { S.buf[@sizeOf(dummy)..][0] = 0; try expect(S.buf[0] == 0); } + +test "@TypeOf null C pointer dereference" { + comptime assert(@TypeOf(@as([*c]u8, null).*) == u8); + comptime assert(@TypeOf(&@as([*c]u8, null).*) == *u8); +} diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index b0be08391b83db7a4260fee68c01c9dbb26b47de..a30469821a3a279766dd6302bbc2272c7dfa826f 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -67,6 +67,7 @@ test "comptime slice of undefined pointer of length 0" { test "implicitly cast array of size 0 to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var msg = [_]u8{}; try assertLenIsZero(&msg); @@ -172,7 +173,6 @@ test "pass a slice of types to a function" { test "generic malloc free" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - const a = memAlloc(u8, 10) catch unreachable; memFree(u8, a); } @@ -186,7 +186,6 @@ fn memFree(comptime T: type, memory: []T) void { test "slice of hardcoded address to pointer" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn doTheTest() !void { const pointer = @as([*]u8, @ptrFromInt(0x04))[0..2]; @@ -225,7 +224,6 @@ test "comptime pointer cast array and then slice" { test "slicing zero length array" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const s1 = ""[0..]; const s2 = ([_]u32{})[0..]; try expect(s1.len == 0); @@ -276,6 +274,7 @@ test "slice string literal has correct type" { test "result location zero sized array inside struct field implicit cast to slice" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const E = struct { entries: []u32, @@ -382,6 +381,8 @@ test "obtaining a null terminated slice" { } test "empty array to slice" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { const empty: []align(16) u8 = &[_]u8{}; @@ -786,6 +787,8 @@ test "slice bounds in comptime concatenation" { } test "slice sentinel access at comptime" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + { const str0 = &[_:0]u8{ '1', '2', '3' }; const slice0: [:0]const u8 = str0; @@ -852,6 +855,8 @@ test "slice len modification at comptime" { } test "slice field ptr const" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const const_slice: []const u8 = "string"; const const_ptr_const_slice = &const_slice; @@ -865,6 +870,7 @@ test "slice field ptr const" { test "slice field ptr var" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; var var_slice: []const u8 = "string"; @@ -1050,6 +1056,8 @@ test "peer slices keep abi alignment with empty struct" { } test "sentinel expression in slice operation has result type" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const sentinel = std.math.maxInt(u16); const arr: [3]u16 = .{ 1, 2, sentinel }; @@ -1075,3 +1083,15 @@ test "conditionally return second argument slice" { try expectEqualStrings("", S.foo(false, "false")); try expectEqualStrings("true", S.foo(true, "true")); } + +test "slice field alignment" { + const S = struct { + fn doTheTest(p: *align(1) const []u8) !void { + comptime assert(@TypeOf(&p.ptr) == *align(1) const [*]u8); + comptime assert(@TypeOf(&p.len) == *align(1) const usize); + try expect(p.len == 10); + } + }; + var arr: [10]u8 = @splat(0); + try S.doTheTest(&&arr); +} diff --git a/test/behavior/spirv.zig b/test/behavior/spirv.zig new file mode 100644 index 0000000000000000000000000000000000000000..6d11032959e665ed26063894e494cd7084f953e4 --- /dev/null +++ b/test/behavior/spirv.zig @@ -0,0 +1,47 @@ +const Sampler = @SpirvType(.sampler); +const Image = @SpirvType(.{ .image = .{ + .usage = .{ .sampled = u32 }, + .format = .unknown, + .dim = .@"2d", + .depth = .unknown, + .arrayed = false, + .multisampled = false, + .access = .unknown, +} }); +const SampledImage = @SpirvType(.{ .sampled_image = Image }); +const StorageImage = @SpirvType(.{ .image = .{ + .usage = .{ .storage = u32 }, + .format = .unknown, + .dim = .@"2d", + .depth = .unknown, + .arrayed = false, + .multisampled = false, + .access = .unknown, +} }); +const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); + +const RuntimeArrayBuf = extern struct { e: RuntimeArray }; + +const sampler = @extern(*addrspace(.constant) const Sampler, .{ + .name = "sampler", + .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, +}); +const sampled_image = @extern(*addrspace(.constant) const SampledImage, .{ + .name = "sampled_image", + .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } }, +}); +const storage_image = @extern(*addrspace(.constant) const StorageImage, .{ + .name = "storage_image", + .decoration = .{ .descriptor = .{ .set = 0, .binding = 2 } }, +}); +const runtime_array = @extern(*addrspace(.storage_buffer) const RuntimeArrayBuf, .{ + .name = "runtime_array", + .decoration = .{ .descriptor = .{ .set = 0, .binding = 3 } }, +}); + +test "@SpirvType" { + _ = sampler; + _ = sampled_image; + _ = storage_image; + _ = runtime_array; +} diff --git a/test/behavior/string_literals.zig b/test/behavior/string_literals.zig index c1e89bacb2b296b7d5dc193e0f90650bab257745..ff5f57f23510f598127e950a828b41a40dbcac5a 100644 --- a/test/behavior/string_literals.zig +++ b/test/behavior/string_literals.zig @@ -101,7 +101,6 @@ test "Peer type resolution with string literals and unknown length u8 pointers" test "including the sentinel when dereferencing a string literal" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - var var_str = "abc"; const var_derefed = var_str[0 .. var_str.len + 1].*; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 4a4906699578f5f36e7bd9e0b31a563f7718c384..103ecc8994a6c66ab2be8a0aeee6781cf7ba66ef 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -378,7 +378,6 @@ const APackedStruct = packed struct { test "packed struct" { 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_aarch64) return error.SkipZigTest; var foo = APackedStruct{ @@ -447,7 +446,6 @@ test "runtime struct initialization of bitfield" { 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_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const s1 = Nibbles{ @@ -488,7 +486,6 @@ test "packed struct fields are ordered from LSB to MSB" { 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; - var all: u64 = 0x7765443322221111; var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined; @memcpy(bytes[0..8], @as([*]u8, @ptrCast(&all))); @@ -507,7 +504,6 @@ test "implicit cast packed struct field to const ptr" { 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_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO const LevelUpMove = packed struct { @@ -991,6 +987,7 @@ test "struct with 0-length union array field" { } test "packed struct with undefined initializers" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -1645,6 +1642,8 @@ test "struct init with no result pointer sets field result types" { } test "runtime side-effects in comptime-known struct init" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + var side_effects: u4 = 0; const S = struct { a: u4, b: u4, c: u4, d: u4 }; const init = S{ @@ -1921,6 +1920,7 @@ test "runtime value in nested initializer passed as pointer to function" { } test "struct field default value is a call" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -2182,6 +2182,7 @@ test "pass a pointer to a comptime-only struct field to a function" { } test "overaligned extern struct fields" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const A = struct { a: *anyopaque, b: u64, @@ -2231,6 +2232,7 @@ test "overaligned extern struct fields" { } test "runtime-known slice of comptime-only struct" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Mixed = struct { index: u32, T: type }; const static = struct { @@ -2252,6 +2254,7 @@ test "runtime-known slice of comptime-only struct" { } test "struct contains aligned pointer to itself through type decl" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Slab = struct { const Ptr = *align(64) const @This(); next: Ptr, @@ -2269,6 +2272,7 @@ 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 const S = struct { ptr: *align(8) @This() align(1), @@ -2281,6 +2285,7 @@ test "struct contains underaligned field with overaligned pointer to itself" { } test "struct contains pointer to function accepting that struct" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { const FnPtr = ?*const fn (@This()) void; fn_ptr: FnPtr, @@ -2303,6 +2308,7 @@ test "struct queries typeinfo of struct containing pointer back to first struct" } test "pointer to runtime field of struct containing struct containing comptime-only optional" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Foo = struct { padding: struct { a: u8, b: ?comptime_int }, number: u8, @@ -2314,3 +2320,12 @@ test "pointer to runtime field of struct containing struct containing comptime-o ptr = &foo.number; try expect(ptr.* == 123); } + +test "struct field referencing comptime var isn't comptime" { + comptime var v: u8 = 0; + const s = .{ .v = &v }; + // field isn't comptime but struct is still comptime-known + comptime assert(!@typeInfo(@TypeOf(s)).@"struct".field_attrs[0].@"comptime"); + v = 1; + comptime assert(s.v.* == 1); +} diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 43286ea0fcefdd3ca1371243ea81a5f483e96349..e56da92324e578190ea4119e04b5379abf687c2d 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -9,7 +9,6 @@ const maxInt = std.math.maxInt; test "switch with numbers" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; try testSwitchWithNumbers(13); } @@ -25,7 +24,6 @@ fn testSwitchWithNumbers(x: u32) !void { test "switch with all ranges" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO try expect(testSwitchWithAllRanges(50, 3) == 1); try expect(testSwitchWithAllRanges(101, 0) == 2); @@ -214,8 +212,6 @@ test "undefined.u0" { test "switch with disjoint range" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - var q: u8 = 0; _ = &q; switch (q) { @@ -226,8 +222,6 @@ test "switch with disjoint range" { } test "switch variable for range and multiple prongs" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO - const S = struct { fn doTheTest() !void { try doTheSwitch(16); @@ -276,6 +270,7 @@ test "switch prong with variable" { 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; try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); @@ -299,6 +294,7 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void { test "switch on enum using pointer capture" { 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; try testSwitchEnumPtrCapture(); try comptime testSwitchEnumPtrCapture(); @@ -359,6 +355,7 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 { test "switch on union with some prongs capturing" { 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; const X = union(enum) { a, @@ -395,6 +392,7 @@ test "switch on const enum with var" { test "anon enum literal used in switch on union enum" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Foo = union(enum) { a: i32, @@ -576,6 +574,7 @@ test "switch with null and T peer types and inferred result location type" { test "switch prongs with cases with identical payload 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; const Union = union(enum) { A: usize, @@ -617,6 +616,8 @@ test "switch prongs with cases with identical payload types" { } test "switch prong pointer capture alignment" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const U = union(enum) { a: u8 align(8), b: u8 align(4), @@ -794,6 +795,7 @@ test "enum value without tag name used as switch item" { } test "switch item sizeof" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { var a: usize = 0; @@ -840,6 +842,7 @@ test "switch capture peer type resolution" { test "switch capture peer type resolution for in-memory coercible payloads" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const T1 = c_int; const t1_info = @typeInfo(T1).int; @@ -863,6 +866,7 @@ test "switch capture peer type resolution for in-memory coercible payloads" { test "switch pointer capture peer type resolution" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const T1 = c_int; const t1_info = @typeInfo(T1).int; @@ -968,6 +972,8 @@ test "switch prong captures range" { } test "prong with inline call to unreachable" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const U = union(enum) { void: void, bool: bool, @@ -1174,6 +1180,8 @@ test "switch with uninstantiable union fields" { } test "switch with tag capture" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const U = union(enum) { a, b: i32, @@ -1307,6 +1315,8 @@ test "single-item prong in switch on enum has comptime-known capture" { } test "single range switch prong capture" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { fn doTheTest(x: u8) !void { switch (x) { @@ -1328,6 +1338,8 @@ test "single range switch prong capture" { } test "switch on packed struct" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const P = packed struct { a: u1, b: u1, @@ -1358,6 +1370,8 @@ test "switch on packed struct" { } test "switch on packed union" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const P = packed union(u2) { a: u2, b: i2, @@ -1405,6 +1419,8 @@ test "switch on packed union" { } test "switch on nested packed containers" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const P = packed struct { iu: u17, is: i31, @@ -1458,6 +1474,8 @@ test "switch on nested packed containers" { } test "switch on large types" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { fn doTheTest(a: u128, b: i500) !void { switch (a) { @@ -1519,3 +1537,59 @@ test "error captures narrow error sets" { try comptime S.doTheTest(error.B); try comptime S.doTheTest(error.C); } + +test "repeated switch analysis overrides previous analysis results" { + // This tests an implementation detail where semantic analysis of switch + // statements uses the switch inst itself to store capture values and result + // type information while analyzing (parts of) that switch inst. + // If that inst has already been assigned a result by a previous analysis + // that result needs to be overwritten. + + comptime { + const x: u32 = 123; + for (0..2) |_| _ = switch (x) { + 123 => |capture| capture, + else => unreachable, + }; + } + comptime { + const x: union(enum) { a, b, c } = .a; + for (0..2) |_| _ = switch (x) { + .a => |_, tag| tag, + else => unreachable, + }; + } + comptime { + const x: enum { a, b, c } = .a; + for (0..2) |_| _ = label: switch (x) { + .a => continue :label .b, + else => 123, + }; + } + comptime { + const x: anyerror!void = error.MyError; + for (0..2) |_| _ = x catch |err| switch (err) { + error.MyError => {}, + else => unreachable, + }; + } +} + +test "union field pointer capture preserves alignment in inline prong" { + const U = union(enum) { + a: u32, + b: u32, + fn doTheTest(u: *align(1) const @This()) !void { + switch (u.*) { + inline .a, .b => |*a_ptr| { + comptime assert(@TypeOf(a_ptr) == *align(1) const u32); + try expect(a_ptr.* == 123); + }, + } + } + }; + try U.doTheTest(&.{ .a = 123 }); + try U.doTheTest(&.{ .b = 123 }); + try comptime U.doTheTest(&.{ .a = 123 }); + try comptime U.doTheTest(&.{ .b = 123 }); +} diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 19293a472bc2a6dc12b319412fe54870e55dec0c..c86c297fa42836456f1b7f64002dffc6aa96313d 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -7,7 +7,6 @@ test "simple switch loop" { 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_spirv) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -31,7 +30,6 @@ test "switch loop with ranges" { 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_spirv) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -52,7 +50,6 @@ test "switch loop on enum" { 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_spirv) return error.SkipZigTest; // TODO const S = struct { const E = enum { a, b, c }; @@ -76,7 +73,6 @@ test "switch loop with error set" { 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_spirv) return error.SkipZigTest; // TODO const S = struct { const E = error{ Foo, Bar, Baz }; @@ -252,7 +248,6 @@ test "switch loop on non-exhaustive enum" { if (builtin.zig_backend == .stage2_aarch64) 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; // TODO const S = struct { const E = enum(u8) { a, b, c, _ }; @@ -275,8 +270,6 @@ 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; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { const U = union(enum) { a: u32, @@ -301,7 +294,6 @@ test "switch loop with discarded tag capture" { test "switch loop with single catch-all prong" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { const E = enum { a, b, c }; const U = union(E) { a: u32, b: u16, c: u8 }; @@ -397,6 +389,8 @@ test "switch loop on type with opv" { } test "switch loop with tag capture" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const U = union(enum) { a, b: i32, @@ -511,6 +505,7 @@ test "switch loop for error handling" { } test "switch loop with packed structs" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const P = packed struct { a: u7, b: u20, @@ -528,6 +523,8 @@ test "switch loop with packed structs" { } test "switch loop with packed unions" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const P = packed union { a: u7, b: i7, @@ -566,6 +563,8 @@ test "switch loop with packed unions with OPV" { } test "switch loop on large types" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { fn doTheTest(a: u128, b: i500) !void { label: switch (a) { diff --git a/test/behavior/switch_prong_err_enum.zig b/test/behavior/switch_prong_err_enum.zig index a2eed86c0f6e30db3f16182e31bdf2529cce3078..a316cacc61cd24cc3eac913fed77d33fe1430f7e 100644 --- a/test/behavior/switch_prong_err_enum.zig +++ b/test/behavior/switch_prong_err_enum.zig @@ -24,6 +24,7 @@ test "switch prong returns error enum" { if (builtin.zig_backend == .stage2_arm) 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_spirv) return error.SkipZigTest; switch (doThing(17) catch unreachable) { FormValue.Address => |payload| { diff --git a/test/behavior/switch_prong_implicit_cast.zig b/test/behavior/switch_prong_implicit_cast.zig index 0de343898df9a5b0a47b381bd25d45c0d265cb91..aab365f027ea17273c77e05bf96da48cfbedd612 100644 --- a/test/behavior/switch_prong_implicit_cast.zig +++ b/test/behavior/switch_prong_implicit_cast.zig @@ -18,6 +18,7 @@ test "switch prong implicit cast" { if (builtin.zig_backend == .stage2_aarch64) 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; const result = switch (foo(2) catch unreachable) { FormValue.One => false, diff --git a/test/behavior/truncate.zig b/test/behavior/truncate.zig index 01d9490d0c033678f5876bb4b633004c10e53d91..07d19f29c0da73a045ae58d35836502cbebe5cdc 100644 --- a/test/behavior/truncate.zig +++ b/test/behavior/truncate.zig @@ -50,6 +50,7 @@ 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); try testTruncate(u140, maxInt(u140), u128, maxInt(u128)); diff --git a/test/behavior/try.zig b/test/behavior/try.zig index df852abfa15d9c6618b15dd0ebfbfc23ae880208..649e22d5f94b1e30bd7892816b1ddbeb0da22db3 100644 --- a/test/behavior/try.zig +++ b/test/behavior/try.zig @@ -1,5 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); +const assert = std.debug.assert; const expect = std.testing.expect; test "try on error union" { @@ -197,3 +198,14 @@ test "try ptr propagation mutate" { try S.doTheTest(); try comptime S.doTheTest(); } + +test "try pointer expression alignment" { + const S = struct { + fn doTheTest(p: *align(1) (anyerror!u32)) !void { + comptime assert(@TypeOf(&(try p.*)) == *align(1) u32); + try expect((try p.*) == 10); + } + }; + var x: anyerror!u32 = 10; + try S.doTheTest(&x); +} diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index d8510b664b690980c1233eb83bd2351c74209e35..dabc3eb01af28b08e8cdcae8de076069ff054693 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -105,8 +105,6 @@ test "tuple initializer for var" { test "array-like initializer for tuple types" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const T = @Tuple(&.{ i32, u8 }); const S = struct { fn doTheTest() !void { @@ -172,7 +170,6 @@ test "fieldParentPtr of tuple" { 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; - var x: u32 = 0; _ = &x; const tuple = .{ x, x }; @@ -217,8 +214,6 @@ test "initializing tuple with mixed comptime-runtime fields" { } test "initializing anon struct with mixed comptime-runtime fields" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - var x: u32 = 15; _ = &x; const T = @TypeOf(.{ .foo = @as(i32, -1234), .bar = x }); @@ -230,8 +225,6 @@ test "initializing anon struct with mixed comptime-runtime fields" { test "tuple in tuple passed to generic function" { 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; - const S = struct { fn pair(x: f32, y: f32) @Tuple(&.{ f32, f32 }) { return .{ x, y }; @@ -299,6 +292,7 @@ test "tuple type with void field and a runtime field" { test "branching inside tuple literal" { 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; const S = struct { fn foo(a: anytype) !void { @@ -559,6 +553,8 @@ test "OPV tuple fields aren't comptime" { } test "array of tuples that end with a zero-bit field followed by padding" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { var foo: [2]struct { u32, u8, void } = .{ .{ 1, 2, {} }, .{ 3, 4, {} } }; }; diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 79f6769940713716288333d26fb290db3f3240a6..c2d1fc2f4fbf36674bdf3eab2b506fd4acd1fdb4 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -277,6 +277,7 @@ test "Type.Union from empty Type.Enum" { test "Type.Fn" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const some_opaque = opaque {}; const some_ptr = *some_opaque; diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index 882edcf3aba30b33d9f611837ed293551c42c91d..eeea34879b7a7cb8226a8c9107b381a79981a474 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -253,11 +253,11 @@ fn testUnion() !void { try expect(typeinfo_info == .@"union"); try expect(typeinfo_info.@"union".layout == .auto); try expect(typeinfo_info.@"union".tag_type.? == TypeId); - try expect(typeinfo_info.@"union".field_names.len == 24); + try expect(typeinfo_info.@"union".field_names.len == 25); try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_types.len); try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_attrs.len); try expect(typeinfo_info.@"union".field_types[4] == @TypeOf(@typeInfo(u8).int)); - try expect(typeinfo_info.@"union".decl_names.len == 16); + try expect(typeinfo_info.@"union".decl_names.len == 17); const TestNoTagUnion = union { Foo: void, @@ -310,6 +310,8 @@ const TestStruct = struct { }; test "type info: packed struct info" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + try testPackedStruct(); try comptime testPackedStruct(); } @@ -594,6 +596,8 @@ test "value from struct @typeInfo default_value_ptr can be loaded at comptime" { } test "type info of tuple of string literal default value" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const struct_info = @typeInfo(@TypeOf(.{"hi"})).@"struct"; const struct_field_attrs = struct_info.field_attrs[0]; const struct_field_type = struct_info.field_types[0]; @@ -609,3 +613,43 @@ test "@typeInfo function with generic return type and inferred error set" { const ret_ty = @typeInfo(@TypeOf(S.testFn)).@"fn".return_type; comptime assert(ret_ty == null); } + +test "type info: spirv info" { + if (builtin.zig_backend != .stage2_spirv) return error.SkipZigTest; + + try testSpirv(); + try comptime testSpirv(); +} + +fn testSpirv() !void { + const image_info = @typeInfo(Image); + try expect(image_info.spirv.image.usage.sampled == f32); + try expect(image_info.spirv.image.format == .unknown); + try expect(image_info.spirv.image.dim == .@"2d"); + try expect(image_info.spirv.image.depth == .not_depth); + try expect(image_info.spirv.image.arrayed == false); + try expect(image_info.spirv.image.multisampled == false); + try expect(image_info.spirv.image.access == .unknown); + + const sampled_image_info = @typeInfo(SampledImage); + try expect(sampled_image_info.spirv.sampled_image == Image); + + const sampler_info = @typeInfo(Sampler); + try expect(sampler_info.spirv.sampler == {}); + + const runtime_array_info = @typeInfo(RuntimeArray); + try expect(runtime_array_info.spirv.runtime_array == f32); +} + +pub const Image = @SpirvType(.{ .image = .{ + .usage = .{ .sampled = f32 }, + .format = .unknown, + .dim = .@"2d", + .depth = .not_depth, + .arrayed = false, + .multisampled = false, + .access = .unknown, +} }); +pub const SampledImage = @SpirvType(.{ .sampled_image = Image }); +pub const Sampler = @SpirvType(.sampler); +pub const RuntimeArray = @SpirvType(.{ .runtime_array = f32 }); diff --git a/test/behavior/union.zig b/test/behavior/union.zig index e9dbc49aaa9876b3c40ff9816749150a26aa6f1a..be8ae37a4eb5e9287f4392b62d35e73a5f5f1777 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -31,6 +31,7 @@ test "init union with runtime value - floats" { if (builtin.zig_backend == .stage2_arm) 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_spirv) return error.SkipZigTest; var foo: FooWithFloats = undefined; @@ -407,6 +408,7 @@ test "tagged union with no payloads" { test "union with only 1 field casted to its enum type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Literal = union(enum) { Number: f64, @@ -443,6 +445,7 @@ var glbl: Foo1 = undefined; test "global union with single field is correctly initialized" { 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; glbl = Foo1{ .f = @typeInfo(Foo1).@"union".field_types[0]{ .x = 123 }, @@ -485,6 +488,7 @@ test "update the tag value for zero-sized unions" { test "union initializer generates padding only if needed" { 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; const U = union(enum) { A: u24, @@ -550,6 +554,7 @@ const Baz = enum { A, B, C, D }; test "tagged union type" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const foo1 = TaggedFoo{ .One = 13 }; const foo2 = TaggedFoo{ @@ -654,6 +659,7 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { test "switch on union with only 1 field" { 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; var r: PartialInst = undefined; r = PartialInst.Compiled; @@ -682,6 +688,7 @@ const PartialInstWithPayload = union(enum) { test "union with only 1 field casted to its enum type which has enum value specified" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const Literal = union(enum) { number: f64, @@ -706,6 +713,7 @@ test "union with only 1 field casted to its enum type which has enum value speci test "@intFromEnum works on unions" { 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; const Bar = union(enum) { A: bool, @@ -765,6 +773,7 @@ test "return union init with void payload" { if (builtin.zig_backend == .stage2_aarch64) 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; const S = struct { fn entry() !void { @@ -789,6 +798,7 @@ test "@unionInit stored to a const" { 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 { const U = union(enum) { @@ -818,6 +828,7 @@ test "@unionInit stored to a const" { test "@unionInit can modify a union type" { 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; const UnionInitEnum = union(enum) { Boolean: bool, @@ -840,6 +851,7 @@ test "@unionInit can modify a union type" { test "@unionInit can modify a pointer value" { 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; const UnionInitEnum = union(enum) { Boolean: bool, @@ -887,7 +899,6 @@ test "anonymous union literal syntax" { 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 { const Number = union { int: i32, @@ -914,6 +925,7 @@ test "function call result coerces from tagged union to the tag" { 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_spirv) return error.SkipZigTest; const S = struct { const Arch = union(enum) { @@ -948,6 +960,7 @@ test "function call result coerces from tagged union to the tag" { test "switching on non exhaustive 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; const S = struct { const E = enum(u8) { @@ -1004,6 +1017,7 @@ test "containers with single-field enums" { test "@unionInit on union with u8 tag but no fields" { 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; const S = struct { const Type = enum(u8) { no_op = 105 }; @@ -1108,6 +1122,8 @@ test "union with a large struct field" { } test "comptime equality of extern unions with same tag" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { const U = extern union { a: i32, @@ -1126,6 +1142,7 @@ test "union tag is set when initiated as a temporary value at runtime" { 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 U = union(enum) { a, @@ -1165,6 +1182,7 @@ test "return an extern union from C calling convention" { 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 namespace = struct { const S = extern struct { @@ -1195,7 +1213,6 @@ test "return an extern union from C calling convention" { test "noreturn field in union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - const U = union(enum) { a: u32, b: noreturn, @@ -1246,7 +1263,7 @@ test "@unionInit uses tag value instead of field index" { 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 E = enum(u8) { b = 255, a = 3, @@ -1303,6 +1320,7 @@ test "packed union in packed struct" { 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_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = packed struct { nested: packed union { @@ -1374,6 +1392,7 @@ test "no dependency loop when function pointer in union returns the union" { test "union reassignment can use previous value" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const U = union { a: u32, @@ -1386,6 +1405,7 @@ test "union reassignment can use previous value" { test "reinterpreting enum value inside packed union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const U = packed union { tag: enum(u8) { a, b }, @@ -1864,6 +1884,7 @@ test "extern union initialized via reintepreted struct field initializer" { test "packed union initialized via reintepreted struct field initializer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; @@ -1909,6 +1930,7 @@ test "store of comptime reinterpreted memory to extern union" { test "store of comptime reinterpreted memory to packed union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; @@ -2256,6 +2278,8 @@ test "assign global tagged union" { } test "set mutable union by switching on same union" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const U = union(enum) { foo, bar: usize, diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index a01fc0a218dac64e24d7c43637d9dfcae43fe8f3..deedc94eab33a748e1d76a1ca08ea0d2241f0071 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -8,6 +8,7 @@ const expectEqual = std.testing.expectEqual; test "implicit cast vector to array - bool" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -30,6 +31,7 @@ test "implicit cast vector to array - bool" { } test "implicit cast array to vector - bool" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const S = struct { @@ -311,6 +313,7 @@ test "peer type resolution with coercible element types" { } test "tuple to vector" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -376,8 +379,6 @@ test "vector @splat" { 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 testForT(comptime N: comptime_int, v: anytype) !void { const T = @TypeOf(v); @@ -413,6 +414,7 @@ test "vector @splat" { } test "load vector elements via comptime index" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -433,6 +435,7 @@ test "load vector elements via comptime index" { } test "store vector elements via comptime index" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -528,8 +531,6 @@ test "vector division 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_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - const S = struct { fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void { const is_signed_int = switch (@typeInfo(T)) { @@ -1223,6 +1224,7 @@ test "@subWithOverflow" { } test "@mulWithOverflow" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -1243,6 +1245,7 @@ test "@mulWithOverflow" { } test "@shlWithOverflow" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -1371,6 +1374,7 @@ test "zero multiplicand" { 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_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const zeros = @Vector(2, u32){ 0.0, 0.0 }; var ones = @Vector(2, u32){ 1.0, 1.0 }; @@ -1413,6 +1417,7 @@ test "modRem with zero divisor" { } test "array operands to shuffle are coerced to vectors" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -1438,6 +1443,7 @@ test "load packed vector element" { } test "store packed vector element" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -1500,6 +1506,7 @@ test "store vector with memset" { } test "addition of vectors represented as strings" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -1510,6 +1517,7 @@ test "addition of vectors represented as strings" { } test "compare vectors with different element types" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; 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 @@ -1528,12 +1536,12 @@ test "vector pointer is indexable" { const V = @Vector(2, u32); const x: V = .{ 123, 456 }; - comptime assert(@TypeOf(&(&x)[0]) == *const u32); // validate constness + comptime assert(@typeInfo(@TypeOf(&(&x)[0])).pointer.attrs.@"const"); try expectEqual(@as(u32, 123), (&x)[0]); try expectEqual(@as(u32, 456), (&x)[1]); var y: V = .{ 123, 456 }; - comptime assert(@TypeOf(&(&y)[0]) == *u32); // validate constness + comptime assert(!@typeInfo(@TypeOf(&(&y)[0])).pointer.attrs.@"const"); try expectEqual(@as(u32, 123), (&y)[0]); try expectEqual(@as(u32, 456), (&y)[1]); @@ -1612,6 +1620,7 @@ 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/while.zig b/test/behavior/while.zig index 2854f8a8d492615f3c3a244b86e6f796a012b42f..d62495589b9458a441aaed0000514f60a0942528 100644 --- a/test/behavior/while.zig +++ b/test/behavior/while.zig @@ -38,8 +38,6 @@ fn staticWhileLoop2() i32 { } test "while with continue expression" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - var sum: i32 = 0; { var i: i32 = 0; @@ -158,7 +156,6 @@ test "while with optional as condition with else" { if (builtin.zig_backend == .stage2_arm) 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_spirv) return error.SkipZigTest; numbers_left = 10; var sum: i32 = 0; @@ -176,7 +173,6 @@ test "while with optional as condition with else" { test "while with error union condition" { 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; numbers_left = 10; var sum: i32 = 0; @@ -401,6 +397,8 @@ test "breaking from a loop in an if statement" { } test "labeled break from else" { + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + const S = struct { fn doTheTest(x: u32) !void { const arr: []const u32 = &.{ 1, 3, 10 }; diff --git a/test/behavior/widening.zig b/test/behavior/widening.zig index 48d0a7407ca126454a9bf12ff7e00fae7bc0a93e..c6571319d4fbb3a2265dd48fd31e67a9061e2055 100644 --- a/test/behavior/widening.zig +++ b/test/behavior/widening.zig @@ -6,7 +6,6 @@ const builtin = @import("builtin"); test "integer widening" { 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_riscv64) return error.SkipZigTest; var a: u8 = 250; diff --git a/test/behavior/wrapping_arithmetic.zig b/test/behavior/wrapping_arithmetic.zig index 247023c17a4d3531f5c45b66b9cc8742fe681b4a..2ea35241efbd2e236bc2d2ff2f3f02c7b58cbc64 100644 --- a/test/behavior/wrapping_arithmetic.zig +++ b/test/behavior/wrapping_arithmetic.zig @@ -5,7 +5,6 @@ const maxInt = std.math.maxInt; const expect = std.testing.expect; test "wrapping add" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -43,7 +42,6 @@ test "wrapping add" { } test "wrapping subtraction" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { @@ -79,7 +77,6 @@ test "wrapping subtraction" { } test "wrapping multiplication" { - if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; const S = struct { diff --git a/test/behavior/x86_64/unary.zig b/test/behavior/x86_64/unary.zig index a8446caae6e0ed7b125e6997eab8601a4253d2e6..2b2a9e288b30c1c0a1d0ab1de61b23522582b6e8 100644 --- a/test/behavior/x86_64/unary.zig +++ b/test/behavior/x86_64/unary.zig @@ -5262,6 +5262,7 @@ inline fn splat(comptime Type: type, rhs: Type) Type { } test splat { const test_splat = unary(splat, .{}); + try test_splat.testBoolVectors(); try test_splat.testIntVectors(); try test_splat.testFloatVectors(); } diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index 5e9d192c6ffc83fd4352281742730a6a58712995..302503ad4d839449c9aad546e712f3ebb6bdff3d 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -13,7 +13,15 @@ static void assert_or_panic(bool ok) { } } -#if defined __powerpc__ && !defined _ARCH_PPC64 +#if defined(__mips64__) +# define ZIG_MIPS64 +#elif defined(__mips__) +# define ZIG_MIPS32 +#endif + +#if defined(_ARCH_PPC64) +# define ZIG_PPC64 +#elif defined(__powerpc__) # define ZIG_PPC32 #endif @@ -69,7 +77,7 @@ static void assert_or_panic(bool ok) { # define ZIG_NO_COMPLEX #endif -#ifdef __powerpc__ +#ifdef ZIG_PPC32 # define ZIG_NO_COMPLEX #endif @@ -153,6 +161,10 @@ static void assert_or_panic(bool ok) { #define ZIG_NO_F128 #endif +#ifdef _MSC_VER +#define ZIG_NO_F128 +#endif + #ifndef ZIG_NO_I128 struct i128 { __int128 value; @@ -198,414 +210,93 @@ void zig_ptr(void *); void zig_bool(bool); +#ifndef ZIG_NO_COMPLEX // Note: These two functions match the signature of __mulsc3 and __muldc3 in compiler-rt (and libgcc) float complex zig_cmultf_comp(float a_r, float a_i, float b_r, float b_i); double complex zig_cmultd_comp(double a_r, double a_i, double b_r, double b_i); float complex zig_cmultf(float complex a, float complex b); double complex zig_cmultd(double complex a, double complex b); - -struct Struct_u8 { - uint8_t a; -}; - -struct Struct_u8 zig_ret_struct_u8(void); - -void zig_struct_u8(struct Struct_u8, size_t); - -struct Struct_u8 c_ret_struct_u8(void) { - return (struct Struct_u8){ .a = 4 }; -} - -void c_struct_u8(struct Struct_u8 s, size_t i) { - assert_or_panic(s.a == 5); - assert_or_panic(i == 6); -} - -struct Struct_u16 { - uint16_t a; -}; - -struct Struct_u16 zig_ret_struct_u16(void); - -void zig_struct_u16(struct Struct_u16, size_t); - -struct Struct_u16 c_ret_struct_u16(void) { - return (struct Struct_u16){ .a = 10 }; -} - -void c_struct_u16(struct Struct_u16 s, size_t i) { - assert_or_panic(s.a == 11); - assert_or_panic(i == 12); -} - -struct Struct_u32 { - uint32_t a; -}; - -struct Struct_u32 zig_ret_struct_u32(void); - -void zig_struct_u32(struct Struct_u32, size_t); - -struct Struct_u32 c_ret_struct_u32(void) { - return (struct Struct_u32){ .a = 16 }; -} - -void c_struct_u32(struct Struct_u32 s, size_t i) { - assert_or_panic(s.a == 17); - assert_or_panic(i == 18); -} - -struct Struct_u64 { - uint64_t a; -}; - -struct Struct_u64 zig_ret_struct_u64(void); - -void zig_struct_u64(struct Struct_u64, size_t); - -struct Struct_u64 c_ret_struct_u64(void) { - return (struct Struct_u64){ .a = 22 }; -} - -void c_struct_u64(struct Struct_u64 s, size_t i) { - assert_or_panic(s.a == 23); - assert_or_panic(i == 24); -} - -struct Struct_u64_u64 { - uint64_t a; - uint64_t b; -}; - -struct Struct_u64_u64 zig_ret_struct_u64_u64(void); - -void zig_struct_u64_u64_0(struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_1(size_t, struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_2(size_t, size_t, struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_3(size_t, size_t, size_t, struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_4(size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_5(size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_6(size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_7(size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); -void zig_struct_u64_u64_8(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); - -struct Struct_u64_u64 c_ret_struct_u64_u64(void) { - return (struct Struct_u64_u64){ .a = 21, .b = 22 }; -} - -void c_struct_u64_u64_0(struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 23); - assert_or_panic(s.b == 24); - assert_or_panic(i == 1); -} -void c_struct_u64_u64_1(size_t a0, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 25); - assert_or_panic(s.b == 26); - assert_or_panic(i == 2); -} -void c_struct_u64_u64_2(size_t, size_t, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 27); - assert_or_panic(s.b == 28); - assert_or_panic(i == 3); -} -void c_struct_u64_u64_3(size_t, size_t, size_t, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 29); - assert_or_panic(s.b == 30); - assert_or_panic(i == 4); -} -void c_struct_u64_u64_4(size_t, size_t, size_t, size_t, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 31); - assert_or_panic(s.b == 32); - assert_or_panic(i == 5); -} -void c_struct_u64_u64_5(size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 33); - assert_or_panic(s.b == 34); - assert_or_panic(i == 6); -} -void c_struct_u64_u64_6(size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 35); - assert_or_panic(s.b == 36); - assert_or_panic(i == 7); -} -void c_struct_u64_u64_7(size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 37); - assert_or_panic(s.b == 38); - assert_or_panic(i == 8); -} -void c_struct_u64_u64_8(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64 s, size_t i) { - assert_or_panic(s.a == 39); - assert_or_panic(s.b == 40); - assert_or_panic(i == 9); -} - -struct Struct_f32 { - float a; -}; - -struct Struct_f32 zig_ret_struct_f32(void); - -void zig_struct_f32(struct Struct_f32); - -struct Struct_f32 c_ret_struct_f32(void) { - return (struct Struct_f32){ .a = 2.5f }; -} - -void c_struct_f32(struct Struct_f32 s) { - assert_or_panic(s.a == 2.5f); -} - -struct Struct_f64 { - double a; -}; - -struct Struct_f64 zig_ret_struct_f64(void); - -void zig_struct_f64(struct Struct_f64); - -struct Struct_f64 c_ret_struct_f64(void) { - return (struct Struct_f64){ .a = 2.5 }; -} - -void c_struct_f64(struct Struct_f64 s) { - assert_or_panic(s.a == 2.5); -} - -struct Struct_f32a8 { - alignas(8) float a; -}; - -struct Struct_f32a8 zig_ret_struct_f32a8(void); - -void zig_struct_f32a8(struct Struct_f32a8, float); - -struct Struct_f32a8 c_ret_struct_f32a8(void) { - return (struct Struct_f32a8){ .a = 4.125f }; -} - -void c_struct_f32a8(struct Struct_f32a8 s, float f) { - assert_or_panic(s.a == 5.375f); - assert_or_panic(f == 6.5f); -} - -struct Struct_f32a8_f32a8 { - alignas(8) float a; - alignas(8) float b; -}; - -struct Struct_f32a8_f32a8 zig_ret_struct_f32a8_f32a8(void); - -void zig_struct_f32a8_f32a8(struct Struct_f32a8_f32a8, float); - -struct Struct_f32a8_f32a8 c_ret_struct_f32a8_f32a8(void) { - return (struct Struct_f32a8_f32a8){ .a = 6.625f, .b = 7.875f }; -} - -void c_struct_f32a8_f32a8(struct Struct_f32a8_f32a8 s, float f) { - assert_or_panic(s.a == 8.0625f); - assert_or_panic(s.b == 9.1875f); - assert_or_panic(f == 10.5f); -} - -struct Struct_f32f32_f32 { - struct { - float b, c; - } a; - float d; -}; - -struct Struct_f32f32_f32 zig_ret_struct_f32f32_f32(void); - -void zig_struct_f32f32_f32(struct Struct_f32f32_f32); - -struct Struct_f32f32_f32 c_ret_struct_f32f32_f32(void) { - return (struct Struct_f32f32_f32){ .a = { .b = 1.0f, .c = 2.0f }, .d = 3.0f }; -} - -void c_struct_f32f32_f32(struct Struct_f32f32_f32 s) { - assert_or_panic(s.a.b == 1.0f); - assert_or_panic(s.a.c == 2.0f); - assert_or_panic(s.d == 3.0f); -} - -struct Struct_f32_f32f32 { - float a; - struct { - float c, d; - } b; -}; - -struct Struct_f32_f32f32 zig_ret_struct_f32_f32f32(void); - -void zig_struct_f32_f32f32(struct Struct_f32_f32f32); - -struct Struct_f32_f32f32 c_ret_struct_f32_f32f32(void) { - return (struct Struct_f32_f32f32){ .a = 1.0f, .b = { .c = 2.0f, .d = 3.0f } }; -} - -void c_struct_f32_f32f32(struct Struct_f32_f32f32 s) { - assert_or_panic(s.a == 1.0f); - assert_or_panic(s.b.c == 2.0f); - assert_or_panic(s.b.d == 3.0f); -} - -struct Struct_u32_Union_u32_u32u32 { - uint32_t a; - union { - struct { - uint32_t d, e; - } c; - } b; -}; - -struct Struct_u32_Union_u32_u32u32 zig_ret_struct_u32_union_u32_u32u32(void); - -void zig_struct_u32_union_u32_u32u32(struct Struct_u32_Union_u32_u32u32); - -struct Struct_u32_Union_u32_u32u32 c_ret_struct_u32_union_u32_u32u32(void) { - struct Struct_u32_Union_u32_u32u32 s; - s.a = 1; - s.b.c.d = 2; - s.b.c.e = 3; - return s; -} - -void c_struct_u32_union_u32_u32u32(struct Struct_u32_Union_u32_u32u32 s) { - assert_or_panic(s.a == 1); - assert_or_panic(s.b.c.d == 2); - assert_or_panic(s.b.c.e == 3); -} - -struct Struct_i32_i32 { - int32_t a; - int32_t b; -}; - -void zig_struct_i32_i32(struct Struct_i32_i32); - -struct BigStruct { - uint64_t a; - uint64_t b; - uint64_t c; - uint64_t d; - uint8_t e; -}; - -void zig_big_struct(struct BigStruct); - -union BigUnion { - struct BigStruct a; -}; - -void zig_big_union(union BigUnion); - -struct SmallStructInts { - uint8_t a; - uint8_t b; - uint8_t c; - uint8_t d; -}; - -void zig_small_struct_ints(struct SmallStructInts); -struct SmallStructInts zig_ret_small_struct_ints(); - -struct MedStructInts { - int32_t x; - int32_t y; - int32_t z; -}; - -void zig_med_struct_ints(struct MedStructInts); -struct MedStructInts zig_ret_med_struct_ints(); - -struct MedStructMixed { - uint32_t a; - float b; - float c; - uint32_t d; -}; - -void zig_med_struct_mixed(struct MedStructMixed); -struct MedStructMixed zig_ret_med_struct_mixed(); - -void zig_small_packed_struct(uint8_t); -#ifndef ZIG_NO_I128 -void zig_big_packed_struct(__int128); #endif -struct SplitStructInts { - uint64_t a; - uint8_t b; - uint32_t c; -}; -void zig_split_struct_ints(struct SplitStructInts); - -struct SplitStructMixed { - uint64_t a; - uint8_t b; - float c; -}; -void zig_split_struct_mixed(struct SplitStructMixed); -struct SplitStructMixed zig_ret_split_struct_mixed(); - -struct BigStruct zig_big_struct_both(struct BigStruct); - -typedef float Vector2Float __attribute__((ext_vector_type(2))); -typedef float Vector4Float __attribute__((ext_vector_type(4))); - -void c_vector_2_float(Vector2Float vec) { - assert_or_panic(vec[0] == 1.0); - assert_or_panic(vec[1] == 2.0); -} - -void c_vector_4_float(Vector4Float vec) { - assert_or_panic(vec[0] == 1.0); - assert_or_panic(vec[1] == 2.0); - assert_or_panic(vec[2] == 3.0); - assert_or_panic(vec[3] == 4.0); -} - -Vector2Float c_ret_vector_2_float(void) { - return (Vector2Float){ - 1.0, - 2.0, - }; -} -Vector4Float c_ret_vector_4_float(void) { - return (Vector4Float){ - 1.0, - 2.0, - 3.0, - 4.0, - }; -} - #if defined(ZIG_BACKEND_STAGE2_X86_64) || defined(ZIG_PPC32) || defined(__wasm__) -typedef bool Vector2Bool __attribute__((ext_vector_type(2))); -typedef bool Vector4Bool __attribute__((ext_vector_type(4))); -typedef bool Vector8Bool __attribute__((ext_vector_type(8))); -typedef bool Vector16Bool __attribute__((ext_vector_type(16))); -typedef bool Vector32Bool __attribute__((ext_vector_type(32))); -typedef bool Vector64Bool __attribute__((ext_vector_type(64))); -typedef bool Vector128Bool __attribute__((ext_vector_type(128))); -typedef bool Vector256Bool __attribute__((ext_vector_type(256))); -typedef bool Vector512Bool __attribute__((ext_vector_type(512))); +typedef bool Vector_2_bool __attribute__((ext_vector_type(2))); -void c_vector_2_bool(Vector2Bool vec) { +Vector_2_bool zig_ret_vector_2_bool(void); +void zig_vector_2_bool(Vector_2_bool vec); + +Vector_2_bool c_ret_vector_2_bool(void) { + return (Vector_2_bool){ + true, + false, + }; +} +void c_vector_2_bool(Vector_2_bool vec) { assert_or_panic(vec[0] == true); assert_or_panic(vec[1] == true); } +void c_test_vector_2_bool(void) { + Vector_2_bool vec = zig_ret_vector_2_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == false); + zig_vector_2_bool((Vector_2_bool){ + false, + true, + }); +} -void c_vector_4_bool(Vector4Bool vec) { +typedef bool Vector_4_bool __attribute__((ext_vector_type(4))); + +Vector_4_bool zig_ret_vector_4_bool(void); +void zig_vector_4_bool(Vector_4_bool vec); + +Vector_4_bool c_ret_vector_4_bool(void) { + return (Vector_4_bool){ + true, + false, + true, + false, + }; +} +void c_vector_4_bool(Vector_4_bool vec) { assert_or_panic(vec[0] == true); assert_or_panic(vec[1] == true); assert_or_panic(vec[2] == false); assert_or_panic(vec[3] == true); } +void c_test_vector_4_bool(void) { + Vector_4_bool vec = zig_ret_vector_4_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == true); + zig_vector_4_bool((Vector_4_bool){ + false, + false, + false, + false, + }); +} -void c_vector_8_bool(Vector8Bool vec) { +typedef bool Vector_8_bool __attribute__((ext_vector_type(8))); + +Vector_8_bool zig_ret_vector_8_bool(void); +void zig_vector_8_bool(Vector_8_bool vec); + +Vector_8_bool c_ret_vector_8_bool(void) { + return (Vector_8_bool){ + false, + true, + false, + false, + true, + false, + false, + true, + }; +} +void c_vector_8_bool(Vector_8_bool vec) { assert_or_panic(vec[0] == true); assert_or_panic(vec[1] == false); assert_or_panic(vec[2] == true); @@ -615,8 +306,54 @@ void c_vector_8_bool(Vector8Bool vec) { assert_or_panic(vec[6] == false); assert_or_panic(vec[7] == true); } +void c_test_vector_8_bool(void) { + Vector_8_bool vec = zig_ret_vector_8_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == false); + zig_vector_8_bool((Vector_8_bool){ + true, + true, + false, + true, + false, + true, + true, + false, + }); +} -void c_vector_16_bool(Vector16Bool vec) { +typedef bool Vector_16_bool __attribute__((ext_vector_type(16))); + +Vector_16_bool zig_ret_vector_16_bool(void); +void zig_vector_16_bool(Vector_16_bool vec); + +Vector_16_bool c_ret_vector_16_bool(void) { + return (Vector_16_bool){ + true, + true, + false, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + }; +} +void c_vector_16_bool(Vector_16_bool vec) { assert_or_panic(vec[0] == true); assert_or_panic(vec[1] == false); assert_or_panic(vec[2] == false); @@ -634,8 +371,86 @@ void c_vector_16_bool(Vector16Bool vec) { assert_or_panic(vec[14] == false); assert_or_panic(vec[15] == false); } +void c_test_vector_16_bool(void) { + Vector_16_bool vec = zig_ret_vector_16_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == false); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == true); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); + zig_vector_16_bool((Vector_16_bool){ + true, + false, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + }); +} -void c_vector_32_bool(Vector32Bool vec) { +typedef bool Vector_32_bool __attribute__((ext_vector_type(32))); + +Vector_32_bool zig_ret_vector_32_bool(void); +void zig_vector_32_bool(Vector_32_bool vec); + +Vector_32_bool c_ret_vector_32_bool(void) { + return (Vector_32_bool){ + true, + false, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + false, + }; +} +void c_vector_32_bool(Vector_32_bool vec) { assert_or_panic(vec[0] == true); assert_or_panic(vec[1] == false); assert_or_panic(vec[2] == true); @@ -669,8 +484,150 @@ void c_vector_32_bool(Vector32Bool vec) { assert_or_panic(vec[30] == true); assert_or_panic(vec[31] == false); } +void c_test_vector_32_bool(void) { + Vector_32_bool vec = zig_ret_vector_32_bool(); + assert_or_panic(vec[0] == false); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); + assert_or_panic(vec[16] == false); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == false); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == true); + assert_or_panic(vec[25] == false); + assert_or_panic(vec[26] == false); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == false); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == true); + zig_vector_32_bool((Vector_32_bool){ + false, + false, + false, + true, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + }); +} -void c_vector_64_bool(Vector64Bool vec) { +typedef bool Vector_64_bool __attribute__((ext_vector_type(64))); + +Vector_64_bool zig_ret_vector_64_bool(void); +void zig_vector_64_bool(Vector_64_bool vec); + +Vector_64_bool c_ret_vector_64_bool(void) { + return (Vector_64_bool){ + false, + true, + false, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + }; +} +void c_vector_64_bool(Vector_64_bool vec) { assert_or_panic(vec[0] == true); assert_or_panic(vec[1] == true); assert_or_panic(vec[2] == true); @@ -736,8 +693,278 @@ void c_vector_64_bool(Vector64Bool vec) { assert_or_panic(vec[62] == true); assert_or_panic(vec[63] == false); } +void c_test_vector_64_bool(void) { + Vector_64_bool vec = zig_ret_vector_64_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == false); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == true); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == true); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == false); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == false); + assert_or_panic(vec[21] == false); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == true); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == false); + assert_or_panic(vec[31] == false); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == true); + assert_or_panic(vec[34] == true); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == false); + assert_or_panic(vec[37] == true); + assert_or_panic(vec[38] == false); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == true); + assert_or_panic(vec[41] == true); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == true); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == true); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == true); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == true); + assert_or_panic(vec[54] == false); + assert_or_panic(vec[55] == false); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == false); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == false); + assert_or_panic(vec[62] == true); + assert_or_panic(vec[63] == false); + zig_vector_64_bool((Vector_64_bool){ + true, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + false, + false, + false, + false, + false, + true, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + }); +} -void c_vector_128_bool(Vector128Bool vec) { +typedef bool Vector_128_bool __attribute__((ext_vector_type(128))); + +Vector_128_bool zig_ret_vector_128_bool(void); +void zig_vector_128_bool(Vector_128_bool vec); + +Vector_128_bool c_ret_vector_128_bool(void) { + return (Vector_128_bool){ + false, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + }; +} +void c_vector_128_bool(Vector_128_bool vec) { assert_or_panic(vec[0] == false); assert_or_panic(vec[1] == false); assert_or_panic(vec[2] == false); @@ -867,11 +1094,536 @@ void c_vector_128_bool(Vector128Bool vec) { assert_or_panic(vec[126] == true); assert_or_panic(vec[127] == true); } +void c_test_vector_128_bool(void) { + Vector_128_bool vec = zig_ret_vector_128_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == false); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == true); + assert_or_panic(vec[7] == false); + assert_or_panic(vec[8] == false); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == true); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == false); + assert_or_panic(vec[19] == true); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == true); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == false); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == true); + assert_or_panic(vec[28] == true); + assert_or_panic(vec[29] == false); + assert_or_panic(vec[30] == false); + assert_or_panic(vec[31] == true); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == false); + assert_or_panic(vec[34] == true); + assert_or_panic(vec[35] == true); + assert_or_panic(vec[36] == true); + assert_or_panic(vec[37] == false); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == true); + assert_or_panic(vec[41] == false); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == true); + assert_or_panic(vec[48] == false); + assert_or_panic(vec[49] == false); + assert_or_panic(vec[50] == false); + assert_or_panic(vec[51] == false); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == false); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == false); + assert_or_panic(vec[56] == true); + assert_or_panic(vec[57] == false); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == true); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == true); + assert_or_panic(vec[62] == true); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == false); + assert_or_panic(vec[65] == false); + assert_or_panic(vec[66] == false); + assert_or_panic(vec[67] == true); + assert_or_panic(vec[68] == true); + assert_or_panic(vec[69] == false); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == true); + assert_or_panic(vec[72] == false); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == true); + assert_or_panic(vec[75] == false); + assert_or_panic(vec[76] == false); + assert_or_panic(vec[77] == true); + assert_or_panic(vec[78] == false); + assert_or_panic(vec[79] == true); + assert_or_panic(vec[80] == false); + assert_or_panic(vec[81] == false); + assert_or_panic(vec[82] == true); + assert_or_panic(vec[83] == true); + assert_or_panic(vec[84] == false); + assert_or_panic(vec[85] == true); + assert_or_panic(vec[86] == false); + assert_or_panic(vec[87] == false); + assert_or_panic(vec[88] == true); + assert_or_panic(vec[89] == true); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == true); + assert_or_panic(vec[92] == true); + assert_or_panic(vec[93] == false); + assert_or_panic(vec[94] == false); + assert_or_panic(vec[95] == true); + assert_or_panic(vec[96] == false); + assert_or_panic(vec[97] == false); + assert_or_panic(vec[98] == true); + assert_or_panic(vec[99] == true); + assert_or_panic(vec[100] == true); + assert_or_panic(vec[101] == true); + assert_or_panic(vec[102] == true); + assert_or_panic(vec[103] == true); + assert_or_panic(vec[104] == true); + assert_or_panic(vec[105] == false); + assert_or_panic(vec[106] == false); + assert_or_panic(vec[107] == true); + assert_or_panic(vec[108] == false); + assert_or_panic(vec[109] == false); + assert_or_panic(vec[110] == true); + assert_or_panic(vec[111] == false); + assert_or_panic(vec[112] == false); + assert_or_panic(vec[113] == true); + assert_or_panic(vec[114] == false); + assert_or_panic(vec[115] == false); + assert_or_panic(vec[116] == false); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == false); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == true); + assert_or_panic(vec[122] == true); + assert_or_panic(vec[123] == false); + assert_or_panic(vec[124] == true); + assert_or_panic(vec[125] == false); + assert_or_panic(vec[126] == false); + assert_or_panic(vec[127] == true); + zig_vector_128_bool((Vector_128_bool){ + true, + true, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + }); +} +typedef bool Vector_256_bool __attribute__((ext_vector_type(256))); + +Vector_256_bool zig_ret_vector_256_bool(void); +void zig_vector_256_bool(Vector_256_bool vec); + +Vector_256_bool c_ret_vector_256_bool(void) { + return (Vector_256_bool){ + true, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + true, + false, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + }; +} // WASM: The following vector functions define too many Wasm locals for wasmtime in debug mode and are therefore disabled for the wasm target. -#if !defined(__wasm__) - -void c_vector_256_bool(Vector256Bool vec) { +#ifndef __wasm__ +void c_vector_256_bool(Vector_256_bool vec) { assert_or_panic(vec[0] == false); assert_or_panic(vec[1] == true); assert_or_panic(vec[2] == true); @@ -1129,8 +1881,1049 @@ void c_vector_256_bool(Vector256Bool vec) { assert_or_panic(vec[254] == true); assert_or_panic(vec[255] == false); } +#endif +void c_test_vector_256_bool(void) { + Vector_256_bool vec = zig_ret_vector_256_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == false); + assert_or_panic(vec[4] == true); + assert_or_panic(vec[5] == false); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == false); + assert_or_panic(vec[9] == false); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == false); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == false); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == true); + assert_or_panic(vec[19] == false); + assert_or_panic(vec[20] == false); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == true); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == true); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == false); + assert_or_panic(vec[28] == true); + assert_or_panic(vec[29] == true); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == false); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == false); + assert_or_panic(vec[34] == true); + assert_or_panic(vec[35] == false); + assert_or_panic(vec[36] == true); + assert_or_panic(vec[37] == false); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == false); + assert_or_panic(vec[40] == false); + assert_or_panic(vec[41] == false); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == true); + assert_or_panic(vec[44] == true); + assert_or_panic(vec[45] == false); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == false); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == false); + assert_or_panic(vec[50] == true); + assert_or_panic(vec[51] == false); + assert_or_panic(vec[52] == true); + assert_or_panic(vec[53] == false); + assert_or_panic(vec[54] == true); + assert_or_panic(vec[55] == true); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == false); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == true); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == true); + assert_or_panic(vec[62] == false); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == false); + assert_or_panic(vec[65] == true); + assert_or_panic(vec[66] == false); + assert_or_panic(vec[67] == true); + assert_or_panic(vec[68] == true); + assert_or_panic(vec[69] == false); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == false); + assert_or_panic(vec[72] == true); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == false); + assert_or_panic(vec[75] == false); + assert_or_panic(vec[76] == false); + assert_or_panic(vec[77] == false); + assert_or_panic(vec[78] == false); + assert_or_panic(vec[79] == false); + assert_or_panic(vec[80] == false); + assert_or_panic(vec[81] == false); + assert_or_panic(vec[82] == false); + assert_or_panic(vec[83] == true); + assert_or_panic(vec[84] == false); + assert_or_panic(vec[85] == false); + assert_or_panic(vec[86] == false); + assert_or_panic(vec[87] == true); + assert_or_panic(vec[88] == false); + assert_or_panic(vec[89] == true); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == false); + assert_or_panic(vec[92] == false); + assert_or_panic(vec[93] == true); + assert_or_panic(vec[94] == true); + assert_or_panic(vec[95] == false); + assert_or_panic(vec[96] == false); + assert_or_panic(vec[97] == true); + assert_or_panic(vec[98] == false); + assert_or_panic(vec[99] == false); + assert_or_panic(vec[100] == false); + assert_or_panic(vec[101] == false); + assert_or_panic(vec[102] == false); + assert_or_panic(vec[103] == false); + assert_or_panic(vec[104] == false); + assert_or_panic(vec[105] == true); + assert_or_panic(vec[106] == true); + assert_or_panic(vec[107] == false); + assert_or_panic(vec[108] == true); + assert_or_panic(vec[109] == false); + assert_or_panic(vec[110] == true); + assert_or_panic(vec[111] == true); + assert_or_panic(vec[112] == false); + assert_or_panic(vec[113] == false); + assert_or_panic(vec[114] == false); + assert_or_panic(vec[115] == false); + assert_or_panic(vec[116] == false); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == true); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == true); + assert_or_panic(vec[122] == false); + assert_or_panic(vec[123] == true); + assert_or_panic(vec[124] == true); + assert_or_panic(vec[125] == false); + assert_or_panic(vec[126] == false); + assert_or_panic(vec[127] == true); + assert_or_panic(vec[128] == true); + assert_or_panic(vec[129] == true); + assert_or_panic(vec[130] == true); + assert_or_panic(vec[131] == true); + assert_or_panic(vec[132] == false); + assert_or_panic(vec[133] == true); + assert_or_panic(vec[134] == true); + assert_or_panic(vec[135] == false); + assert_or_panic(vec[136] == false); + assert_or_panic(vec[137] == true); + assert_or_panic(vec[138] == true); + assert_or_panic(vec[139] == false); + assert_or_panic(vec[140] == true); + assert_or_panic(vec[141] == false); + assert_or_panic(vec[142] == true); + assert_or_panic(vec[143] == false); + assert_or_panic(vec[144] == true); + assert_or_panic(vec[145] == true); + assert_or_panic(vec[146] == true); + assert_or_panic(vec[147] == true); + assert_or_panic(vec[148] == false); + assert_or_panic(vec[149] == false); + assert_or_panic(vec[150] == false); + assert_or_panic(vec[151] == true); + assert_or_panic(vec[152] == false); + assert_or_panic(vec[153] == true); + assert_or_panic(vec[154] == false); + assert_or_panic(vec[155] == true); + assert_or_panic(vec[156] == true); + assert_or_panic(vec[157] == false); + assert_or_panic(vec[158] == true); + assert_or_panic(vec[159] == true); + assert_or_panic(vec[160] == true); + assert_or_panic(vec[161] == true); + assert_or_panic(vec[162] == true); + assert_or_panic(vec[163] == false); + assert_or_panic(vec[164] == false); + assert_or_panic(vec[165] == true); + assert_or_panic(vec[166] == false); + assert_or_panic(vec[167] == true); + assert_or_panic(vec[168] == true); + assert_or_panic(vec[169] == true); + assert_or_panic(vec[170] == true); + assert_or_panic(vec[171] == false); + assert_or_panic(vec[172] == true); + assert_or_panic(vec[173] == true); + assert_or_panic(vec[174] == true); + assert_or_panic(vec[175] == true); + assert_or_panic(vec[176] == true); + assert_or_panic(vec[177] == true); + assert_or_panic(vec[178] == true); + assert_or_panic(vec[179] == false); + assert_or_panic(vec[180] == true); + assert_or_panic(vec[181] == false); + assert_or_panic(vec[182] == false); + assert_or_panic(vec[183] == false); + assert_or_panic(vec[184] == true); + assert_or_panic(vec[185] == false); + assert_or_panic(vec[186] == true); + assert_or_panic(vec[187] == true); + assert_or_panic(vec[188] == false); + assert_or_panic(vec[189] == true); + assert_or_panic(vec[190] == false); + assert_or_panic(vec[191] == true); + assert_or_panic(vec[192] == false); + assert_or_panic(vec[193] == true); + assert_or_panic(vec[194] == false); + assert_or_panic(vec[195] == false); + assert_or_panic(vec[196] == true); + assert_or_panic(vec[197] == true); + assert_or_panic(vec[198] == true); + assert_or_panic(vec[199] == true); + assert_or_panic(vec[200] == true); + assert_or_panic(vec[201] == true); + assert_or_panic(vec[202] == true); + assert_or_panic(vec[203] == false); + assert_or_panic(vec[204] == true); + assert_or_panic(vec[205] == false); + assert_or_panic(vec[206] == false); + assert_or_panic(vec[207] == true); + assert_or_panic(vec[208] == true); + assert_or_panic(vec[209] == false); + assert_or_panic(vec[210] == false); + assert_or_panic(vec[211] == false); + assert_or_panic(vec[212] == true); + assert_or_panic(vec[213] == true); + assert_or_panic(vec[214] == true); + assert_or_panic(vec[215] == false); + assert_or_panic(vec[216] == false); + assert_or_panic(vec[217] == true); + assert_or_panic(vec[218] == true); + assert_or_panic(vec[219] == true); + assert_or_panic(vec[220] == true); + assert_or_panic(vec[221] == false); + assert_or_panic(vec[222] == true); + assert_or_panic(vec[223] == false); + assert_or_panic(vec[224] == true); + assert_or_panic(vec[225] == true); + assert_or_panic(vec[226] == true); + assert_or_panic(vec[227] == false); + assert_or_panic(vec[228] == false); + assert_or_panic(vec[229] == false); + assert_or_panic(vec[230] == false); + assert_or_panic(vec[231] == false); + assert_or_panic(vec[232] == true); + assert_or_panic(vec[233] == true); + assert_or_panic(vec[234] == false); + assert_or_panic(vec[235] == false); + assert_or_panic(vec[236] == false); + assert_or_panic(vec[237] == true); + assert_or_panic(vec[238] == true); + assert_or_panic(vec[239] == false); + assert_or_panic(vec[240] == true); + assert_or_panic(vec[241] == true); + assert_or_panic(vec[242] == true); + assert_or_panic(vec[243] == false); + assert_or_panic(vec[244] == true); + assert_or_panic(vec[245] == true); + assert_or_panic(vec[246] == false); + assert_or_panic(vec[247] == true); + assert_or_panic(vec[248] == false); + assert_or_panic(vec[249] == false); + assert_or_panic(vec[250] == true); + assert_or_panic(vec[251] == true); + assert_or_panic(vec[252] == false); + assert_or_panic(vec[253] == true); + assert_or_panic(vec[254] == false); + assert_or_panic(vec[255] == true); + zig_vector_256_bool((Vector_256_bool){ + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + false, + false, + true, + true, + true, + true, + }); +} -void c_vector_512_bool(Vector512Bool vec) { +typedef bool Vector_512_bool __attribute__((ext_vector_type(512))); + +Vector_512_bool zig_ret_vector_512_bool(void); +void zig_vector_512_bool(Vector_512_bool vec); + +Vector_512_bool c_ret_vector_512_bool(void) { + return (Vector_512_bool){ + false, + true, + false, + false, + false, + true, + false, + false, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false, + }; +} +// WASM: The following vector functions define too many Wasm locals for wasmtime in debug mode and are therefore disabled for the wasm target. +#ifndef __wasm__ +void c_vector_512_bool(Vector_512_bool vec) { assert_or_panic(vec[0] == true); assert_or_panic(vec[1] == true); assert_or_panic(vec[2] == true); @@ -1644,43 +3437,531 @@ void c_vector_512_bool(Vector512Bool vec) { assert_or_panic(vec[510] == false); assert_or_panic(vec[511] == true); } - #endif - -Vector2Bool c_ret_vector_2_bool(void) { - return (Vector2Bool){ - true, +void c_test_vector_512_bool(void) { + Vector_512_bool vec = zig_ret_vector_512_bool(); + assert_or_panic(vec[0] == true); + assert_or_panic(vec[1] == true); + assert_or_panic(vec[2] == true); + assert_or_panic(vec[3] == true); + assert_or_panic(vec[4] == false); + assert_or_panic(vec[5] == true); + assert_or_panic(vec[6] == false); + assert_or_panic(vec[7] == true); + assert_or_panic(vec[8] == true); + assert_or_panic(vec[9] == true); + assert_or_panic(vec[10] == false); + assert_or_panic(vec[11] == true); + assert_or_panic(vec[12] == false); + assert_or_panic(vec[13] == false); + assert_or_panic(vec[14] == false); + assert_or_panic(vec[15] == true); + assert_or_panic(vec[16] == true); + assert_or_panic(vec[17] == false); + assert_or_panic(vec[18] == false); + assert_or_panic(vec[19] == false); + assert_or_panic(vec[20] == true); + assert_or_panic(vec[21] == true); + assert_or_panic(vec[22] == false); + assert_or_panic(vec[23] == false); + assert_or_panic(vec[24] == false); + assert_or_panic(vec[25] == false); + assert_or_panic(vec[26] == true); + assert_or_panic(vec[27] == false); + assert_or_panic(vec[28] == false); + assert_or_panic(vec[29] == false); + assert_or_panic(vec[30] == true); + assert_or_panic(vec[31] == true); + assert_or_panic(vec[32] == true); + assert_or_panic(vec[33] == true); + assert_or_panic(vec[34] == false); + assert_or_panic(vec[35] == false); + assert_or_panic(vec[36] == false); + assert_or_panic(vec[37] == true); + assert_or_panic(vec[38] == true); + assert_or_panic(vec[39] == true); + assert_or_panic(vec[40] == false); + assert_or_panic(vec[41] == false); + assert_or_panic(vec[42] == true); + assert_or_panic(vec[43] == false); + assert_or_panic(vec[44] == false); + assert_or_panic(vec[45] == true); + assert_or_panic(vec[46] == false); + assert_or_panic(vec[47] == false); + assert_or_panic(vec[48] == true); + assert_or_panic(vec[49] == true); + assert_or_panic(vec[50] == true); + assert_or_panic(vec[51] == true); + assert_or_panic(vec[52] == false); + assert_or_panic(vec[53] == false); + assert_or_panic(vec[54] == false); + assert_or_panic(vec[55] == true); + assert_or_panic(vec[56] == false); + assert_or_panic(vec[57] == true); + assert_or_panic(vec[58] == false); + assert_or_panic(vec[59] == true); + assert_or_panic(vec[60] == true); + assert_or_panic(vec[61] == false); + assert_or_panic(vec[62] == false); + assert_or_panic(vec[63] == true); + assert_or_panic(vec[64] == true); + assert_or_panic(vec[65] == false); + assert_or_panic(vec[66] == true); + assert_or_panic(vec[67] == false); + assert_or_panic(vec[68] == false); + assert_or_panic(vec[69] == false); + assert_or_panic(vec[70] == true); + assert_or_panic(vec[71] == true); + assert_or_panic(vec[72] == true); + assert_or_panic(vec[73] == true); + assert_or_panic(vec[74] == true); + assert_or_panic(vec[75] == false); + assert_or_panic(vec[76] == true); + assert_or_panic(vec[77] == false); + assert_or_panic(vec[78] == true); + assert_or_panic(vec[79] == true); + assert_or_panic(vec[80] == true); + assert_or_panic(vec[81] == true); + assert_or_panic(vec[82] == true); + assert_or_panic(vec[83] == false); + assert_or_panic(vec[84] == true); + assert_or_panic(vec[85] == true); + assert_or_panic(vec[86] == false); + assert_or_panic(vec[87] == true); + assert_or_panic(vec[88] == false); + assert_or_panic(vec[89] == false); + assert_or_panic(vec[90] == true); + assert_or_panic(vec[91] == false); + assert_or_panic(vec[92] == true); + assert_or_panic(vec[93] == false); + assert_or_panic(vec[94] == false); + assert_or_panic(vec[95] == false); + assert_or_panic(vec[96] == true); + assert_or_panic(vec[97] == true); + assert_or_panic(vec[98] == false); + assert_or_panic(vec[99] == true); + assert_or_panic(vec[100] == true); + assert_or_panic(vec[101] == false); + assert_or_panic(vec[102] == true); + assert_or_panic(vec[103] == false); + assert_or_panic(vec[104] == true); + assert_or_panic(vec[105] == false); + assert_or_panic(vec[106] == true); + assert_or_panic(vec[107] == false); + assert_or_panic(vec[108] == false); + assert_or_panic(vec[109] == true); + assert_or_panic(vec[110] == false); + assert_or_panic(vec[111] == false); + assert_or_panic(vec[112] == true); + assert_or_panic(vec[113] == false); + assert_or_panic(vec[114] == true); + assert_or_panic(vec[115] == false); + assert_or_panic(vec[116] == true); + assert_or_panic(vec[117] == false); + assert_or_panic(vec[118] == false); + assert_or_panic(vec[119] == true); + assert_or_panic(vec[120] == true); + assert_or_panic(vec[121] == true); + assert_or_panic(vec[122] == false); + assert_or_panic(vec[123] == true); + assert_or_panic(vec[124] == false); + assert_or_panic(vec[125] == false); + assert_or_panic(vec[126] == true); + assert_or_panic(vec[127] == true); + assert_or_panic(vec[128] == false); + assert_or_panic(vec[129] == true); + assert_or_panic(vec[130] == true); + assert_or_panic(vec[131] == false); + assert_or_panic(vec[132] == true); + assert_or_panic(vec[133] == true); + assert_or_panic(vec[134] == false); + assert_or_panic(vec[135] == true); + assert_or_panic(vec[136] == true); + assert_or_panic(vec[137] == false); + assert_or_panic(vec[138] == false); + assert_or_panic(vec[139] == false); + assert_or_panic(vec[140] == true); + assert_or_panic(vec[141] == false); + assert_or_panic(vec[142] == true); + assert_or_panic(vec[143] == false); + assert_or_panic(vec[144] == false); + assert_or_panic(vec[145] == false); + assert_or_panic(vec[146] == true); + assert_or_panic(vec[147] == false); + assert_or_panic(vec[148] == true); + assert_or_panic(vec[149] == false); + assert_or_panic(vec[150] == false); + assert_or_panic(vec[151] == true); + assert_or_panic(vec[152] == false); + assert_or_panic(vec[153] == true); + assert_or_panic(vec[154] == true); + assert_or_panic(vec[155] == false); + assert_or_panic(vec[156] == true); + assert_or_panic(vec[157] == true); + assert_or_panic(vec[158] == false); + assert_or_panic(vec[159] == true); + assert_or_panic(vec[160] == true); + assert_or_panic(vec[161] == false); + assert_or_panic(vec[162] == false); + assert_or_panic(vec[163] == false); + assert_or_panic(vec[164] == true); + assert_or_panic(vec[165] == false); + assert_or_panic(vec[166] == true); + assert_or_panic(vec[167] == true); + assert_or_panic(vec[168] == true); + assert_or_panic(vec[169] == true); + assert_or_panic(vec[170] == false); + assert_or_panic(vec[171] == true); + assert_or_panic(vec[172] == false); + assert_or_panic(vec[173] == false); + assert_or_panic(vec[174] == true); + assert_or_panic(vec[175] == true); + assert_or_panic(vec[176] == true); + assert_or_panic(vec[177] == false); + assert_or_panic(vec[178] == false); + assert_or_panic(vec[179] == false); + assert_or_panic(vec[180] == true); + assert_or_panic(vec[181] == false); + assert_or_panic(vec[182] == false); + assert_or_panic(vec[183] == true); + assert_or_panic(vec[184] == true); + assert_or_panic(vec[185] == false); + assert_or_panic(vec[186] == true); + assert_or_panic(vec[187] == false); + assert_or_panic(vec[188] == true); + assert_or_panic(vec[189] == true); + assert_or_panic(vec[190] == true); + assert_or_panic(vec[191] == true); + assert_or_panic(vec[192] == true); + assert_or_panic(vec[193] == true); + assert_or_panic(vec[194] == true); + assert_or_panic(vec[195] == false); + assert_or_panic(vec[196] == false); + assert_or_panic(vec[197] == false); + assert_or_panic(vec[198] == false); + assert_or_panic(vec[199] == false); + assert_or_panic(vec[200] == true); + assert_or_panic(vec[201] == false); + assert_or_panic(vec[202] == true); + assert_or_panic(vec[203] == false); + assert_or_panic(vec[204] == true); + assert_or_panic(vec[205] == true); + assert_or_panic(vec[206] == false); + assert_or_panic(vec[207] == false); + assert_or_panic(vec[208] == false); + assert_or_panic(vec[209] == true); + assert_or_panic(vec[210] == true); + assert_or_panic(vec[211] == true); + assert_or_panic(vec[212] == false); + assert_or_panic(vec[213] == false); + assert_or_panic(vec[214] == true); + assert_or_panic(vec[215] == true); + assert_or_panic(vec[216] == true); + assert_or_panic(vec[217] == false); + assert_or_panic(vec[218] == false); + assert_or_panic(vec[219] == true); + assert_or_panic(vec[220] == false); + assert_or_panic(vec[221] == true); + assert_or_panic(vec[222] == true); + assert_or_panic(vec[223] == false); + assert_or_panic(vec[224] == true); + assert_or_panic(vec[225] == false); + assert_or_panic(vec[226] == false); + assert_or_panic(vec[227] == true); + assert_or_panic(vec[228] == false); + assert_or_panic(vec[229] == false); + assert_or_panic(vec[230] == true); + assert_or_panic(vec[231] == true); + assert_or_panic(vec[232] == false); + assert_or_panic(vec[233] == true); + assert_or_panic(vec[234] == true); + assert_or_panic(vec[235] == true); + assert_or_panic(vec[236] == true); + assert_or_panic(vec[237] == true); + assert_or_panic(vec[238] == false); + assert_or_panic(vec[239] == true); + assert_or_panic(vec[240] == false); + assert_or_panic(vec[241] == false); + assert_or_panic(vec[242] == true); + assert_or_panic(vec[243] == false); + assert_or_panic(vec[244] == true); + assert_or_panic(vec[245] == false); + assert_or_panic(vec[246] == true); + assert_or_panic(vec[247] == false); + assert_or_panic(vec[248] == true); + assert_or_panic(vec[249] == true); + assert_or_panic(vec[250] == true); + assert_or_panic(vec[251] == true); + assert_or_panic(vec[252] == true); + assert_or_panic(vec[253] == false); + assert_or_panic(vec[254] == false); + assert_or_panic(vec[255] == false); + assert_or_panic(vec[256] == false); + assert_or_panic(vec[257] == false); + assert_or_panic(vec[258] == false); + assert_or_panic(vec[259] == true); + assert_or_panic(vec[260] == true); + assert_or_panic(vec[261] == true); + assert_or_panic(vec[262] == true); + assert_or_panic(vec[263] == false); + assert_or_panic(vec[264] == false); + assert_or_panic(vec[265] == false); + assert_or_panic(vec[266] == true); + assert_or_panic(vec[267] == false); + assert_or_panic(vec[268] == true); + assert_or_panic(vec[269] == false); + assert_or_panic(vec[270] == true); + assert_or_panic(vec[271] == true); + assert_or_panic(vec[272] == true); + assert_or_panic(vec[273] == true); + assert_or_panic(vec[274] == true); + assert_or_panic(vec[275] == true); + assert_or_panic(vec[276] == false); + assert_or_panic(vec[277] == false); + assert_or_panic(vec[278] == true); + assert_or_panic(vec[279] == true); + assert_or_panic(vec[280] == false); + assert_or_panic(vec[281] == false); + assert_or_panic(vec[282] == false); + assert_or_panic(vec[283] == false); + assert_or_panic(vec[284] == true); + assert_or_panic(vec[285] == true); + assert_or_panic(vec[286] == true); + assert_or_panic(vec[287] == false); + assert_or_panic(vec[288] == false); + assert_or_panic(vec[289] == false); + assert_or_panic(vec[290] == true); + assert_or_panic(vec[291] == false); + assert_or_panic(vec[292] == true); + assert_or_panic(vec[293] == true); + assert_or_panic(vec[294] == false); + assert_or_panic(vec[295] == true); + assert_or_panic(vec[296] == true); + assert_or_panic(vec[297] == true); + assert_or_panic(vec[298] == false); + assert_or_panic(vec[299] == true); + assert_or_panic(vec[300] == true); + assert_or_panic(vec[301] == false); + assert_or_panic(vec[302] == false); + assert_or_panic(vec[303] == true); + assert_or_panic(vec[304] == false); + assert_or_panic(vec[305] == false); + assert_or_panic(vec[306] == true); + assert_or_panic(vec[307] == true); + assert_or_panic(vec[308] == true); + assert_or_panic(vec[309] == true); + assert_or_panic(vec[310] == false); + assert_or_panic(vec[311] == false); + assert_or_panic(vec[312] == false); + assert_or_panic(vec[313] == false); + assert_or_panic(vec[314] == false); + assert_or_panic(vec[315] == true); + assert_or_panic(vec[316] == false); + assert_or_panic(vec[317] == false); + assert_or_panic(vec[318] == true); + assert_or_panic(vec[319] == false); + assert_or_panic(vec[320] == false); + assert_or_panic(vec[321] == true); + assert_or_panic(vec[322] == true); + assert_or_panic(vec[323] == true); + assert_or_panic(vec[324] == true); + assert_or_panic(vec[325] == false); + assert_or_panic(vec[326] == false); + assert_or_panic(vec[327] == false); + assert_or_panic(vec[328] == true); + assert_or_panic(vec[329] == true); + assert_or_panic(vec[330] == false); + assert_or_panic(vec[331] == true); + assert_or_panic(vec[332] == true); + assert_or_panic(vec[333] == false); + assert_or_panic(vec[334] == false); + assert_or_panic(vec[335] == true); + assert_or_panic(vec[336] == true); + assert_or_panic(vec[337] == false); + assert_or_panic(vec[338] == true); + assert_or_panic(vec[339] == true); + assert_or_panic(vec[340] == true); + assert_or_panic(vec[341] == false); + assert_or_panic(vec[342] == false); + assert_or_panic(vec[343] == false); + assert_or_panic(vec[344] == true); + assert_or_panic(vec[345] == true); + assert_or_panic(vec[346] == false); + assert_or_panic(vec[347] == true); + assert_or_panic(vec[348] == false); + assert_or_panic(vec[349] == true); + assert_or_panic(vec[350] == false); + assert_or_panic(vec[351] == false); + assert_or_panic(vec[352] == true); + assert_or_panic(vec[353] == false); + assert_or_panic(vec[354] == true); + assert_or_panic(vec[355] == false); + assert_or_panic(vec[356] == false); + assert_or_panic(vec[357] == false); + assert_or_panic(vec[358] == false); + assert_or_panic(vec[359] == false); + assert_or_panic(vec[360] == true); + assert_or_panic(vec[361] == true); + assert_or_panic(vec[362] == false); + assert_or_panic(vec[363] == false); + assert_or_panic(vec[364] == false); + assert_or_panic(vec[365] == false); + assert_or_panic(vec[366] == true); + assert_or_panic(vec[367] == false); + assert_or_panic(vec[368] == true); + assert_or_panic(vec[369] == false); + assert_or_panic(vec[370] == true); + assert_or_panic(vec[371] == true); + assert_or_panic(vec[372] == false); + assert_or_panic(vec[373] == true); + assert_or_panic(vec[374] == true); + assert_or_panic(vec[375] == true); + assert_or_panic(vec[376] == true); + assert_or_panic(vec[377] == true); + assert_or_panic(vec[378] == false); + assert_or_panic(vec[379] == true); + assert_or_panic(vec[380] == false); + assert_or_panic(vec[381] == true); + assert_or_panic(vec[382] == true); + assert_or_panic(vec[383] == true); + assert_or_panic(vec[384] == true); + assert_or_panic(vec[385] == true); + assert_or_panic(vec[386] == false); + assert_or_panic(vec[387] == true); + assert_or_panic(vec[388] == true); + assert_or_panic(vec[389] == false); + assert_or_panic(vec[390] == true); + assert_or_panic(vec[391] == false); + assert_or_panic(vec[392] == true); + assert_or_panic(vec[393] == false); + assert_or_panic(vec[394] == true); + assert_or_panic(vec[395] == false); + assert_or_panic(vec[396] == true); + assert_or_panic(vec[397] == false); + assert_or_panic(vec[398] == false); + assert_or_panic(vec[399] == true); + assert_or_panic(vec[400] == true); + assert_or_panic(vec[401] == true); + assert_or_panic(vec[402] == true); + assert_or_panic(vec[403] == false); + assert_or_panic(vec[404] == false); + assert_or_panic(vec[405] == true); + assert_or_panic(vec[406] == false); + assert_or_panic(vec[407] == false); + assert_or_panic(vec[408] == false); + assert_or_panic(vec[409] == true); + assert_or_panic(vec[410] == false); + assert_or_panic(vec[411] == true); + assert_or_panic(vec[412] == true); + assert_or_panic(vec[413] == false); + assert_or_panic(vec[414] == true); + assert_or_panic(vec[415] == true); + assert_or_panic(vec[416] == false); + assert_or_panic(vec[417] == true); + assert_or_panic(vec[418] == true); + assert_or_panic(vec[419] == false); + assert_or_panic(vec[420] == false); + assert_or_panic(vec[421] == true); + assert_or_panic(vec[422] == false); + assert_or_panic(vec[423] == false); + assert_or_panic(vec[424] == true); + assert_or_panic(vec[425] == false); + assert_or_panic(vec[426] == true); + assert_or_panic(vec[427] == false); + assert_or_panic(vec[428] == false); + assert_or_panic(vec[429] == true); + assert_or_panic(vec[430] == false); + assert_or_panic(vec[431] == true); + assert_or_panic(vec[432] == true); + assert_or_panic(vec[433] == false); + assert_or_panic(vec[434] == true); + assert_or_panic(vec[435] == false); + assert_or_panic(vec[436] == true); + assert_or_panic(vec[437] == false); + assert_or_panic(vec[438] == true); + assert_or_panic(vec[439] == false); + assert_or_panic(vec[440] == false); + assert_or_panic(vec[441] == true); + assert_or_panic(vec[442] == true); + assert_or_panic(vec[443] == false); + assert_or_panic(vec[444] == true); + assert_or_panic(vec[445] == true); + assert_or_panic(vec[446] == false); + assert_or_panic(vec[447] == true); + assert_or_panic(vec[448] == true); + assert_or_panic(vec[449] == false); + assert_or_panic(vec[450] == false); + assert_or_panic(vec[451] == false); + assert_or_panic(vec[452] == false); + assert_or_panic(vec[453] == false); + assert_or_panic(vec[454] == true); + assert_or_panic(vec[455] == false); + assert_or_panic(vec[456] == false); + assert_or_panic(vec[457] == true); + assert_or_panic(vec[458] == false); + assert_or_panic(vec[459] == true); + assert_or_panic(vec[460] == false); + assert_or_panic(vec[461] == false); + assert_or_panic(vec[462] == false); + assert_or_panic(vec[463] == true); + assert_or_panic(vec[464] == false); + assert_or_panic(vec[465] == true); + assert_or_panic(vec[466] == false); + assert_or_panic(vec[467] == false); + assert_or_panic(vec[468] == false); + assert_or_panic(vec[469] == false); + assert_or_panic(vec[470] == true); + assert_or_panic(vec[471] == true); + assert_or_panic(vec[472] == false); + assert_or_panic(vec[473] == true); + assert_or_panic(vec[474] == true); + assert_or_panic(vec[475] == false); + assert_or_panic(vec[476] == false); + assert_or_panic(vec[477] == true); + assert_or_panic(vec[478] == true); + assert_or_panic(vec[479] == true); + assert_or_panic(vec[480] == false); + assert_or_panic(vec[481] == false); + assert_or_panic(vec[482] == true); + assert_or_panic(vec[483] == false); + assert_or_panic(vec[484] == false); + assert_or_panic(vec[485] == false); + assert_or_panic(vec[486] == true); + assert_or_panic(vec[487] == true); + assert_or_panic(vec[488] == false); + assert_or_panic(vec[489] == false); + assert_or_panic(vec[490] == false); + assert_or_panic(vec[491] == false); + assert_or_panic(vec[492] == false); + assert_or_panic(vec[493] == true); + assert_or_panic(vec[494] == true); + assert_or_panic(vec[495] == true); + assert_or_panic(vec[496] == true); + assert_or_panic(vec[497] == false); + assert_or_panic(vec[498] == false); + assert_or_panic(vec[499] == false); + assert_or_panic(vec[500] == true); + assert_or_panic(vec[501] == false); + assert_or_panic(vec[502] == true); + assert_or_panic(vec[503] == true); + assert_or_panic(vec[504] == true); + assert_or_panic(vec[505] == true); + assert_or_panic(vec[506] == false); + assert_or_panic(vec[507] == false); + assert_or_panic(vec[508] == true); + assert_or_panic(vec[509] == true); + assert_or_panic(vec[510] == false); + assert_or_panic(vec[511] == false); + zig_vector_512_bool((Vector_512_bool){ false, - }; -} - -Vector4Bool c_ret_vector_4_bool(void) { - return (Vector4Bool){ true, - false, true, false, - }; -} - -Vector8Bool c_ret_vector_8_bool(void) { - return (Vector8Bool){ - false, true, false, - false, true, false, false, - true, - }; -} - -Vector16Bool c_ret_vector_16_bool(void) { - return (Vector16Bool){ - true, - true, - false, false, false, false, @@ -1689,68 +3970,49 @@ Vector16Bool c_ret_vector_16_bool(void) { true, false, false, - true, - true, false, true, true, - }; -} - -Vector32Bool c_ret_vector_32_bool(void) { - return (Vector32Bool){ - true, - false, - true, true, true, false, - true, false, - true, - true, - true, false, true, true, false, - false, + true, true, false, false, - false, - false, - true, true, true, false, - true, false, false, - true, false, false, false, - }; -} - -Vector64Bool c_ret_vector_64_bool(void) { - return (Vector64Bool){ false, true, + true, + true, false, true, true, true, - false, true, true, + false, true, true, true, + false, true, false, + false, true, + false, true, true, false, @@ -1758,35 +4020,36 @@ Vector64Bool c_ret_vector_64_bool(void) { false, true, true, - false, true, - false, true, false, - true, false, true, + true, false, true, + true, false, false, true, - true, false, false, false, true, true, true, - true, false, false, + true, false, true, + false, + false, true, false, false, true, + true, false, false, false, @@ -1795,76 +4058,68 @@ Vector64Bool c_ret_vector_64_bool(void) { false, false, false, + false, + false, + false, true, true, true, true, true, - }; -} - -Vector128Bool c_ret_vector_128_bool(void) { - return (Vector128Bool){ false, - true, - true, false, - true, false, false, true, true, false, true, - false, - false, - false, - true, - false, true, false, false, true, false, - true, false, false, false, true, true, true, + true, false, false, false, false, true, - true, - true, - false, - true, - true, false, false, false, false, true, true, + false, true, false, + true, false, false, + true, + true, false, true, + true, false, false, - true, false, + true, false, false, false, false, true, true, + false, + false, true, false, true, @@ -1875,12 +4130,6 @@ Vector128Bool c_ret_vector_128_bool(void) { false, false, false, - false, - false, - true, - true, - true, - true, true, false, false, @@ -1890,41 +4139,35 @@ Vector128Bool c_ret_vector_128_bool(void) { false, true, false, - true, false, - true, false, - true, false, true, - true, - true, - true, false, false, - true, false, false, - true, + false, + false, true, true, true, false, true, true, - true, false, false, - true, + false, false, false, true, true, false, - true, + false, false, true, - true, + false, + false, true, true, true, @@ -1933,53 +4176,39 @@ Vector128Bool c_ret_vector_128_bool(void) { true, false, true, - }; -} - -Vector256Bool c_ret_vector_256_bool(void) { - return (Vector256Bool){ true, - false, true, true, false, - false, + true, false, false, false, true, false, - true, false, - true, false, false, - true, - true, - true, false, false, false, true, false, - true, false, false, true, true, true, - false, - false, - true, - true, true, false, true, true, - true, + false, + false, false, true, false, + false, true, true, false, @@ -1989,38 +4218,33 @@ Vector256Bool c_ret_vector_256_bool(void) { true, false, false, - true, - true, false, false, true, false, true, true, - true, false, - true, - true, false, true, true, + true, false, true, false, + false, true, true, + false, true, false, true, true, - false, true, true, true, true, - false, true, - false, true, true, true, @@ -2029,23 +4253,22 @@ Vector256Bool c_ret_vector_256_bool(void) { false, true, false, - false, + true, true, false, + true, false, + true, false, true, true, false, - false, - false, true, true, true, false, false, false, - true, false, true, true, @@ -2055,24 +4278,17 @@ Vector256Bool c_ret_vector_256_bool(void) { true, true, true, - false, true, false, true, false, false, true, - true, - false, - true, - false, false, false, false, - true, false, false, - true, false, false, false, @@ -2080,22 +4296,12 @@ Vector256Bool c_ret_vector_256_bool(void) { false, false, true, - false, true, false, - true, - true, - true, false, - true, - true, false, - true, - true, false, - true, - true, - true, + false, true, true, true, @@ -2103,18 +4309,19 @@ Vector256Bool c_ret_vector_256_bool(void) { false, false, false, + false, + true, true, false, false, - true, false, true, true, - true, false, false, - true, - true, + false, + false, + false, true, true, false, @@ -2122,19 +4329,19 @@ Vector256Bool c_ret_vector_256_bool(void) { true, false, true, - false, - false, + true, false, true, true, + false, true, true, + false, true, + false, true, true, true, - false, - false, true, false, false, @@ -2143,20 +4350,15 @@ Vector256Bool c_ret_vector_256_bool(void) { true, true, true, - true, - true, - false, - false, false, true, true, true, false, - true, false, true, false, - true, + false, false, true, true, @@ -2164,53 +4366,28 @@ Vector256Bool c_ret_vector_256_bool(void) { false, true, false, - true, false, - true, false, true, false, false, true, - false, true, true, - false, - false, true, false, - false, - false, true, true, false, false, false, - false, - false, - true, - false, true, - false, - false, - false, - }; -} - -Vector512Bool c_ret_vector_512_bool(void) { - return (Vector512Bool){ false, true, - false, - false, - false, true, false, false, false, - true, - false, - false, false, true, false, @@ -2219,46 +4396,34 @@ Vector512Bool c_ret_vector_512_bool(void) { false, false, false, - false, - false, - true, true, false, false, - false, - false, true, true, - false, true, false, true, true, - true, - false, false, true, + false, true, false, false, false, + true, false, false, - true, false, true, true, - false, - true, true, true, true, false, false, false, - true, - true, - false, false, false, false, @@ -2268,44 +4433,26 @@ Vector512Bool c_ret_vector_512_bool(void) { true, true, false, - false, - false, - false, - false, - true, - false, - true, - false, - false, true, true, false, - false, - false, true, false, true, - true, - true, false, true, false, false, - true, - true, false, true, - true, false, - true, false, - true, - true, false, true, true, false, false, + true, false, true, false, @@ -2314,459 +4461,10843 @@ Vector512Bool c_ret_vector_512_bool(void) { true, true, true, - false, true, false, - true, false, true, - true, - false, - true, - false, - true, - true, - true, - false, - true, - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - true, - false, - true, - false, - true, - false, - false, - true, - false, - true, - true, - true, - false, - false, - true, - false, - false, - false, - true, - true, - true, - false, - true, - false, - false, - false, - false, - false, - true, - true, - false, - false, - true, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - true, - true, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - true, - false, - true, - true, - true, - true, - false, - true, - false, - true, - false, - true, - false, - false, - false, - true, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - true, - false, - true, - false, - false, - true, - false, - true, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - true, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - true, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - false, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - false, - false, - true, - true, - false, - true, - true, - true, - true, - true, - true, - false, - true, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - false, - true, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - true, - false, - true, - true, - false, - false, - true, - false, - false, - true, - false, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - true, - true, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - true, - false, - false, - false, - false, - true, - true, - true, - false, - true, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - true, - true, - true, - false, - true, - true, - true, - false, - true, - false, - true, - false, - true, - false, - true, - true, - true, - true, - false, - true, - true, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - true, - false, + }); +} + +#endif + +typedef uint8_t Vector_1_u8 __attribute__((vector_size(1 * sizeof(uint8_t)))); + +Vector_1_u8 zig_ret_vector_1_u8(void); +void zig_vector_1_u8(Vector_1_u8, size_t); + +Vector_1_u8 c_ret_vector_1_u8(void) { + return (Vector_1_u8){ 3 }; +} +void c_vector_1_u8(Vector_1_u8 v, size_t i) { + assert_or_panic(v[0] == 4); + assert_or_panic(i == 1); +} +void c_test_vector_1_u8(void) { + Vector_1_u8 v = zig_ret_vector_1_u8(); + assert_or_panic(v[0] == 1); + zig_vector_1_u8((Vector_1_u8){ 2 }, 1); +} + +typedef uint8_t Vector_2_u8 __attribute__((vector_size(2 * sizeof(uint8_t)))); + +Vector_2_u8 zig_ret_vector_2_u8(void); +void zig_vector_2_u8(Vector_2_u8, size_t); + +Vector_2_u8 c_ret_vector_2_u8(void) { + return (Vector_2_u8){ 9, 10 }; +} +void c_vector_2_u8(Vector_2_u8 v, size_t i) { + assert_or_panic(v[0] == 11); + assert_or_panic(v[1] == 12); + assert_or_panic(i == 2); +} +void c_test_vector_2_u8(void) { + Vector_2_u8 v = zig_ret_vector_2_u8(); + assert_or_panic(v[0] == 5); + assert_or_panic(v[1] == 6); + zig_vector_2_u8((Vector_2_u8){ 7, 8 }, 2); +} + +typedef uint8_t Vector_3_u8 __attribute__((vector_size(3 * sizeof(uint8_t)))); + +Vector_3_u8 zig_ret_vector_3_u8(void); +void zig_vector_3_u8(Vector_3_u8, size_t); + +Vector_3_u8 c_ret_vector_3_u8(void) { + return (Vector_3_u8){ 19, 20, 21 }; +} +void c_vector_3_u8(Vector_3_u8 v, size_t i) { + assert_or_panic(v[0] == 22); + assert_or_panic(v[1] == 23); + assert_or_panic(v[2] == 24); + assert_or_panic(i == 3); +} +void c_test_vector_3_u8(void) { + Vector_3_u8 v = zig_ret_vector_3_u8(); + assert_or_panic(v[0] == 13); + assert_or_panic(v[1] == 14); + assert_or_panic(v[2] == 15); + zig_vector_3_u8((Vector_3_u8){ 16, 17, 18 }, 3); +} + +typedef uint8_t Vector_4_u8 __attribute__((vector_size(4 * sizeof(uint8_t)))); + +Vector_4_u8 zig_ret_vector_4_u8(void); +void zig_vector_4_u8(Vector_4_u8, size_t); +void zig_vector_4_u8_vector_4_u8(Vector_4_u8, Vector_4_u8, size_t); + +Vector_4_u8 c_ret_vector_4_u8(void) { + return (Vector_4_u8){ 41, 42, 43, 44 }; +} +void c_vector_4_u8(Vector_4_u8 v, size_t i) { + assert_or_panic(v[0] == 45); + assert_or_panic(v[1] == 46); + assert_or_panic(v[2] == 47); + assert_or_panic(v[3] == 48); + assert_or_panic(i == 4); +} +void c_vector_4_u8_vector_4_u8(Vector_4_u8 v0, Vector_4_u8 v1, size_t i) { + assert_or_panic(v0[0] == 49); + assert_or_panic(v0[1] == 50); + assert_or_panic(v0[2] == 51); + assert_or_panic(v0[3] == 52); + assert_or_panic(v1[0] == 53); + assert_or_panic(v1[1] == 54); + assert_or_panic(v1[2] == 55); + assert_or_panic(v1[3] == 56); + assert_or_panic(i == 8); +} +void c_test_vector_4_u8(void) { + Vector_4_u8 v = zig_ret_vector_4_u8(); + assert_or_panic(v[0] == 25); + assert_or_panic(v[1] == 26); + assert_or_panic(v[2] == 27); + assert_or_panic(v[3] == 28); + zig_vector_4_u8((Vector_4_u8){ 29, 30, 31, 32 }, 4); + zig_vector_4_u8_vector_4_u8((Vector_4_u8){ 33, 34, 35, 36 }, (Vector_4_u8){ 37, 38, 39, 40 }, 8); +} + +typedef uint8_t Vector_6_u8 __attribute__((vector_size(6 * sizeof(uint8_t)))); + +Vector_6_u8 zig_ret_vector_6_u8(void); +void zig_vector_6_u8(Vector_6_u8, size_t); + +Vector_6_u8 c_ret_vector_6_u8(void) { + return (Vector_6_u8){ 53, 54, 55, 56, 57, 58 }; +} +void c_vector_6_u8(Vector_6_u8 v, size_t i) { + assert_or_panic(v[0] == 59); + assert_or_panic(v[1] == 60); + assert_or_panic(v[2] == 61); + assert_or_panic(v[3] == 62); + assert_or_panic(v[4] == 63); + assert_or_panic(v[5] == 64); + assert_or_panic(i == 6); +} +void c_test_vector_6_u8(void) { + Vector_6_u8 v = zig_ret_vector_6_u8(); + assert_or_panic(v[0] == 41); + assert_or_panic(v[1] == 42); + assert_or_panic(v[2] == 43); + assert_or_panic(v[3] == 44); + assert_or_panic(v[4] == 45); + assert_or_panic(v[5] == 46); + zig_vector_6_u8((Vector_6_u8){ 47, 48, 49, 50, 51, 52 }, 6); +} + +typedef uint8_t Vector_8_u8 __attribute__((vector_size(8 * sizeof(uint8_t)))); + +Vector_8_u8 zig_ret_vector_8_u8(void); +void zig_vector_8_u8(Vector_8_u8, size_t); + +Vector_8_u8 c_ret_vector_8_u8(void) { + return (Vector_8_u8){ 81, 82, 83, 84, 85, 86, 87, 88 }; +} +void c_vector_8_u8(Vector_8_u8 v, size_t i) { + assert_or_panic(v[0] == 89); + assert_or_panic(v[1] == 90); + assert_or_panic(v[2] == 91); + assert_or_panic(v[3] == 92); + assert_or_panic(v[4] == 93); + assert_or_panic(v[5] == 94); + assert_or_panic(v[6] == 95); + assert_or_panic(v[7] == 96); + assert_or_panic(i == 8); +} +void c_test_vector_8_u8(void) { + Vector_8_u8 v = zig_ret_vector_8_u8(); + assert_or_panic(v[0] == 65); + assert_or_panic(v[1] == 66); + assert_or_panic(v[2] == 67); + assert_or_panic(v[3] == 68); + assert_or_panic(v[4] == 69); + assert_or_panic(v[5] == 70); + assert_or_panic(v[6] == 71); + assert_or_panic(v[7] == 72); + zig_vector_8_u8((Vector_8_u8){ 73, 74, 75, 76, 77, 78, 79, 80 }, 8); +} + +typedef uint8_t Vector_12_u8 __attribute__((vector_size(12 * sizeof(uint8_t)))); + +Vector_12_u8 zig_ret_vector_12_u8(void); +void zig_vector_12_u8(Vector_12_u8, size_t); + +Vector_12_u8 c_ret_vector_12_u8(void) { + return (Vector_12_u8){ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }; +} +void c_vector_12_u8(Vector_12_u8 v, size_t i) { + assert_or_panic(v[0] == 33); + assert_or_panic(v[1] == 34); + assert_or_panic(v[2] == 35); + assert_or_panic(v[3] == 36); + assert_or_panic(v[4] == 37); + assert_or_panic(v[5] == 38); + assert_or_panic(v[6] == 39); + assert_or_panic(v[7] == 40); + assert_or_panic(v[8] == 41); + assert_or_panic(v[9] == 42); + assert_or_panic(v[10] == 43); + assert_or_panic(v[11] == 44); + assert_or_panic(i == 12); +} +void c_test_vector_12_u8(void) { + Vector_12_u8 v = zig_ret_vector_12_u8(); + assert_or_panic(v[0] == 97); + assert_or_panic(v[1] == 98); + assert_or_panic(v[2] == 99); + assert_or_panic(v[3] == 0); + assert_or_panic(v[4] == 1); + assert_or_panic(v[5] == 2); + assert_or_panic(v[6] == 3); + assert_or_panic(v[7] == 4); + assert_or_panic(v[8] == 5); + assert_or_panic(v[9] == 6); + assert_or_panic(v[10] == 7); + assert_or_panic(v[11] == 8); + zig_vector_12_u8((Vector_12_u8){ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }, 12); +} + +typedef uint8_t Vector_16_u8 __attribute__((vector_size(16 * sizeof(uint8_t)))); + +Vector_16_u8 zig_ret_vector_16_u8(void); +void zig_vector_16_u8(Vector_16_u8, size_t); + +Vector_16_u8 c_ret_vector_16_u8(void) { + return (Vector_16_u8){ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92 }; +} +void c_vector_16_u8(Vector_16_u8 v, size_t i) { + assert_or_panic(v[0] == 93); + assert_or_panic(v[1] == 94); + assert_or_panic(v[2] == 95); + assert_or_panic(v[3] == 96); + assert_or_panic(v[4] == 97); + assert_or_panic(v[5] == 98); + assert_or_panic(v[6] == 99); + assert_or_panic(v[7] == 0); + assert_or_panic(v[8] == 1); + assert_or_panic(v[9] == 2); + assert_or_panic(v[10] == 3); + assert_or_panic(v[11] == 4); + assert_or_panic(v[12] == 5); + assert_or_panic(v[13] == 6); + assert_or_panic(v[14] == 7); + assert_or_panic(v[15] == 8); + assert_or_panic(i == 16); +} +void c_test_vector_16_u8(void) { + Vector_16_u8 v = zig_ret_vector_16_u8(); + assert_or_panic(v[0] == 45); + assert_or_panic(v[1] == 46); + assert_or_panic(v[2] == 47); + assert_or_panic(v[3] == 48); + assert_or_panic(v[4] == 49); + assert_or_panic(v[5] == 50); + assert_or_panic(v[6] == 51); + assert_or_panic(v[7] == 52); + assert_or_panic(v[8] == 53); + assert_or_panic(v[9] == 54); + assert_or_panic(v[10] == 55); + assert_or_panic(v[11] == 56); + assert_or_panic(v[12] == 57); + assert_or_panic(v[13] == 58); + assert_or_panic(v[14] == 59); + assert_or_panic(v[15] == 60); + zig_vector_16_u8((Vector_16_u8){ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76 }, 16); +} + +typedef uint8_t Vector_24_u8 __attribute__((vector_size(24 * sizeof(uint8_t)))); + +Vector_24_u8 zig_ret_vector_24_u8(void); +void zig_vector_24_u8(Vector_24_u8, size_t); + +Vector_24_u8 c_ret_vector_24_u8(void) { + return (Vector_24_u8){ + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, + }; +} +void c_vector_24_u8(Vector_24_u8 v, size_t i) { + assert_or_panic(v[0] == 81); + assert_or_panic(v[1] == 82); + assert_or_panic(v[2] == 83); + assert_or_panic(v[3] == 84); + assert_or_panic(v[4] == 85); + assert_or_panic(v[5] == 86); + assert_or_panic(v[6] == 87); + assert_or_panic(v[7] == 88); + assert_or_panic(v[8] == 89); + assert_or_panic(v[9] == 90); + assert_or_panic(v[10] == 91); + assert_or_panic(v[11] == 92); + assert_or_panic(v[12] == 93); + assert_or_panic(v[13] == 94); + assert_or_panic(v[14] == 95); + assert_or_panic(v[15] == 96); + assert_or_panic(v[16] == 97); + assert_or_panic(v[17] == 98); + assert_or_panic(v[18] == 99); + assert_or_panic(v[19] == 0); + assert_or_panic(v[20] == 1); + assert_or_panic(v[21] == 2); + assert_or_panic(v[22] == 3); + assert_or_panic(v[23] == 4); + assert_or_panic(i == 24); +} +void c_test_vector_24_u8(void) { + Vector_24_u8 v = zig_ret_vector_24_u8(); + assert_or_panic(v[0] == 9); + assert_or_panic(v[1] == 10); + assert_or_panic(v[2] == 11); + assert_or_panic(v[3] == 12); + assert_or_panic(v[4] == 13); + assert_or_panic(v[5] == 14); + assert_or_panic(v[6] == 15); + assert_or_panic(v[7] == 16); + assert_or_panic(v[8] == 17); + assert_or_panic(v[9] == 18); + assert_or_panic(v[10] == 19); + assert_or_panic(v[11] == 20); + assert_or_panic(v[12] == 21); + assert_or_panic(v[13] == 22); + assert_or_panic(v[14] == 23); + assert_or_panic(v[15] == 24); + assert_or_panic(v[16] == 25); + assert_or_panic(v[17] == 26); + assert_or_panic(v[18] == 27); + assert_or_panic(v[19] == 28); + assert_or_panic(v[20] == 29); + assert_or_panic(v[21] == 30); + assert_or_panic(v[22] == 31); + assert_or_panic(v[23] == 32); + zig_vector_24_u8((Vector_24_u8){ + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, + }, 24); +} + +typedef uint8_t Vector_32_u8 __attribute__((vector_size(32 * sizeof(uint8_t)))); + +Vector_32_u8 zig_ret_vector_32_u8(void); +void zig_vector_32_u8(Vector_32_u8, size_t); + +Vector_32_u8 c_ret_vector_32_u8(void) { + return (Vector_32_u8){ + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, + }; +} +void c_vector_32_u8(Vector_32_u8 v, size_t i) { + assert_or_panic(v[0] == 1); + assert_or_panic(v[1] == 2); + assert_or_panic(v[2] == 3); + assert_or_panic(v[3] == 4); + assert_or_panic(v[4] == 5); + assert_or_panic(v[5] == 6); + assert_or_panic(v[6] == 7); + assert_or_panic(v[7] == 8); + assert_or_panic(v[8] == 9); + assert_or_panic(v[9] == 10); + assert_or_panic(v[10] == 11); + assert_or_panic(v[11] == 12); + assert_or_panic(v[12] == 13); + assert_or_panic(v[13] == 14); + assert_or_panic(v[14] == 15); + assert_or_panic(v[15] == 16); + assert_or_panic(v[16] == 17); + assert_or_panic(v[17] == 18); + assert_or_panic(v[18] == 19); + assert_or_panic(v[19] == 20); + assert_or_panic(v[20] == 21); + assert_or_panic(v[21] == 22); + assert_or_panic(v[22] == 23); + assert_or_panic(v[23] == 24); + assert_or_panic(v[24] == 25); + assert_or_panic(v[25] == 26); + assert_or_panic(v[26] == 27); + assert_or_panic(v[27] == 28); + assert_or_panic(v[28] == 29); + assert_or_panic(v[29] == 30); + assert_or_panic(v[30] == 31); + assert_or_panic(v[31] == 32); + assert_or_panic(i == 32); +} +void c_test_vector_32_u8(void) { + Vector_32_u8 v = zig_ret_vector_32_u8(); + assert_or_panic(v[0] == 5); + assert_or_panic(v[1] == 6); + assert_or_panic(v[2] == 7); + assert_or_panic(v[3] == 8); + assert_or_panic(v[4] == 9); + assert_or_panic(v[5] == 10); + assert_or_panic(v[6] == 11); + assert_or_panic(v[7] == 12); + assert_or_panic(v[8] == 13); + assert_or_panic(v[9] == 14); + assert_or_panic(v[10] == 15); + assert_or_panic(v[11] == 16); + assert_or_panic(v[12] == 17); + assert_or_panic(v[13] == 18); + assert_or_panic(v[14] == 19); + assert_or_panic(v[15] == 20); + assert_or_panic(v[16] == 21); + assert_or_panic(v[17] == 22); + assert_or_panic(v[18] == 23); + assert_or_panic(v[19] == 24); + assert_or_panic(v[20] == 25); + assert_or_panic(v[21] == 26); + assert_or_panic(v[22] == 27); + assert_or_panic(v[23] == 28); + assert_or_panic(v[24] == 29); + assert_or_panic(v[25] == 30); + assert_or_panic(v[26] == 31); + assert_or_panic(v[27] == 32); + assert_or_panic(v[28] == 33); + assert_or_panic(v[29] == 34); + assert_or_panic(v[30] == 35); + assert_or_panic(v[31] == 36); + zig_vector_32_u8((Vector_32_u8){ + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + }, 32); +} + +typedef uint8_t Vector_48_u8 __attribute__((vector_size(48 * sizeof(uint8_t)))); + +Vector_48_u8 zig_ret_vector_48_u8(void); +void zig_vector_48_u8(Vector_48_u8, size_t); + +Vector_48_u8 c_ret_vector_48_u8(void) { + return (Vector_48_u8){ + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + }; +} +void c_vector_48_u8(Vector_48_u8 v, size_t i) { + assert_or_panic(v[0] == 77); + assert_or_panic(v[1] == 78); + assert_or_panic(v[2] == 79); + assert_or_panic(v[3] == 80); + assert_or_panic(v[4] == 81); + assert_or_panic(v[5] == 82); + assert_or_panic(v[6] == 83); + assert_or_panic(v[7] == 84); + assert_or_panic(v[8] == 85); + assert_or_panic(v[9] == 86); + assert_or_panic(v[10] == 87); + assert_or_panic(v[11] == 88); + assert_or_panic(v[12] == 89); + assert_or_panic(v[13] == 90); + assert_or_panic(v[14] == 91); + assert_or_panic(v[15] == 92); + assert_or_panic(v[16] == 93); + assert_or_panic(v[17] == 94); + assert_or_panic(v[18] == 95); + assert_or_panic(v[19] == 96); + assert_or_panic(v[20] == 97); + assert_or_panic(v[21] == 98); + assert_or_panic(v[22] == 99); + assert_or_panic(v[23] == 0); + assert_or_panic(v[24] == 1); + assert_or_panic(v[25] == 2); + assert_or_panic(v[26] == 3); + assert_or_panic(v[27] == 4); + assert_or_panic(v[28] == 5); + assert_or_panic(v[29] == 6); + assert_or_panic(v[30] == 7); + assert_or_panic(v[31] == 8); + assert_or_panic(v[32] == 9); + assert_or_panic(v[33] == 10); + assert_or_panic(v[34] == 11); + assert_or_panic(v[35] == 12); + assert_or_panic(v[36] == 13); + assert_or_panic(v[37] == 14); + assert_or_panic(v[38] == 15); + assert_or_panic(v[39] == 16); + assert_or_panic(v[40] == 17); + assert_or_panic(v[41] == 18); + assert_or_panic(v[42] == 19); + assert_or_panic(v[43] == 20); + assert_or_panic(v[44] == 21); + assert_or_panic(v[45] == 22); + assert_or_panic(v[46] == 23); + assert_or_panic(v[47] == 24); + assert_or_panic(i == 48); +} +void c_test_vector_48_u8(void) { + Vector_48_u8 v = zig_ret_vector_48_u8(); + assert_or_panic(v[0] == 33); + assert_or_panic(v[1] == 34); + assert_or_panic(v[2] == 35); + assert_or_panic(v[3] == 36); + assert_or_panic(v[4] == 37); + assert_or_panic(v[5] == 38); + assert_or_panic(v[6] == 39); + assert_or_panic(v[7] == 40); + assert_or_panic(v[8] == 41); + assert_or_panic(v[9] == 42); + assert_or_panic(v[10] == 43); + assert_or_panic(v[11] == 44); + assert_or_panic(v[12] == 45); + assert_or_panic(v[13] == 46); + assert_or_panic(v[14] == 47); + assert_or_panic(v[15] == 48); + assert_or_panic(v[16] == 49); + assert_or_panic(v[17] == 50); + assert_or_panic(v[18] == 51); + assert_or_panic(v[19] == 52); + assert_or_panic(v[20] == 53); + assert_or_panic(v[21] == 54); + assert_or_panic(v[22] == 55); + assert_or_panic(v[23] == 56); + assert_or_panic(v[24] == 57); + assert_or_panic(v[25] == 58); + assert_or_panic(v[26] == 59); + assert_or_panic(v[27] == 60); + assert_or_panic(v[28] == 61); + assert_or_panic(v[29] == 62); + assert_or_panic(v[30] == 63); + assert_or_panic(v[31] == 64); + assert_or_panic(v[32] == 65); + assert_or_panic(v[33] == 66); + assert_or_panic(v[34] == 67); + assert_or_panic(v[35] == 68); + assert_or_panic(v[36] == 69); + assert_or_panic(v[37] == 70); + assert_or_panic(v[38] == 71); + assert_or_panic(v[39] == 72); + assert_or_panic(v[40] == 73); + assert_or_panic(v[41] == 74); + assert_or_panic(v[42] == 75); + assert_or_panic(v[43] == 76); + assert_or_panic(v[44] == 77); + assert_or_panic(v[45] == 78); + assert_or_panic(v[46] == 79); + assert_or_panic(v[47] == 80); + zig_vector_48_u8((Vector_48_u8){ + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + }, 48); +} + +typedef uint8_t Vector_64_u8 __attribute__((vector_size(64 * sizeof(uint8_t)))); + +Vector_64_u8 zig_ret_vector_64_u8(void); +void zig_vector_64_u8(Vector_64_u8, size_t); + +Vector_64_u8 c_ret_vector_64_u8(void) { + return (Vector_64_u8){ + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + }; +} +void c_vector_64_u8(Vector_64_u8 v, size_t i) { + assert_or_panic(v[0] == 17); + assert_or_panic(v[1] == 18); + assert_or_panic(v[2] == 19); + assert_or_panic(v[3] == 20); + assert_or_panic(v[4] == 21); + assert_or_panic(v[5] == 22); + assert_or_panic(v[6] == 23); + assert_or_panic(v[7] == 24); + assert_or_panic(v[8] == 25); + assert_or_panic(v[9] == 26); + assert_or_panic(v[10] == 27); + assert_or_panic(v[11] == 28); + assert_or_panic(v[12] == 29); + assert_or_panic(v[13] == 30); + assert_or_panic(v[14] == 31); + assert_or_panic(v[15] == 32); + assert_or_panic(v[16] == 33); + assert_or_panic(v[17] == 34); + assert_or_panic(v[18] == 35); + assert_or_panic(v[19] == 36); + assert_or_panic(v[20] == 37); + assert_or_panic(v[21] == 38); + assert_or_panic(v[22] == 39); + assert_or_panic(v[23] == 40); + assert_or_panic(v[24] == 41); + assert_or_panic(v[25] == 42); + assert_or_panic(v[26] == 43); + assert_or_panic(v[27] == 44); + assert_or_panic(v[28] == 45); + assert_or_panic(v[29] == 46); + assert_or_panic(v[30] == 47); + assert_or_panic(v[31] == 48); + assert_or_panic(v[32] == 49); + assert_or_panic(v[33] == 50); + assert_or_panic(v[34] == 51); + assert_or_panic(v[35] == 52); + assert_or_panic(v[36] == 53); + assert_or_panic(v[37] == 54); + assert_or_panic(v[38] == 55); + assert_or_panic(v[39] == 56); + assert_or_panic(v[40] == 57); + assert_or_panic(v[41] == 58); + assert_or_panic(v[42] == 59); + assert_or_panic(v[43] == 60); + assert_or_panic(v[44] == 61); + assert_or_panic(v[45] == 62); + assert_or_panic(v[46] == 63); + assert_or_panic(v[47] == 64); + assert_or_panic(v[48] == 65); + assert_or_panic(v[49] == 66); + assert_or_panic(v[50] == 67); + assert_or_panic(v[51] == 68); + assert_or_panic(v[52] == 69); + assert_or_panic(v[53] == 70); + assert_or_panic(v[54] == 71); + assert_or_panic(v[55] == 72); + assert_or_panic(v[56] == 73); + assert_or_panic(v[57] == 74); + assert_or_panic(v[58] == 75); + assert_or_panic(v[59] == 76); + assert_or_panic(v[60] == 77); + assert_or_panic(v[61] == 78); + assert_or_panic(v[62] == 79); + assert_or_panic(v[63] == 80); + assert_or_panic(i == 64); +} +void c_test_vector_64_u8(void) { + Vector_64_u8 v = zig_ret_vector_64_u8(); + assert_or_panic(v[0] == 25); + assert_or_panic(v[1] == 26); + assert_or_panic(v[2] == 27); + assert_or_panic(v[3] == 28); + assert_or_panic(v[4] == 29); + assert_or_panic(v[5] == 30); + assert_or_panic(v[6] == 31); + assert_or_panic(v[7] == 32); + assert_or_panic(v[8] == 33); + assert_or_panic(v[9] == 34); + assert_or_panic(v[10] == 35); + assert_or_panic(v[11] == 36); + assert_or_panic(v[12] == 37); + assert_or_panic(v[13] == 38); + assert_or_panic(v[14] == 39); + assert_or_panic(v[15] == 40); + assert_or_panic(v[16] == 41); + assert_or_panic(v[17] == 42); + assert_or_panic(v[18] == 43); + assert_or_panic(v[19] == 44); + assert_or_panic(v[20] == 45); + assert_or_panic(v[21] == 46); + assert_or_panic(v[22] == 47); + assert_or_panic(v[23] == 48); + assert_or_panic(v[24] == 49); + assert_or_panic(v[25] == 50); + assert_or_panic(v[26] == 51); + assert_or_panic(v[27] == 52); + assert_or_panic(v[28] == 53); + assert_or_panic(v[29] == 54); + assert_or_panic(v[30] == 55); + assert_or_panic(v[31] == 56); + assert_or_panic(v[32] == 57); + assert_or_panic(v[33] == 58); + assert_or_panic(v[34] == 59); + assert_or_panic(v[35] == 60); + assert_or_panic(v[36] == 61); + assert_or_panic(v[37] == 62); + assert_or_panic(v[38] == 63); + assert_or_panic(v[39] == 64); + assert_or_panic(v[40] == 65); + assert_or_panic(v[41] == 66); + assert_or_panic(v[42] == 67); + assert_or_panic(v[43] == 68); + assert_or_panic(v[44] == 69); + assert_or_panic(v[45] == 70); + assert_or_panic(v[46] == 71); + assert_or_panic(v[47] == 72); + assert_or_panic(v[48] == 73); + assert_or_panic(v[49] == 74); + assert_or_panic(v[50] == 75); + assert_or_panic(v[51] == 76); + assert_or_panic(v[52] == 77); + assert_or_panic(v[53] == 78); + assert_or_panic(v[54] == 79); + assert_or_panic(v[55] == 80); + assert_or_panic(v[56] == 81); + assert_or_panic(v[57] == 82); + assert_or_panic(v[58] == 83); + assert_or_panic(v[59] == 84); + assert_or_panic(v[60] == 85); + assert_or_panic(v[61] == 86); + assert_or_panic(v[62] == 87); + assert_or_panic(v[63] == 88); + zig_vector_64_u8((Vector_64_u8){ + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, + }, 64); +} + +typedef uint8_t Vector_96_u8 __attribute__((vector_size(96 * sizeof(uint8_t)))); + +Vector_96_u8 zig_ret_vector_96_u8(void); +void zig_vector_96_u8(Vector_96_u8, size_t); + +Vector_96_u8 c_ret_vector_96_u8(void) { + return (Vector_96_u8){ + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + }; +} +void c_vector_96_u8(Vector_96_u8 v, size_t i) { + assert_or_panic(v[0] == 78); + assert_or_panic(v[1] == 79); + assert_or_panic(v[2] == 80); + assert_or_panic(v[3] == 81); + assert_or_panic(v[4] == 82); + assert_or_panic(v[5] == 83); + assert_or_panic(v[6] == 84); + assert_or_panic(v[7] == 85); + assert_or_panic(v[8] == 86); + assert_or_panic(v[9] == 87); + assert_or_panic(v[10] == 88); + assert_or_panic(v[11] == 89); + assert_or_panic(v[12] == 90); + assert_or_panic(v[13] == 91); + assert_or_panic(v[14] == 92); + assert_or_panic(v[15] == 93); + assert_or_panic(v[16] == 94); + assert_or_panic(v[17] == 95); + assert_or_panic(v[18] == 96); + assert_or_panic(v[19] == 97); + assert_or_panic(v[20] == 98); + assert_or_panic(v[21] == 99); + assert_or_panic(v[22] == 0); + assert_or_panic(v[23] == 1); + assert_or_panic(v[24] == 2); + assert_or_panic(v[25] == 3); + assert_or_panic(v[26] == 4); + assert_or_panic(v[27] == 5); + assert_or_panic(v[28] == 6); + assert_or_panic(v[29] == 7); + assert_or_panic(v[30] == 8); + assert_or_panic(v[31] == 9); + assert_or_panic(v[32] == 10); + assert_or_panic(v[33] == 11); + assert_or_panic(v[34] == 12); + assert_or_panic(v[35] == 13); + assert_or_panic(v[36] == 14); + assert_or_panic(v[37] == 15); + assert_or_panic(v[38] == 16); + assert_or_panic(v[39] == 17); + assert_or_panic(v[40] == 18); + assert_or_panic(v[41] == 19); + assert_or_panic(v[42] == 20); + assert_or_panic(v[43] == 21); + assert_or_panic(v[44] == 22); + assert_or_panic(v[45] == 23); + assert_or_panic(v[46] == 24); + assert_or_panic(v[47] == 25); + assert_or_panic(v[48] == 26); + assert_or_panic(v[49] == 27); + assert_or_panic(v[50] == 28); + assert_or_panic(v[51] == 29); + assert_or_panic(v[52] == 30); + assert_or_panic(v[53] == 31); + assert_or_panic(v[54] == 32); + assert_or_panic(v[55] == 33); + assert_or_panic(v[56] == 34); + assert_or_panic(v[57] == 35); + assert_or_panic(v[58] == 36); + assert_or_panic(v[59] == 37); + assert_or_panic(v[60] == 38); + assert_or_panic(v[61] == 39); + assert_or_panic(v[62] == 40); + assert_or_panic(v[63] == 41); + assert_or_panic(v[64] == 42); + assert_or_panic(v[65] == 43); + assert_or_panic(v[66] == 44); + assert_or_panic(v[67] == 45); + assert_or_panic(v[68] == 46); + assert_or_panic(v[69] == 47); + assert_or_panic(v[70] == 48); + assert_or_panic(v[71] == 49); + assert_or_panic(v[72] == 50); + assert_or_panic(v[73] == 51); + assert_or_panic(v[74] == 52); + assert_or_panic(v[75] == 53); + assert_or_panic(v[76] == 54); + assert_or_panic(v[77] == 55); + assert_or_panic(v[80] == 58); + assert_or_panic(v[81] == 59); + assert_or_panic(v[82] == 60); + assert_or_panic(v[83] == 61); + assert_or_panic(v[84] == 62); + assert_or_panic(v[85] == 63); + assert_or_panic(v[86] == 64); + assert_or_panic(v[87] == 65); + assert_or_panic(v[88] == 66); + assert_or_panic(v[89] == 67); + assert_or_panic(v[90] == 68); + assert_or_panic(v[91] == 69); + assert_or_panic(v[92] == 70); + assert_or_panic(v[93] == 71); + assert_or_panic(v[94] == 72); + assert_or_panic(v[95] == 73); + assert_or_panic(i == 96); +} +void c_test_vector_96_u8(void) { + Vector_96_u8 v = zig_ret_vector_96_u8(); + assert_or_panic(v[0] == 90); + assert_or_panic(v[1] == 91); + assert_or_panic(v[2] == 92); + assert_or_panic(v[3] == 93); + assert_or_panic(v[4] == 94); + assert_or_panic(v[5] == 95); + assert_or_panic(v[6] == 96); + assert_or_panic(v[7] == 97); + assert_or_panic(v[8] == 98); + assert_or_panic(v[9] == 99); + assert_or_panic(v[10] == 0); + assert_or_panic(v[11] == 1); + assert_or_panic(v[12] == 2); + assert_or_panic(v[13] == 3); + assert_or_panic(v[14] == 4); + assert_or_panic(v[15] == 5); + assert_or_panic(v[16] == 6); + assert_or_panic(v[17] == 7); + assert_or_panic(v[18] == 8); + assert_or_panic(v[19] == 9); + assert_or_panic(v[20] == 10); + assert_or_panic(v[21] == 11); + assert_or_panic(v[22] == 12); + assert_or_panic(v[23] == 13); + assert_or_panic(v[24] == 14); + assert_or_panic(v[25] == 15); + assert_or_panic(v[26] == 16); + assert_or_panic(v[27] == 17); + assert_or_panic(v[28] == 18); + assert_or_panic(v[29] == 19); + assert_or_panic(v[30] == 20); + assert_or_panic(v[31] == 21); + assert_or_panic(v[32] == 22); + assert_or_panic(v[33] == 23); + assert_or_panic(v[34] == 24); + assert_or_panic(v[35] == 25); + assert_or_panic(v[36] == 26); + assert_or_panic(v[37] == 27); + assert_or_panic(v[38] == 28); + assert_or_panic(v[39] == 29); + assert_or_panic(v[40] == 30); + assert_or_panic(v[41] == 31); + assert_or_panic(v[42] == 32); + assert_or_panic(v[43] == 33); + assert_or_panic(v[44] == 34); + assert_or_panic(v[45] == 35); + assert_or_panic(v[46] == 36); + assert_or_panic(v[47] == 37); + assert_or_panic(v[48] == 38); + assert_or_panic(v[49] == 39); + assert_or_panic(v[50] == 40); + assert_or_panic(v[51] == 41); + assert_or_panic(v[52] == 42); + assert_or_panic(v[53] == 43); + assert_or_panic(v[54] == 44); + assert_or_panic(v[55] == 45); + assert_or_panic(v[56] == 46); + assert_or_panic(v[57] == 47); + assert_or_panic(v[58] == 48); + assert_or_panic(v[59] == 49); + assert_or_panic(v[60] == 50); + assert_or_panic(v[61] == 51); + assert_or_panic(v[62] == 52); + assert_or_panic(v[63] == 53); + assert_or_panic(v[64] == 54); + assert_or_panic(v[65] == 55); + assert_or_panic(v[66] == 56); + assert_or_panic(v[67] == 57); + assert_or_panic(v[68] == 58); + assert_or_panic(v[69] == 59); + assert_or_panic(v[70] == 60); + assert_or_panic(v[71] == 61); + assert_or_panic(v[72] == 62); + assert_or_panic(v[73] == 63); + assert_or_panic(v[74] == 64); + assert_or_panic(v[75] == 65); + assert_or_panic(v[76] == 66); + assert_or_panic(v[77] == 67); + assert_or_panic(v[78] == 68); + assert_or_panic(v[79] == 69); + assert_or_panic(v[80] == 70); + assert_or_panic(v[81] == 71); + assert_or_panic(v[82] == 72); + assert_or_panic(v[83] == 73); + assert_or_panic(v[84] == 74); + assert_or_panic(v[85] == 75); + assert_or_panic(v[86] == 76); + assert_or_panic(v[87] == 77); + assert_or_panic(v[88] == 78); + assert_or_panic(v[89] == 79); + assert_or_panic(v[90] == 80); + assert_or_panic(v[91] == 81); + assert_or_panic(v[92] == 82); + assert_or_panic(v[93] == 83); + assert_or_panic(v[94] == 84); + assert_or_panic(v[95] == 85); + zig_vector_96_u8((Vector_96_u8){ + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + }, 96); +} + +typedef uint8_t Vector_128_u8 __attribute__((vector_size(128 * sizeof(uint8_t)))); + +Vector_128_u8 zig_ret_vector_128_u8(void); +void zig_vector_128_u8(Vector_128_u8, size_t); + +Vector_128_u8 c_ret_vector_128_u8(void) { + return (Vector_128_u8){ + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + }; +} +void c_vector_128_u8(Vector_128_u8 v, size_t i) { + assert_or_panic(v[0] == 58); + assert_or_panic(v[1] == 59); + assert_or_panic(v[2] == 60); + assert_or_panic(v[3] == 61); + assert_or_panic(v[4] == 62); + assert_or_panic(v[5] == 63); + assert_or_panic(v[6] == 64); + assert_or_panic(v[7] == 65); + assert_or_panic(v[8] == 66); + assert_or_panic(v[9] == 67); + assert_or_panic(v[10] == 68); + assert_or_panic(v[11] == 69); + assert_or_panic(v[12] == 70); + assert_or_panic(v[13] == 71); + assert_or_panic(v[14] == 72); + assert_or_panic(v[15] == 73); + assert_or_panic(v[16] == 74); + assert_or_panic(v[17] == 75); + assert_or_panic(v[18] == 76); + assert_or_panic(v[19] == 77); + assert_or_panic(v[20] == 78); + assert_or_panic(v[21] == 79); + assert_or_panic(v[22] == 80); + assert_or_panic(v[23] == 81); + assert_or_panic(v[24] == 82); + assert_or_panic(v[25] == 83); + assert_or_panic(v[26] == 84); + assert_or_panic(v[27] == 85); + assert_or_panic(v[28] == 86); + assert_or_panic(v[29] == 87); + assert_or_panic(v[30] == 88); + assert_or_panic(v[31] == 89); + assert_or_panic(v[32] == 90); + assert_or_panic(v[33] == 91); + assert_or_panic(v[34] == 92); + assert_or_panic(v[35] == 93); + assert_or_panic(v[36] == 94); + assert_or_panic(v[37] == 95); + assert_or_panic(v[38] == 96); + assert_or_panic(v[39] == 97); + assert_or_panic(v[40] == 98); + assert_or_panic(v[41] == 99); + assert_or_panic(v[42] == 0); + assert_or_panic(v[43] == 1); + assert_or_panic(v[44] == 2); + assert_or_panic(v[45] == 3); + assert_or_panic(v[46] == 4); + assert_or_panic(v[47] == 5); + assert_or_panic(v[48] == 6); + assert_or_panic(v[49] == 7); + assert_or_panic(v[50] == 8); + assert_or_panic(v[51] == 9); + assert_or_panic(v[52] == 10); + assert_or_panic(v[53] == 11); + assert_or_panic(v[54] == 12); + assert_or_panic(v[55] == 13); + assert_or_panic(v[56] == 14); + assert_or_panic(v[57] == 15); + assert_or_panic(v[58] == 16); + assert_or_panic(v[59] == 17); + assert_or_panic(v[60] == 18); + assert_or_panic(v[61] == 19); + assert_or_panic(v[62] == 20); + assert_or_panic(v[63] == 21); + assert_or_panic(v[64] == 22); + assert_or_panic(v[65] == 23); + assert_or_panic(v[66] == 24); + assert_or_panic(v[67] == 25); + assert_or_panic(v[68] == 26); + assert_or_panic(v[69] == 27); + assert_or_panic(v[70] == 28); + assert_or_panic(v[71] == 29); + assert_or_panic(v[72] == 30); + assert_or_panic(v[73] == 31); + assert_or_panic(v[74] == 32); + assert_or_panic(v[75] == 33); + assert_or_panic(v[76] == 34); + assert_or_panic(v[77] == 35); + assert_or_panic(v[78] == 36); + assert_or_panic(v[79] == 37); + assert_or_panic(v[80] == 38); + assert_or_panic(v[81] == 39); + assert_or_panic(v[82] == 40); + assert_or_panic(v[83] == 41); + assert_or_panic(v[84] == 42); + assert_or_panic(v[85] == 43); + assert_or_panic(v[86] == 44); + assert_or_panic(v[87] == 45); + assert_or_panic(v[88] == 46); + assert_or_panic(v[89] == 47); + assert_or_panic(v[90] == 48); + assert_or_panic(v[91] == 49); + assert_or_panic(v[92] == 50); + assert_or_panic(v[93] == 51); + assert_or_panic(v[94] == 52); + assert_or_panic(v[95] == 53); + assert_or_panic(v[96] == 54); + assert_or_panic(v[97] == 55); + assert_or_panic(v[98] == 56); + assert_or_panic(v[99] == 57); + assert_or_panic(v[100] == 58); + assert_or_panic(v[101] == 59); + assert_or_panic(v[102] == 60); + assert_or_panic(v[103] == 61); + assert_or_panic(v[104] == 62); + assert_or_panic(v[105] == 63); + assert_or_panic(v[106] == 64); + assert_or_panic(v[107] == 65); + assert_or_panic(v[108] == 66); + assert_or_panic(v[109] == 67); + assert_or_panic(v[110] == 68); + assert_or_panic(v[111] == 69); + assert_or_panic(v[112] == 70); + assert_or_panic(v[113] == 71); + assert_or_panic(v[114] == 72); + assert_or_panic(v[115] == 73); + assert_or_panic(v[116] == 74); + assert_or_panic(v[117] == 75); + assert_or_panic(v[118] == 76); + assert_or_panic(v[119] == 77); + assert_or_panic(v[120] == 78); + assert_or_panic(v[121] == 79); + assert_or_panic(v[122] == 80); + assert_or_panic(v[123] == 81); + assert_or_panic(v[124] == 82); + assert_or_panic(v[125] == 83); + assert_or_panic(v[126] == 84); + assert_or_panic(v[127] == 85); + assert_or_panic(i == 128); +} +void c_test_vector_128_u8(void) { + Vector_128_u8 v = zig_ret_vector_128_u8(); + assert_or_panic(v[0] == 74); + assert_or_panic(v[1] == 75); + assert_or_panic(v[2] == 76); + assert_or_panic(v[3] == 77); + assert_or_panic(v[4] == 78); + assert_or_panic(v[5] == 79); + assert_or_panic(v[6] == 80); + assert_or_panic(v[7] == 81); + assert_or_panic(v[8] == 82); + assert_or_panic(v[9] == 83); + assert_or_panic(v[10] == 84); + assert_or_panic(v[11] == 85); + assert_or_panic(v[12] == 86); + assert_or_panic(v[13] == 87); + assert_or_panic(v[14] == 88); + assert_or_panic(v[15] == 89); + assert_or_panic(v[16] == 90); + assert_or_panic(v[17] == 91); + assert_or_panic(v[18] == 92); + assert_or_panic(v[19] == 93); + assert_or_panic(v[20] == 94); + assert_or_panic(v[21] == 95); + assert_or_panic(v[22] == 96); + assert_or_panic(v[23] == 97); + assert_or_panic(v[24] == 98); + assert_or_panic(v[25] == 99); + assert_or_panic(v[26] == 0); + assert_or_panic(v[27] == 1); + assert_or_panic(v[28] == 2); + assert_or_panic(v[29] == 3); + assert_or_panic(v[30] == 4); + assert_or_panic(v[31] == 5); + assert_or_panic(v[32] == 6); + assert_or_panic(v[33] == 7); + assert_or_panic(v[34] == 8); + assert_or_panic(v[35] == 9); + assert_or_panic(v[36] == 10); + assert_or_panic(v[37] == 11); + assert_or_panic(v[38] == 12); + assert_or_panic(v[39] == 13); + assert_or_panic(v[40] == 14); + assert_or_panic(v[41] == 15); + assert_or_panic(v[42] == 16); + assert_or_panic(v[43] == 17); + assert_or_panic(v[44] == 18); + assert_or_panic(v[45] == 19); + assert_or_panic(v[46] == 20); + assert_or_panic(v[47] == 21); + assert_or_panic(v[48] == 22); + assert_or_panic(v[49] == 23); + assert_or_panic(v[50] == 24); + assert_or_panic(v[51] == 25); + assert_or_panic(v[52] == 26); + assert_or_panic(v[53] == 27); + assert_or_panic(v[54] == 28); + assert_or_panic(v[55] == 29); + assert_or_panic(v[56] == 30); + assert_or_panic(v[57] == 31); + assert_or_panic(v[58] == 32); + assert_or_panic(v[59] == 33); + assert_or_panic(v[60] == 34); + assert_or_panic(v[61] == 35); + assert_or_panic(v[62] == 36); + assert_or_panic(v[63] == 37); + assert_or_panic(v[64] == 38); + assert_or_panic(v[65] == 39); + assert_or_panic(v[66] == 40); + assert_or_panic(v[67] == 41); + assert_or_panic(v[68] == 42); + assert_or_panic(v[69] == 43); + assert_or_panic(v[70] == 44); + assert_or_panic(v[71] == 45); + assert_or_panic(v[72] == 46); + assert_or_panic(v[73] == 47); + assert_or_panic(v[74] == 48); + assert_or_panic(v[75] == 49); + assert_or_panic(v[76] == 50); + assert_or_panic(v[77] == 51); + assert_or_panic(v[78] == 52); + assert_or_panic(v[79] == 53); + assert_or_panic(v[80] == 54); + assert_or_panic(v[81] == 55); + assert_or_panic(v[82] == 56); + assert_or_panic(v[83] == 57); + assert_or_panic(v[84] == 58); + assert_or_panic(v[85] == 59); + assert_or_panic(v[86] == 60); + assert_or_panic(v[87] == 61); + assert_or_panic(v[88] == 62); + assert_or_panic(v[89] == 63); + assert_or_panic(v[90] == 64); + assert_or_panic(v[91] == 65); + assert_or_panic(v[92] == 66); + assert_or_panic(v[93] == 67); + assert_or_panic(v[94] == 68); + assert_or_panic(v[95] == 69); + assert_or_panic(v[96] == 70); + assert_or_panic(v[97] == 71); + assert_or_panic(v[98] == 72); + assert_or_panic(v[99] == 73); + assert_or_panic(v[100] == 74); + assert_or_panic(v[101] == 75); + assert_or_panic(v[102] == 76); + assert_or_panic(v[103] == 77); + assert_or_panic(v[104] == 78); + assert_or_panic(v[105] == 79); + assert_or_panic(v[106] == 80); + assert_or_panic(v[107] == 81); + assert_or_panic(v[108] == 82); + assert_or_panic(v[109] == 83); + assert_or_panic(v[110] == 84); + assert_or_panic(v[111] == 85); + assert_or_panic(v[112] == 86); + assert_or_panic(v[113] == 87); + assert_or_panic(v[114] == 88); + assert_or_panic(v[115] == 89); + assert_or_panic(v[116] == 90); + assert_or_panic(v[117] == 91); + assert_or_panic(v[118] == 92); + assert_or_panic(v[119] == 93); + assert_or_panic(v[120] == 94); + assert_or_panic(v[121] == 95); + assert_or_panic(v[122] == 96); + assert_or_panic(v[123] == 97); + assert_or_panic(v[124] == 98); + assert_or_panic(v[125] == 99); + assert_or_panic(v[126] == 0); + assert_or_panic(v[127] == 1); + zig_vector_128_u8((Vector_128_u8){ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + }, 128); +} + +typedef uint8_t Vector_192_u8 __attribute__((vector_size(192 * sizeof(uint8_t)))); + +Vector_192_u8 zig_ret_vector_192_u8(void); +void zig_vector_192_u8(Vector_192_u8, size_t); + +Vector_192_u8 c_ret_vector_192_u8(void) { + return (Vector_192_u8){ + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + }; +} +void c_vector_192_u8(Vector_192_u8 v, size_t i) { + assert_or_panic(v[0] == 62); + assert_or_panic(v[1] == 63); + assert_or_panic(v[2] == 64); + assert_or_panic(v[3] == 65); + assert_or_panic(v[4] == 66); + assert_or_panic(v[5] == 67); + assert_or_panic(v[6] == 68); + assert_or_panic(v[7] == 69); + assert_or_panic(v[8] == 70); + assert_or_panic(v[9] == 71); + assert_or_panic(v[10] == 72); + assert_or_panic(v[11] == 73); + assert_or_panic(v[12] == 74); + assert_or_panic(v[13] == 75); + assert_or_panic(v[14] == 76); + assert_or_panic(v[15] == 77); + assert_or_panic(v[16] == 78); + assert_or_panic(v[17] == 79); + assert_or_panic(v[18] == 80); + assert_or_panic(v[19] == 81); + assert_or_panic(v[20] == 82); + assert_or_panic(v[21] == 83); + assert_or_panic(v[22] == 84); + assert_or_panic(v[23] == 85); + assert_or_panic(v[24] == 86); + assert_or_panic(v[25] == 87); + assert_or_panic(v[26] == 88); + assert_or_panic(v[27] == 89); + assert_or_panic(v[28] == 90); + assert_or_panic(v[29] == 91); + assert_or_panic(v[30] == 92); + assert_or_panic(v[31] == 93); + assert_or_panic(v[32] == 94); + assert_or_panic(v[33] == 95); + assert_or_panic(v[34] == 96); + assert_or_panic(v[35] == 97); + assert_or_panic(v[36] == 98); + assert_or_panic(v[37] == 99); + assert_or_panic(v[38] == 0); + assert_or_panic(v[39] == 1); + assert_or_panic(v[40] == 2); + assert_or_panic(v[41] == 3); + assert_or_panic(v[42] == 4); + assert_or_panic(v[43] == 5); + assert_or_panic(v[44] == 6); + assert_or_panic(v[45] == 7); + assert_or_panic(v[46] == 8); + assert_or_panic(v[47] == 9); + assert_or_panic(v[48] == 10); + assert_or_panic(v[49] == 11); + assert_or_panic(v[50] == 12); + assert_or_panic(v[51] == 13); + assert_or_panic(v[52] == 14); + assert_or_panic(v[53] == 15); + assert_or_panic(v[54] == 16); + assert_or_panic(v[55] == 17); + assert_or_panic(v[56] == 18); + assert_or_panic(v[57] == 19); + assert_or_panic(v[58] == 20); + assert_or_panic(v[59] == 21); + assert_or_panic(v[60] == 22); + assert_or_panic(v[61] == 23); + assert_or_panic(v[62] == 24); + assert_or_panic(v[63] == 25); + assert_or_panic(v[64] == 26); + assert_or_panic(v[65] == 27); + assert_or_panic(v[66] == 28); + assert_or_panic(v[67] == 29); + assert_or_panic(v[68] == 30); + assert_or_panic(v[69] == 31); + assert_or_panic(v[70] == 32); + assert_or_panic(v[71] == 33); + assert_or_panic(v[72] == 34); + assert_or_panic(v[73] == 35); + assert_or_panic(v[74] == 36); + assert_or_panic(v[75] == 37); + assert_or_panic(v[76] == 38); + assert_or_panic(v[77] == 39); + assert_or_panic(v[78] == 40); + assert_or_panic(v[79] == 41); + assert_or_panic(v[80] == 42); + assert_or_panic(v[81] == 43); + assert_or_panic(v[82] == 44); + assert_or_panic(v[83] == 45); + assert_or_panic(v[84] == 46); + assert_or_panic(v[85] == 47); + assert_or_panic(v[86] == 48); + assert_or_panic(v[87] == 49); + assert_or_panic(v[88] == 50); + assert_or_panic(v[89] == 51); + assert_or_panic(v[90] == 52); + assert_or_panic(v[91] == 53); + assert_or_panic(v[92] == 54); + assert_or_panic(v[93] == 55); + assert_or_panic(v[94] == 56); + assert_or_panic(v[95] == 57); + assert_or_panic(v[96] == 58); + assert_or_panic(v[97] == 59); + assert_or_panic(v[98] == 60); + assert_or_panic(v[99] == 61); + assert_or_panic(v[100] == 62); + assert_or_panic(v[101] == 63); + assert_or_panic(v[102] == 64); + assert_or_panic(v[103] == 65); + assert_or_panic(v[104] == 66); + assert_or_panic(v[105] == 67); + assert_or_panic(v[106] == 68); + assert_or_panic(v[107] == 69); + assert_or_panic(v[108] == 70); + assert_or_panic(v[109] == 71); + assert_or_panic(v[110] == 72); + assert_or_panic(v[111] == 73); + assert_or_panic(v[112] == 74); + assert_or_panic(v[113] == 75); + assert_or_panic(v[114] == 76); + assert_or_panic(v[115] == 77); + assert_or_panic(v[116] == 78); + assert_or_panic(v[117] == 79); + assert_or_panic(v[118] == 80); + assert_or_panic(v[119] == 81); + assert_or_panic(v[120] == 82); + assert_or_panic(v[121] == 83); + assert_or_panic(v[122] == 84); + assert_or_panic(v[123] == 85); + assert_or_panic(v[124] == 86); + assert_or_panic(v[125] == 87); + assert_or_panic(v[126] == 88); + assert_or_panic(v[127] == 89); + assert_or_panic(v[128] == 90); + assert_or_panic(v[129] == 91); + assert_or_panic(v[130] == 92); + assert_or_panic(v[131] == 93); + assert_or_panic(v[132] == 94); + assert_or_panic(v[133] == 95); + assert_or_panic(v[134] == 96); + assert_or_panic(v[135] == 97); + assert_or_panic(v[136] == 98); + assert_or_panic(v[137] == 99); + assert_or_panic(v[138] == 0); + assert_or_panic(v[139] == 1); + assert_or_panic(v[140] == 2); + assert_or_panic(v[141] == 3); + assert_or_panic(v[142] == 4); + assert_or_panic(v[143] == 5); + assert_or_panic(v[144] == 6); + assert_or_panic(v[145] == 7); + assert_or_panic(v[146] == 8); + assert_or_panic(v[147] == 9); + assert_or_panic(v[148] == 10); + assert_or_panic(v[149] == 11); + assert_or_panic(v[150] == 12); + assert_or_panic(v[151] == 13); + assert_or_panic(v[152] == 14); + assert_or_panic(v[153] == 15); + assert_or_panic(v[154] == 16); + assert_or_panic(v[155] == 17); + assert_or_panic(v[156] == 18); + assert_or_panic(v[157] == 19); + assert_or_panic(v[158] == 20); + assert_or_panic(v[159] == 21); + assert_or_panic(v[160] == 22); + assert_or_panic(v[161] == 23); + assert_or_panic(v[162] == 24); + assert_or_panic(v[163] == 25); + assert_or_panic(v[164] == 26); + assert_or_panic(v[165] == 27); + assert_or_panic(v[166] == 28); + assert_or_panic(v[167] == 29); + assert_or_panic(v[168] == 30); + assert_or_panic(v[169] == 31); + assert_or_panic(v[170] == 32); + assert_or_panic(v[171] == 33); + assert_or_panic(v[172] == 34); + assert_or_panic(v[173] == 35); + assert_or_panic(v[174] == 36); + assert_or_panic(v[175] == 37); + assert_or_panic(v[176] == 38); + assert_or_panic(v[177] == 39); + assert_or_panic(v[178] == 40); + assert_or_panic(v[179] == 41); + assert_or_panic(v[180] == 42); + assert_or_panic(v[181] == 43); + assert_or_panic(v[182] == 44); + assert_or_panic(v[183] == 45); + assert_or_panic(v[184] == 46); + assert_or_panic(v[185] == 47); + assert_or_panic(v[186] == 48); + assert_or_panic(v[187] == 49); + assert_or_panic(v[188] == 50); + assert_or_panic(v[189] == 51); + assert_or_panic(v[190] == 52); + assert_or_panic(v[191] == 53); + assert_or_panic(i == 192); +} +void c_test_vector_192_u8(void) { + Vector_192_u8 v = zig_ret_vector_192_u8(); + assert_or_panic(v[0] == 86); + assert_or_panic(v[1] == 87); + assert_or_panic(v[2] == 88); + assert_or_panic(v[3] == 89); + assert_or_panic(v[4] == 90); + assert_or_panic(v[5] == 91); + assert_or_panic(v[6] == 92); + assert_or_panic(v[7] == 93); + assert_or_panic(v[8] == 94); + assert_or_panic(v[9] == 95); + assert_or_panic(v[10] == 96); + assert_or_panic(v[11] == 97); + assert_or_panic(v[12] == 98); + assert_or_panic(v[13] == 99); + assert_or_panic(v[14] == 0); + assert_or_panic(v[15] == 1); + assert_or_panic(v[16] == 2); + assert_or_panic(v[17] == 3); + assert_or_panic(v[18] == 4); + assert_or_panic(v[19] == 5); + assert_or_panic(v[20] == 6); + assert_or_panic(v[21] == 7); + assert_or_panic(v[22] == 8); + assert_or_panic(v[23] == 9); + assert_or_panic(v[24] == 10); + assert_or_panic(v[25] == 11); + assert_or_panic(v[26] == 12); + assert_or_panic(v[27] == 13); + assert_or_panic(v[28] == 14); + assert_or_panic(v[29] == 15); + assert_or_panic(v[30] == 16); + assert_or_panic(v[31] == 17); + assert_or_panic(v[32] == 18); + assert_or_panic(v[33] == 19); + assert_or_panic(v[34] == 20); + assert_or_panic(v[35] == 21); + assert_or_panic(v[36] == 22); + assert_or_panic(v[37] == 23); + assert_or_panic(v[38] == 24); + assert_or_panic(v[39] == 25); + assert_or_panic(v[40] == 26); + assert_or_panic(v[41] == 27); + assert_or_panic(v[42] == 28); + assert_or_panic(v[43] == 29); + assert_or_panic(v[44] == 30); + assert_or_panic(v[45] == 31); + assert_or_panic(v[46] == 32); + assert_or_panic(v[47] == 33); + assert_or_panic(v[48] == 34); + assert_or_panic(v[49] == 35); + assert_or_panic(v[50] == 36); + assert_or_panic(v[51] == 37); + assert_or_panic(v[52] == 38); + assert_or_panic(v[53] == 39); + assert_or_panic(v[54] == 40); + assert_or_panic(v[55] == 41); + assert_or_panic(v[56] == 42); + assert_or_panic(v[57] == 43); + assert_or_panic(v[58] == 44); + assert_or_panic(v[59] == 45); + assert_or_panic(v[60] == 46); + assert_or_panic(v[61] == 47); + assert_or_panic(v[62] == 48); + assert_or_panic(v[63] == 49); + assert_or_panic(v[64] == 50); + assert_or_panic(v[65] == 51); + assert_or_panic(v[66] == 52); + assert_or_panic(v[67] == 53); + assert_or_panic(v[68] == 54); + assert_or_panic(v[69] == 55); + assert_or_panic(v[70] == 56); + assert_or_panic(v[71] == 57); + assert_or_panic(v[72] == 58); + assert_or_panic(v[73] == 59); + assert_or_panic(v[74] == 60); + assert_or_panic(v[75] == 61); + assert_or_panic(v[76] == 62); + assert_or_panic(v[77] == 63); + assert_or_panic(v[78] == 64); + assert_or_panic(v[79] == 65); + assert_or_panic(v[80] == 66); + assert_or_panic(v[81] == 67); + assert_or_panic(v[82] == 68); + assert_or_panic(v[83] == 69); + assert_or_panic(v[84] == 70); + assert_or_panic(v[85] == 71); + assert_or_panic(v[86] == 72); + assert_or_panic(v[87] == 73); + assert_or_panic(v[88] == 74); + assert_or_panic(v[89] == 75); + assert_or_panic(v[90] == 76); + assert_or_panic(v[91] == 77); + assert_or_panic(v[92] == 78); + assert_or_panic(v[93] == 79); + assert_or_panic(v[94] == 80); + assert_or_panic(v[95] == 81); + assert_or_panic(v[96] == 82); + assert_or_panic(v[97] == 83); + assert_or_panic(v[98] == 84); + assert_or_panic(v[99] == 85); + assert_or_panic(v[100] == 86); + assert_or_panic(v[101] == 87); + assert_or_panic(v[102] == 88); + assert_or_panic(v[103] == 89); + assert_or_panic(v[104] == 90); + assert_or_panic(v[105] == 91); + assert_or_panic(v[106] == 92); + assert_or_panic(v[107] == 93); + assert_or_panic(v[108] == 94); + assert_or_panic(v[109] == 95); + assert_or_panic(v[110] == 96); + assert_or_panic(v[111] == 97); + assert_or_panic(v[112] == 98); + assert_or_panic(v[113] == 99); + assert_or_panic(v[114] == 0); + assert_or_panic(v[115] == 1); + assert_or_panic(v[116] == 2); + assert_or_panic(v[117] == 3); + assert_or_panic(v[118] == 4); + assert_or_panic(v[119] == 5); + assert_or_panic(v[120] == 6); + assert_or_panic(v[121] == 7); + assert_or_panic(v[122] == 8); + assert_or_panic(v[123] == 9); + assert_or_panic(v[124] == 10); + assert_or_panic(v[125] == 11); + assert_or_panic(v[126] == 12); + assert_or_panic(v[127] == 13); + assert_or_panic(v[128] == 14); + assert_or_panic(v[129] == 15); + assert_or_panic(v[130] == 16); + assert_or_panic(v[131] == 17); + assert_or_panic(v[132] == 18); + assert_or_panic(v[133] == 19); + assert_or_panic(v[134] == 20); + assert_or_panic(v[135] == 21); + assert_or_panic(v[136] == 22); + assert_or_panic(v[137] == 23); + assert_or_panic(v[138] == 24); + assert_or_panic(v[139] == 25); + assert_or_panic(v[140] == 26); + assert_or_panic(v[141] == 27); + assert_or_panic(v[142] == 28); + assert_or_panic(v[143] == 29); + assert_or_panic(v[144] == 30); + assert_or_panic(v[145] == 31); + assert_or_panic(v[146] == 32); + assert_or_panic(v[147] == 33); + assert_or_panic(v[148] == 34); + assert_or_panic(v[149] == 35); + assert_or_panic(v[150] == 36); + assert_or_panic(v[151] == 37); + assert_or_panic(v[152] == 38); + assert_or_panic(v[153] == 39); + assert_or_panic(v[154] == 40); + assert_or_panic(v[155] == 41); + assert_or_panic(v[156] == 42); + assert_or_panic(v[157] == 43); + assert_or_panic(v[158] == 44); + assert_or_panic(v[159] == 45); + assert_or_panic(v[160] == 46); + assert_or_panic(v[161] == 47); + assert_or_panic(v[162] == 48); + assert_or_panic(v[163] == 49); + assert_or_panic(v[164] == 50); + assert_or_panic(v[165] == 51); + assert_or_panic(v[166] == 52); + assert_or_panic(v[167] == 53); + assert_or_panic(v[168] == 54); + assert_or_panic(v[169] == 55); + assert_or_panic(v[170] == 56); + assert_or_panic(v[171] == 57); + assert_or_panic(v[172] == 58); + assert_or_panic(v[173] == 59); + assert_or_panic(v[174] == 60); + assert_or_panic(v[175] == 61); + assert_or_panic(v[176] == 62); + assert_or_panic(v[177] == 63); + assert_or_panic(v[178] == 64); + assert_or_panic(v[179] == 65); + assert_or_panic(v[180] == 66); + assert_or_panic(v[181] == 67); + assert_or_panic(v[182] == 68); + assert_or_panic(v[183] == 69); + assert_or_panic(v[184] == 70); + assert_or_panic(v[185] == 71); + assert_or_panic(v[186] == 72); + assert_or_panic(v[187] == 73); + assert_or_panic(v[188] == 74); + assert_or_panic(v[189] == 75); + assert_or_panic(v[190] == 76); + assert_or_panic(v[191] == 77); + zig_vector_192_u8((Vector_192_u8){ + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + }, 192); +} + +typedef uint8_t Vector_256_u8 __attribute__((vector_size(256 * sizeof(uint8_t)))); + +Vector_256_u8 zig_ret_vector_256_u8(void); +void zig_vector_256_u8(Vector_256_u8, size_t); + +Vector_256_u8 c_ret_vector_256_u8(void) { + return (Vector_256_u8){ + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + }; +} +void c_vector_256_u8(Vector_256_u8 v, size_t i) { + assert_or_panic(v[0] == 22); + assert_or_panic(v[1] == 23); + assert_or_panic(v[2] == 24); + assert_or_panic(v[3] == 25); + assert_or_panic(v[4] == 26); + assert_or_panic(v[5] == 27); + assert_or_panic(v[6] == 28); + assert_or_panic(v[7] == 29); + assert_or_panic(v[8] == 30); + assert_or_panic(v[9] == 31); + assert_or_panic(v[10] == 32); + assert_or_panic(v[11] == 33); + assert_or_panic(v[12] == 34); + assert_or_panic(v[13] == 35); + assert_or_panic(v[14] == 36); + assert_or_panic(v[15] == 37); + assert_or_panic(v[16] == 38); + assert_or_panic(v[17] == 39); + assert_or_panic(v[18] == 40); + assert_or_panic(v[19] == 41); + assert_or_panic(v[20] == 42); + assert_or_panic(v[21] == 43); + assert_or_panic(v[22] == 44); + assert_or_panic(v[23] == 45); + assert_or_panic(v[24] == 46); + assert_or_panic(v[25] == 47); + assert_or_panic(v[26] == 48); + assert_or_panic(v[27] == 49); + assert_or_panic(v[28] == 50); + assert_or_panic(v[29] == 51); + assert_or_panic(v[30] == 52); + assert_or_panic(v[31] == 53); + assert_or_panic(v[32] == 54); + assert_or_panic(v[33] == 55); + assert_or_panic(v[34] == 56); + assert_or_panic(v[35] == 57); + assert_or_panic(v[36] == 58); + assert_or_panic(v[37] == 59); + assert_or_panic(v[38] == 60); + assert_or_panic(v[39] == 61); + assert_or_panic(v[40] == 62); + assert_or_panic(v[41] == 63); + assert_or_panic(v[42] == 64); + assert_or_panic(v[43] == 65); + assert_or_panic(v[44] == 66); + assert_or_panic(v[45] == 67); + assert_or_panic(v[46] == 68); + assert_or_panic(v[47] == 69); + assert_or_panic(v[48] == 70); + assert_or_panic(v[49] == 71); + assert_or_panic(v[50] == 72); + assert_or_panic(v[51] == 73); + assert_or_panic(v[52] == 74); + assert_or_panic(v[53] == 75); + assert_or_panic(v[54] == 76); + assert_or_panic(v[55] == 77); + assert_or_panic(v[56] == 78); + assert_or_panic(v[57] == 79); + assert_or_panic(v[58] == 80); + assert_or_panic(v[59] == 81); + assert_or_panic(v[60] == 82); + assert_or_panic(v[61] == 83); + assert_or_panic(v[62] == 84); + assert_or_panic(v[63] == 85); + assert_or_panic(v[64] == 86); + assert_or_panic(v[65] == 87); + assert_or_panic(v[66] == 88); + assert_or_panic(v[67] == 89); + assert_or_panic(v[68] == 90); + assert_or_panic(v[69] == 91); + assert_or_panic(v[70] == 92); + assert_or_panic(v[71] == 93); + assert_or_panic(v[72] == 94); + assert_or_panic(v[73] == 95); + assert_or_panic(v[74] == 96); + assert_or_panic(v[75] == 97); + assert_or_panic(v[76] == 98); + assert_or_panic(v[77] == 99); + assert_or_panic(v[78] == 0); + assert_or_panic(v[79] == 1); + assert_or_panic(v[80] == 2); + assert_or_panic(v[81] == 3); + assert_or_panic(v[82] == 4); + assert_or_panic(v[83] == 5); + assert_or_panic(v[84] == 6); + assert_or_panic(v[85] == 7); + assert_or_panic(v[86] == 8); + assert_or_panic(v[87] == 9); + assert_or_panic(v[88] == 10); + assert_or_panic(v[89] == 11); + assert_or_panic(v[90] == 12); + assert_or_panic(v[91] == 13); + assert_or_panic(v[92] == 14); + assert_or_panic(v[93] == 15); + assert_or_panic(v[94] == 16); + assert_or_panic(v[95] == 17); + assert_or_panic(v[96] == 18); + assert_or_panic(v[97] == 19); + assert_or_panic(v[98] == 20); + assert_or_panic(v[99] == 21); + assert_or_panic(v[100] == 22); + assert_or_panic(v[101] == 23); + assert_or_panic(v[102] == 24); + assert_or_panic(v[103] == 25); + assert_or_panic(v[104] == 26); + assert_or_panic(v[105] == 27); + assert_or_panic(v[106] == 28); + assert_or_panic(v[107] == 29); + assert_or_panic(v[108] == 30); + assert_or_panic(v[109] == 31); + assert_or_panic(v[110] == 32); + assert_or_panic(v[111] == 33); + assert_or_panic(v[112] == 34); + assert_or_panic(v[113] == 35); + assert_or_panic(v[114] == 36); + assert_or_panic(v[115] == 37); + assert_or_panic(v[116] == 38); + assert_or_panic(v[117] == 39); + assert_or_panic(v[118] == 40); + assert_or_panic(v[119] == 41); + assert_or_panic(v[120] == 42); + assert_or_panic(v[121] == 43); + assert_or_panic(v[122] == 44); + assert_or_panic(v[123] == 45); + assert_or_panic(v[124] == 46); + assert_or_panic(v[125] == 47); + assert_or_panic(v[126] == 48); + assert_or_panic(v[127] == 49); + assert_or_panic(v[128] == 50); + assert_or_panic(v[129] == 51); + assert_or_panic(v[130] == 52); + assert_or_panic(v[131] == 53); + assert_or_panic(v[132] == 54); + assert_or_panic(v[133] == 55); + assert_or_panic(v[134] == 56); + assert_or_panic(v[135] == 57); + assert_or_panic(v[136] == 58); + assert_or_panic(v[137] == 59); + assert_or_panic(v[138] == 60); + assert_or_panic(v[139] == 61); + assert_or_panic(v[140] == 62); + assert_or_panic(v[141] == 63); + assert_or_panic(v[142] == 64); + assert_or_panic(v[143] == 65); + assert_or_panic(v[144] == 66); + assert_or_panic(v[145] == 67); + assert_or_panic(v[146] == 68); + assert_or_panic(v[147] == 69); + assert_or_panic(v[148] == 70); + assert_or_panic(v[149] == 71); + assert_or_panic(v[150] == 72); + assert_or_panic(v[151] == 73); + assert_or_panic(v[152] == 74); + assert_or_panic(v[153] == 75); + assert_or_panic(v[154] == 76); + assert_or_panic(v[155] == 77); + assert_or_panic(v[156] == 78); + assert_or_panic(v[157] == 79); + assert_or_panic(v[158] == 80); + assert_or_panic(v[159] == 81); + assert_or_panic(v[160] == 82); + assert_or_panic(v[161] == 83); + assert_or_panic(v[162] == 84); + assert_or_panic(v[163] == 85); + assert_or_panic(v[164] == 86); + assert_or_panic(v[165] == 87); + assert_or_panic(v[166] == 88); + assert_or_panic(v[167] == 89); + assert_or_panic(v[168] == 90); + assert_or_panic(v[169] == 91); + assert_or_panic(v[170] == 92); + assert_or_panic(v[171] == 93); + assert_or_panic(v[172] == 94); + assert_or_panic(v[173] == 95); + assert_or_panic(v[174] == 96); + assert_or_panic(v[175] == 97); + assert_or_panic(v[176] == 98); + assert_or_panic(v[177] == 99); + assert_or_panic(v[178] == 0); + assert_or_panic(v[179] == 1); + assert_or_panic(v[180] == 2); + assert_or_panic(v[181] == 3); + assert_or_panic(v[182] == 4); + assert_or_panic(v[183] == 5); + assert_or_panic(v[184] == 6); + assert_or_panic(v[185] == 7); + assert_or_panic(v[186] == 8); + assert_or_panic(v[187] == 9); + assert_or_panic(v[188] == 10); + assert_or_panic(v[189] == 11); + assert_or_panic(v[190] == 12); + assert_or_panic(v[191] == 13); + assert_or_panic(v[192] == 14); + assert_or_panic(v[193] == 15); + assert_or_panic(v[194] == 16); + assert_or_panic(v[195] == 17); + assert_or_panic(v[196] == 18); + assert_or_panic(v[197] == 19); + assert_or_panic(v[198] == 20); + assert_or_panic(v[199] == 21); + assert_or_panic(v[200] == 22); + assert_or_panic(v[201] == 23); + assert_or_panic(v[202] == 24); + assert_or_panic(v[203] == 25); + assert_or_panic(v[204] == 26); + assert_or_panic(v[205] == 27); + assert_or_panic(v[206] == 28); + assert_or_panic(v[207] == 29); + assert_or_panic(v[208] == 30); + assert_or_panic(v[209] == 31); + assert_or_panic(v[210] == 32); + assert_or_panic(v[211] == 33); + assert_or_panic(v[212] == 34); + assert_or_panic(v[213] == 35); + assert_or_panic(v[214] == 36); + assert_or_panic(v[215] == 37); + assert_or_panic(v[216] == 38); + assert_or_panic(v[217] == 39); + assert_or_panic(v[218] == 40); + assert_or_panic(v[219] == 41); + assert_or_panic(v[220] == 42); + assert_or_panic(v[221] == 43); + assert_or_panic(v[222] == 44); + assert_or_panic(v[223] == 45); + assert_or_panic(v[224] == 46); + assert_or_panic(v[225] == 47); + assert_or_panic(v[226] == 48); + assert_or_panic(v[227] == 49); + assert_or_panic(v[228] == 50); + assert_or_panic(v[229] == 51); + assert_or_panic(v[230] == 52); + assert_or_panic(v[231] == 53); + assert_or_panic(v[232] == 54); + assert_or_panic(v[233] == 55); + assert_or_panic(v[234] == 56); + assert_or_panic(v[235] == 57); + assert_or_panic(v[236] == 58); + assert_or_panic(v[237] == 59); + assert_or_panic(v[238] == 60); + assert_or_panic(v[239] == 61); + assert_or_panic(v[240] == 62); + assert_or_panic(v[241] == 63); + assert_or_panic(v[242] == 64); + assert_or_panic(v[243] == 65); + assert_or_panic(v[244] == 66); + assert_or_panic(v[245] == 67); + assert_or_panic(v[246] == 68); + assert_or_panic(v[247] == 69); + assert_or_panic(v[248] == 70); + assert_or_panic(v[249] == 71); + assert_or_panic(v[250] == 72); + assert_or_panic(v[251] == 73); + assert_or_panic(v[252] == 74); + assert_or_panic(v[253] == 75); + assert_or_panic(v[254] == 76); + assert_or_panic(v[255] == 77); + assert_or_panic(i == 256); +} +void c_test_vector_256_u8(void) { + Vector_256_u8 v = zig_ret_vector_256_u8(); + assert_or_panic(v[0] == 54); + assert_or_panic(v[1] == 55); + assert_or_panic(v[2] == 56); + assert_or_panic(v[3] == 57); + assert_or_panic(v[4] == 58); + assert_or_panic(v[5] == 59); + assert_or_panic(v[6] == 60); + assert_or_panic(v[7] == 61); + assert_or_panic(v[8] == 62); + assert_or_panic(v[9] == 63); + assert_or_panic(v[10] == 64); + assert_or_panic(v[11] == 65); + assert_or_panic(v[12] == 66); + assert_or_panic(v[13] == 67); + assert_or_panic(v[14] == 68); + assert_or_panic(v[15] == 69); + assert_or_panic(v[16] == 70); + assert_or_panic(v[17] == 71); + assert_or_panic(v[18] == 72); + assert_or_panic(v[19] == 73); + assert_or_panic(v[20] == 74); + assert_or_panic(v[21] == 75); + assert_or_panic(v[22] == 76); + assert_or_panic(v[23] == 77); + assert_or_panic(v[24] == 78); + assert_or_panic(v[25] == 79); + assert_or_panic(v[26] == 80); + assert_or_panic(v[27] == 81); + assert_or_panic(v[28] == 82); + assert_or_panic(v[29] == 83); + assert_or_panic(v[30] == 84); + assert_or_panic(v[31] == 85); + assert_or_panic(v[32] == 86); + assert_or_panic(v[33] == 87); + assert_or_panic(v[34] == 88); + assert_or_panic(v[35] == 89); + assert_or_panic(v[36] == 90); + assert_or_panic(v[37] == 91); + assert_or_panic(v[38] == 92); + assert_or_panic(v[39] == 93); + assert_or_panic(v[40] == 94); + assert_or_panic(v[41] == 95); + assert_or_panic(v[42] == 96); + assert_or_panic(v[43] == 97); + assert_or_panic(v[44] == 98); + assert_or_panic(v[45] == 99); + assert_or_panic(v[46] == 0); + assert_or_panic(v[47] == 1); + assert_or_panic(v[48] == 2); + assert_or_panic(v[49] == 3); + assert_or_panic(v[50] == 4); + assert_or_panic(v[51] == 5); + assert_or_panic(v[52] == 6); + assert_or_panic(v[53] == 7); + assert_or_panic(v[54] == 8); + assert_or_panic(v[55] == 9); + assert_or_panic(v[56] == 10); + assert_or_panic(v[57] == 11); + assert_or_panic(v[58] == 12); + assert_or_panic(v[59] == 13); + assert_or_panic(v[60] == 14); + assert_or_panic(v[61] == 15); + assert_or_panic(v[62] == 16); + assert_or_panic(v[63] == 17); + assert_or_panic(v[64] == 18); + assert_or_panic(v[65] == 19); + assert_or_panic(v[66] == 20); + assert_or_panic(v[67] == 21); + assert_or_panic(v[68] == 22); + assert_or_panic(v[69] == 23); + assert_or_panic(v[70] == 24); + assert_or_panic(v[71] == 25); + assert_or_panic(v[72] == 26); + assert_or_panic(v[73] == 27); + assert_or_panic(v[74] == 28); + assert_or_panic(v[75] == 29); + assert_or_panic(v[76] == 30); + assert_or_panic(v[77] == 31); + assert_or_panic(v[78] == 32); + assert_or_panic(v[79] == 33); + assert_or_panic(v[80] == 34); + assert_or_panic(v[81] == 35); + assert_or_panic(v[82] == 36); + assert_or_panic(v[83] == 37); + assert_or_panic(v[84] == 38); + assert_or_panic(v[85] == 39); + assert_or_panic(v[86] == 40); + assert_or_panic(v[87] == 41); + assert_or_panic(v[88] == 42); + assert_or_panic(v[89] == 43); + assert_or_panic(v[90] == 44); + assert_or_panic(v[91] == 45); + assert_or_panic(v[92] == 46); + assert_or_panic(v[93] == 47); + assert_or_panic(v[94] == 48); + assert_or_panic(v[95] == 49); + assert_or_panic(v[96] == 50); + assert_or_panic(v[97] == 51); + assert_or_panic(v[98] == 52); + assert_or_panic(v[99] == 53); + assert_or_panic(v[100] == 54); + assert_or_panic(v[101] == 55); + assert_or_panic(v[102] == 56); + assert_or_panic(v[103] == 57); + assert_or_panic(v[104] == 58); + assert_or_panic(v[105] == 59); + assert_or_panic(v[106] == 60); + assert_or_panic(v[107] == 61); + assert_or_panic(v[108] == 62); + assert_or_panic(v[109] == 63); + assert_or_panic(v[110] == 64); + assert_or_panic(v[111] == 65); + assert_or_panic(v[112] == 66); + assert_or_panic(v[113] == 67); + assert_or_panic(v[114] == 68); + assert_or_panic(v[115] == 69); + assert_or_panic(v[116] == 70); + assert_or_panic(v[117] == 71); + assert_or_panic(v[118] == 72); + assert_or_panic(v[119] == 73); + assert_or_panic(v[120] == 74); + assert_or_panic(v[121] == 75); + assert_or_panic(v[122] == 76); + assert_or_panic(v[123] == 77); + assert_or_panic(v[124] == 78); + assert_or_panic(v[125] == 79); + assert_or_panic(v[126] == 80); + assert_or_panic(v[127] == 81); + assert_or_panic(v[128] == 82); + assert_or_panic(v[129] == 83); + assert_or_panic(v[130] == 84); + assert_or_panic(v[131] == 85); + assert_or_panic(v[132] == 86); + assert_or_panic(v[133] == 87); + assert_or_panic(v[134] == 88); + assert_or_panic(v[135] == 89); + assert_or_panic(v[136] == 90); + assert_or_panic(v[137] == 91); + assert_or_panic(v[138] == 92); + assert_or_panic(v[139] == 93); + assert_or_panic(v[140] == 94); + assert_or_panic(v[141] == 95); + assert_or_panic(v[142] == 96); + assert_or_panic(v[143] == 97); + assert_or_panic(v[144] == 98); + assert_or_panic(v[145] == 99); + assert_or_panic(v[146] == 0); + assert_or_panic(v[147] == 1); + assert_or_panic(v[148] == 2); + assert_or_panic(v[149] == 3); + assert_or_panic(v[150] == 4); + assert_or_panic(v[151] == 5); + assert_or_panic(v[152] == 6); + assert_or_panic(v[153] == 7); + assert_or_panic(v[154] == 8); + assert_or_panic(v[155] == 9); + assert_or_panic(v[156] == 10); + assert_or_panic(v[157] == 11); + assert_or_panic(v[158] == 12); + assert_or_panic(v[159] == 13); + assert_or_panic(v[160] == 14); + assert_or_panic(v[161] == 15); + assert_or_panic(v[162] == 16); + assert_or_panic(v[163] == 17); + assert_or_panic(v[164] == 18); + assert_or_panic(v[165] == 19); + assert_or_panic(v[166] == 20); + assert_or_panic(v[167] == 21); + assert_or_panic(v[168] == 22); + assert_or_panic(v[169] == 23); + assert_or_panic(v[170] == 24); + assert_or_panic(v[171] == 25); + assert_or_panic(v[172] == 26); + assert_or_panic(v[173] == 27); + assert_or_panic(v[174] == 28); + assert_or_panic(v[175] == 29); + assert_or_panic(v[176] == 30); + assert_or_panic(v[177] == 31); + assert_or_panic(v[178] == 32); + assert_or_panic(v[179] == 33); + assert_or_panic(v[180] == 34); + assert_or_panic(v[181] == 35); + assert_or_panic(v[182] == 36); + assert_or_panic(v[183] == 37); + assert_or_panic(v[184] == 38); + assert_or_panic(v[185] == 39); + assert_or_panic(v[186] == 40); + assert_or_panic(v[187] == 41); + assert_or_panic(v[188] == 42); + assert_or_panic(v[189] == 43); + assert_or_panic(v[190] == 44); + assert_or_panic(v[191] == 45); + assert_or_panic(v[192] == 46); + assert_or_panic(v[193] == 47); + assert_or_panic(v[194] == 48); + assert_or_panic(v[195] == 49); + assert_or_panic(v[196] == 50); + assert_or_panic(v[197] == 51); + assert_or_panic(v[198] == 52); + assert_or_panic(v[199] == 53); + assert_or_panic(v[200] == 54); + assert_or_panic(v[201] == 55); + assert_or_panic(v[202] == 56); + assert_or_panic(v[203] == 57); + assert_or_panic(v[204] == 58); + assert_or_panic(v[205] == 59); + assert_or_panic(v[206] == 60); + assert_or_panic(v[207] == 61); + assert_or_panic(v[208] == 62); + assert_or_panic(v[209] == 63); + assert_or_panic(v[210] == 64); + assert_or_panic(v[211] == 65); + assert_or_panic(v[212] == 66); + assert_or_panic(v[213] == 67); + assert_or_panic(v[214] == 68); + assert_or_panic(v[215] == 69); + assert_or_panic(v[216] == 70); + assert_or_panic(v[217] == 71); + assert_or_panic(v[218] == 72); + assert_or_panic(v[219] == 73); + assert_or_panic(v[220] == 74); + assert_or_panic(v[221] == 75); + assert_or_panic(v[222] == 76); + assert_or_panic(v[223] == 77); + assert_or_panic(v[224] == 78); + assert_or_panic(v[225] == 79); + assert_or_panic(v[226] == 80); + assert_or_panic(v[227] == 81); + assert_or_panic(v[228] == 82); + assert_or_panic(v[229] == 83); + assert_or_panic(v[230] == 84); + assert_or_panic(v[231] == 85); + assert_or_panic(v[232] == 86); + assert_or_panic(v[233] == 87); + assert_or_panic(v[234] == 88); + assert_or_panic(v[235] == 89); + assert_or_panic(v[236] == 90); + assert_or_panic(v[237] == 91); + assert_or_panic(v[238] == 92); + assert_or_panic(v[239] == 93); + assert_or_panic(v[240] == 94); + assert_or_panic(v[241] == 95); + assert_or_panic(v[242] == 96); + assert_or_panic(v[243] == 97); + assert_or_panic(v[244] == 98); + assert_or_panic(v[245] == 99); + assert_or_panic(v[246] == 0); + assert_or_panic(v[247] == 1); + assert_or_panic(v[248] == 2); + assert_or_panic(v[249] == 3); + assert_or_panic(v[250] == 4); + assert_or_panic(v[251] == 5); + assert_or_panic(v[252] == 6); + assert_or_panic(v[253] == 7); + assert_or_panic(v[254] == 8); + assert_or_panic(v[255] == 9); + zig_vector_256_u8((Vector_256_u8){ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + }, 256); +} + +typedef uint8_t Vector_384_u8 __attribute__((vector_size(384 * sizeof(uint8_t)))); + +Vector_384_u8 zig_ret_vector_384_u8(void); +void zig_vector_384_u8(Vector_384_u8, size_t); + +Vector_384_u8 c_ret_vector_384_u8(void) { + return (Vector_384_u8){ + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + }; +} +void c_vector_384_u8(Vector_384_u8 v, size_t i) { + assert_or_panic(v[0] == 30); + assert_or_panic(v[1] == 31); + assert_or_panic(v[2] == 32); + assert_or_panic(v[3] == 33); + assert_or_panic(v[4] == 34); + assert_or_panic(v[5] == 35); + assert_or_panic(v[6] == 36); + assert_or_panic(v[7] == 37); + assert_or_panic(v[8] == 38); + assert_or_panic(v[9] == 39); + assert_or_panic(v[10] == 40); + assert_or_panic(v[11] == 41); + assert_or_panic(v[12] == 42); + assert_or_panic(v[13] == 43); + assert_or_panic(v[14] == 44); + assert_or_panic(v[15] == 45); + assert_or_panic(v[16] == 46); + assert_or_panic(v[17] == 47); + assert_or_panic(v[18] == 48); + assert_or_panic(v[19] == 49); + assert_or_panic(v[20] == 50); + assert_or_panic(v[21] == 51); + assert_or_panic(v[22] == 52); + assert_or_panic(v[23] == 53); + assert_or_panic(v[24] == 54); + assert_or_panic(v[25] == 55); + assert_or_panic(v[26] == 56); + assert_or_panic(v[27] == 57); + assert_or_panic(v[28] == 58); + assert_or_panic(v[29] == 59); + assert_or_panic(v[30] == 60); + assert_or_panic(v[31] == 61); + assert_or_panic(v[32] == 62); + assert_or_panic(v[33] == 63); + assert_or_panic(v[34] == 64); + assert_or_panic(v[35] == 65); + assert_or_panic(v[36] == 66); + assert_or_panic(v[37] == 67); + assert_or_panic(v[38] == 68); + assert_or_panic(v[39] == 69); + assert_or_panic(v[40] == 70); + assert_or_panic(v[41] == 71); + assert_or_panic(v[42] == 72); + assert_or_panic(v[43] == 73); + assert_or_panic(v[44] == 74); + assert_or_panic(v[45] == 75); + assert_or_panic(v[46] == 76); + assert_or_panic(v[47] == 77); + assert_or_panic(v[48] == 78); + assert_or_panic(v[49] == 79); + assert_or_panic(v[50] == 80); + assert_or_panic(v[51] == 81); + assert_or_panic(v[52] == 82); + assert_or_panic(v[53] == 83); + assert_or_panic(v[54] == 84); + assert_or_panic(v[55] == 85); + assert_or_panic(v[56] == 86); + assert_or_panic(v[57] == 87); + assert_or_panic(v[58] == 88); + assert_or_panic(v[59] == 89); + assert_or_panic(v[60] == 90); + assert_or_panic(v[61] == 91); + assert_or_panic(v[62] == 92); + assert_or_panic(v[63] == 93); + assert_or_panic(v[64] == 94); + assert_or_panic(v[65] == 95); + assert_or_panic(v[66] == 96); + assert_or_panic(v[67] == 97); + assert_or_panic(v[68] == 98); + assert_or_panic(v[69] == 99); + assert_or_panic(v[70] == 0); + assert_or_panic(v[71] == 1); + assert_or_panic(v[72] == 2); + assert_or_panic(v[73] == 3); + assert_or_panic(v[74] == 4); + assert_or_panic(v[75] == 5); + assert_or_panic(v[76] == 6); + assert_or_panic(v[77] == 7); + assert_or_panic(v[78] == 8); + assert_or_panic(v[79] == 9); + assert_or_panic(v[80] == 10); + assert_or_panic(v[81] == 11); + assert_or_panic(v[82] == 12); + assert_or_panic(v[83] == 13); + assert_or_panic(v[84] == 14); + assert_or_panic(v[85] == 15); + assert_or_panic(v[86] == 16); + assert_or_panic(v[87] == 17); + assert_or_panic(v[88] == 18); + assert_or_panic(v[89] == 19); + assert_or_panic(v[90] == 20); + assert_or_panic(v[91] == 21); + assert_or_panic(v[92] == 22); + assert_or_panic(v[93] == 23); + assert_or_panic(v[94] == 24); + assert_or_panic(v[95] == 25); + assert_or_panic(v[96] == 26); + assert_or_panic(v[97] == 27); + assert_or_panic(v[98] == 28); + assert_or_panic(v[99] == 29); + assert_or_panic(v[100] == 30); + assert_or_panic(v[101] == 31); + assert_or_panic(v[102] == 32); + assert_or_panic(v[103] == 33); + assert_or_panic(v[104] == 34); + assert_or_panic(v[105] == 35); + assert_or_panic(v[106] == 36); + assert_or_panic(v[107] == 37); + assert_or_panic(v[108] == 38); + assert_or_panic(v[109] == 39); + assert_or_panic(v[110] == 40); + assert_or_panic(v[111] == 41); + assert_or_panic(v[112] == 42); + assert_or_panic(v[113] == 43); + assert_or_panic(v[114] == 44); + assert_or_panic(v[115] == 45); + assert_or_panic(v[116] == 46); + assert_or_panic(v[117] == 47); + assert_or_panic(v[118] == 48); + assert_or_panic(v[119] == 49); + assert_or_panic(v[120] == 50); + assert_or_panic(v[121] == 51); + assert_or_panic(v[122] == 52); + assert_or_panic(v[123] == 53); + assert_or_panic(v[124] == 54); + assert_or_panic(v[125] == 55); + assert_or_panic(v[126] == 56); + assert_or_panic(v[127] == 57); + assert_or_panic(v[128] == 58); + assert_or_panic(v[129] == 59); + assert_or_panic(v[130] == 60); + assert_or_panic(v[131] == 61); + assert_or_panic(v[132] == 62); + assert_or_panic(v[133] == 63); + assert_or_panic(v[134] == 64); + assert_or_panic(v[135] == 65); + assert_or_panic(v[136] == 66); + assert_or_panic(v[137] == 67); + assert_or_panic(v[138] == 68); + assert_or_panic(v[139] == 69); + assert_or_panic(v[140] == 70); + assert_or_panic(v[141] == 71); + assert_or_panic(v[142] == 72); + assert_or_panic(v[143] == 73); + assert_or_panic(v[144] == 74); + assert_or_panic(v[145] == 75); + assert_or_panic(v[146] == 76); + assert_or_panic(v[147] == 77); + assert_or_panic(v[148] == 78); + assert_or_panic(v[149] == 79); + assert_or_panic(v[150] == 80); + assert_or_panic(v[151] == 81); + assert_or_panic(v[152] == 82); + assert_or_panic(v[153] == 83); + assert_or_panic(v[154] == 84); + assert_or_panic(v[155] == 85); + assert_or_panic(v[156] == 86); + assert_or_panic(v[157] == 87); + assert_or_panic(v[158] == 88); + assert_or_panic(v[159] == 89); + assert_or_panic(v[160] == 90); + assert_or_panic(v[161] == 91); + assert_or_panic(v[162] == 92); + assert_or_panic(v[163] == 93); + assert_or_panic(v[164] == 94); + assert_or_panic(v[165] == 95); + assert_or_panic(v[166] == 96); + assert_or_panic(v[167] == 97); + assert_or_panic(v[168] == 98); + assert_or_panic(v[169] == 99); + assert_or_panic(v[170] == 0); + assert_or_panic(v[171] == 1); + assert_or_panic(v[172] == 2); + assert_or_panic(v[173] == 3); + assert_or_panic(v[174] == 4); + assert_or_panic(v[175] == 5); + assert_or_panic(v[176] == 6); + assert_or_panic(v[177] == 7); + assert_or_panic(v[178] == 8); + assert_or_panic(v[179] == 9); + assert_or_panic(v[180] == 10); + assert_or_panic(v[181] == 11); + assert_or_panic(v[182] == 12); + assert_or_panic(v[183] == 13); + assert_or_panic(v[184] == 14); + assert_or_panic(v[185] == 15); + assert_or_panic(v[186] == 16); + assert_or_panic(v[187] == 17); + assert_or_panic(v[188] == 18); + assert_or_panic(v[189] == 19); + assert_or_panic(v[190] == 20); + assert_or_panic(v[191] == 21); + assert_or_panic(v[192] == 22); + assert_or_panic(v[193] == 23); + assert_or_panic(v[194] == 24); + assert_or_panic(v[195] == 25); + assert_or_panic(v[196] == 26); + assert_or_panic(v[197] == 27); + assert_or_panic(v[198] == 28); + assert_or_panic(v[199] == 29); + assert_or_panic(v[200] == 30); + assert_or_panic(v[201] == 31); + assert_or_panic(v[202] == 32); + assert_or_panic(v[203] == 33); + assert_or_panic(v[204] == 34); + assert_or_panic(v[205] == 35); + assert_or_panic(v[206] == 36); + assert_or_panic(v[207] == 37); + assert_or_panic(v[208] == 38); + assert_or_panic(v[209] == 39); + assert_or_panic(v[210] == 40); + assert_or_panic(v[211] == 41); + assert_or_panic(v[212] == 42); + assert_or_panic(v[213] == 43); + assert_or_panic(v[214] == 44); + assert_or_panic(v[215] == 45); + assert_or_panic(v[216] == 46); + assert_or_panic(v[217] == 47); + assert_or_panic(v[218] == 48); + assert_or_panic(v[219] == 49); + assert_or_panic(v[220] == 50); + assert_or_panic(v[221] == 51); + assert_or_panic(v[222] == 52); + assert_or_panic(v[223] == 53); + assert_or_panic(v[224] == 54); + assert_or_panic(v[225] == 55); + assert_or_panic(v[226] == 56); + assert_or_panic(v[227] == 57); + assert_or_panic(v[228] == 58); + assert_or_panic(v[229] == 59); + assert_or_panic(v[230] == 60); + assert_or_panic(v[231] == 61); + assert_or_panic(v[232] == 62); + assert_or_panic(v[233] == 63); + assert_or_panic(v[234] == 64); + assert_or_panic(v[235] == 65); + assert_or_panic(v[236] == 66); + assert_or_panic(v[237] == 67); + assert_or_panic(v[238] == 68); + assert_or_panic(v[239] == 69); + assert_or_panic(v[240] == 70); + assert_or_panic(v[241] == 71); + assert_or_panic(v[242] == 72); + assert_or_panic(v[243] == 73); + assert_or_panic(v[244] == 74); + assert_or_panic(v[245] == 75); + assert_or_panic(v[246] == 76); + assert_or_panic(v[247] == 77); + assert_or_panic(v[248] == 78); + assert_or_panic(v[249] == 79); + assert_or_panic(v[250] == 80); + assert_or_panic(v[251] == 81); + assert_or_panic(v[252] == 82); + assert_or_panic(v[253] == 83); + assert_or_panic(v[254] == 84); + assert_or_panic(v[255] == 85); + assert_or_panic(v[256] == 86); + assert_or_panic(v[257] == 87); + assert_or_panic(v[258] == 88); + assert_or_panic(v[259] == 89); + assert_or_panic(v[260] == 90); + assert_or_panic(v[261] == 91); + assert_or_panic(v[262] == 92); + assert_or_panic(v[263] == 93); + assert_or_panic(v[264] == 94); + assert_or_panic(v[265] == 95); + assert_or_panic(v[266] == 96); + assert_or_panic(v[267] == 97); + assert_or_panic(v[268] == 98); + assert_or_panic(v[269] == 99); + assert_or_panic(v[270] == 0); + assert_or_panic(v[271] == 1); + assert_or_panic(v[272] == 2); + assert_or_panic(v[273] == 3); + assert_or_panic(v[274] == 4); + assert_or_panic(v[275] == 5); + assert_or_panic(v[276] == 6); + assert_or_panic(v[277] == 7); + assert_or_panic(v[278] == 8); + assert_or_panic(v[279] == 9); + assert_or_panic(v[280] == 10); + assert_or_panic(v[281] == 11); + assert_or_panic(v[282] == 12); + assert_or_panic(v[283] == 13); + assert_or_panic(v[284] == 14); + assert_or_panic(v[285] == 15); + assert_or_panic(v[286] == 16); + assert_or_panic(v[287] == 17); + assert_or_panic(v[288] == 18); + assert_or_panic(v[289] == 19); + assert_or_panic(v[290] == 20); + assert_or_panic(v[291] == 21); + assert_or_panic(v[292] == 22); + assert_or_panic(v[293] == 23); + assert_or_panic(v[294] == 24); + assert_or_panic(v[295] == 25); + assert_or_panic(v[296] == 26); + assert_or_panic(v[297] == 27); + assert_or_panic(v[298] == 28); + assert_or_panic(v[299] == 29); + assert_or_panic(v[300] == 30); + assert_or_panic(v[301] == 31); + assert_or_panic(v[302] == 32); + assert_or_panic(v[303] == 33); + assert_or_panic(v[304] == 34); + assert_or_panic(v[305] == 35); + assert_or_panic(v[306] == 36); + assert_or_panic(v[307] == 37); + assert_or_panic(v[308] == 38); + assert_or_panic(v[309] == 39); + assert_or_panic(v[310] == 40); + assert_or_panic(v[311] == 41); + assert_or_panic(v[312] == 42); + assert_or_panic(v[313] == 43); + assert_or_panic(v[314] == 44); + assert_or_panic(v[315] == 45); + assert_or_panic(v[316] == 46); + assert_or_panic(v[317] == 47); + assert_or_panic(v[318] == 48); + assert_or_panic(v[319] == 49); + assert_or_panic(v[320] == 50); + assert_or_panic(v[321] == 51); + assert_or_panic(v[322] == 52); + assert_or_panic(v[323] == 53); + assert_or_panic(v[324] == 54); + assert_or_panic(v[325] == 55); + assert_or_panic(v[326] == 56); + assert_or_panic(v[327] == 57); + assert_or_panic(v[328] == 58); + assert_or_panic(v[329] == 59); + assert_or_panic(v[330] == 60); + assert_or_panic(v[331] == 61); + assert_or_panic(v[332] == 62); + assert_or_panic(v[333] == 63); + assert_or_panic(v[334] == 64); + assert_or_panic(v[335] == 65); + assert_or_panic(v[336] == 66); + assert_or_panic(v[337] == 67); + assert_or_panic(v[338] == 68); + assert_or_panic(v[339] == 69); + assert_or_panic(v[340] == 70); + assert_or_panic(v[341] == 71); + assert_or_panic(v[342] == 72); + assert_or_panic(v[343] == 73); + assert_or_panic(v[344] == 74); + assert_or_panic(v[345] == 75); + assert_or_panic(v[346] == 76); + assert_or_panic(v[347] == 77); + assert_or_panic(v[348] == 78); + assert_or_panic(v[349] == 79); + assert_or_panic(v[350] == 80); + assert_or_panic(v[351] == 81); + assert_or_panic(v[352] == 82); + assert_or_panic(v[353] == 83); + assert_or_panic(v[354] == 84); + assert_or_panic(v[355] == 85); + assert_or_panic(v[356] == 86); + assert_or_panic(v[357] == 87); + assert_or_panic(v[358] == 88); + assert_or_panic(v[359] == 89); + assert_or_panic(v[360] == 90); + assert_or_panic(v[361] == 91); + assert_or_panic(v[362] == 92); + assert_or_panic(v[363] == 93); + assert_or_panic(v[364] == 94); + assert_or_panic(v[365] == 95); + assert_or_panic(v[366] == 96); + assert_or_panic(v[367] == 97); + assert_or_panic(v[368] == 98); + assert_or_panic(v[369] == 99); + assert_or_panic(v[370] == 0); + assert_or_panic(v[371] == 1); + assert_or_panic(v[372] == 2); + assert_or_panic(v[373] == 3); + assert_or_panic(v[374] == 4); + assert_or_panic(v[375] == 5); + assert_or_panic(v[376] == 6); + assert_or_panic(v[377] == 7); + assert_or_panic(v[378] == 8); + assert_or_panic(v[379] == 9); + assert_or_panic(v[380] == 10); + assert_or_panic(v[381] == 11); + assert_or_panic(v[382] == 12); + assert_or_panic(v[383] == 13); + assert_or_panic(i == 384); +} +void c_test_vector_384_u8(void) { + Vector_384_u8 v = zig_ret_vector_384_u8(); + assert_or_panic(v[0] == 78); + assert_or_panic(v[1] == 79); + assert_or_panic(v[2] == 80); + assert_or_panic(v[3] == 81); + assert_or_panic(v[4] == 82); + assert_or_panic(v[5] == 83); + assert_or_panic(v[6] == 84); + assert_or_panic(v[7] == 85); + assert_or_panic(v[8] == 86); + assert_or_panic(v[9] == 87); + assert_or_panic(v[10] == 88); + assert_or_panic(v[11] == 89); + assert_or_panic(v[12] == 90); + assert_or_panic(v[13] == 91); + assert_or_panic(v[14] == 92); + assert_or_panic(v[15] == 93); + assert_or_panic(v[16] == 94); + assert_or_panic(v[17] == 95); + assert_or_panic(v[18] == 96); + assert_or_panic(v[19] == 97); + assert_or_panic(v[20] == 98); + assert_or_panic(v[21] == 99); + assert_or_panic(v[22] == 0); + assert_or_panic(v[23] == 1); + assert_or_panic(v[24] == 2); + assert_or_panic(v[25] == 3); + assert_or_panic(v[26] == 4); + assert_or_panic(v[27] == 5); + assert_or_panic(v[28] == 6); + assert_or_panic(v[29] == 7); + assert_or_panic(v[30] == 8); + assert_or_panic(v[31] == 9); + assert_or_panic(v[32] == 10); + assert_or_panic(v[33] == 11); + assert_or_panic(v[34] == 12); + assert_or_panic(v[35] == 13); + assert_or_panic(v[36] == 14); + assert_or_panic(v[37] == 15); + assert_or_panic(v[38] == 16); + assert_or_panic(v[39] == 17); + assert_or_panic(v[40] == 18); + assert_or_panic(v[41] == 19); + assert_or_panic(v[42] == 20); + assert_or_panic(v[43] == 21); + assert_or_panic(v[44] == 22); + assert_or_panic(v[45] == 23); + assert_or_panic(v[46] == 24); + assert_or_panic(v[47] == 25); + assert_or_panic(v[48] == 26); + assert_or_panic(v[49] == 27); + assert_or_panic(v[50] == 28); + assert_or_panic(v[51] == 29); + assert_or_panic(v[52] == 30); + assert_or_panic(v[53] == 31); + assert_or_panic(v[54] == 32); + assert_or_panic(v[55] == 33); + assert_or_panic(v[56] == 34); + assert_or_panic(v[57] == 35); + assert_or_panic(v[58] == 36); + assert_or_panic(v[59] == 37); + assert_or_panic(v[60] == 38); + assert_or_panic(v[61] == 39); + assert_or_panic(v[62] == 40); + assert_or_panic(v[63] == 41); + assert_or_panic(v[64] == 42); + assert_or_panic(v[65] == 43); + assert_or_panic(v[66] == 44); + assert_or_panic(v[67] == 45); + assert_or_panic(v[68] == 46); + assert_or_panic(v[69] == 47); + assert_or_panic(v[70] == 48); + assert_or_panic(v[71] == 49); + assert_or_panic(v[72] == 50); + assert_or_panic(v[73] == 51); + assert_or_panic(v[74] == 52); + assert_or_panic(v[75] == 53); + assert_or_panic(v[76] == 54); + assert_or_panic(v[77] == 55); + assert_or_panic(v[78] == 56); + assert_or_panic(v[79] == 57); + assert_or_panic(v[80] == 58); + assert_or_panic(v[81] == 59); + assert_or_panic(v[82] == 60); + assert_or_panic(v[83] == 61); + assert_or_panic(v[84] == 62); + assert_or_panic(v[85] == 63); + assert_or_panic(v[86] == 64); + assert_or_panic(v[87] == 65); + assert_or_panic(v[88] == 66); + assert_or_panic(v[89] == 67); + assert_or_panic(v[90] == 68); + assert_or_panic(v[91] == 69); + assert_or_panic(v[92] == 70); + assert_or_panic(v[93] == 71); + assert_or_panic(v[94] == 72); + assert_or_panic(v[95] == 73); + assert_or_panic(v[96] == 74); + assert_or_panic(v[97] == 75); + assert_or_panic(v[98] == 76); + assert_or_panic(v[99] == 77); + assert_or_panic(v[100] == 78); + assert_or_panic(v[101] == 79); + assert_or_panic(v[102] == 80); + assert_or_panic(v[103] == 81); + assert_or_panic(v[104] == 82); + assert_or_panic(v[105] == 83); + assert_or_panic(v[106] == 84); + assert_or_panic(v[107] == 85); + assert_or_panic(v[108] == 86); + assert_or_panic(v[109] == 87); + assert_or_panic(v[110] == 88); + assert_or_panic(v[111] == 89); + assert_or_panic(v[112] == 90); + assert_or_panic(v[113] == 91); + assert_or_panic(v[114] == 92); + assert_or_panic(v[115] == 93); + assert_or_panic(v[116] == 94); + assert_or_panic(v[117] == 95); + assert_or_panic(v[118] == 96); + assert_or_panic(v[119] == 97); + assert_or_panic(v[120] == 98); + assert_or_panic(v[121] == 99); + assert_or_panic(v[122] == 0); + assert_or_panic(v[123] == 1); + assert_or_panic(v[124] == 2); + assert_or_panic(v[125] == 3); + assert_or_panic(v[126] == 4); + assert_or_panic(v[127] == 5); + assert_or_panic(v[128] == 6); + assert_or_panic(v[129] == 7); + assert_or_panic(v[130] == 8); + assert_or_panic(v[131] == 9); + assert_or_panic(v[132] == 10); + assert_or_panic(v[133] == 11); + assert_or_panic(v[134] == 12); + assert_or_panic(v[135] == 13); + assert_or_panic(v[136] == 14); + assert_or_panic(v[137] == 15); + assert_or_panic(v[138] == 16); + assert_or_panic(v[139] == 17); + assert_or_panic(v[140] == 18); + assert_or_panic(v[141] == 19); + assert_or_panic(v[142] == 20); + assert_or_panic(v[143] == 21); + assert_or_panic(v[144] == 22); + assert_or_panic(v[145] == 23); + assert_or_panic(v[146] == 24); + assert_or_panic(v[147] == 25); + assert_or_panic(v[148] == 26); + assert_or_panic(v[149] == 27); + assert_or_panic(v[150] == 28); + assert_or_panic(v[151] == 29); + assert_or_panic(v[152] == 30); + assert_or_panic(v[153] == 31); + assert_or_panic(v[154] == 32); + assert_or_panic(v[155] == 33); + assert_or_panic(v[156] == 34); + assert_or_panic(v[157] == 35); + assert_or_panic(v[158] == 36); + assert_or_panic(v[159] == 37); + assert_or_panic(v[160] == 38); + assert_or_panic(v[161] == 39); + assert_or_panic(v[162] == 40); + assert_or_panic(v[163] == 41); + assert_or_panic(v[164] == 42); + assert_or_panic(v[165] == 43); + assert_or_panic(v[166] == 44); + assert_or_panic(v[167] == 45); + assert_or_panic(v[168] == 46); + assert_or_panic(v[169] == 47); + assert_or_panic(v[170] == 48); + assert_or_panic(v[171] == 49); + assert_or_panic(v[172] == 50); + assert_or_panic(v[173] == 51); + assert_or_panic(v[174] == 52); + assert_or_panic(v[175] == 53); + assert_or_panic(v[176] == 54); + assert_or_panic(v[177] == 55); + assert_or_panic(v[178] == 56); + assert_or_panic(v[179] == 57); + assert_or_panic(v[180] == 58); + assert_or_panic(v[181] == 59); + assert_or_panic(v[182] == 60); + assert_or_panic(v[183] == 61); + assert_or_panic(v[184] == 62); + assert_or_panic(v[185] == 63); + assert_or_panic(v[186] == 64); + assert_or_panic(v[187] == 65); + assert_or_panic(v[188] == 66); + assert_or_panic(v[189] == 67); + assert_or_panic(v[190] == 68); + assert_or_panic(v[191] == 69); + assert_or_panic(v[192] == 70); + assert_or_panic(v[193] == 71); + assert_or_panic(v[194] == 72); + assert_or_panic(v[195] == 73); + assert_or_panic(v[196] == 74); + assert_or_panic(v[197] == 75); + assert_or_panic(v[198] == 76); + assert_or_panic(v[199] == 77); + assert_or_panic(v[200] == 78); + assert_or_panic(v[201] == 79); + assert_or_panic(v[202] == 80); + assert_or_panic(v[203] == 81); + assert_or_panic(v[204] == 82); + assert_or_panic(v[205] == 83); + assert_or_panic(v[206] == 84); + assert_or_panic(v[207] == 85); + assert_or_panic(v[208] == 86); + assert_or_panic(v[209] == 87); + assert_or_panic(v[210] == 88); + assert_or_panic(v[211] == 89); + assert_or_panic(v[212] == 90); + assert_or_panic(v[213] == 91); + assert_or_panic(v[214] == 92); + assert_or_panic(v[215] == 93); + assert_or_panic(v[216] == 94); + assert_or_panic(v[217] == 95); + assert_or_panic(v[218] == 96); + assert_or_panic(v[219] == 97); + assert_or_panic(v[220] == 98); + assert_or_panic(v[221] == 99); + assert_or_panic(v[222] == 0); + assert_or_panic(v[223] == 1); + assert_or_panic(v[224] == 2); + assert_or_panic(v[225] == 3); + assert_or_panic(v[226] == 4); + assert_or_panic(v[227] == 5); + assert_or_panic(v[228] == 6); + assert_or_panic(v[229] == 7); + assert_or_panic(v[230] == 8); + assert_or_panic(v[231] == 9); + assert_or_panic(v[232] == 10); + assert_or_panic(v[233] == 11); + assert_or_panic(v[234] == 12); + assert_or_panic(v[235] == 13); + assert_or_panic(v[236] == 14); + assert_or_panic(v[237] == 15); + assert_or_panic(v[238] == 16); + assert_or_panic(v[239] == 17); + assert_or_panic(v[240] == 18); + assert_or_panic(v[241] == 19); + assert_or_panic(v[242] == 20); + assert_or_panic(v[243] == 21); + assert_or_panic(v[244] == 22); + assert_or_panic(v[245] == 23); + assert_or_panic(v[246] == 24); + assert_or_panic(v[247] == 25); + assert_or_panic(v[248] == 26); + assert_or_panic(v[249] == 27); + assert_or_panic(v[250] == 28); + assert_or_panic(v[251] == 29); + assert_or_panic(v[252] == 30); + assert_or_panic(v[253] == 31); + assert_or_panic(v[254] == 32); + assert_or_panic(v[255] == 33); + assert_or_panic(v[256] == 34); + assert_or_panic(v[257] == 35); + assert_or_panic(v[258] == 36); + assert_or_panic(v[259] == 37); + assert_or_panic(v[260] == 38); + assert_or_panic(v[261] == 39); + assert_or_panic(v[262] == 40); + assert_or_panic(v[263] == 41); + assert_or_panic(v[264] == 42); + assert_or_panic(v[265] == 43); + assert_or_panic(v[266] == 44); + assert_or_panic(v[267] == 45); + assert_or_panic(v[268] == 46); + assert_or_panic(v[269] == 47); + assert_or_panic(v[270] == 48); + assert_or_panic(v[271] == 49); + assert_or_panic(v[272] == 50); + assert_or_panic(v[273] == 51); + assert_or_panic(v[274] == 52); + assert_or_panic(v[275] == 53); + assert_or_panic(v[276] == 54); + assert_or_panic(v[277] == 55); + assert_or_panic(v[278] == 56); + assert_or_panic(v[279] == 57); + assert_or_panic(v[280] == 58); + assert_or_panic(v[281] == 59); + assert_or_panic(v[282] == 60); + assert_or_panic(v[283] == 61); + assert_or_panic(v[284] == 62); + assert_or_panic(v[285] == 63); + assert_or_panic(v[286] == 64); + assert_or_panic(v[287] == 65); + assert_or_panic(v[288] == 66); + assert_or_panic(v[289] == 67); + assert_or_panic(v[290] == 68); + assert_or_panic(v[291] == 69); + assert_or_panic(v[292] == 70); + assert_or_panic(v[293] == 71); + assert_or_panic(v[294] == 72); + assert_or_panic(v[295] == 73); + assert_or_panic(v[296] == 74); + assert_or_panic(v[297] == 75); + assert_or_panic(v[298] == 76); + assert_or_panic(v[299] == 77); + assert_or_panic(v[300] == 78); + assert_or_panic(v[301] == 79); + assert_or_panic(v[302] == 80); + assert_or_panic(v[303] == 81); + assert_or_panic(v[304] == 82); + assert_or_panic(v[305] == 83); + assert_or_panic(v[306] == 84); + assert_or_panic(v[307] == 85); + assert_or_panic(v[308] == 86); + assert_or_panic(v[309] == 87); + assert_or_panic(v[310] == 88); + assert_or_panic(v[311] == 89); + assert_or_panic(v[312] == 90); + assert_or_panic(v[313] == 91); + assert_or_panic(v[314] == 92); + assert_or_panic(v[315] == 93); + assert_or_panic(v[316] == 94); + assert_or_panic(v[317] == 95); + assert_or_panic(v[318] == 96); + assert_or_panic(v[319] == 97); + assert_or_panic(v[320] == 98); + assert_or_panic(v[321] == 99); + assert_or_panic(v[322] == 0); + assert_or_panic(v[323] == 1); + assert_or_panic(v[324] == 2); + assert_or_panic(v[325] == 3); + assert_or_panic(v[326] == 4); + assert_or_panic(v[327] == 5); + assert_or_panic(v[328] == 6); + assert_or_panic(v[329] == 7); + assert_or_panic(v[330] == 8); + assert_or_panic(v[331] == 9); + assert_or_panic(v[332] == 10); + assert_or_panic(v[333] == 11); + assert_or_panic(v[334] == 12); + assert_or_panic(v[335] == 13); + assert_or_panic(v[336] == 14); + assert_or_panic(v[337] == 15); + assert_or_panic(v[338] == 16); + assert_or_panic(v[339] == 17); + assert_or_panic(v[340] == 18); + assert_or_panic(v[341] == 19); + assert_or_panic(v[342] == 20); + assert_or_panic(v[343] == 21); + assert_or_panic(v[344] == 22); + assert_or_panic(v[345] == 23); + assert_or_panic(v[346] == 24); + assert_or_panic(v[347] == 25); + assert_or_panic(v[348] == 26); + assert_or_panic(v[349] == 27); + assert_or_panic(v[350] == 28); + assert_or_panic(v[351] == 29); + assert_or_panic(v[352] == 30); + assert_or_panic(v[353] == 31); + assert_or_panic(v[354] == 32); + assert_or_panic(v[355] == 33); + assert_or_panic(v[356] == 34); + assert_or_panic(v[357] == 35); + assert_or_panic(v[358] == 36); + assert_or_panic(v[359] == 37); + assert_or_panic(v[360] == 38); + assert_or_panic(v[361] == 39); + assert_or_panic(v[362] == 40); + assert_or_panic(v[363] == 41); + assert_or_panic(v[364] == 42); + assert_or_panic(v[365] == 43); + assert_or_panic(v[366] == 44); + assert_or_panic(v[367] == 45); + assert_or_panic(v[368] == 46); + assert_or_panic(v[369] == 47); + assert_or_panic(v[370] == 48); + assert_or_panic(v[371] == 49); + assert_or_panic(v[372] == 50); + assert_or_panic(v[373] == 51); + assert_or_panic(v[374] == 52); + assert_or_panic(v[375] == 53); + assert_or_panic(v[376] == 54); + assert_or_panic(v[377] == 55); + assert_or_panic(v[378] == 56); + assert_or_panic(v[379] == 57); + assert_or_panic(v[380] == 58); + assert_or_panic(v[381] == 59); + assert_or_panic(v[382] == 60); + assert_or_panic(v[383] == 61); + zig_vector_384_u8((Vector_384_u8){ + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + }, 384); +} + +typedef uint8_t Vector_512_u8 __attribute__((vector_size(512 * sizeof(uint8_t)))); + +Vector_512_u8 zig_ret_vector_512_u8(void); +void zig_vector_512_u8(Vector_512_u8, size_t); + +Vector_512_u8 c_ret_vector_512_u8(void) { + return (Vector_512_u8){ + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + }; +} +void c_vector_512_u8(Vector_512_u8 v, size_t i) { + assert_or_panic(v[0] == 50); + assert_or_panic(v[1] == 51); + assert_or_panic(v[2] == 52); + assert_or_panic(v[3] == 53); + assert_or_panic(v[4] == 54); + assert_or_panic(v[5] == 55); + assert_or_panic(v[6] == 56); + assert_or_panic(v[7] == 57); + assert_or_panic(v[8] == 58); + assert_or_panic(v[9] == 59); + assert_or_panic(v[10] == 60); + assert_or_panic(v[11] == 61); + assert_or_panic(v[12] == 62); + assert_or_panic(v[13] == 63); + assert_or_panic(v[14] == 64); + assert_or_panic(v[15] == 65); + assert_or_panic(v[16] == 66); + assert_or_panic(v[17] == 67); + assert_or_panic(v[18] == 68); + assert_or_panic(v[19] == 69); + assert_or_panic(v[20] == 70); + assert_or_panic(v[21] == 71); + assert_or_panic(v[22] == 72); + assert_or_panic(v[23] == 73); + assert_or_panic(v[24] == 74); + assert_or_panic(v[25] == 75); + assert_or_panic(v[26] == 76); + assert_or_panic(v[27] == 77); + assert_or_panic(v[28] == 78); + assert_or_panic(v[29] == 79); + assert_or_panic(v[30] == 80); + assert_or_panic(v[31] == 81); + assert_or_panic(v[32] == 82); + assert_or_panic(v[33] == 83); + assert_or_panic(v[34] == 84); + assert_or_panic(v[35] == 85); + assert_or_panic(v[36] == 86); + assert_or_panic(v[37] == 87); + assert_or_panic(v[38] == 88); + assert_or_panic(v[39] == 89); + assert_or_panic(v[40] == 90); + assert_or_panic(v[41] == 91); + assert_or_panic(v[42] == 92); + assert_or_panic(v[43] == 93); + assert_or_panic(v[44] == 94); + assert_or_panic(v[45] == 95); + assert_or_panic(v[46] == 96); + assert_or_panic(v[47] == 97); + assert_or_panic(v[48] == 98); + assert_or_panic(v[49] == 99); + assert_or_panic(v[50] == 0); + assert_or_panic(v[51] == 1); + assert_or_panic(v[52] == 2); + assert_or_panic(v[53] == 3); + assert_or_panic(v[54] == 4); + assert_or_panic(v[55] == 5); + assert_or_panic(v[56] == 6); + assert_or_panic(v[57] == 7); + assert_or_panic(v[58] == 8); + assert_or_panic(v[59] == 9); + assert_or_panic(v[60] == 10); + assert_or_panic(v[61] == 11); + assert_or_panic(v[62] == 12); + assert_or_panic(v[63] == 13); + assert_or_panic(v[64] == 14); + assert_or_panic(v[65] == 15); + assert_or_panic(v[66] == 16); + assert_or_panic(v[67] == 17); + assert_or_panic(v[68] == 18); + assert_or_panic(v[69] == 19); + assert_or_panic(v[70] == 20); + assert_or_panic(v[71] == 21); + assert_or_panic(v[72] == 22); + assert_or_panic(v[73] == 23); + assert_or_panic(v[74] == 24); + assert_or_panic(v[75] == 25); + assert_or_panic(v[76] == 26); + assert_or_panic(v[77] == 27); + assert_or_panic(v[78] == 28); + assert_or_panic(v[79] == 29); + assert_or_panic(v[80] == 30); + assert_or_panic(v[81] == 31); + assert_or_panic(v[82] == 32); + assert_or_panic(v[83] == 33); + assert_or_panic(v[84] == 34); + assert_or_panic(v[85] == 35); + assert_or_panic(v[86] == 36); + assert_or_panic(v[87] == 37); + assert_or_panic(v[88] == 38); + assert_or_panic(v[89] == 39); + assert_or_panic(v[90] == 40); + assert_or_panic(v[91] == 41); + assert_or_panic(v[92] == 42); + assert_or_panic(v[93] == 43); + assert_or_panic(v[94] == 44); + assert_or_panic(v[95] == 45); + assert_or_panic(v[96] == 46); + assert_or_panic(v[97] == 47); + assert_or_panic(v[98] == 48); + assert_or_panic(v[99] == 49); + assert_or_panic(v[100] == 50); + assert_or_panic(v[101] == 51); + assert_or_panic(v[102] == 52); + assert_or_panic(v[103] == 53); + assert_or_panic(v[104] == 54); + assert_or_panic(v[105] == 55); + assert_or_panic(v[106] == 56); + assert_or_panic(v[107] == 57); + assert_or_panic(v[108] == 58); + assert_or_panic(v[109] == 59); + assert_or_panic(v[110] == 60); + assert_or_panic(v[111] == 61); + assert_or_panic(v[112] == 62); + assert_or_panic(v[113] == 63); + assert_or_panic(v[114] == 64); + assert_or_panic(v[115] == 65); + assert_or_panic(v[116] == 66); + assert_or_panic(v[117] == 67); + assert_or_panic(v[118] == 68); + assert_or_panic(v[119] == 69); + assert_or_panic(v[120] == 70); + assert_or_panic(v[121] == 71); + assert_or_panic(v[122] == 72); + assert_or_panic(v[123] == 73); + assert_or_panic(v[124] == 74); + assert_or_panic(v[125] == 75); + assert_or_panic(v[126] == 76); + assert_or_panic(v[127] == 77); + assert_or_panic(v[128] == 78); + assert_or_panic(v[129] == 79); + assert_or_panic(v[130] == 80); + assert_or_panic(v[131] == 81); + assert_or_panic(v[132] == 82); + assert_or_panic(v[133] == 83); + assert_or_panic(v[134] == 84); + assert_or_panic(v[135] == 85); + assert_or_panic(v[136] == 86); + assert_or_panic(v[137] == 87); + assert_or_panic(v[138] == 88); + assert_or_panic(v[139] == 89); + assert_or_panic(v[140] == 90); + assert_or_panic(v[141] == 91); + assert_or_panic(v[142] == 92); + assert_or_panic(v[143] == 93); + assert_or_panic(v[144] == 94); + assert_or_panic(v[145] == 95); + assert_or_panic(v[146] == 96); + assert_or_panic(v[147] == 97); + assert_or_panic(v[148] == 98); + assert_or_panic(v[149] == 99); + assert_or_panic(v[150] == 0); + assert_or_panic(v[151] == 1); + assert_or_panic(v[152] == 2); + assert_or_panic(v[153] == 3); + assert_or_panic(v[154] == 4); + assert_or_panic(v[155] == 5); + assert_or_panic(v[156] == 6); + assert_or_panic(v[157] == 7); + assert_or_panic(v[158] == 8); + assert_or_panic(v[159] == 9); + assert_or_panic(v[160] == 10); + assert_or_panic(v[161] == 11); + assert_or_panic(v[162] == 12); + assert_or_panic(v[163] == 13); + assert_or_panic(v[164] == 14); + assert_or_panic(v[165] == 15); + assert_or_panic(v[166] == 16); + assert_or_panic(v[167] == 17); + assert_or_panic(v[168] == 18); + assert_or_panic(v[169] == 19); + assert_or_panic(v[170] == 20); + assert_or_panic(v[171] == 21); + assert_or_panic(v[172] == 22); + assert_or_panic(v[173] == 23); + assert_or_panic(v[174] == 24); + assert_or_panic(v[175] == 25); + assert_or_panic(v[176] == 26); + assert_or_panic(v[177] == 27); + assert_or_panic(v[178] == 28); + assert_or_panic(v[179] == 29); + assert_or_panic(v[180] == 30); + assert_or_panic(v[181] == 31); + assert_or_panic(v[182] == 32); + assert_or_panic(v[183] == 33); + assert_or_panic(v[184] == 34); + assert_or_panic(v[185] == 35); + assert_or_panic(v[186] == 36); + assert_or_panic(v[187] == 37); + assert_or_panic(v[188] == 38); + assert_or_panic(v[189] == 39); + assert_or_panic(v[190] == 40); + assert_or_panic(v[191] == 41); + assert_or_panic(v[192] == 42); + assert_or_panic(v[193] == 43); + assert_or_panic(v[194] == 44); + assert_or_panic(v[195] == 45); + assert_or_panic(v[196] == 46); + assert_or_panic(v[197] == 47); + assert_or_panic(v[198] == 48); + assert_or_panic(v[199] == 49); + assert_or_panic(v[200] == 50); + assert_or_panic(v[201] == 51); + assert_or_panic(v[202] == 52); + assert_or_panic(v[203] == 53); + assert_or_panic(v[204] == 54); + assert_or_panic(v[205] == 55); + assert_or_panic(v[206] == 56); + assert_or_panic(v[207] == 57); + assert_or_panic(v[208] == 58); + assert_or_panic(v[209] == 59); + assert_or_panic(v[210] == 60); + assert_or_panic(v[211] == 61); + assert_or_panic(v[212] == 62); + assert_or_panic(v[213] == 63); + assert_or_panic(v[214] == 64); + assert_or_panic(v[215] == 65); + assert_or_panic(v[216] == 66); + assert_or_panic(v[217] == 67); + assert_or_panic(v[218] == 68); + assert_or_panic(v[219] == 69); + assert_or_panic(v[220] == 70); + assert_or_panic(v[221] == 71); + assert_or_panic(v[222] == 72); + assert_or_panic(v[223] == 73); + assert_or_panic(v[224] == 74); + assert_or_panic(v[225] == 75); + assert_or_panic(v[226] == 76); + assert_or_panic(v[227] == 77); + assert_or_panic(v[228] == 78); + assert_or_panic(v[229] == 79); + assert_or_panic(v[230] == 80); + assert_or_panic(v[231] == 81); + assert_or_panic(v[232] == 82); + assert_or_panic(v[233] == 83); + assert_or_panic(v[234] == 84); + assert_or_panic(v[235] == 85); + assert_or_panic(v[236] == 86); + assert_or_panic(v[237] == 87); + assert_or_panic(v[238] == 88); + assert_or_panic(v[239] == 89); + assert_or_panic(v[240] == 90); + assert_or_panic(v[241] == 91); + assert_or_panic(v[242] == 92); + assert_or_panic(v[243] == 93); + assert_or_panic(v[244] == 94); + assert_or_panic(v[245] == 95); + assert_or_panic(v[246] == 96); + assert_or_panic(v[247] == 97); + assert_or_panic(v[248] == 98); + assert_or_panic(v[249] == 99); + assert_or_panic(v[250] == 0); + assert_or_panic(v[251] == 1); + assert_or_panic(v[252] == 2); + assert_or_panic(v[253] == 3); + assert_or_panic(v[254] == 4); + assert_or_panic(v[255] == 5); + assert_or_panic(v[256] == 6); + assert_or_panic(v[257] == 7); + assert_or_panic(v[258] == 8); + assert_or_panic(v[259] == 9); + assert_or_panic(v[260] == 10); + assert_or_panic(v[261] == 11); + assert_or_panic(v[262] == 12); + assert_or_panic(v[263] == 13); + assert_or_panic(v[264] == 14); + assert_or_panic(v[265] == 15); + assert_or_panic(v[266] == 16); + assert_or_panic(v[267] == 17); + assert_or_panic(v[268] == 18); + assert_or_panic(v[269] == 19); + assert_or_panic(v[270] == 20); + assert_or_panic(v[271] == 21); + assert_or_panic(v[272] == 22); + assert_or_panic(v[273] == 23); + assert_or_panic(v[274] == 24); + assert_or_panic(v[275] == 25); + assert_or_panic(v[276] == 26); + assert_or_panic(v[277] == 27); + assert_or_panic(v[278] == 28); + assert_or_panic(v[279] == 29); + assert_or_panic(v[280] == 30); + assert_or_panic(v[281] == 31); + assert_or_panic(v[282] == 32); + assert_or_panic(v[283] == 33); + assert_or_panic(v[284] == 34); + assert_or_panic(v[285] == 35); + assert_or_panic(v[286] == 36); + assert_or_panic(v[287] == 37); + assert_or_panic(v[288] == 38); + assert_or_panic(v[289] == 39); + assert_or_panic(v[290] == 40); + assert_or_panic(v[291] == 41); + assert_or_panic(v[292] == 42); + assert_or_panic(v[293] == 43); + assert_or_panic(v[294] == 44); + assert_or_panic(v[295] == 45); + assert_or_panic(v[296] == 46); + assert_or_panic(v[297] == 47); + assert_or_panic(v[298] == 48); + assert_or_panic(v[299] == 49); + assert_or_panic(v[300] == 50); + assert_or_panic(v[301] == 51); + assert_or_panic(v[302] == 52); + assert_or_panic(v[303] == 53); + assert_or_panic(v[304] == 54); + assert_or_panic(v[305] == 55); + assert_or_panic(v[306] == 56); + assert_or_panic(v[307] == 57); + assert_or_panic(v[308] == 58); + assert_or_panic(v[309] == 59); + assert_or_panic(v[310] == 60); + assert_or_panic(v[311] == 61); + assert_or_panic(v[312] == 62); + assert_or_panic(v[313] == 63); + assert_or_panic(v[314] == 64); + assert_or_panic(v[315] == 65); + assert_or_panic(v[316] == 66); + assert_or_panic(v[317] == 67); + assert_or_panic(v[318] == 68); + assert_or_panic(v[319] == 69); + assert_or_panic(v[320] == 70); + assert_or_panic(v[321] == 71); + assert_or_panic(v[322] == 72); + assert_or_panic(v[323] == 73); + assert_or_panic(v[324] == 74); + assert_or_panic(v[325] == 75); + assert_or_panic(v[326] == 76); + assert_or_panic(v[327] == 77); + assert_or_panic(v[328] == 78); + assert_or_panic(v[329] == 79); + assert_or_panic(v[330] == 80); + assert_or_panic(v[331] == 81); + assert_or_panic(v[332] == 82); + assert_or_panic(v[333] == 83); + assert_or_panic(v[334] == 84); + assert_or_panic(v[335] == 85); + assert_or_panic(v[336] == 86); + assert_or_panic(v[337] == 87); + assert_or_panic(v[338] == 88); + assert_or_panic(v[339] == 89); + assert_or_panic(v[340] == 90); + assert_or_panic(v[341] == 91); + assert_or_panic(v[342] == 92); + assert_or_panic(v[343] == 93); + assert_or_panic(v[344] == 94); + assert_or_panic(v[345] == 95); + assert_or_panic(v[346] == 96); + assert_or_panic(v[347] == 97); + assert_or_panic(v[348] == 98); + assert_or_panic(v[349] == 99); + assert_or_panic(v[350] == 0); + assert_or_panic(v[351] == 1); + assert_or_panic(v[352] == 2); + assert_or_panic(v[353] == 3); + assert_or_panic(v[354] == 4); + assert_or_panic(v[355] == 5); + assert_or_panic(v[356] == 6); + assert_or_panic(v[357] == 7); + assert_or_panic(v[358] == 8); + assert_or_panic(v[359] == 9); + assert_or_panic(v[360] == 10); + assert_or_panic(v[361] == 11); + assert_or_panic(v[362] == 12); + assert_or_panic(v[363] == 13); + assert_or_panic(v[364] == 14); + assert_or_panic(v[365] == 15); + assert_or_panic(v[366] == 16); + assert_or_panic(v[367] == 17); + assert_or_panic(v[368] == 18); + assert_or_panic(v[369] == 19); + assert_or_panic(v[370] == 20); + assert_or_panic(v[371] == 21); + assert_or_panic(v[372] == 22); + assert_or_panic(v[373] == 23); + assert_or_panic(v[374] == 24); + assert_or_panic(v[375] == 25); + assert_or_panic(v[376] == 26); + assert_or_panic(v[377] == 27); + assert_or_panic(v[378] == 28); + assert_or_panic(v[379] == 29); + assert_or_panic(v[380] == 30); + assert_or_panic(v[381] == 31); + assert_or_panic(v[382] == 32); + assert_or_panic(v[383] == 33); + assert_or_panic(v[384] == 34); + assert_or_panic(v[385] == 35); + assert_or_panic(v[386] == 36); + assert_or_panic(v[387] == 37); + assert_or_panic(v[388] == 38); + assert_or_panic(v[389] == 39); + assert_or_panic(v[390] == 40); + assert_or_panic(v[391] == 41); + assert_or_panic(v[392] == 42); + assert_or_panic(v[393] == 43); + assert_or_panic(v[394] == 44); + assert_or_panic(v[395] == 45); + assert_or_panic(v[396] == 46); + assert_or_panic(v[397] == 47); + assert_or_panic(v[398] == 48); + assert_or_panic(v[399] == 49); + assert_or_panic(v[400] == 50); + assert_or_panic(v[401] == 51); + assert_or_panic(v[402] == 52); + assert_or_panic(v[403] == 53); + assert_or_panic(v[404] == 54); + assert_or_panic(v[405] == 55); + assert_or_panic(v[406] == 56); + assert_or_panic(v[407] == 57); + assert_or_panic(v[408] == 58); + assert_or_panic(v[409] == 59); + assert_or_panic(v[410] == 60); + assert_or_panic(v[411] == 61); + assert_or_panic(v[412] == 62); + assert_or_panic(v[413] == 63); + assert_or_panic(v[414] == 64); + assert_or_panic(v[415] == 65); + assert_or_panic(v[416] == 66); + assert_or_panic(v[417] == 67); + assert_or_panic(v[418] == 68); + assert_or_panic(v[419] == 69); + assert_or_panic(v[420] == 70); + assert_or_panic(v[421] == 71); + assert_or_panic(v[422] == 72); + assert_or_panic(v[423] == 73); + assert_or_panic(v[424] == 74); + assert_or_panic(v[425] == 75); + assert_or_panic(v[426] == 76); + assert_or_panic(v[427] == 77); + assert_or_panic(v[428] == 78); + assert_or_panic(v[429] == 79); + assert_or_panic(v[430] == 80); + assert_or_panic(v[431] == 81); + assert_or_panic(v[432] == 82); + assert_or_panic(v[433] == 83); + assert_or_panic(v[434] == 84); + assert_or_panic(v[435] == 85); + assert_or_panic(v[436] == 86); + assert_or_panic(v[437] == 87); + assert_or_panic(v[438] == 88); + assert_or_panic(v[439] == 89); + assert_or_panic(v[440] == 90); + assert_or_panic(v[441] == 91); + assert_or_panic(v[442] == 92); + assert_or_panic(v[443] == 93); + assert_or_panic(v[444] == 94); + assert_or_panic(v[445] == 95); + assert_or_panic(v[446] == 96); + assert_or_panic(v[447] == 97); + assert_or_panic(v[448] == 98); + assert_or_panic(v[449] == 99); + assert_or_panic(v[450] == 0); + assert_or_panic(v[451] == 1); + assert_or_panic(v[452] == 2); + assert_or_panic(v[453] == 3); + assert_or_panic(v[454] == 4); + assert_or_panic(v[455] == 5); + assert_or_panic(v[456] == 6); + assert_or_panic(v[457] == 7); + assert_or_panic(v[458] == 8); + assert_or_panic(v[459] == 9); + assert_or_panic(v[460] == 10); + assert_or_panic(v[461] == 11); + assert_or_panic(v[462] == 12); + assert_or_panic(v[463] == 13); + assert_or_panic(v[464] == 14); + assert_or_panic(v[465] == 15); + assert_or_panic(v[466] == 16); + assert_or_panic(v[467] == 17); + assert_or_panic(v[468] == 18); + assert_or_panic(v[469] == 19); + assert_or_panic(v[470] == 20); + assert_or_panic(v[471] == 21); + assert_or_panic(v[472] == 22); + assert_or_panic(v[473] == 23); + assert_or_panic(v[474] == 24); + assert_or_panic(v[475] == 25); + assert_or_panic(v[476] == 26); + assert_or_panic(v[477] == 27); + assert_or_panic(v[478] == 28); + assert_or_panic(v[479] == 29); + assert_or_panic(v[480] == 30); + assert_or_panic(v[481] == 31); + assert_or_panic(v[482] == 32); + assert_or_panic(v[483] == 33); + assert_or_panic(v[484] == 34); + assert_or_panic(v[485] == 35); + assert_or_panic(v[486] == 36); + assert_or_panic(v[487] == 37); + assert_or_panic(v[488] == 38); + assert_or_panic(v[489] == 39); + assert_or_panic(v[490] == 40); + assert_or_panic(v[491] == 41); + assert_or_panic(v[492] == 42); + assert_or_panic(v[493] == 43); + assert_or_panic(v[494] == 44); + assert_or_panic(v[495] == 45); + assert_or_panic(v[496] == 46); + assert_or_panic(v[497] == 47); + assert_or_panic(v[498] == 48); + assert_or_panic(v[499] == 49); + assert_or_panic(v[500] == 50); + assert_or_panic(v[501] == 51); + assert_or_panic(v[502] == 52); + assert_or_panic(v[503] == 53); + assert_or_panic(v[504] == 54); + assert_or_panic(v[505] == 55); + assert_or_panic(v[506] == 56); + assert_or_panic(v[507] == 57); + assert_or_panic(v[508] == 58); + assert_or_panic(v[509] == 59); + assert_or_panic(v[510] == 60); + assert_or_panic(v[511] == 61); + assert_or_panic(i == 512); +} +void c_test_vector_512_u8(void) { + Vector_512_u8 v = zig_ret_vector_512_u8(); + assert_or_panic(v[0] == 14); + assert_or_panic(v[1] == 15); + assert_or_panic(v[2] == 16); + assert_or_panic(v[3] == 17); + assert_or_panic(v[4] == 18); + assert_or_panic(v[5] == 19); + assert_or_panic(v[6] == 20); + assert_or_panic(v[7] == 21); + assert_or_panic(v[8] == 22); + assert_or_panic(v[9] == 23); + assert_or_panic(v[10] == 24); + assert_or_panic(v[11] == 25); + assert_or_panic(v[12] == 26); + assert_or_panic(v[13] == 27); + assert_or_panic(v[14] == 28); + assert_or_panic(v[15] == 29); + assert_or_panic(v[16] == 30); + assert_or_panic(v[17] == 31); + assert_or_panic(v[18] == 32); + assert_or_panic(v[19] == 33); + assert_or_panic(v[20] == 34); + assert_or_panic(v[21] == 35); + assert_or_panic(v[22] == 36); + assert_or_panic(v[23] == 37); + assert_or_panic(v[24] == 38); + assert_or_panic(v[25] == 39); + assert_or_panic(v[26] == 40); + assert_or_panic(v[27] == 41); + assert_or_panic(v[28] == 42); + assert_or_panic(v[29] == 43); + assert_or_panic(v[30] == 44); + assert_or_panic(v[31] == 45); + assert_or_panic(v[32] == 46); + assert_or_panic(v[33] == 47); + assert_or_panic(v[34] == 48); + assert_or_panic(v[35] == 49); + assert_or_panic(v[36] == 50); + assert_or_panic(v[37] == 51); + assert_or_panic(v[38] == 52); + assert_or_panic(v[39] == 53); + assert_or_panic(v[40] == 54); + assert_or_panic(v[41] == 55); + assert_or_panic(v[42] == 56); + assert_or_panic(v[43] == 57); + assert_or_panic(v[44] == 58); + assert_or_panic(v[45] == 59); + assert_or_panic(v[46] == 60); + assert_or_panic(v[47] == 61); + assert_or_panic(v[48] == 62); + assert_or_panic(v[49] == 63); + assert_or_panic(v[50] == 64); + assert_or_panic(v[51] == 65); + assert_or_panic(v[52] == 66); + assert_or_panic(v[53] == 67); + assert_or_panic(v[54] == 68); + assert_or_panic(v[55] == 69); + assert_or_panic(v[56] == 70); + assert_or_panic(v[57] == 71); + assert_or_panic(v[58] == 72); + assert_or_panic(v[59] == 73); + assert_or_panic(v[60] == 74); + assert_or_panic(v[61] == 75); + assert_or_panic(v[62] == 76); + assert_or_panic(v[63] == 77); + assert_or_panic(v[64] == 78); + assert_or_panic(v[65] == 79); + assert_or_panic(v[66] == 80); + assert_or_panic(v[67] == 81); + assert_or_panic(v[68] == 82); + assert_or_panic(v[69] == 83); + assert_or_panic(v[70] == 84); + assert_or_panic(v[71] == 85); + assert_or_panic(v[72] == 86); + assert_or_panic(v[73] == 87); + assert_or_panic(v[74] == 88); + assert_or_panic(v[75] == 89); + assert_or_panic(v[76] == 90); + assert_or_panic(v[77] == 91); + assert_or_panic(v[78] == 92); + assert_or_panic(v[79] == 93); + assert_or_panic(v[80] == 94); + assert_or_panic(v[81] == 95); + assert_or_panic(v[82] == 96); + assert_or_panic(v[83] == 97); + assert_or_panic(v[84] == 98); + assert_or_panic(v[85] == 99); + assert_or_panic(v[86] == 0); + assert_or_panic(v[87] == 1); + assert_or_panic(v[88] == 2); + assert_or_panic(v[89] == 3); + assert_or_panic(v[90] == 4); + assert_or_panic(v[91] == 5); + assert_or_panic(v[92] == 6); + assert_or_panic(v[93] == 7); + assert_or_panic(v[94] == 8); + assert_or_panic(v[95] == 9); + assert_or_panic(v[96] == 10); + assert_or_panic(v[97] == 11); + assert_or_panic(v[98] == 12); + assert_or_panic(v[99] == 13); + assert_or_panic(v[100] == 14); + assert_or_panic(v[101] == 15); + assert_or_panic(v[102] == 16); + assert_or_panic(v[103] == 17); + assert_or_panic(v[104] == 18); + assert_or_panic(v[105] == 19); + assert_or_panic(v[106] == 20); + assert_or_panic(v[107] == 21); + assert_or_panic(v[108] == 22); + assert_or_panic(v[109] == 23); + assert_or_panic(v[110] == 24); + assert_or_panic(v[111] == 25); + assert_or_panic(v[112] == 26); + assert_or_panic(v[113] == 27); + assert_or_panic(v[114] == 28); + assert_or_panic(v[115] == 29); + assert_or_panic(v[116] == 30); + assert_or_panic(v[117] == 31); + assert_or_panic(v[118] == 32); + assert_or_panic(v[119] == 33); + assert_or_panic(v[120] == 34); + assert_or_panic(v[121] == 35); + assert_or_panic(v[122] == 36); + assert_or_panic(v[123] == 37); + assert_or_panic(v[124] == 38); + assert_or_panic(v[125] == 39); + assert_or_panic(v[126] == 40); + assert_or_panic(v[127] == 41); + assert_or_panic(v[128] == 42); + assert_or_panic(v[129] == 43); + assert_or_panic(v[130] == 44); + assert_or_panic(v[131] == 45); + assert_or_panic(v[132] == 46); + assert_or_panic(v[133] == 47); + assert_or_panic(v[134] == 48); + assert_or_panic(v[135] == 49); + assert_or_panic(v[136] == 50); + assert_or_panic(v[137] == 51); + assert_or_panic(v[138] == 52); + assert_or_panic(v[139] == 53); + assert_or_panic(v[140] == 54); + assert_or_panic(v[141] == 55); + assert_or_panic(v[142] == 56); + assert_or_panic(v[143] == 57); + assert_or_panic(v[144] == 58); + assert_or_panic(v[145] == 59); + assert_or_panic(v[146] == 60); + assert_or_panic(v[147] == 61); + assert_or_panic(v[148] == 62); + assert_or_panic(v[149] == 63); + assert_or_panic(v[150] == 64); + assert_or_panic(v[151] == 65); + assert_or_panic(v[152] == 66); + assert_or_panic(v[153] == 67); + assert_or_panic(v[154] == 68); + assert_or_panic(v[155] == 69); + assert_or_panic(v[156] == 70); + assert_or_panic(v[157] == 71); + assert_or_panic(v[158] == 72); + assert_or_panic(v[159] == 73); + assert_or_panic(v[160] == 74); + assert_or_panic(v[161] == 75); + assert_or_panic(v[162] == 76); + assert_or_panic(v[163] == 77); + assert_or_panic(v[164] == 78); + assert_or_panic(v[165] == 79); + assert_or_panic(v[166] == 80); + assert_or_panic(v[167] == 81); + assert_or_panic(v[168] == 82); + assert_or_panic(v[169] == 83); + assert_or_panic(v[170] == 84); + assert_or_panic(v[171] == 85); + assert_or_panic(v[172] == 86); + assert_or_panic(v[173] == 87); + assert_or_panic(v[174] == 88); + assert_or_panic(v[175] == 89); + assert_or_panic(v[176] == 90); + assert_or_panic(v[177] == 91); + assert_or_panic(v[178] == 92); + assert_or_panic(v[179] == 93); + assert_or_panic(v[180] == 94); + assert_or_panic(v[181] == 95); + assert_or_panic(v[182] == 96); + assert_or_panic(v[183] == 97); + assert_or_panic(v[184] == 98); + assert_or_panic(v[185] == 99); + assert_or_panic(v[186] == 0); + assert_or_panic(v[187] == 1); + assert_or_panic(v[188] == 2); + assert_or_panic(v[189] == 3); + assert_or_panic(v[190] == 4); + assert_or_panic(v[191] == 5); + assert_or_panic(v[192] == 6); + assert_or_panic(v[193] == 7); + assert_or_panic(v[194] == 8); + assert_or_panic(v[195] == 9); + assert_or_panic(v[196] == 10); + assert_or_panic(v[197] == 11); + assert_or_panic(v[198] == 12); + assert_or_panic(v[199] == 13); + assert_or_panic(v[200] == 14); + assert_or_panic(v[201] == 15); + assert_or_panic(v[202] == 16); + assert_or_panic(v[203] == 17); + assert_or_panic(v[204] == 18); + assert_or_panic(v[205] == 19); + assert_or_panic(v[206] == 20); + assert_or_panic(v[207] == 21); + assert_or_panic(v[208] == 22); + assert_or_panic(v[209] == 23); + assert_or_panic(v[210] == 24); + assert_or_panic(v[211] == 25); + assert_or_panic(v[212] == 26); + assert_or_panic(v[213] == 27); + assert_or_panic(v[214] == 28); + assert_or_panic(v[215] == 29); + assert_or_panic(v[216] == 30); + assert_or_panic(v[217] == 31); + assert_or_panic(v[218] == 32); + assert_or_panic(v[219] == 33); + assert_or_panic(v[220] == 34); + assert_or_panic(v[221] == 35); + assert_or_panic(v[222] == 36); + assert_or_panic(v[223] == 37); + assert_or_panic(v[224] == 38); + assert_or_panic(v[225] == 39); + assert_or_panic(v[226] == 40); + assert_or_panic(v[227] == 41); + assert_or_panic(v[228] == 42); + assert_or_panic(v[229] == 43); + assert_or_panic(v[230] == 44); + assert_or_panic(v[231] == 45); + assert_or_panic(v[232] == 46); + assert_or_panic(v[233] == 47); + assert_or_panic(v[234] == 48); + assert_or_panic(v[235] == 49); + assert_or_panic(v[236] == 50); + assert_or_panic(v[237] == 51); + assert_or_panic(v[238] == 52); + assert_or_panic(v[239] == 53); + assert_or_panic(v[240] == 54); + assert_or_panic(v[241] == 55); + assert_or_panic(v[242] == 56); + assert_or_panic(v[243] == 57); + assert_or_panic(v[244] == 58); + assert_or_panic(v[245] == 59); + assert_or_panic(v[246] == 60); + assert_or_panic(v[247] == 61); + assert_or_panic(v[248] == 62); + assert_or_panic(v[249] == 63); + assert_or_panic(v[250] == 64); + assert_or_panic(v[251] == 65); + assert_or_panic(v[252] == 66); + assert_or_panic(v[253] == 67); + assert_or_panic(v[254] == 68); + assert_or_panic(v[255] == 69); + assert_or_panic(v[256] == 70); + assert_or_panic(v[257] == 71); + assert_or_panic(v[258] == 72); + assert_or_panic(v[259] == 73); + assert_or_panic(v[260] == 74); + assert_or_panic(v[261] == 75); + assert_or_panic(v[262] == 76); + assert_or_panic(v[263] == 77); + assert_or_panic(v[264] == 78); + assert_or_panic(v[265] == 79); + assert_or_panic(v[266] == 80); + assert_or_panic(v[267] == 81); + assert_or_panic(v[268] == 82); + assert_or_panic(v[269] == 83); + assert_or_panic(v[270] == 84); + assert_or_panic(v[271] == 85); + assert_or_panic(v[272] == 86); + assert_or_panic(v[273] == 87); + assert_or_panic(v[274] == 88); + assert_or_panic(v[275] == 89); + assert_or_panic(v[276] == 90); + assert_or_panic(v[277] == 91); + assert_or_panic(v[278] == 92); + assert_or_panic(v[279] == 93); + assert_or_panic(v[280] == 94); + assert_or_panic(v[281] == 95); + assert_or_panic(v[282] == 96); + assert_or_panic(v[283] == 97); + assert_or_panic(v[284] == 98); + assert_or_panic(v[285] == 99); + assert_or_panic(v[286] == 0); + assert_or_panic(v[287] == 1); + assert_or_panic(v[288] == 2); + assert_or_panic(v[289] == 3); + assert_or_panic(v[290] == 4); + assert_or_panic(v[291] == 5); + assert_or_panic(v[292] == 6); + assert_or_panic(v[293] == 7); + assert_or_panic(v[294] == 8); + assert_or_panic(v[295] == 9); + assert_or_panic(v[296] == 10); + assert_or_panic(v[297] == 11); + assert_or_panic(v[298] == 12); + assert_or_panic(v[299] == 13); + assert_or_panic(v[300] == 14); + assert_or_panic(v[301] == 15); + assert_or_panic(v[302] == 16); + assert_or_panic(v[303] == 17); + assert_or_panic(v[304] == 18); + assert_or_panic(v[305] == 19); + assert_or_panic(v[306] == 20); + assert_or_panic(v[307] == 21); + assert_or_panic(v[308] == 22); + assert_or_panic(v[309] == 23); + assert_or_panic(v[310] == 24); + assert_or_panic(v[311] == 25); + assert_or_panic(v[312] == 26); + assert_or_panic(v[313] == 27); + assert_or_panic(v[314] == 28); + assert_or_panic(v[315] == 29); + assert_or_panic(v[316] == 30); + assert_or_panic(v[317] == 31); + assert_or_panic(v[318] == 32); + assert_or_panic(v[319] == 33); + assert_or_panic(v[320] == 34); + assert_or_panic(v[321] == 35); + assert_or_panic(v[322] == 36); + assert_or_panic(v[323] == 37); + assert_or_panic(v[324] == 38); + assert_or_panic(v[325] == 39); + assert_or_panic(v[326] == 40); + assert_or_panic(v[327] == 41); + assert_or_panic(v[328] == 42); + assert_or_panic(v[329] == 43); + assert_or_panic(v[330] == 44); + assert_or_panic(v[331] == 45); + assert_or_panic(v[332] == 46); + assert_or_panic(v[333] == 47); + assert_or_panic(v[334] == 48); + assert_or_panic(v[335] == 49); + assert_or_panic(v[336] == 50); + assert_or_panic(v[337] == 51); + assert_or_panic(v[338] == 52); + assert_or_panic(v[339] == 53); + assert_or_panic(v[340] == 54); + assert_or_panic(v[341] == 55); + assert_or_panic(v[342] == 56); + assert_or_panic(v[343] == 57); + assert_or_panic(v[344] == 58); + assert_or_panic(v[345] == 59); + assert_or_panic(v[346] == 60); + assert_or_panic(v[347] == 61); + assert_or_panic(v[348] == 62); + assert_or_panic(v[349] == 63); + assert_or_panic(v[350] == 64); + assert_or_panic(v[351] == 65); + assert_or_panic(v[352] == 66); + assert_or_panic(v[353] == 67); + assert_or_panic(v[354] == 68); + assert_or_panic(v[355] == 69); + assert_or_panic(v[356] == 70); + assert_or_panic(v[357] == 71); + assert_or_panic(v[358] == 72); + assert_or_panic(v[359] == 73); + assert_or_panic(v[360] == 74); + assert_or_panic(v[361] == 75); + assert_or_panic(v[362] == 76); + assert_or_panic(v[363] == 77); + assert_or_panic(v[364] == 78); + assert_or_panic(v[365] == 79); + assert_or_panic(v[366] == 80); + assert_or_panic(v[367] == 81); + assert_or_panic(v[368] == 82); + assert_or_panic(v[369] == 83); + assert_or_panic(v[370] == 84); + assert_or_panic(v[371] == 85); + assert_or_panic(v[372] == 86); + assert_or_panic(v[373] == 87); + assert_or_panic(v[374] == 88); + assert_or_panic(v[375] == 89); + assert_or_panic(v[376] == 90); + assert_or_panic(v[377] == 91); + assert_or_panic(v[378] == 92); + assert_or_panic(v[379] == 93); + assert_or_panic(v[380] == 94); + assert_or_panic(v[381] == 95); + assert_or_panic(v[382] == 96); + assert_or_panic(v[383] == 97); + assert_or_panic(v[384] == 98); + assert_or_panic(v[385] == 99); + assert_or_panic(v[386] == 0); + assert_or_panic(v[387] == 1); + assert_or_panic(v[388] == 2); + assert_or_panic(v[389] == 3); + assert_or_panic(v[390] == 4); + assert_or_panic(v[391] == 5); + assert_or_panic(v[392] == 6); + assert_or_panic(v[393] == 7); + assert_or_panic(v[394] == 8); + assert_or_panic(v[395] == 9); + assert_or_panic(v[396] == 10); + assert_or_panic(v[397] == 11); + assert_or_panic(v[398] == 12); + assert_or_panic(v[399] == 13); + assert_or_panic(v[400] == 14); + assert_or_panic(v[401] == 15); + assert_or_panic(v[402] == 16); + assert_or_panic(v[403] == 17); + assert_or_panic(v[404] == 18); + assert_or_panic(v[405] == 19); + assert_or_panic(v[406] == 20); + assert_or_panic(v[407] == 21); + assert_or_panic(v[408] == 22); + assert_or_panic(v[409] == 23); + assert_or_panic(v[410] == 24); + assert_or_panic(v[411] == 25); + assert_or_panic(v[412] == 26); + assert_or_panic(v[413] == 27); + assert_or_panic(v[414] == 28); + assert_or_panic(v[415] == 29); + assert_or_panic(v[416] == 30); + assert_or_panic(v[417] == 31); + assert_or_panic(v[418] == 32); + assert_or_panic(v[419] == 33); + assert_or_panic(v[420] == 34); + assert_or_panic(v[421] == 35); + assert_or_panic(v[422] == 36); + assert_or_panic(v[423] == 37); + assert_or_panic(v[424] == 38); + assert_or_panic(v[425] == 39); + assert_or_panic(v[426] == 40); + assert_or_panic(v[427] == 41); + assert_or_panic(v[428] == 42); + assert_or_panic(v[429] == 43); + assert_or_panic(v[430] == 44); + assert_or_panic(v[431] == 45); + assert_or_panic(v[432] == 46); + assert_or_panic(v[433] == 47); + assert_or_panic(v[434] == 48); + assert_or_panic(v[435] == 49); + assert_or_panic(v[436] == 50); + assert_or_panic(v[437] == 51); + assert_or_panic(v[438] == 52); + assert_or_panic(v[439] == 53); + assert_or_panic(v[440] == 54); + assert_or_panic(v[441] == 55); + assert_or_panic(v[442] == 56); + assert_or_panic(v[443] == 57); + assert_or_panic(v[444] == 58); + assert_or_panic(v[445] == 59); + assert_or_panic(v[446] == 60); + assert_or_panic(v[447] == 61); + assert_or_panic(v[448] == 62); + assert_or_panic(v[449] == 63); + assert_or_panic(v[450] == 64); + assert_or_panic(v[451] == 65); + assert_or_panic(v[452] == 66); + assert_or_panic(v[453] == 67); + assert_or_panic(v[454] == 68); + assert_or_panic(v[455] == 69); + assert_or_panic(v[456] == 70); + assert_or_panic(v[457] == 71); + assert_or_panic(v[458] == 72); + assert_or_panic(v[459] == 73); + assert_or_panic(v[460] == 74); + assert_or_panic(v[461] == 75); + assert_or_panic(v[462] == 76); + assert_or_panic(v[463] == 77); + assert_or_panic(v[464] == 78); + assert_or_panic(v[465] == 79); + assert_or_panic(v[466] == 80); + assert_or_panic(v[467] == 81); + assert_or_panic(v[468] == 82); + assert_or_panic(v[469] == 83); + assert_or_panic(v[470] == 84); + assert_or_panic(v[471] == 85); + assert_or_panic(v[472] == 86); + assert_or_panic(v[473] == 87); + assert_or_panic(v[474] == 88); + assert_or_panic(v[475] == 89); + assert_or_panic(v[476] == 90); + assert_or_panic(v[477] == 91); + assert_or_panic(v[478] == 92); + assert_or_panic(v[479] == 93); + assert_or_panic(v[480] == 94); + assert_or_panic(v[481] == 95); + assert_or_panic(v[482] == 96); + assert_or_panic(v[483] == 97); + assert_or_panic(v[484] == 98); + assert_or_panic(v[485] == 99); + assert_or_panic(v[486] == 0); + assert_or_panic(v[487] == 1); + assert_or_panic(v[488] == 2); + assert_or_panic(v[489] == 3); + assert_or_panic(v[490] == 4); + assert_or_panic(v[491] == 5); + assert_or_panic(v[492] == 6); + assert_or_panic(v[493] == 7); + assert_or_panic(v[494] == 8); + assert_or_panic(v[495] == 9); + assert_or_panic(v[496] == 10); + assert_or_panic(v[497] == 11); + assert_or_panic(v[498] == 12); + assert_or_panic(v[499] == 13); + assert_or_panic(v[500] == 14); + assert_or_panic(v[501] == 15); + assert_or_panic(v[502] == 16); + assert_or_panic(v[503] == 17); + assert_or_panic(v[504] == 18); + assert_or_panic(v[505] == 19); + assert_or_panic(v[506] == 20); + assert_or_panic(v[507] == 21); + assert_or_panic(v[508] == 22); + assert_or_panic(v[509] == 23); + assert_or_panic(v[510] == 24); + assert_or_panic(v[511] == 25); + zig_vector_512_u8((Vector_512_u8){ + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + }, 512); +} + +typedef uint16_t Vector_1_u16 __attribute__((vector_size(1 * sizeof(uint16_t)))); + +Vector_1_u16 zig_ret_vector_1_u16(void); +void zig_vector_1_u16(Vector_1_u16, size_t); + +Vector_1_u16 c_ret_vector_1_u16(void) { + return (Vector_1_u16){ 3 }; +} +void c_vector_1_u16(Vector_1_u16 v, size_t i) { + assert_or_panic(v[0] == 4); + assert_or_panic(i == 1); +} +void c_test_vector_1_u16(void) { + Vector_1_u16 v = zig_ret_vector_1_u16(); + assert_or_panic(v[0] == 1); + zig_vector_1_u16((Vector_1_u16){ 2 }, 1); +} + +typedef uint16_t Vector_2_u16 __attribute__((vector_size(2 * sizeof(uint16_t)))); + +Vector_2_u16 zig_ret_vector_2_u16(void); +void zig_vector_2_u16(Vector_2_u16, size_t); + +Vector_2_u16 c_ret_vector_2_u16(void) { + return (Vector_2_u16){ 9, 10 }; +} +void c_vector_2_u16(Vector_2_u16 v, size_t i) { + assert_or_panic(v[0] == 11); + assert_or_panic(v[1] == 12); + assert_or_panic(i == 2); +} +void c_test_vector_2_u16(void) { + Vector_2_u16 v = zig_ret_vector_2_u16(); + assert_or_panic(v[0] == 5); + assert_or_panic(v[1] == 6); + zig_vector_2_u16((Vector_2_u16){ 7, 8 }, 2); +} + +typedef uint16_t Vector_3_u16 __attribute__((vector_size(3 * sizeof(uint16_t)))); + +Vector_3_u16 zig_ret_vector_3_u16(void); +void zig_vector_3_u16(Vector_3_u16, size_t); + +Vector_3_u16 c_ret_vector_3_u16(void) { + return (Vector_3_u16){ 19, 20, 21 }; +} +void c_vector_3_u16(Vector_3_u16 v, size_t i) { + assert_or_panic(v[0] == 22); + assert_or_panic(v[1] == 23); + assert_or_panic(v[2] == 24); + assert_or_panic(i == 3); +} +void c_test_vector_3_u16(void) { + Vector_3_u16 v = zig_ret_vector_3_u16(); + assert_or_panic(v[0] == 13); + assert_or_panic(v[1] == 14); + assert_or_panic(v[2] == 15); + zig_vector_3_u16((Vector_3_u16){ 16, 17, 18 }, 3); +} + +typedef uint16_t Vector_4_u16 __attribute__((vector_size(4 * sizeof(uint16_t)))); + +Vector_4_u16 zig_ret_vector_4_u16(void); + +void zig_vector_4_u16(Vector_4_u16, size_t); +void zig_vector_4_u16_vector_4_u16(Vector_4_u16, Vector_4_u16, size_t); + +Vector_4_u16 c_ret_vector_4_u16(void) { + return (Vector_4_u16){ 41, 42, 43, 44 }; +} +void c_vector_4_u16(Vector_4_u16 v, size_t i) { + assert_or_panic(v[0] == 45); + assert_or_panic(v[1] == 46); + assert_or_panic(v[2] == 47); + assert_or_panic(v[3] == 48); + assert_or_panic(i == 4); +} +void c_vector_4_u16_vector_4_u16(Vector_4_u16 v0, Vector_4_u16 v1, size_t i) { + assert_or_panic(v0[0] == 49); + assert_or_panic(v0[1] == 50); + assert_or_panic(v0[2] == 51); + assert_or_panic(v0[3] == 52); + assert_or_panic(v1[0] == 53); + assert_or_panic(v1[1] == 54); + assert_or_panic(v1[2] == 55); + assert_or_panic(v1[3] == 56); + assert_or_panic(i == 8); +} +void c_test_vector_4_u16(void) { + Vector_4_u16 v = zig_ret_vector_4_u16(); + assert_or_panic(v[0] == 25); + assert_or_panic(v[1] == 26); + assert_or_panic(v[2] == 27); + assert_or_panic(v[3] == 28); + zig_vector_4_u16((Vector_4_u16){ 29, 30, 31, 32 }, 4); + zig_vector_4_u16_vector_4_u16((Vector_4_u16){ 33, 34, 35, 36 }, (Vector_4_u16){ 37, 38, 39, 40 }, 8); +} + +typedef uint16_t Vector_6_u16 __attribute__((vector_size(6 * sizeof(uint16_t)))); + +Vector_6_u16 zig_ret_vector_6_u16(void); +void zig_vector_6_u16(Vector_6_u16, size_t); + +Vector_6_u16 c_ret_vector_6_u16(void) { + return (Vector_6_u16){ 53, 54, 55, 56, 57, 58 }; +} +void c_vector_6_u16(Vector_6_u16 v, size_t i) { + assert_or_panic(v[0] == 59); + assert_or_panic(v[1] == 60); + assert_or_panic(v[2] == 61); + assert_or_panic(v[3] == 62); + assert_or_panic(v[4] == 63); + assert_or_panic(v[5] == 64); + assert_or_panic(i == 6); +} +void c_test_vector_6_u16(void) { + Vector_6_u16 v = zig_ret_vector_6_u16(); + assert_or_panic(v[0] == 41); + assert_or_panic(v[1] == 42); + assert_or_panic(v[2] == 43); + assert_or_panic(v[3] == 44); + assert_or_panic(v[4] == 45); + assert_or_panic(v[5] == 46); + zig_vector_6_u16((Vector_6_u16){ 47, 48, 49, 50, 51, 52 }, 6); +} + +typedef uint16_t Vector_8_u16 __attribute__((vector_size(8 * sizeof(uint16_t)))); + +Vector_8_u16 zig_ret_vector_8_u16(void); +void zig_vector_8_u16(Vector_8_u16, size_t); + +Vector_8_u16 c_ret_vector_8_u16(void) { + return (Vector_8_u16){ 81, 82, 83, 84, 85, 86, 87, 88 }; +} +void c_vector_8_u16(Vector_8_u16 v, size_t i) { + assert_or_panic(v[0] == 89); + assert_or_panic(v[1] == 90); + assert_or_panic(v[2] == 91); + assert_or_panic(v[3] == 92); + assert_or_panic(v[4] == 93); + assert_or_panic(v[5] == 94); + assert_or_panic(v[6] == 95); + assert_or_panic(v[7] == 96); + assert_or_panic(i == 8); +} +void c_test_vector_8_u16(void) { + Vector_8_u16 v = zig_ret_vector_8_u16(); + assert_or_panic(v[0] == 65); + assert_or_panic(v[1] == 66); + assert_or_panic(v[2] == 67); + assert_or_panic(v[3] == 68); + assert_or_panic(v[4] == 69); + assert_or_panic(v[5] == 70); + assert_or_panic(v[6] == 71); + assert_or_panic(v[7] == 72); + zig_vector_8_u16((Vector_8_u16){ 73, 74, 75, 76, 77, 78, 79, 80 }, 8); +} + +typedef uint16_t Vector_12_u16 __attribute__((vector_size(12 * sizeof(uint16_t)))); + +Vector_12_u16 zig_ret_vector_12_u16(void); +void zig_vector_12_u16(Vector_12_u16, size_t); + +Vector_12_u16 c_ret_vector_12_u16(void) { + return (Vector_12_u16){ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132 }; +} +void c_vector_12_u16(Vector_12_u16 v, size_t i) { + assert_or_panic(v[0] == 133); + assert_or_panic(v[1] == 134); + assert_or_panic(v[2] == 135); + assert_or_panic(v[3] == 136); + assert_or_panic(v[4] == 137); + assert_or_panic(v[5] == 138); + assert_or_panic(v[6] == 139); + assert_or_panic(v[7] == 140); + assert_or_panic(v[8] == 141); + assert_or_panic(v[9] == 142); + assert_or_panic(v[10] == 143); + assert_or_panic(v[11] == 144); + assert_or_panic(i == 12); +} +void c_test_vector_12_u16(void) { + Vector_12_u16 v = zig_ret_vector_12_u16(); + assert_or_panic(v[0] == 97); + assert_or_panic(v[1] == 98); + assert_or_panic(v[2] == 99); + assert_or_panic(v[3] == 100); + assert_or_panic(v[4] == 101); + assert_or_panic(v[5] == 102); + assert_or_panic(v[6] == 103); + assert_or_panic(v[7] == 104); + assert_or_panic(v[8] == 105); + assert_or_panic(v[9] == 106); + assert_or_panic(v[10] == 107); + assert_or_panic(v[11] == 108); + zig_vector_12_u16((Vector_12_u16){ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 }, 12); +} + +typedef uint16_t Vector_16_u16 __attribute__((vector_size(16 * sizeof(uint16_t)))); + +Vector_16_u16 zig_ret_vector_16_u16(void); +void zig_vector_16_u16(Vector_16_u16, size_t); + +Vector_16_u16 c_ret_vector_16_u16(void) { + return (Vector_16_u16){ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192 }; +} +void c_vector_16_u16(Vector_16_u16 v, size_t i) { + assert_or_panic(v[0] == 193); + assert_or_panic(v[1] == 194); + assert_or_panic(v[2] == 195); + assert_or_panic(v[3] == 196); + assert_or_panic(v[4] == 197); + assert_or_panic(v[5] == 198); + assert_or_panic(v[6] == 199); + assert_or_panic(v[7] == 200); + assert_or_panic(v[8] == 201); + assert_or_panic(v[9] == 202); + assert_or_panic(v[10] == 203); + assert_or_panic(v[11] == 204); + assert_or_panic(v[12] == 205); + assert_or_panic(v[13] == 206); + assert_or_panic(v[14] == 207); + assert_or_panic(v[15] == 208); + assert_or_panic(i == 16); +} +void c_test_vector_16_u16(void) { + Vector_16_u16 v = zig_ret_vector_16_u16(); + assert_or_panic(v[0] == 145); + assert_or_panic(v[1] == 146); + assert_or_panic(v[2] == 147); + assert_or_panic(v[3] == 148); + assert_or_panic(v[4] == 149); + assert_or_panic(v[5] == 150); + assert_or_panic(v[6] == 151); + assert_or_panic(v[7] == 152); + assert_or_panic(v[8] == 153); + assert_or_panic(v[9] == 154); + assert_or_panic(v[10] == 155); + assert_or_panic(v[11] == 156); + assert_or_panic(v[12] == 157); + assert_or_panic(v[13] == 158); + assert_or_panic(v[14] == 159); + assert_or_panic(v[15] == 160); + zig_vector_16_u16((Vector_16_u16){ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176 }, 16); +} + +typedef uint16_t Vector_24_u16 __attribute__((vector_size(24 * sizeof(uint16_t)))); + +Vector_24_u16 zig_ret_vector_24_u16(void); +void zig_vector_24_u16(Vector_24_u16, size_t); + +Vector_24_u16 c_ret_vector_24_u16(void) { + return (Vector_24_u16){ + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + }; +} +void c_vector_24_u16(Vector_24_u16 v, size_t i) { + assert_or_panic(v[0] == 281); + assert_or_panic(v[1] == 282); + assert_or_panic(v[2] == 283); + assert_or_panic(v[3] == 284); + assert_or_panic(v[4] == 285); + assert_or_panic(v[5] == 286); + assert_or_panic(v[6] == 287); + assert_or_panic(v[7] == 288); + assert_or_panic(v[8] == 289); + assert_or_panic(v[9] == 290); + assert_or_panic(v[10] == 291); + assert_or_panic(v[11] == 292); + assert_or_panic(v[12] == 293); + assert_or_panic(v[13] == 294); + assert_or_panic(v[14] == 295); + assert_or_panic(v[15] == 296); + assert_or_panic(v[16] == 297); + assert_or_panic(v[17] == 298); + assert_or_panic(v[18] == 299); + assert_or_panic(v[19] == 300); + assert_or_panic(v[20] == 301); + assert_or_panic(v[21] == 302); + assert_or_panic(v[22] == 303); + assert_or_panic(v[23] == 304); + assert_or_panic(i == 24); +} +void c_test_vector_24_u16(void) { + Vector_24_u16 v = zig_ret_vector_24_u16(); + assert_or_panic(v[0] == 209); + assert_or_panic(v[1] == 210); + assert_or_panic(v[2] == 211); + assert_or_panic(v[3] == 212); + assert_or_panic(v[4] == 213); + assert_or_panic(v[5] == 214); + assert_or_panic(v[6] == 215); + assert_or_panic(v[7] == 216); + assert_or_panic(v[8] == 217); + assert_or_panic(v[9] == 218); + assert_or_panic(v[10] == 219); + assert_or_panic(v[11] == 220); + assert_or_panic(v[12] == 221); + assert_or_panic(v[13] == 222); + assert_or_panic(v[14] == 223); + assert_or_panic(v[15] == 224); + assert_or_panic(v[16] == 225); + assert_or_panic(v[17] == 226); + assert_or_panic(v[18] == 227); + assert_or_panic(v[19] == 228); + assert_or_panic(v[20] == 229); + assert_or_panic(v[21] == 230); + assert_or_panic(v[22] == 231); + assert_or_panic(v[23] == 232); + zig_vector_24_u16((Vector_24_u16){ + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, + }, 24); +} + +typedef uint16_t Vector_32_u16 __attribute__((vector_size(32 * sizeof(uint16_t)))); + +Vector_32_u16 zig_ret_vector_32_u16(void); +void zig_vector_32_u16(Vector_32_u16, size_t); + +Vector_32_u16 c_ret_vector_32_u16(void) { + return (Vector_32_u16){ + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + }; +} +void c_vector_32_u16(Vector_32_u16 v, size_t i) { + assert_or_panic(v[0] == 401); + assert_or_panic(v[1] == 402); + assert_or_panic(v[2] == 403); + assert_or_panic(v[3] == 404); + assert_or_panic(v[4] == 405); + assert_or_panic(v[5] == 406); + assert_or_panic(v[6] == 407); + assert_or_panic(v[7] == 408); + assert_or_panic(v[8] == 409); + assert_or_panic(v[9] == 410); + assert_or_panic(v[10] == 411); + assert_or_panic(v[11] == 412); + assert_or_panic(v[12] == 413); + assert_or_panic(v[13] == 414); + assert_or_panic(v[14] == 415); + assert_or_panic(v[15] == 416); + assert_or_panic(v[16] == 417); + assert_or_panic(v[17] == 418); + assert_or_panic(v[18] == 419); + assert_or_panic(v[19] == 420); + assert_or_panic(v[20] == 421); + assert_or_panic(v[21] == 422); + assert_or_panic(v[22] == 423); + assert_or_panic(v[23] == 424); + assert_or_panic(v[24] == 425); + assert_or_panic(v[25] == 426); + assert_or_panic(v[26] == 427); + assert_or_panic(v[27] == 428); + assert_or_panic(v[28] == 429); + assert_or_panic(v[29] == 430); + assert_or_panic(v[30] == 431); + assert_or_panic(v[31] == 432); + assert_or_panic(i == 32); +} +void c_test_vector_32_u16(void) { + Vector_32_u16 v = zig_ret_vector_32_u16(); + assert_or_panic(v[0] == 305); + assert_or_panic(v[1] == 306); + assert_or_panic(v[2] == 307); + assert_or_panic(v[3] == 308); + assert_or_panic(v[4] == 309); + assert_or_panic(v[5] == 310); + assert_or_panic(v[6] == 311); + assert_or_panic(v[7] == 312); + assert_or_panic(v[8] == 313); + assert_or_panic(v[9] == 314); + assert_or_panic(v[10] == 315); + assert_or_panic(v[11] == 316); + assert_or_panic(v[12] == 317); + assert_or_panic(v[13] == 318); + assert_or_panic(v[14] == 319); + assert_or_panic(v[15] == 320); + assert_or_panic(v[16] == 321); + assert_or_panic(v[17] == 322); + assert_or_panic(v[18] == 323); + assert_or_panic(v[19] == 324); + assert_or_panic(v[20] == 325); + assert_or_panic(v[21] == 326); + assert_or_panic(v[22] == 327); + assert_or_panic(v[23] == 328); + assert_or_panic(v[24] == 329); + assert_or_panic(v[25] == 330); + assert_or_panic(v[26] == 331); + assert_or_panic(v[27] == 332); + assert_or_panic(v[28] == 333); + assert_or_panic(v[29] == 334); + assert_or_panic(v[30] == 335); + assert_or_panic(v[31] == 336); + zig_vector_32_u16((Vector_32_u16){ + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + }, 32); +} + +typedef uint16_t Vector_48_u16 __attribute__((vector_size(48 * sizeof(uint16_t)))); + +Vector_48_u16 zig_ret_vector_48_u16(void); +void zig_vector_48_u16(Vector_48_u16, size_t); + +Vector_48_u16 c_ret_vector_48_u16(void) { + return (Vector_48_u16){ + 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, + 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, + }; +} +void c_vector_48_u16(Vector_48_u16 v, size_t i) { + assert_or_panic(v[0] == 577); + assert_or_panic(v[1] == 578); + assert_or_panic(v[2] == 579); + assert_or_panic(v[3] == 580); + assert_or_panic(v[4] == 581); + assert_or_panic(v[5] == 582); + assert_or_panic(v[6] == 583); + assert_or_panic(v[7] == 584); + assert_or_panic(v[8] == 585); + assert_or_panic(v[9] == 586); + assert_or_panic(v[10] == 587); + assert_or_panic(v[11] == 588); + assert_or_panic(v[12] == 589); + assert_or_panic(v[13] == 590); + assert_or_panic(v[14] == 591); + assert_or_panic(v[15] == 592); + assert_or_panic(v[16] == 593); + assert_or_panic(v[17] == 594); + assert_or_panic(v[18] == 595); + assert_or_panic(v[19] == 596); + assert_or_panic(v[20] == 597); + assert_or_panic(v[21] == 598); + assert_or_panic(v[22] == 599); + assert_or_panic(v[23] == 600); + assert_or_panic(v[24] == 601); + assert_or_panic(v[25] == 602); + assert_or_panic(v[26] == 603); + assert_or_panic(v[27] == 604); + assert_or_panic(v[28] == 605); + assert_or_panic(v[29] == 606); + assert_or_panic(v[30] == 607); + assert_or_panic(v[31] == 608); + assert_or_panic(v[32] == 609); + assert_or_panic(v[33] == 610); + assert_or_panic(v[34] == 611); + assert_or_panic(v[35] == 612); + assert_or_panic(v[36] == 613); + assert_or_panic(v[37] == 614); + assert_or_panic(v[38] == 615); + assert_or_panic(v[39] == 616); + assert_or_panic(v[40] == 617); + assert_or_panic(v[41] == 618); + assert_or_panic(v[42] == 619); + assert_or_panic(v[43] == 620); + assert_or_panic(v[44] == 621); + assert_or_panic(v[45] == 622); + assert_or_panic(v[46] == 623); + assert_or_panic(v[47] == 624); + assert_or_panic(i == 48); +} +void c_test_vector_48_u16(void) { + Vector_48_u16 v = zig_ret_vector_48_u16(); + assert_or_panic(v[0] == 433); + assert_or_panic(v[1] == 434); + assert_or_panic(v[2] == 435); + assert_or_panic(v[3] == 436); + assert_or_panic(v[4] == 437); + assert_or_panic(v[5] == 438); + assert_or_panic(v[6] == 439); + assert_or_panic(v[7] == 440); + assert_or_panic(v[8] == 441); + assert_or_panic(v[9] == 442); + assert_or_panic(v[10] == 443); + assert_or_panic(v[11] == 444); + assert_or_panic(v[12] == 445); + assert_or_panic(v[13] == 446); + assert_or_panic(v[14] == 447); + assert_or_panic(v[15] == 448); + assert_or_panic(v[16] == 449); + assert_or_panic(v[17] == 450); + assert_or_panic(v[18] == 451); + assert_or_panic(v[19] == 452); + assert_or_panic(v[20] == 453); + assert_or_panic(v[21] == 454); + assert_or_panic(v[22] == 455); + assert_or_panic(v[23] == 456); + assert_or_panic(v[24] == 457); + assert_or_panic(v[25] == 458); + assert_or_panic(v[26] == 459); + assert_or_panic(v[27] == 460); + assert_or_panic(v[28] == 461); + assert_or_panic(v[29] == 462); + assert_or_panic(v[30] == 463); + assert_or_panic(v[31] == 464); + assert_or_panic(v[32] == 465); + assert_or_panic(v[33] == 466); + assert_or_panic(v[34] == 467); + assert_or_panic(v[35] == 468); + assert_or_panic(v[36] == 469); + assert_or_panic(v[37] == 470); + assert_or_panic(v[38] == 471); + assert_or_panic(v[39] == 472); + assert_or_panic(v[40] == 473); + assert_or_panic(v[41] == 474); + assert_or_panic(v[42] == 475); + assert_or_panic(v[43] == 476); + assert_or_panic(v[44] == 477); + assert_or_panic(v[45] == 478); + assert_or_panic(v[46] == 479); + assert_or_panic(v[47] == 480); + zig_vector_48_u16((Vector_48_u16){ + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, + }, 48); +} + +typedef uint16_t Vector_64_u16 __attribute__((vector_size(64 * sizeof(uint16_t)))); + +Vector_64_u16 zig_ret_vector_64_u16(void); +void zig_vector_64_u16(Vector_64_u16, size_t); + +Vector_64_u16 c_ret_vector_64_u16(void) { + return (Vector_64_u16){ + 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, + 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, + }; +} +void c_vector_64_u16(Vector_64_u16 v, size_t i) { + assert_or_panic(v[0] == 817); + assert_or_panic(v[1] == 818); + assert_or_panic(v[2] == 819); + assert_or_panic(v[3] == 820); + assert_or_panic(v[4] == 821); + assert_or_panic(v[5] == 822); + assert_or_panic(v[6] == 823); + assert_or_panic(v[7] == 824); + assert_or_panic(v[8] == 825); + assert_or_panic(v[9] == 826); + assert_or_panic(v[10] == 827); + assert_or_panic(v[11] == 828); + assert_or_panic(v[12] == 829); + assert_or_panic(v[13] == 830); + assert_or_panic(v[14] == 831); + assert_or_panic(v[15] == 832); + assert_or_panic(v[16] == 833); + assert_or_panic(v[17] == 834); + assert_or_panic(v[18] == 835); + assert_or_panic(v[19] == 836); + assert_or_panic(v[20] == 837); + assert_or_panic(v[21] == 838); + assert_or_panic(v[22] == 839); + assert_or_panic(v[23] == 840); + assert_or_panic(v[24] == 841); + assert_or_panic(v[25] == 842); + assert_or_panic(v[26] == 843); + assert_or_panic(v[27] == 844); + assert_or_panic(v[28] == 845); + assert_or_panic(v[29] == 846); + assert_or_panic(v[30] == 847); + assert_or_panic(v[31] == 848); + assert_or_panic(v[32] == 849); + assert_or_panic(v[33] == 850); + assert_or_panic(v[34] == 851); + assert_or_panic(v[35] == 852); + assert_or_panic(v[36] == 853); + assert_or_panic(v[37] == 854); + assert_or_panic(v[38] == 855); + assert_or_panic(v[39] == 856); + assert_or_panic(v[40] == 857); + assert_or_panic(v[41] == 858); + assert_or_panic(v[42] == 859); + assert_or_panic(v[43] == 860); + assert_or_panic(v[44] == 861); + assert_or_panic(v[45] == 862); + assert_or_panic(v[46] == 863); + assert_or_panic(v[47] == 864); + assert_or_panic(v[48] == 865); + assert_or_panic(v[49] == 866); + assert_or_panic(v[50] == 867); + assert_or_panic(v[51] == 868); + assert_or_panic(v[52] == 869); + assert_or_panic(v[53] == 870); + assert_or_panic(v[54] == 871); + assert_or_panic(v[55] == 872); + assert_or_panic(v[56] == 873); + assert_or_panic(v[57] == 874); + assert_or_panic(v[58] == 875); + assert_or_panic(v[59] == 876); + assert_or_panic(v[60] == 877); + assert_or_panic(v[61] == 878); + assert_or_panic(v[62] == 879); + assert_or_panic(v[63] == 880); + assert_or_panic(i == 64); +} +void c_test_vector_64_u16(void) { + Vector_64_u16 v = zig_ret_vector_64_u16(); + assert_or_panic(v[0] == 625); + assert_or_panic(v[1] == 626); + assert_or_panic(v[2] == 627); + assert_or_panic(v[3] == 628); + assert_or_panic(v[4] == 629); + assert_or_panic(v[5] == 630); + assert_or_panic(v[6] == 631); + assert_or_panic(v[7] == 632); + assert_or_panic(v[8] == 633); + assert_or_panic(v[9] == 634); + assert_or_panic(v[10] == 635); + assert_or_panic(v[11] == 636); + assert_or_panic(v[12] == 637); + assert_or_panic(v[13] == 638); + assert_or_panic(v[14] == 639); + assert_or_panic(v[15] == 640); + assert_or_panic(v[16] == 641); + assert_or_panic(v[17] == 642); + assert_or_panic(v[18] == 643); + assert_or_panic(v[19] == 644); + assert_or_panic(v[20] == 645); + assert_or_panic(v[21] == 646); + assert_or_panic(v[22] == 647); + assert_or_panic(v[23] == 648); + assert_or_panic(v[24] == 649); + assert_or_panic(v[25] == 650); + assert_or_panic(v[26] == 651); + assert_or_panic(v[27] == 652); + assert_or_panic(v[28] == 653); + assert_or_panic(v[29] == 654); + assert_or_panic(v[30] == 655); + assert_or_panic(v[31] == 656); + assert_or_panic(v[32] == 657); + assert_or_panic(v[33] == 658); + assert_or_panic(v[34] == 659); + assert_or_panic(v[35] == 660); + assert_or_panic(v[36] == 661); + assert_or_panic(v[37] == 662); + assert_or_panic(v[38] == 663); + assert_or_panic(v[39] == 664); + assert_or_panic(v[40] == 665); + assert_or_panic(v[41] == 666); + assert_or_panic(v[42] == 667); + assert_or_panic(v[43] == 668); + assert_or_panic(v[44] == 669); + assert_or_panic(v[45] == 670); + assert_or_panic(v[46] == 671); + assert_or_panic(v[47] == 672); + assert_or_panic(v[48] == 673); + assert_or_panic(v[49] == 674); + assert_or_panic(v[50] == 675); + assert_or_panic(v[51] == 676); + assert_or_panic(v[52] == 677); + assert_or_panic(v[53] == 678); + assert_or_panic(v[54] == 679); + assert_or_panic(v[55] == 680); + assert_or_panic(v[56] == 681); + assert_or_panic(v[57] == 682); + assert_or_panic(v[58] == 683); + assert_or_panic(v[59] == 684); + assert_or_panic(v[60] == 685); + assert_or_panic(v[61] == 686); + assert_or_panic(v[62] == 687); + assert_or_panic(v[63] == 688); + zig_vector_64_u16((Vector_64_u16){ + 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, + 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, + }, 64); +} + +typedef uint16_t Vector_96_u16 __attribute__((vector_size(96 * sizeof(uint16_t)))); + +Vector_96_u16 zig_ret_vector_96_u16(void); +void zig_vector_96_u16(Vector_96_u16, size_t); + +Vector_96_u16 c_ret_vector_96_u16(void) { + return (Vector_96_u16){ + 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, + 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, + 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, + 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, + 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, + 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, + }; +} +void c_vector_96_u16(Vector_96_u16 v, size_t i) { + assert_or_panic(v[0] == 1178); + assert_or_panic(v[1] == 1179); + assert_or_panic(v[2] == 1180); + assert_or_panic(v[3] == 1181); + assert_or_panic(v[4] == 1182); + assert_or_panic(v[5] == 1183); + assert_or_panic(v[6] == 1184); + assert_or_panic(v[7] == 1185); + assert_or_panic(v[8] == 1186); + assert_or_panic(v[9] == 1187); + assert_or_panic(v[10] == 1188); + assert_or_panic(v[11] == 1189); + assert_or_panic(v[12] == 1190); + assert_or_panic(v[13] == 1191); + assert_or_panic(v[14] == 1192); + assert_or_panic(v[15] == 1193); + assert_or_panic(v[16] == 1194); + assert_or_panic(v[17] == 1195); + assert_or_panic(v[18] == 1196); + assert_or_panic(v[19] == 1197); + assert_or_panic(v[20] == 1198); + assert_or_panic(v[21] == 1199); + assert_or_panic(v[22] == 1200); + assert_or_panic(v[23] == 1201); + assert_or_panic(v[24] == 1202); + assert_or_panic(v[25] == 1203); + assert_or_panic(v[26] == 1204); + assert_or_panic(v[27] == 1205); + assert_or_panic(v[28] == 1206); + assert_or_panic(v[29] == 1207); + assert_or_panic(v[30] == 1208); + assert_or_panic(v[31] == 1209); + assert_or_panic(v[32] == 1210); + assert_or_panic(v[33] == 1211); + assert_or_panic(v[34] == 1212); + assert_or_panic(v[35] == 1213); + assert_or_panic(v[36] == 1214); + assert_or_panic(v[37] == 1215); + assert_or_panic(v[38] == 1216); + assert_or_panic(v[39] == 1217); + assert_or_panic(v[40] == 1218); + assert_or_panic(v[41] == 1219); + assert_or_panic(v[42] == 1220); + assert_or_panic(v[43] == 1221); + assert_or_panic(v[44] == 1222); + assert_or_panic(v[45] == 1223); + assert_or_panic(v[46] == 1224); + assert_or_panic(v[47] == 1225); + assert_or_panic(v[48] == 1226); + assert_or_panic(v[49] == 1227); + assert_or_panic(v[50] == 1228); + assert_or_panic(v[51] == 1229); + assert_or_panic(v[52] == 1230); + assert_or_panic(v[53] == 1231); + assert_or_panic(v[54] == 1232); + assert_or_panic(v[55] == 1233); + assert_or_panic(v[56] == 1234); + assert_or_panic(v[57] == 1235); + assert_or_panic(v[58] == 1236); + assert_or_panic(v[59] == 1237); + assert_or_panic(v[60] == 1238); + assert_or_panic(v[61] == 1239); + assert_or_panic(v[62] == 1240); + assert_or_panic(v[63] == 1241); + assert_or_panic(v[64] == 1242); + assert_or_panic(v[65] == 1243); + assert_or_panic(v[66] == 1244); + assert_or_panic(v[67] == 1245); + assert_or_panic(v[68] == 1246); + assert_or_panic(v[69] == 1247); + assert_or_panic(v[70] == 1248); + assert_or_panic(v[71] == 1249); + assert_or_panic(v[72] == 1250); + assert_or_panic(v[73] == 1251); + assert_or_panic(v[74] == 1252); + assert_or_panic(v[75] == 1253); + assert_or_panic(v[76] == 1254); + assert_or_panic(v[77] == 1255); + assert_or_panic(v[80] == 1258); + assert_or_panic(v[81] == 1259); + assert_or_panic(v[82] == 1260); + assert_or_panic(v[83] == 1261); + assert_or_panic(v[84] == 1262); + assert_or_panic(v[85] == 1263); + assert_or_panic(v[86] == 1264); + assert_or_panic(v[87] == 1265); + assert_or_panic(v[88] == 1266); + assert_or_panic(v[89] == 1267); + assert_or_panic(v[90] == 1268); + assert_or_panic(v[91] == 1269); + assert_or_panic(v[92] == 1270); + assert_or_panic(v[93] == 1271); + assert_or_panic(v[94] == 1272); + assert_or_panic(v[95] == 1273); + assert_or_panic(i == 96); +} +void c_test_vector_96_u16(void) { + Vector_96_u16 v = zig_ret_vector_96_u16(); + assert_or_panic(v[0] == 890); + assert_or_panic(v[1] == 891); + assert_or_panic(v[2] == 892); + assert_or_panic(v[3] == 893); + assert_or_panic(v[4] == 894); + assert_or_panic(v[5] == 895); + assert_or_panic(v[6] == 896); + assert_or_panic(v[7] == 897); + assert_or_panic(v[8] == 898); + assert_or_panic(v[9] == 899); + assert_or_panic(v[10] == 900); + assert_or_panic(v[11] == 901); + assert_or_panic(v[12] == 902); + assert_or_panic(v[13] == 903); + assert_or_panic(v[14] == 904); + assert_or_panic(v[15] == 905); + assert_or_panic(v[16] == 906); + assert_or_panic(v[17] == 907); + assert_or_panic(v[18] == 908); + assert_or_panic(v[19] == 909); + assert_or_panic(v[20] == 910); + assert_or_panic(v[21] == 911); + assert_or_panic(v[22] == 912); + assert_or_panic(v[23] == 913); + assert_or_panic(v[24] == 914); + assert_or_panic(v[25] == 915); + assert_or_panic(v[26] == 916); + assert_or_panic(v[27] == 917); + assert_or_panic(v[28] == 918); + assert_or_panic(v[29] == 919); + assert_or_panic(v[30] == 920); + assert_or_panic(v[31] == 921); + assert_or_panic(v[32] == 922); + assert_or_panic(v[33] == 923); + assert_or_panic(v[34] == 924); + assert_or_panic(v[35] == 925); + assert_or_panic(v[36] == 926); + assert_or_panic(v[37] == 927); + assert_or_panic(v[38] == 928); + assert_or_panic(v[39] == 929); + assert_or_panic(v[40] == 930); + assert_or_panic(v[41] == 931); + assert_or_panic(v[42] == 932); + assert_or_panic(v[43] == 933); + assert_or_panic(v[44] == 934); + assert_or_panic(v[45] == 935); + assert_or_panic(v[46] == 936); + assert_or_panic(v[47] == 937); + assert_or_panic(v[48] == 938); + assert_or_panic(v[49] == 939); + assert_or_panic(v[50] == 940); + assert_or_panic(v[51] == 941); + assert_or_panic(v[52] == 942); + assert_or_panic(v[53] == 943); + assert_or_panic(v[54] == 944); + assert_or_panic(v[55] == 945); + assert_or_panic(v[56] == 946); + assert_or_panic(v[57] == 947); + assert_or_panic(v[58] == 948); + assert_or_panic(v[59] == 949); + assert_or_panic(v[60] == 950); + assert_or_panic(v[61] == 951); + assert_or_panic(v[62] == 952); + assert_or_panic(v[63] == 953); + assert_or_panic(v[64] == 954); + assert_or_panic(v[65] == 955); + assert_or_panic(v[66] == 956); + assert_or_panic(v[67] == 957); + assert_or_panic(v[68] == 958); + assert_or_panic(v[69] == 959); + assert_or_panic(v[70] == 960); + assert_or_panic(v[71] == 961); + assert_or_panic(v[72] == 962); + assert_or_panic(v[73] == 963); + assert_or_panic(v[74] == 964); + assert_or_panic(v[75] == 965); + assert_or_panic(v[76] == 966); + assert_or_panic(v[77] == 967); + assert_or_panic(v[78] == 968); + assert_or_panic(v[79] == 969); + assert_or_panic(v[80] == 970); + assert_or_panic(v[81] == 971); + assert_or_panic(v[82] == 972); + assert_or_panic(v[83] == 973); + assert_or_panic(v[84] == 974); + assert_or_panic(v[85] == 975); + assert_or_panic(v[86] == 976); + assert_or_panic(v[87] == 977); + assert_or_panic(v[88] == 978); + assert_or_panic(v[89] == 979); + assert_or_panic(v[90] == 980); + assert_or_panic(v[91] == 981); + assert_or_panic(v[92] == 982); + assert_or_panic(v[93] == 983); + assert_or_panic(v[94] == 984); + assert_or_panic(v[95] == 985); + zig_vector_96_u16((Vector_96_u16){ + 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, + 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, + 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, + 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, + 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, + 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, + }, 96); +} + +typedef uint16_t Vector_128_u16 __attribute__((vector_size(128 * sizeof(uint16_t)))); + +Vector_128_u16 zig_ret_vector_128_u16(void); +void zig_vector_128_u16(Vector_128_u16, size_t); + +Vector_128_u16 c_ret_vector_128_u16(void) { + return (Vector_128_u16){ + 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, + 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, + 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, + 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, + 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, + 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, + 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, + 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, + }; +} +void c_vector_128_u16(Vector_128_u16 v, size_t i) { + assert_or_panic(v[0] == 1658); + assert_or_panic(v[1] == 1659); + assert_or_panic(v[2] == 1660); + assert_or_panic(v[3] == 1661); + assert_or_panic(v[4] == 1662); + assert_or_panic(v[5] == 1663); + assert_or_panic(v[6] == 1664); + assert_or_panic(v[7] == 1665); + assert_or_panic(v[8] == 1666); + assert_or_panic(v[9] == 1667); + assert_or_panic(v[10] == 1668); + assert_or_panic(v[11] == 1669); + assert_or_panic(v[12] == 1670); + assert_or_panic(v[13] == 1671); + assert_or_panic(v[14] == 1672); + assert_or_panic(v[15] == 1673); + assert_or_panic(v[16] == 1674); + assert_or_panic(v[17] == 1675); + assert_or_panic(v[18] == 1676); + assert_or_panic(v[19] == 1677); + assert_or_panic(v[20] == 1678); + assert_or_panic(v[21] == 1679); + assert_or_panic(v[22] == 1680); + assert_or_panic(v[23] == 1681); + assert_or_panic(v[24] == 1682); + assert_or_panic(v[25] == 1683); + assert_or_panic(v[26] == 1684); + assert_or_panic(v[27] == 1685); + assert_or_panic(v[28] == 1686); + assert_or_panic(v[29] == 1687); + assert_or_panic(v[30] == 1688); + assert_or_panic(v[31] == 1689); + assert_or_panic(v[32] == 1690); + assert_or_panic(v[33] == 1691); + assert_or_panic(v[34] == 1692); + assert_or_panic(v[35] == 1693); + assert_or_panic(v[36] == 1694); + assert_or_panic(v[37] == 1695); + assert_or_panic(v[38] == 1696); + assert_or_panic(v[39] == 1697); + assert_or_panic(v[40] == 1698); + assert_or_panic(v[41] == 1699); + assert_or_panic(v[42] == 1700); + assert_or_panic(v[43] == 1701); + assert_or_panic(v[44] == 1702); + assert_or_panic(v[45] == 1703); + assert_or_panic(v[46] == 1704); + assert_or_panic(v[47] == 1705); + assert_or_panic(v[48] == 1706); + assert_or_panic(v[49] == 1707); + assert_or_panic(v[50] == 1708); + assert_or_panic(v[51] == 1709); + assert_or_panic(v[52] == 1710); + assert_or_panic(v[53] == 1711); + assert_or_panic(v[54] == 1712); + assert_or_panic(v[55] == 1713); + assert_or_panic(v[56] == 1714); + assert_or_panic(v[57] == 1715); + assert_or_panic(v[58] == 1716); + assert_or_panic(v[59] == 1717); + assert_or_panic(v[60] == 1718); + assert_or_panic(v[61] == 1719); + assert_or_panic(v[62] == 1720); + assert_or_panic(v[63] == 1721); + assert_or_panic(v[64] == 1722); + assert_or_panic(v[65] == 1723); + assert_or_panic(v[66] == 1724); + assert_or_panic(v[67] == 1725); + assert_or_panic(v[68] == 1726); + assert_or_panic(v[69] == 1727); + assert_or_panic(v[70] == 1728); + assert_or_panic(v[71] == 1729); + assert_or_panic(v[72] == 1730); + assert_or_panic(v[73] == 1731); + assert_or_panic(v[74] == 1732); + assert_or_panic(v[75] == 1733); + assert_or_panic(v[76] == 1734); + assert_or_panic(v[77] == 1735); + assert_or_panic(v[78] == 1736); + assert_or_panic(v[79] == 1737); + assert_or_panic(v[80] == 1738); + assert_or_panic(v[81] == 1739); + assert_or_panic(v[82] == 1740); + assert_or_panic(v[83] == 1741); + assert_or_panic(v[84] == 1742); + assert_or_panic(v[85] == 1743); + assert_or_panic(v[86] == 1744); + assert_or_panic(v[87] == 1745); + assert_or_panic(v[88] == 1746); + assert_or_panic(v[89] == 1747); + assert_or_panic(v[90] == 1748); + assert_or_panic(v[91] == 1749); + assert_or_panic(v[92] == 1750); + assert_or_panic(v[93] == 1751); + assert_or_panic(v[94] == 1752); + assert_or_panic(v[95] == 1753); + assert_or_panic(v[96] == 1754); + assert_or_panic(v[97] == 1755); + assert_or_panic(v[98] == 1756); + assert_or_panic(v[99] == 1757); + assert_or_panic(v[100] == 1758); + assert_or_panic(v[101] == 1759); + assert_or_panic(v[102] == 1760); + assert_or_panic(v[103] == 1761); + assert_or_panic(v[104] == 1762); + assert_or_panic(v[105] == 1763); + assert_or_panic(v[106] == 1764); + assert_or_panic(v[107] == 1765); + assert_or_panic(v[108] == 1766); + assert_or_panic(v[109] == 1767); + assert_or_panic(v[110] == 1768); + assert_or_panic(v[111] == 1769); + assert_or_panic(v[112] == 1770); + assert_or_panic(v[113] == 1771); + assert_or_panic(v[114] == 1772); + assert_or_panic(v[115] == 1773); + assert_or_panic(v[116] == 1774); + assert_or_panic(v[117] == 1775); + assert_or_panic(v[118] == 1776); + assert_or_panic(v[119] == 1777); + assert_or_panic(v[120] == 1778); + assert_or_panic(v[121] == 1779); + assert_or_panic(v[122] == 1780); + assert_or_panic(v[123] == 1781); + assert_or_panic(v[124] == 1782); + assert_or_panic(v[125] == 1783); + assert_or_panic(v[126] == 1784); + assert_or_panic(v[127] == 1785); + assert_or_panic(i == 128); +} +void c_test_vector_128_u16(void) { + Vector_128_u16 v = zig_ret_vector_128_u16(); + assert_or_panic(v[0] == 1274); + assert_or_panic(v[1] == 1275); + assert_or_panic(v[2] == 1276); + assert_or_panic(v[3] == 1277); + assert_or_panic(v[4] == 1278); + assert_or_panic(v[5] == 1279); + assert_or_panic(v[6] == 1280); + assert_or_panic(v[7] == 1281); + assert_or_panic(v[8] == 1282); + assert_or_panic(v[9] == 1283); + assert_or_panic(v[10] == 1284); + assert_or_panic(v[11] == 1285); + assert_or_panic(v[12] == 1286); + assert_or_panic(v[13] == 1287); + assert_or_panic(v[14] == 1288); + assert_or_panic(v[15] == 1289); + assert_or_panic(v[16] == 1290); + assert_or_panic(v[17] == 1291); + assert_or_panic(v[18] == 1292); + assert_or_panic(v[19] == 1293); + assert_or_panic(v[20] == 1294); + assert_or_panic(v[21] == 1295); + assert_or_panic(v[22] == 1296); + assert_or_panic(v[23] == 1297); + assert_or_panic(v[24] == 1298); + assert_or_panic(v[25] == 1299); + assert_or_panic(v[26] == 1300); + assert_or_panic(v[27] == 1301); + assert_or_panic(v[28] == 1302); + assert_or_panic(v[29] == 1303); + assert_or_panic(v[30] == 1304); + assert_or_panic(v[31] == 1305); + assert_or_panic(v[32] == 1306); + assert_or_panic(v[33] == 1307); + assert_or_panic(v[34] == 1308); + assert_or_panic(v[35] == 1309); + assert_or_panic(v[36] == 1310); + assert_or_panic(v[37] == 1311); + assert_or_panic(v[38] == 1312); + assert_or_panic(v[39] == 1313); + assert_or_panic(v[40] == 1314); + assert_or_panic(v[41] == 1315); + assert_or_panic(v[42] == 1316); + assert_or_panic(v[43] == 1317); + assert_or_panic(v[44] == 1318); + assert_or_panic(v[45] == 1319); + assert_or_panic(v[46] == 1320); + assert_or_panic(v[47] == 1321); + assert_or_panic(v[48] == 1322); + assert_or_panic(v[49] == 1323); + assert_or_panic(v[50] == 1324); + assert_or_panic(v[51] == 1325); + assert_or_panic(v[52] == 1326); + assert_or_panic(v[53] == 1327); + assert_or_panic(v[54] == 1328); + assert_or_panic(v[55] == 1329); + assert_or_panic(v[56] == 1330); + assert_or_panic(v[57] == 1331); + assert_or_panic(v[58] == 1332); + assert_or_panic(v[59] == 1333); + assert_or_panic(v[60] == 1334); + assert_or_panic(v[61] == 1335); + assert_or_panic(v[62] == 1336); + assert_or_panic(v[63] == 1337); + assert_or_panic(v[64] == 1338); + assert_or_panic(v[65] == 1339); + assert_or_panic(v[66] == 1340); + assert_or_panic(v[67] == 1341); + assert_or_panic(v[68] == 1342); + assert_or_panic(v[69] == 1343); + assert_or_panic(v[70] == 1344); + assert_or_panic(v[71] == 1345); + assert_or_panic(v[72] == 1346); + assert_or_panic(v[73] == 1347); + assert_or_panic(v[74] == 1348); + assert_or_panic(v[75] == 1349); + assert_or_panic(v[76] == 1350); + assert_or_panic(v[77] == 1351); + assert_or_panic(v[78] == 1352); + assert_or_panic(v[79] == 1353); + assert_or_panic(v[80] == 1354); + assert_or_panic(v[81] == 1355); + assert_or_panic(v[82] == 1356); + assert_or_panic(v[83] == 1357); + assert_or_panic(v[84] == 1358); + assert_or_panic(v[85] == 1359); + assert_or_panic(v[86] == 1360); + assert_or_panic(v[87] == 1361); + assert_or_panic(v[88] == 1362); + assert_or_panic(v[89] == 1363); + assert_or_panic(v[90] == 1364); + assert_or_panic(v[91] == 1365); + assert_or_panic(v[92] == 1366); + assert_or_panic(v[93] == 1367); + assert_or_panic(v[94] == 1368); + assert_or_panic(v[95] == 1369); + assert_or_panic(v[96] == 1370); + assert_or_panic(v[97] == 1371); + assert_or_panic(v[98] == 1372); + assert_or_panic(v[99] == 1373); + assert_or_panic(v[100] == 1374); + assert_or_panic(v[101] == 1375); + assert_or_panic(v[102] == 1376); + assert_or_panic(v[103] == 1377); + assert_or_panic(v[104] == 1378); + assert_or_panic(v[105] == 1379); + assert_or_panic(v[106] == 1380); + assert_or_panic(v[107] == 1381); + assert_or_panic(v[108] == 1382); + assert_or_panic(v[109] == 1383); + assert_or_panic(v[110] == 1384); + assert_or_panic(v[111] == 1385); + assert_or_panic(v[112] == 1386); + assert_or_panic(v[113] == 1387); + assert_or_panic(v[114] == 1388); + assert_or_panic(v[115] == 1389); + assert_or_panic(v[116] == 1390); + assert_or_panic(v[117] == 1391); + assert_or_panic(v[118] == 1392); + assert_or_panic(v[119] == 1393); + assert_or_panic(v[120] == 1394); + assert_or_panic(v[121] == 1395); + assert_or_panic(v[122] == 1396); + assert_or_panic(v[123] == 1397); + assert_or_panic(v[124] == 1398); + assert_or_panic(v[125] == 1399); + assert_or_panic(v[126] == 1400); + assert_or_panic(v[127] == 1401); + zig_vector_128_u16((Vector_128_u16){ + 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, + 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, + 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, + 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, + 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, + 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, + 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, + 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, + }, 128); +} + +typedef uint16_t Vector_192_u16 __attribute__((vector_size(192 * sizeof(uint16_t)))); + +Vector_192_u16 zig_ret_vector_192_u16(void); +void zig_vector_192_u16(Vector_192_u16, size_t); + +Vector_192_u16 c_ret_vector_192_u16(void) { + return (Vector_192_u16){ + 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, 2185, + 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2200, 2201, + 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, + 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2233, + 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, + 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, + 2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, + 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, + 2298, 2299, 2300, 2301, 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, + 2314, 2315, 2316, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, 2329, + 2330, 2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345, + 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2355, 2356, 2357, 2358, 2359, 2360, 2361, + }; +} +void c_vector_192_u16(Vector_192_u16 v, size_t i) { + assert_or_panic(v[0] == 2362); + assert_or_panic(v[1] == 2363); + assert_or_panic(v[2] == 2364); + assert_or_panic(v[3] == 2365); + assert_or_panic(v[4] == 2366); + assert_or_panic(v[5] == 2367); + assert_or_panic(v[6] == 2368); + assert_or_panic(v[7] == 2369); + assert_or_panic(v[8] == 2370); + assert_or_panic(v[9] == 2371); + assert_or_panic(v[10] == 2372); + assert_or_panic(v[11] == 2373); + assert_or_panic(v[12] == 2374); + assert_or_panic(v[13] == 2375); + assert_or_panic(v[14] == 2376); + assert_or_panic(v[15] == 2377); + assert_or_panic(v[16] == 2378); + assert_or_panic(v[17] == 2379); + assert_or_panic(v[18] == 2380); + assert_or_panic(v[19] == 2381); + assert_or_panic(v[20] == 2382); + assert_or_panic(v[21] == 2383); + assert_or_panic(v[22] == 2384); + assert_or_panic(v[23] == 2385); + assert_or_panic(v[24] == 2386); + assert_or_panic(v[25] == 2387); + assert_or_panic(v[26] == 2388); + assert_or_panic(v[27] == 2389); + assert_or_panic(v[28] == 2390); + assert_or_panic(v[29] == 2391); + assert_or_panic(v[30] == 2392); + assert_or_panic(v[31] == 2393); + assert_or_panic(v[32] == 2394); + assert_or_panic(v[33] == 2395); + assert_or_panic(v[34] == 2396); + assert_or_panic(v[35] == 2397); + assert_or_panic(v[36] == 2398); + assert_or_panic(v[37] == 2399); + assert_or_panic(v[38] == 2400); + assert_or_panic(v[39] == 2401); + assert_or_panic(v[40] == 2402); + assert_or_panic(v[41] == 2403); + assert_or_panic(v[42] == 2404); + assert_or_panic(v[43] == 2405); + assert_or_panic(v[44] == 2406); + assert_or_panic(v[45] == 2407); + assert_or_panic(v[46] == 2408); + assert_or_panic(v[47] == 2409); + assert_or_panic(v[48] == 2410); + assert_or_panic(v[49] == 2411); + assert_or_panic(v[50] == 2412); + assert_or_panic(v[51] == 2413); + assert_or_panic(v[52] == 2414); + assert_or_panic(v[53] == 2415); + assert_or_panic(v[54] == 2416); + assert_or_panic(v[55] == 2417); + assert_or_panic(v[56] == 2418); + assert_or_panic(v[57] == 2419); + assert_or_panic(v[58] == 2420); + assert_or_panic(v[59] == 2421); + assert_or_panic(v[60] == 2422); + assert_or_panic(v[61] == 2423); + assert_or_panic(v[62] == 2424); + assert_or_panic(v[63] == 2425); + assert_or_panic(v[64] == 2426); + assert_or_panic(v[65] == 2427); + assert_or_panic(v[66] == 2428); + assert_or_panic(v[67] == 2429); + assert_or_panic(v[68] == 2430); + assert_or_panic(v[69] == 2431); + assert_or_panic(v[70] == 2432); + assert_or_panic(v[71] == 2433); + assert_or_panic(v[72] == 2434); + assert_or_panic(v[73] == 2435); + assert_or_panic(v[74] == 2436); + assert_or_panic(v[75] == 2437); + assert_or_panic(v[76] == 2438); + assert_or_panic(v[77] == 2439); + assert_or_panic(v[78] == 2440); + assert_or_panic(v[79] == 2441); + assert_or_panic(v[80] == 2442); + assert_or_panic(v[81] == 2443); + assert_or_panic(v[82] == 2444); + assert_or_panic(v[83] == 2445); + assert_or_panic(v[84] == 2446); + assert_or_panic(v[85] == 2447); + assert_or_panic(v[86] == 2448); + assert_or_panic(v[87] == 2449); + assert_or_panic(v[88] == 2450); + assert_or_panic(v[89] == 2451); + assert_or_panic(v[90] == 2452); + assert_or_panic(v[91] == 2453); + assert_or_panic(v[92] == 2454); + assert_or_panic(v[93] == 2455); + assert_or_panic(v[94] == 2456); + assert_or_panic(v[95] == 2457); + assert_or_panic(v[96] == 2458); + assert_or_panic(v[97] == 2459); + assert_or_panic(v[98] == 2460); + assert_or_panic(v[99] == 2461); + assert_or_panic(v[100] == 2462); + assert_or_panic(v[101] == 2463); + assert_or_panic(v[102] == 2464); + assert_or_panic(v[103] == 2465); + assert_or_panic(v[104] == 2466); + assert_or_panic(v[105] == 2467); + assert_or_panic(v[106] == 2468); + assert_or_panic(v[107] == 2469); + assert_or_panic(v[108] == 2470); + assert_or_panic(v[109] == 2471); + assert_or_panic(v[110] == 2472); + assert_or_panic(v[111] == 2473); + assert_or_panic(v[112] == 2474); + assert_or_panic(v[113] == 2475); + assert_or_panic(v[114] == 2476); + assert_or_panic(v[115] == 2477); + assert_or_panic(v[116] == 2478); + assert_or_panic(v[117] == 2479); + assert_or_panic(v[118] == 2480); + assert_or_panic(v[119] == 2481); + assert_or_panic(v[120] == 2482); + assert_or_panic(v[121] == 2483); + assert_or_panic(v[122] == 2484); + assert_or_panic(v[123] == 2485); + assert_or_panic(v[124] == 2486); + assert_or_panic(v[125] == 2487); + assert_or_panic(v[126] == 2488); + assert_or_panic(v[127] == 2489); + assert_or_panic(v[128] == 2490); + assert_or_panic(v[129] == 2491); + assert_or_panic(v[130] == 2492); + assert_or_panic(v[131] == 2493); + assert_or_panic(v[132] == 2494); + assert_or_panic(v[133] == 2495); + assert_or_panic(v[134] == 2496); + assert_or_panic(v[135] == 2497); + assert_or_panic(v[136] == 2498); + assert_or_panic(v[137] == 2499); + assert_or_panic(v[138] == 2500); + assert_or_panic(v[139] == 2501); + assert_or_panic(v[140] == 2502); + assert_or_panic(v[141] == 2503); + assert_or_panic(v[142] == 2504); + assert_or_panic(v[143] == 2505); + assert_or_panic(v[144] == 2506); + assert_or_panic(v[145] == 2507); + assert_or_panic(v[146] == 2508); + assert_or_panic(v[147] == 2509); + assert_or_panic(v[148] == 2510); + assert_or_panic(v[149] == 2511); + assert_or_panic(v[150] == 2512); + assert_or_panic(v[151] == 2513); + assert_or_panic(v[152] == 2514); + assert_or_panic(v[153] == 2515); + assert_or_panic(v[154] == 2516); + assert_or_panic(v[155] == 2517); + assert_or_panic(v[156] == 2518); + assert_or_panic(v[157] == 2519); + assert_or_panic(v[158] == 2520); + assert_or_panic(v[159] == 2521); + assert_or_panic(v[160] == 2522); + assert_or_panic(v[161] == 2523); + assert_or_panic(v[162] == 2524); + assert_or_panic(v[163] == 2525); + assert_or_panic(v[164] == 2526); + assert_or_panic(v[165] == 2527); + assert_or_panic(v[166] == 2528); + assert_or_panic(v[167] == 2529); + assert_or_panic(v[168] == 2530); + assert_or_panic(v[169] == 2531); + assert_or_panic(v[170] == 2532); + assert_or_panic(v[171] == 2533); + assert_or_panic(v[172] == 2534); + assert_or_panic(v[173] == 2535); + assert_or_panic(v[174] == 2536); + assert_or_panic(v[175] == 2537); + assert_or_panic(v[176] == 2538); + assert_or_panic(v[177] == 2539); + assert_or_panic(v[178] == 2540); + assert_or_panic(v[179] == 2541); + assert_or_panic(v[180] == 2542); + assert_or_panic(v[181] == 2543); + assert_or_panic(v[182] == 2544); + assert_or_panic(v[183] == 2545); + assert_or_panic(v[184] == 2546); + assert_or_panic(v[185] == 2547); + assert_or_panic(v[186] == 2548); + assert_or_panic(v[187] == 2549); + assert_or_panic(v[188] == 2550); + assert_or_panic(v[189] == 2551); + assert_or_panic(v[190] == 2552); + assert_or_panic(v[191] == 2553); + assert_or_panic(i == 192); +} +void c_test_vector_192_u16(void) { + Vector_192_u16 v = zig_ret_vector_192_u16(); + assert_or_panic(v[0] == 1786); + assert_or_panic(v[1] == 1787); + assert_or_panic(v[2] == 1788); + assert_or_panic(v[3] == 1789); + assert_or_panic(v[4] == 1790); + assert_or_panic(v[5] == 1791); + assert_or_panic(v[6] == 1792); + assert_or_panic(v[7] == 1793); + assert_or_panic(v[8] == 1794); + assert_or_panic(v[9] == 1795); + assert_or_panic(v[10] == 1796); + assert_or_panic(v[11] == 1797); + assert_or_panic(v[12] == 1798); + assert_or_panic(v[13] == 1799); + assert_or_panic(v[14] == 1800); + assert_or_panic(v[15] == 1801); + assert_or_panic(v[16] == 1802); + assert_or_panic(v[17] == 1803); + assert_or_panic(v[18] == 1804); + assert_or_panic(v[19] == 1805); + assert_or_panic(v[20] == 1806); + assert_or_panic(v[21] == 1807); + assert_or_panic(v[22] == 1808); + assert_or_panic(v[23] == 1809); + assert_or_panic(v[24] == 1810); + assert_or_panic(v[25] == 1811); + assert_or_panic(v[26] == 1812); + assert_or_panic(v[27] == 1813); + assert_or_panic(v[28] == 1814); + assert_or_panic(v[29] == 1815); + assert_or_panic(v[30] == 1816); + assert_or_panic(v[31] == 1817); + assert_or_panic(v[32] == 1818); + assert_or_panic(v[33] == 1819); + assert_or_panic(v[34] == 1820); + assert_or_panic(v[35] == 1821); + assert_or_panic(v[36] == 1822); + assert_or_panic(v[37] == 1823); + assert_or_panic(v[38] == 1824); + assert_or_panic(v[39] == 1825); + assert_or_panic(v[40] == 1826); + assert_or_panic(v[41] == 1827); + assert_or_panic(v[42] == 1828); + assert_or_panic(v[43] == 1829); + assert_or_panic(v[44] == 1830); + assert_or_panic(v[45] == 1831); + assert_or_panic(v[46] == 1832); + assert_or_panic(v[47] == 1833); + assert_or_panic(v[48] == 1834); + assert_or_panic(v[49] == 1835); + assert_or_panic(v[50] == 1836); + assert_or_panic(v[51] == 1837); + assert_or_panic(v[52] == 1838); + assert_or_panic(v[53] == 1839); + assert_or_panic(v[54] == 1840); + assert_or_panic(v[55] == 1841); + assert_or_panic(v[56] == 1842); + assert_or_panic(v[57] == 1843); + assert_or_panic(v[58] == 1844); + assert_or_panic(v[59] == 1845); + assert_or_panic(v[60] == 1846); + assert_or_panic(v[61] == 1847); + assert_or_panic(v[62] == 1848); + assert_or_panic(v[63] == 1849); + assert_or_panic(v[64] == 1850); + assert_or_panic(v[65] == 1851); + assert_or_panic(v[66] == 1852); + assert_or_panic(v[67] == 1853); + assert_or_panic(v[68] == 1854); + assert_or_panic(v[69] == 1855); + assert_or_panic(v[70] == 1856); + assert_or_panic(v[71] == 1857); + assert_or_panic(v[72] == 1858); + assert_or_panic(v[73] == 1859); + assert_or_panic(v[74] == 1860); + assert_or_panic(v[75] == 1861); + assert_or_panic(v[76] == 1862); + assert_or_panic(v[77] == 1863); + assert_or_panic(v[78] == 1864); + assert_or_panic(v[79] == 1865); + assert_or_panic(v[80] == 1866); + assert_or_panic(v[81] == 1867); + assert_or_panic(v[82] == 1868); + assert_or_panic(v[83] == 1869); + assert_or_panic(v[84] == 1870); + assert_or_panic(v[85] == 1871); + assert_or_panic(v[86] == 1872); + assert_or_panic(v[87] == 1873); + assert_or_panic(v[88] == 1874); + assert_or_panic(v[89] == 1875); + assert_or_panic(v[90] == 1876); + assert_or_panic(v[91] == 1877); + assert_or_panic(v[92] == 1878); + assert_or_panic(v[93] == 1879); + assert_or_panic(v[94] == 1880); + assert_or_panic(v[95] == 1881); + assert_or_panic(v[96] == 1882); + assert_or_panic(v[97] == 1883); + assert_or_panic(v[98] == 1884); + assert_or_panic(v[99] == 1885); + assert_or_panic(v[100] == 1886); + assert_or_panic(v[101] == 1887); + assert_or_panic(v[102] == 1888); + assert_or_panic(v[103] == 1889); + assert_or_panic(v[104] == 1890); + assert_or_panic(v[105] == 1891); + assert_or_panic(v[106] == 1892); + assert_or_panic(v[107] == 1893); + assert_or_panic(v[108] == 1894); + assert_or_panic(v[109] == 1895); + assert_or_panic(v[110] == 1896); + assert_or_panic(v[111] == 1897); + assert_or_panic(v[112] == 1898); + assert_or_panic(v[113] == 1899); + assert_or_panic(v[114] == 1900); + assert_or_panic(v[115] == 1901); + assert_or_panic(v[116] == 1902); + assert_or_panic(v[117] == 1903); + assert_or_panic(v[118] == 1904); + assert_or_panic(v[119] == 1905); + assert_or_panic(v[120] == 1906); + assert_or_panic(v[121] == 1907); + assert_or_panic(v[122] == 1908); + assert_or_panic(v[123] == 1909); + assert_or_panic(v[124] == 1910); + assert_or_panic(v[125] == 1911); + assert_or_panic(v[126] == 1912); + assert_or_panic(v[127] == 1913); + assert_or_panic(v[128] == 1914); + assert_or_panic(v[129] == 1915); + assert_or_panic(v[130] == 1916); + assert_or_panic(v[131] == 1917); + assert_or_panic(v[132] == 1918); + assert_or_panic(v[133] == 1919); + assert_or_panic(v[134] == 1920); + assert_or_panic(v[135] == 1921); + assert_or_panic(v[136] == 1922); + assert_or_panic(v[137] == 1923); + assert_or_panic(v[138] == 1924); + assert_or_panic(v[139] == 1925); + assert_or_panic(v[140] == 1926); + assert_or_panic(v[141] == 1927); + assert_or_panic(v[142] == 1928); + assert_or_panic(v[143] == 1929); + assert_or_panic(v[144] == 1930); + assert_or_panic(v[145] == 1931); + assert_or_panic(v[146] == 1932); + assert_or_panic(v[147] == 1933); + assert_or_panic(v[148] == 1934); + assert_or_panic(v[149] == 1935); + assert_or_panic(v[150] == 1936); + assert_or_panic(v[151] == 1937); + assert_or_panic(v[152] == 1938); + assert_or_panic(v[153] == 1939); + assert_or_panic(v[154] == 1940); + assert_or_panic(v[155] == 1941); + assert_or_panic(v[156] == 1942); + assert_or_panic(v[157] == 1943); + assert_or_panic(v[158] == 1944); + assert_or_panic(v[159] == 1945); + assert_or_panic(v[160] == 1946); + assert_or_panic(v[161] == 1947); + assert_or_panic(v[162] == 1948); + assert_or_panic(v[163] == 1949); + assert_or_panic(v[164] == 1950); + assert_or_panic(v[165] == 1951); + assert_or_panic(v[166] == 1952); + assert_or_panic(v[167] == 1953); + assert_or_panic(v[168] == 1954); + assert_or_panic(v[169] == 1955); + assert_or_panic(v[170] == 1956); + assert_or_panic(v[171] == 1957); + assert_or_panic(v[172] == 1958); + assert_or_panic(v[173] == 1959); + assert_or_panic(v[174] == 1960); + assert_or_panic(v[175] == 1961); + assert_or_panic(v[176] == 1962); + assert_or_panic(v[177] == 1963); + assert_or_panic(v[178] == 1964); + assert_or_panic(v[179] == 1965); + assert_or_panic(v[180] == 1966); + assert_or_panic(v[181] == 1967); + assert_or_panic(v[182] == 1968); + assert_or_panic(v[183] == 1969); + assert_or_panic(v[184] == 1970); + assert_or_panic(v[185] == 1971); + assert_or_panic(v[186] == 1972); + assert_or_panic(v[187] == 1973); + assert_or_panic(v[188] == 1974); + assert_or_panic(v[189] == 1975); + assert_or_panic(v[190] == 1976); + assert_or_panic(v[191] == 1977); + zig_vector_192_u16((Vector_192_u16){ + 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, + 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025, + 2026, 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038, 2039, 2040, 2041, + 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057, + 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, + 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087, 2088, 2089, + 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, + 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, + 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, + 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, 2153, + 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, 2169, + }, 192); +} + +typedef uint16_t Vector_256_u16 __attribute__((vector_size(256 * sizeof(uint16_t)))); + +Vector_256_u16 zig_ret_vector_256_u16(void); +void zig_vector_256_u16(Vector_256_u16, size_t); + +Vector_256_u16 c_ret_vector_256_u16(void) { + return (Vector_256_u16){ + 3066, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, + 3082, 3083, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, 3095, 3096, 3097, + 3098, 3099, 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, 3111, 3112, 3113, + 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128, 3129, + 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, 3144, 3145, + 3146, 3147, 3148, 3149, 3150, 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, + 3162, 3163, 3164, 3165, 3166, 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3175, 3176, 3177, + 3178, 3179, 3180, 3181, 3182, 3183, 3184, 3185, 3186, 3187, 3188, 3189, 3190, 3191, 3192, 3193, + 3194, 3195, 3196, 3197, 3198, 3199, 3200, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, + 3210, 3211, 3212, 3213, 3214, 3215, 3216, 3217, 3218, 3219, 3220, 3221, 3222, 3223, 3224, 3225, + 3226, 3227, 3228, 3229, 3230, 3231, 3232, 3233, 3234, 3235, 3236, 3237, 3238, 3239, 3240, 3241, + 3242, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, 3251, 3252, 3253, 3254, 3255, 3256, 3257, + 3258, 3259, 3260, 3261, 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, 3270, 3271, 3272, 3273, + 3274, 3275, 3276, 3277, 3278, 3279, 3280, 3281, 3282, 3283, 3284, 3285, 3286, 3287, 3288, 3289, + 3290, 3291, 3292, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, + 3306, 3307, 3308, 3309, 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3320, 3321, + }; +} +void c_vector_256_u16(Vector_256_u16 v, size_t i) { + assert_or_panic(v[0] == 3322); + assert_or_panic(v[1] == 3323); + assert_or_panic(v[2] == 3324); + assert_or_panic(v[3] == 3325); + assert_or_panic(v[4] == 3326); + assert_or_panic(v[5] == 3327); + assert_or_panic(v[6] == 3328); + assert_or_panic(v[7] == 3329); + assert_or_panic(v[8] == 3330); + assert_or_panic(v[9] == 3331); + assert_or_panic(v[10] == 3332); + assert_or_panic(v[11] == 3333); + assert_or_panic(v[12] == 3334); + assert_or_panic(v[13] == 3335); + assert_or_panic(v[14] == 3336); + assert_or_panic(v[15] == 3337); + assert_or_panic(v[16] == 3338); + assert_or_panic(v[17] == 3339); + assert_or_panic(v[18] == 3340); + assert_or_panic(v[19] == 3341); + assert_or_panic(v[20] == 3342); + assert_or_panic(v[21] == 3343); + assert_or_panic(v[22] == 3344); + assert_or_panic(v[23] == 3345); + assert_or_panic(v[24] == 3346); + assert_or_panic(v[25] == 3347); + assert_or_panic(v[26] == 3348); + assert_or_panic(v[27] == 3349); + assert_or_panic(v[28] == 3350); + assert_or_panic(v[29] == 3351); + assert_or_panic(v[30] == 3352); + assert_or_panic(v[31] == 3353); + assert_or_panic(v[32] == 3354); + assert_or_panic(v[33] == 3355); + assert_or_panic(v[34] == 3356); + assert_or_panic(v[35] == 3357); + assert_or_panic(v[36] == 3358); + assert_or_panic(v[37] == 3359); + assert_or_panic(v[38] == 3360); + assert_or_panic(v[39] == 3361); + assert_or_panic(v[40] == 3362); + assert_or_panic(v[41] == 3363); + assert_or_panic(v[42] == 3364); + assert_or_panic(v[43] == 3365); + assert_or_panic(v[44] == 3366); + assert_or_panic(v[45] == 3367); + assert_or_panic(v[46] == 3368); + assert_or_panic(v[47] == 3369); + assert_or_panic(v[48] == 3370); + assert_or_panic(v[49] == 3371); + assert_or_panic(v[50] == 3372); + assert_or_panic(v[51] == 3373); + assert_or_panic(v[52] == 3374); + assert_or_panic(v[53] == 3375); + assert_or_panic(v[54] == 3376); + assert_or_panic(v[55] == 3377); + assert_or_panic(v[56] == 3378); + assert_or_panic(v[57] == 3379); + assert_or_panic(v[58] == 3380); + assert_or_panic(v[59] == 3381); + assert_or_panic(v[60] == 3382); + assert_or_panic(v[61] == 3383); + assert_or_panic(v[62] == 3384); + assert_or_panic(v[63] == 3385); + assert_or_panic(v[64] == 3386); + assert_or_panic(v[65] == 3387); + assert_or_panic(v[66] == 3388); + assert_or_panic(v[67] == 3389); + assert_or_panic(v[68] == 3390); + assert_or_panic(v[69] == 3391); + assert_or_panic(v[70] == 3392); + assert_or_panic(v[71] == 3393); + assert_or_panic(v[72] == 3394); + assert_or_panic(v[73] == 3395); + assert_or_panic(v[74] == 3396); + assert_or_panic(v[75] == 3397); + assert_or_panic(v[76] == 3398); + assert_or_panic(v[77] == 3399); + assert_or_panic(v[78] == 3400); + assert_or_panic(v[79] == 3401); + assert_or_panic(v[80] == 3402); + assert_or_panic(v[81] == 3403); + assert_or_panic(v[82] == 3404); + assert_or_panic(v[83] == 3405); + assert_or_panic(v[84] == 3406); + assert_or_panic(v[85] == 3407); + assert_or_panic(v[86] == 3408); + assert_or_panic(v[87] == 3409); + assert_or_panic(v[88] == 3410); + assert_or_panic(v[89] == 3411); + assert_or_panic(v[90] == 3412); + assert_or_panic(v[91] == 3413); + assert_or_panic(v[92] == 3414); + assert_or_panic(v[93] == 3415); + assert_or_panic(v[94] == 3416); + assert_or_panic(v[95] == 3417); + assert_or_panic(v[96] == 3418); + assert_or_panic(v[97] == 3419); + assert_or_panic(v[98] == 3420); + assert_or_panic(v[99] == 3421); + assert_or_panic(v[100] == 3422); + assert_or_panic(v[101] == 3423); + assert_or_panic(v[102] == 3424); + assert_or_panic(v[103] == 3425); + assert_or_panic(v[104] == 3426); + assert_or_panic(v[105] == 3427); + assert_or_panic(v[106] == 3428); + assert_or_panic(v[107] == 3429); + assert_or_panic(v[108] == 3430); + assert_or_panic(v[109] == 3431); + assert_or_panic(v[110] == 3432); + assert_or_panic(v[111] == 3433); + assert_or_panic(v[112] == 3434); + assert_or_panic(v[113] == 3435); + assert_or_panic(v[114] == 3436); + assert_or_panic(v[115] == 3437); + assert_or_panic(v[116] == 3438); + assert_or_panic(v[117] == 3439); + assert_or_panic(v[118] == 3440); + assert_or_panic(v[119] == 3441); + assert_or_panic(v[120] == 3442); + assert_or_panic(v[121] == 3443); + assert_or_panic(v[122] == 3444); + assert_or_panic(v[123] == 3445); + assert_or_panic(v[124] == 3446); + assert_or_panic(v[125] == 3447); + assert_or_panic(v[126] == 3448); + assert_or_panic(v[127] == 3449); + assert_or_panic(v[128] == 3450); + assert_or_panic(v[129] == 3451); + assert_or_panic(v[130] == 3452); + assert_or_panic(v[131] == 3453); + assert_or_panic(v[132] == 3454); + assert_or_panic(v[133] == 3455); + assert_or_panic(v[134] == 3456); + assert_or_panic(v[135] == 3457); + assert_or_panic(v[136] == 3458); + assert_or_panic(v[137] == 3459); + assert_or_panic(v[138] == 3460); + assert_or_panic(v[139] == 3461); + assert_or_panic(v[140] == 3462); + assert_or_panic(v[141] == 3463); + assert_or_panic(v[142] == 3464); + assert_or_panic(v[143] == 3465); + assert_or_panic(v[144] == 3466); + assert_or_panic(v[145] == 3467); + assert_or_panic(v[146] == 3468); + assert_or_panic(v[147] == 3469); + assert_or_panic(v[148] == 3470); + assert_or_panic(v[149] == 3471); + assert_or_panic(v[150] == 3472); + assert_or_panic(v[151] == 3473); + assert_or_panic(v[152] == 3474); + assert_or_panic(v[153] == 3475); + assert_or_panic(v[154] == 3476); + assert_or_panic(v[155] == 3477); + assert_or_panic(v[156] == 3478); + assert_or_panic(v[157] == 3479); + assert_or_panic(v[158] == 3480); + assert_or_panic(v[159] == 3481); + assert_or_panic(v[160] == 3482); + assert_or_panic(v[161] == 3483); + assert_or_panic(v[162] == 3484); + assert_or_panic(v[163] == 3485); + assert_or_panic(v[164] == 3486); + assert_or_panic(v[165] == 3487); + assert_or_panic(v[166] == 3488); + assert_or_panic(v[167] == 3489); + assert_or_panic(v[168] == 3490); + assert_or_panic(v[169] == 3491); + assert_or_panic(v[170] == 3492); + assert_or_panic(v[171] == 3493); + assert_or_panic(v[172] == 3494); + assert_or_panic(v[173] == 3495); + assert_or_panic(v[174] == 3496); + assert_or_panic(v[175] == 3497); + assert_or_panic(v[176] == 3498); + assert_or_panic(v[177] == 3499); + assert_or_panic(v[178] == 3500); + assert_or_panic(v[179] == 3501); + assert_or_panic(v[180] == 3502); + assert_or_panic(v[181] == 3503); + assert_or_panic(v[182] == 3504); + assert_or_panic(v[183] == 3505); + assert_or_panic(v[184] == 3506); + assert_or_panic(v[185] == 3507); + assert_or_panic(v[186] == 3508); + assert_or_panic(v[187] == 3509); + assert_or_panic(v[188] == 3510); + assert_or_panic(v[189] == 3511); + assert_or_panic(v[190] == 3512); + assert_or_panic(v[191] == 3513); + assert_or_panic(v[192] == 3514); + assert_or_panic(v[193] == 3515); + assert_or_panic(v[194] == 3516); + assert_or_panic(v[195] == 3517); + assert_or_panic(v[196] == 3518); + assert_or_panic(v[197] == 3519); + assert_or_panic(v[198] == 3520); + assert_or_panic(v[199] == 3521); + assert_or_panic(v[200] == 3522); + assert_or_panic(v[201] == 3523); + assert_or_panic(v[202] == 3524); + assert_or_panic(v[203] == 3525); + assert_or_panic(v[204] == 3526); + assert_or_panic(v[205] == 3527); + assert_or_panic(v[206] == 3528); + assert_or_panic(v[207] == 3529); + assert_or_panic(v[208] == 3530); + assert_or_panic(v[209] == 3531); + assert_or_panic(v[210] == 3532); + assert_or_panic(v[211] == 3533); + assert_or_panic(v[212] == 3534); + assert_or_panic(v[213] == 3535); + assert_or_panic(v[214] == 3536); + assert_or_panic(v[215] == 3537); + assert_or_panic(v[216] == 3538); + assert_or_panic(v[217] == 3539); + assert_or_panic(v[218] == 3540); + assert_or_panic(v[219] == 3541); + assert_or_panic(v[220] == 3542); + assert_or_panic(v[221] == 3543); + assert_or_panic(v[222] == 3544); + assert_or_panic(v[223] == 3545); + assert_or_panic(v[224] == 3546); + assert_or_panic(v[225] == 3547); + assert_or_panic(v[226] == 3548); + assert_or_panic(v[227] == 3549); + assert_or_panic(v[228] == 3550); + assert_or_panic(v[229] == 3551); + assert_or_panic(v[230] == 3552); + assert_or_panic(v[231] == 3553); + assert_or_panic(v[232] == 3554); + assert_or_panic(v[233] == 3555); + assert_or_panic(v[234] == 3556); + assert_or_panic(v[235] == 3557); + assert_or_panic(v[236] == 3558); + assert_or_panic(v[237] == 3559); + assert_or_panic(v[238] == 3560); + assert_or_panic(v[239] == 3561); + assert_or_panic(v[240] == 3562); + assert_or_panic(v[241] == 3563); + assert_or_panic(v[242] == 3564); + assert_or_panic(v[243] == 3565); + assert_or_panic(v[244] == 3566); + assert_or_panic(v[245] == 3567); + assert_or_panic(v[246] == 3568); + assert_or_panic(v[247] == 3569); + assert_or_panic(v[248] == 3570); + assert_or_panic(v[249] == 3571); + assert_or_panic(v[250] == 3572); + assert_or_panic(v[251] == 3573); + assert_or_panic(v[252] == 3574); + assert_or_panic(v[253] == 3575); + assert_or_panic(v[254] == 3576); + assert_or_panic(v[255] == 3577); + assert_or_panic(i == 256); +} +void c_test_vector_256_u16(void) { + Vector_256_u16 v = zig_ret_vector_256_u16(); + assert_or_panic(v[0] == 2554); + assert_or_panic(v[1] == 2555); + assert_or_panic(v[2] == 2556); + assert_or_panic(v[3] == 2557); + assert_or_panic(v[4] == 2558); + assert_or_panic(v[5] == 2559); + assert_or_panic(v[6] == 2560); + assert_or_panic(v[7] == 2561); + assert_or_panic(v[8] == 2562); + assert_or_panic(v[9] == 2563); + assert_or_panic(v[10] == 2564); + assert_or_panic(v[11] == 2565); + assert_or_panic(v[12] == 2566); + assert_or_panic(v[13] == 2567); + assert_or_panic(v[14] == 2568); + assert_or_panic(v[15] == 2569); + assert_or_panic(v[16] == 2570); + assert_or_panic(v[17] == 2571); + assert_or_panic(v[18] == 2572); + assert_or_panic(v[19] == 2573); + assert_or_panic(v[20] == 2574); + assert_or_panic(v[21] == 2575); + assert_or_panic(v[22] == 2576); + assert_or_panic(v[23] == 2577); + assert_or_panic(v[24] == 2578); + assert_or_panic(v[25] == 2579); + assert_or_panic(v[26] == 2580); + assert_or_panic(v[27] == 2581); + assert_or_panic(v[28] == 2582); + assert_or_panic(v[29] == 2583); + assert_or_panic(v[30] == 2584); + assert_or_panic(v[31] == 2585); + assert_or_panic(v[32] == 2586); + assert_or_panic(v[33] == 2587); + assert_or_panic(v[34] == 2588); + assert_or_panic(v[35] == 2589); + assert_or_panic(v[36] == 2590); + assert_or_panic(v[37] == 2591); + assert_or_panic(v[38] == 2592); + assert_or_panic(v[39] == 2593); + assert_or_panic(v[40] == 2594); + assert_or_panic(v[41] == 2595); + assert_or_panic(v[42] == 2596); + assert_or_panic(v[43] == 2597); + assert_or_panic(v[44] == 2598); + assert_or_panic(v[45] == 2599); + assert_or_panic(v[46] == 2600); + assert_or_panic(v[47] == 2601); + assert_or_panic(v[48] == 2602); + assert_or_panic(v[49] == 2603); + assert_or_panic(v[50] == 2604); + assert_or_panic(v[51] == 2605); + assert_or_panic(v[52] == 2606); + assert_or_panic(v[53] == 2607); + assert_or_panic(v[54] == 2608); + assert_or_panic(v[55] == 2609); + assert_or_panic(v[56] == 2610); + assert_or_panic(v[57] == 2611); + assert_or_panic(v[58] == 2612); + assert_or_panic(v[59] == 2613); + assert_or_panic(v[60] == 2614); + assert_or_panic(v[61] == 2615); + assert_or_panic(v[62] == 2616); + assert_or_panic(v[63] == 2617); + assert_or_panic(v[64] == 2618); + assert_or_panic(v[65] == 2619); + assert_or_panic(v[66] == 2620); + assert_or_panic(v[67] == 2621); + assert_or_panic(v[68] == 2622); + assert_or_panic(v[69] == 2623); + assert_or_panic(v[70] == 2624); + assert_or_panic(v[71] == 2625); + assert_or_panic(v[72] == 2626); + assert_or_panic(v[73] == 2627); + assert_or_panic(v[74] == 2628); + assert_or_panic(v[75] == 2629); + assert_or_panic(v[76] == 2630); + assert_or_panic(v[77] == 2631); + assert_or_panic(v[78] == 2632); + assert_or_panic(v[79] == 2633); + assert_or_panic(v[80] == 2634); + assert_or_panic(v[81] == 2635); + assert_or_panic(v[82] == 2636); + assert_or_panic(v[83] == 2637); + assert_or_panic(v[84] == 2638); + assert_or_panic(v[85] == 2639); + assert_or_panic(v[86] == 2640); + assert_or_panic(v[87] == 2641); + assert_or_panic(v[88] == 2642); + assert_or_panic(v[89] == 2643); + assert_or_panic(v[90] == 2644); + assert_or_panic(v[91] == 2645); + assert_or_panic(v[92] == 2646); + assert_or_panic(v[93] == 2647); + assert_or_panic(v[94] == 2648); + assert_or_panic(v[95] == 2649); + assert_or_panic(v[96] == 2650); + assert_or_panic(v[97] == 2651); + assert_or_panic(v[98] == 2652); + assert_or_panic(v[99] == 2653); + assert_or_panic(v[100] == 2654); + assert_or_panic(v[101] == 2655); + assert_or_panic(v[102] == 2656); + assert_or_panic(v[103] == 2657); + assert_or_panic(v[104] == 2658); + assert_or_panic(v[105] == 2659); + assert_or_panic(v[106] == 2660); + assert_or_panic(v[107] == 2661); + assert_or_panic(v[108] == 2662); + assert_or_panic(v[109] == 2663); + assert_or_panic(v[110] == 2664); + assert_or_panic(v[111] == 2665); + assert_or_panic(v[112] == 2666); + assert_or_panic(v[113] == 2667); + assert_or_panic(v[114] == 2668); + assert_or_panic(v[115] == 2669); + assert_or_panic(v[116] == 2670); + assert_or_panic(v[117] == 2671); + assert_or_panic(v[118] == 2672); + assert_or_panic(v[119] == 2673); + assert_or_panic(v[120] == 2674); + assert_or_panic(v[121] == 2675); + assert_or_panic(v[122] == 2676); + assert_or_panic(v[123] == 2677); + assert_or_panic(v[124] == 2678); + assert_or_panic(v[125] == 2679); + assert_or_panic(v[126] == 2680); + assert_or_panic(v[127] == 2681); + assert_or_panic(v[128] == 2682); + assert_or_panic(v[129] == 2683); + assert_or_panic(v[130] == 2684); + assert_or_panic(v[131] == 2685); + assert_or_panic(v[132] == 2686); + assert_or_panic(v[133] == 2687); + assert_or_panic(v[134] == 2688); + assert_or_panic(v[135] == 2689); + assert_or_panic(v[136] == 2690); + assert_or_panic(v[137] == 2691); + assert_or_panic(v[138] == 2692); + assert_or_panic(v[139] == 2693); + assert_or_panic(v[140] == 2694); + assert_or_panic(v[141] == 2695); + assert_or_panic(v[142] == 2696); + assert_or_panic(v[143] == 2697); + assert_or_panic(v[144] == 2698); + assert_or_panic(v[145] == 2699); + assert_or_panic(v[146] == 2700); + assert_or_panic(v[147] == 2701); + assert_or_panic(v[148] == 2702); + assert_or_panic(v[149] == 2703); + assert_or_panic(v[150] == 2704); + assert_or_panic(v[151] == 2705); + assert_or_panic(v[152] == 2706); + assert_or_panic(v[153] == 2707); + assert_or_panic(v[154] == 2708); + assert_or_panic(v[155] == 2709); + assert_or_panic(v[156] == 2710); + assert_or_panic(v[157] == 2711); + assert_or_panic(v[158] == 2712); + assert_or_panic(v[159] == 2713); + assert_or_panic(v[160] == 2714); + assert_or_panic(v[161] == 2715); + assert_or_panic(v[162] == 2716); + assert_or_panic(v[163] == 2717); + assert_or_panic(v[164] == 2718); + assert_or_panic(v[165] == 2719); + assert_or_panic(v[166] == 2720); + assert_or_panic(v[167] == 2721); + assert_or_panic(v[168] == 2722); + assert_or_panic(v[169] == 2723); + assert_or_panic(v[170] == 2724); + assert_or_panic(v[171] == 2725); + assert_or_panic(v[172] == 2726); + assert_or_panic(v[173] == 2727); + assert_or_panic(v[174] == 2728); + assert_or_panic(v[175] == 2729); + assert_or_panic(v[176] == 2730); + assert_or_panic(v[177] == 2731); + assert_or_panic(v[178] == 2732); + assert_or_panic(v[179] == 2733); + assert_or_panic(v[180] == 2734); + assert_or_panic(v[181] == 2735); + assert_or_panic(v[182] == 2736); + assert_or_panic(v[183] == 2737); + assert_or_panic(v[184] == 2738); + assert_or_panic(v[185] == 2739); + assert_or_panic(v[186] == 2740); + assert_or_panic(v[187] == 2741); + assert_or_panic(v[188] == 2742); + assert_or_panic(v[189] == 2743); + assert_or_panic(v[190] == 2744); + assert_or_panic(v[191] == 2745); + assert_or_panic(v[192] == 2746); + assert_or_panic(v[193] == 2747); + assert_or_panic(v[194] == 2748); + assert_or_panic(v[195] == 2749); + assert_or_panic(v[196] == 2750); + assert_or_panic(v[197] == 2751); + assert_or_panic(v[198] == 2752); + assert_or_panic(v[199] == 2753); + assert_or_panic(v[200] == 2754); + assert_or_panic(v[201] == 2755); + assert_or_panic(v[202] == 2756); + assert_or_panic(v[203] == 2757); + assert_or_panic(v[204] == 2758); + assert_or_panic(v[205] == 2759); + assert_or_panic(v[206] == 2760); + assert_or_panic(v[207] == 2761); + assert_or_panic(v[208] == 2762); + assert_or_panic(v[209] == 2763); + assert_or_panic(v[210] == 2764); + assert_or_panic(v[211] == 2765); + assert_or_panic(v[212] == 2766); + assert_or_panic(v[213] == 2767); + assert_or_panic(v[214] == 2768); + assert_or_panic(v[215] == 2769); + assert_or_panic(v[216] == 2770); + assert_or_panic(v[217] == 2771); + assert_or_panic(v[218] == 2772); + assert_or_panic(v[219] == 2773); + assert_or_panic(v[220] == 2774); + assert_or_panic(v[221] == 2775); + assert_or_panic(v[222] == 2776); + assert_or_panic(v[223] == 2777); + assert_or_panic(v[224] == 2778); + assert_or_panic(v[225] == 2779); + assert_or_panic(v[226] == 2780); + assert_or_panic(v[227] == 2781); + assert_or_panic(v[228] == 2782); + assert_or_panic(v[229] == 2783); + assert_or_panic(v[230] == 2784); + assert_or_panic(v[231] == 2785); + assert_or_panic(v[232] == 2786); + assert_or_panic(v[233] == 2787); + assert_or_panic(v[234] == 2788); + assert_or_panic(v[235] == 2789); + assert_or_panic(v[236] == 2790); + assert_or_panic(v[237] == 2791); + assert_or_panic(v[238] == 2792); + assert_or_panic(v[239] == 2793); + assert_or_panic(v[240] == 2794); + assert_or_panic(v[241] == 2795); + assert_or_panic(v[242] == 2796); + assert_or_panic(v[243] == 2797); + assert_or_panic(v[244] == 2798); + assert_or_panic(v[245] == 2799); + assert_or_panic(v[246] == 2800); + assert_or_panic(v[247] == 2801); + assert_or_panic(v[248] == 2802); + assert_or_panic(v[249] == 2803); + assert_or_panic(v[250] == 2804); + assert_or_panic(v[251] == 2805); + assert_or_panic(v[252] == 2806); + assert_or_panic(v[253] == 2807); + assert_or_panic(v[254] == 2808); + assert_or_panic(v[255] == 2809); + zig_vector_256_u16((Vector_256_u16){ + 2810, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2824, 2825, + 2826, 2827, 2828, 2829, 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2840, 2841, + 2842, 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855, 2856, 2857, + 2858, 2859, 2860, 2861, 2862, 2863, 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, + 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889, + 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2900, 2901, 2902, 2903, 2904, 2905, + 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, 2920, 2921, + 2922, 2923, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 2934, 2935, 2936, 2937, + 2938, 2939, 2940, 2941, 2942, 2943, 2944, 2945, 2946, 2947, 2948, 2949, 2950, 2951, 2952, 2953, + 2954, 2955, 2956, 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968, 2969, + 2970, 2971, 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982, 2983, 2984, 2985, + 2986, 2987, 2988, 2989, 2990, 2991, 2992, 2993, 2994, 2995, 2996, 2997, 2998, 2999, 3000, 3001, + 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, + 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3028, 3029, 3030, 3031, 3032, 3033, + 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049, + 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064, 3065, + }, 256); +} + +typedef uint32_t Vector_1_u32 __attribute__((vector_size(1 * sizeof(uint32_t)))); + +Vector_1_u32 zig_ret_vector_1_u32(void); +void zig_vector_1_u32(Vector_1_u32, size_t); + +Vector_1_u32 c_ret_vector_1_u32(void) { + return (Vector_1_u32){ 3 }; +} +void c_vector_1_u32(Vector_1_u32 v, size_t i) { + assert_or_panic(v[0] == 4); + assert_or_panic(i == 1); +} +void c_test_vector_1_u32(void) { + Vector_1_u32 v = zig_ret_vector_1_u32(); + assert_or_panic(v[0] == 1); + zig_vector_1_u32((Vector_1_u32){ 2 }, 1); +} + +typedef uint32_t Vector_2_u32 __attribute__((vector_size(2 * sizeof(uint32_t)))); + +Vector_2_u32 zig_ret_vector_2_u32(void); +void zig_vector_2_u32(Vector_2_u32, size_t); + +Vector_2_u32 c_ret_vector_2_u32(void) { + return (Vector_2_u32){ 9, 10 }; +} +void c_vector_2_u32(Vector_2_u32 v, size_t i) { + assert_or_panic(v[0] == 11); + assert_or_panic(v[1] == 12); + assert_or_panic(i == 2); +} +void c_test_vector_2_u32(void) { + Vector_2_u32 v = zig_ret_vector_2_u32(); + assert_or_panic(v[0] == 5); + assert_or_panic(v[1] == 6); + zig_vector_2_u32((Vector_2_u32){ 7, 8 }, 2); +} + +typedef uint32_t Vector_3_u32 __attribute__((vector_size(3 * sizeof(uint32_t)))); + +Vector_3_u32 zig_ret_vector_3_u32(void); +void zig_vector_3_u32(Vector_3_u32, size_t); + +Vector_3_u32 c_ret_vector_3_u32(void) { + return (Vector_3_u32){ 19, 20, 21 }; +} +void c_vector_3_u32(Vector_3_u32 v, size_t i) { + assert_or_panic(v[0] == 22); + assert_or_panic(v[1] == 23); + assert_or_panic(v[2] == 24); + assert_or_panic(i == 3); +} +void c_test_vector_3_u32(void) { + Vector_3_u32 v = zig_ret_vector_3_u32(); + assert_or_panic(v[0] == 13); + assert_or_panic(v[1] == 14); + assert_or_panic(v[2] == 15); + zig_vector_3_u32((Vector_3_u32){ 16, 17, 18 }, 3); +} + +typedef uint32_t Vector_4_u32 __attribute__((vector_size(4 * sizeof(uint32_t)))); + +Vector_4_u32 zig_ret_vector_4_u32(void); + +void zig_vector_4_u32(Vector_4_u32, size_t); +void zig_vector_4_u32_vector_4_u32(Vector_4_u32, Vector_4_u32, size_t); + +Vector_4_u32 c_ret_vector_4_u32(void) { + return (Vector_4_u32){ 41, 42, 43, 44 }; +} +void c_vector_4_u32(Vector_4_u32 v, size_t i) { + assert_or_panic(v[0] == 45); + assert_or_panic(v[1] == 46); + assert_or_panic(v[2] == 47); + assert_or_panic(v[3] == 48); + assert_or_panic(i == 4); +} +void c_vector_4_u32_vector_4_u32(Vector_4_u32 v0, Vector_4_u32 v1, size_t i) { + assert_or_panic(v0[0] == 49); + assert_or_panic(v0[1] == 50); + assert_or_panic(v0[2] == 51); + assert_or_panic(v0[3] == 52); + assert_or_panic(v1[0] == 53); + assert_or_panic(v1[1] == 54); + assert_or_panic(v1[2] == 55); + assert_or_panic(v1[3] == 56); + assert_or_panic(i == 8); +} +void c_test_vector_4_u32(void) { + Vector_4_u32 v = zig_ret_vector_4_u32(); + assert_or_panic(v[0] == 25); + assert_or_panic(v[1] == 26); + assert_or_panic(v[2] == 27); + assert_or_panic(v[3] == 28); + zig_vector_4_u32((Vector_4_u32){ 29, 30, 31, 32 }, 4); + zig_vector_4_u32_vector_4_u32((Vector_4_u32){ 33, 34, 35, 36 }, (Vector_4_u32){ 37, 38, 39, 40 }, 8); +} + +typedef uint32_t Vector_6_u32 __attribute__((vector_size(6 * sizeof(uint32_t)))); + +Vector_6_u32 zig_ret_vector_6_u32(void); +void zig_vector_6_u32(Vector_6_u32, size_t); + +Vector_6_u32 c_ret_vector_6_u32(void) { + return (Vector_6_u32){ 53, 54, 55, 56, 57, 58 }; +} +void c_vector_6_u32(Vector_6_u32 v, size_t i) { + assert_or_panic(v[0] == 59); + assert_or_panic(v[1] == 60); + assert_or_panic(v[2] == 61); + assert_or_panic(v[3] == 62); + assert_or_panic(v[4] == 63); + assert_or_panic(v[5] == 64); + assert_or_panic(i == 6); +} +void c_test_vector_6_u32(void) { + Vector_6_u32 v = zig_ret_vector_6_u32(); + assert_or_panic(v[0] == 41); + assert_or_panic(v[1] == 42); + assert_or_panic(v[2] == 43); + assert_or_panic(v[3] == 44); + assert_or_panic(v[4] == 45); + assert_or_panic(v[5] == 46); + zig_vector_6_u32((Vector_6_u32){ 47, 48, 49, 50, 51, 52 }, 6); +} + +typedef uint32_t Vector_8_u32 __attribute__((vector_size(8 * sizeof(uint32_t)))); + +Vector_8_u32 zig_ret_vector_8_u32(void); +void zig_vector_8_u32(Vector_8_u32, size_t); + +Vector_8_u32 c_ret_vector_8_u32(void) { + return (Vector_8_u32){ 81, 82, 83, 84, 85, 86, 87, 88 }; +} +void c_vector_8_u32(Vector_8_u32 v, size_t i) { + assert_or_panic(v[0] == 89); + assert_or_panic(v[1] == 90); + assert_or_panic(v[2] == 91); + assert_or_panic(v[3] == 92); + assert_or_panic(v[4] == 93); + assert_or_panic(v[5] == 94); + assert_or_panic(v[6] == 95); + assert_or_panic(v[7] == 96); + assert_or_panic(i == 8); +} +void c_test_vector_8_u32(void) { + Vector_8_u32 v = zig_ret_vector_8_u32(); + assert_or_panic(v[0] == 65); + assert_or_panic(v[1] == 66); + assert_or_panic(v[2] == 67); + assert_or_panic(v[3] == 68); + assert_or_panic(v[4] == 69); + assert_or_panic(v[5] == 70); + assert_or_panic(v[6] == 71); + assert_or_panic(v[7] == 72); + zig_vector_8_u32((Vector_8_u32){ 73, 74, 75, 76, 77, 78, 79, 80 }, 8); +} + +typedef uint32_t Vector_12_u32 __attribute__((vector_size(12 * sizeof(uint32_t)))); + +Vector_12_u32 zig_ret_vector_12_u32(void); +void zig_vector_12_u32(Vector_12_u32, size_t); + +Vector_12_u32 c_ret_vector_12_u32(void) { + return (Vector_12_u32){ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132 }; +} +void c_vector_12_u32(Vector_12_u32 v, size_t i) { + assert_or_panic(v[0] == 133); + assert_or_panic(v[1] == 134); + assert_or_panic(v[2] == 135); + assert_or_panic(v[3] == 136); + assert_or_panic(v[4] == 137); + assert_or_panic(v[5] == 138); + assert_or_panic(v[6] == 139); + assert_or_panic(v[7] == 140); + assert_or_panic(v[8] == 141); + assert_or_panic(v[9] == 142); + assert_or_panic(v[10] == 143); + assert_or_panic(v[11] == 144); + assert_or_panic(i == 12); +} +void c_test_vector_12_u32(void) { + Vector_12_u32 v = zig_ret_vector_12_u32(); + assert_or_panic(v[0] == 97); + assert_or_panic(v[1] == 98); + assert_or_panic(v[2] == 99); + assert_or_panic(v[3] == 100); + assert_or_panic(v[4] == 101); + assert_or_panic(v[5] == 102); + assert_or_panic(v[6] == 103); + assert_or_panic(v[7] == 104); + assert_or_panic(v[8] == 105); + assert_or_panic(v[9] == 106); + assert_or_panic(v[10] == 107); + assert_or_panic(v[11] == 108); + zig_vector_12_u32((Vector_12_u32){ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 }, 12); +} + +typedef uint32_t Vector_16_u32 __attribute__((vector_size(16 * sizeof(uint32_t)))); + +Vector_16_u32 zig_ret_vector_16_u32(void); +void zig_vector_16_u32(Vector_16_u32, size_t); + +Vector_16_u32 c_ret_vector_16_u32(void) { + return (Vector_16_u32){ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192 }; +} +void c_vector_16_u32(Vector_16_u32 v, size_t i) { + assert_or_panic(v[0] == 193); + assert_or_panic(v[1] == 194); + assert_or_panic(v[2] == 195); + assert_or_panic(v[3] == 196); + assert_or_panic(v[4] == 197); + assert_or_panic(v[5] == 198); + assert_or_panic(v[6] == 199); + assert_or_panic(v[7] == 200); + assert_or_panic(v[8] == 201); + assert_or_panic(v[9] == 202); + assert_or_panic(v[10] == 203); + assert_or_panic(v[11] == 204); + assert_or_panic(v[12] == 205); + assert_or_panic(v[13] == 206); + assert_or_panic(v[14] == 207); + assert_or_panic(v[15] == 208); + assert_or_panic(i == 16); +} +void c_test_vector_16_u32(void) { + Vector_16_u32 v = zig_ret_vector_16_u32(); + assert_or_panic(v[0] == 145); + assert_or_panic(v[1] == 146); + assert_or_panic(v[2] == 147); + assert_or_panic(v[3] == 148); + assert_or_panic(v[4] == 149); + assert_or_panic(v[5] == 150); + assert_or_panic(v[6] == 151); + assert_or_panic(v[7] == 152); + assert_or_panic(v[8] == 153); + assert_or_panic(v[9] == 154); + assert_or_panic(v[10] == 155); + assert_or_panic(v[11] == 156); + assert_or_panic(v[12] == 157); + assert_or_panic(v[13] == 158); + assert_or_panic(v[14] == 159); + assert_or_panic(v[15] == 160); + zig_vector_16_u32((Vector_16_u32){ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176 }, 16); +} + +typedef uint32_t Vector_24_u32 __attribute__((vector_size(24 * sizeof(uint32_t)))); + +Vector_24_u32 zig_ret_vector_24_u32(void); +void zig_vector_24_u32(Vector_24_u32, size_t); + +Vector_24_u32 c_ret_vector_24_u32(void) { + return (Vector_24_u32){ + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + }; +} +void c_vector_24_u32(Vector_24_u32 v, size_t i) { + assert_or_panic(v[0] == 281); + assert_or_panic(v[1] == 282); + assert_or_panic(v[2] == 283); + assert_or_panic(v[3] == 284); + assert_or_panic(v[4] == 285); + assert_or_panic(v[5] == 286); + assert_or_panic(v[6] == 287); + assert_or_panic(v[7] == 288); + assert_or_panic(v[8] == 289); + assert_or_panic(v[9] == 290); + assert_or_panic(v[10] == 291); + assert_or_panic(v[11] == 292); + assert_or_panic(v[12] == 293); + assert_or_panic(v[13] == 294); + assert_or_panic(v[14] == 295); + assert_or_panic(v[15] == 296); + assert_or_panic(v[16] == 297); + assert_or_panic(v[17] == 298); + assert_or_panic(v[18] == 299); + assert_or_panic(v[19] == 300); + assert_or_panic(v[20] == 301); + assert_or_panic(v[21] == 302); + assert_or_panic(v[22] == 303); + assert_or_panic(v[23] == 304); + assert_or_panic(i == 24); +} +void c_test_vector_24_u32(void) { + Vector_24_u32 v = zig_ret_vector_24_u32(); + assert_or_panic(v[0] == 209); + assert_or_panic(v[1] == 210); + assert_or_panic(v[2] == 211); + assert_or_panic(v[3] == 212); + assert_or_panic(v[4] == 213); + assert_or_panic(v[5] == 214); + assert_or_panic(v[6] == 215); + assert_or_panic(v[7] == 216); + assert_or_panic(v[8] == 217); + assert_or_panic(v[9] == 218); + assert_or_panic(v[10] == 219); + assert_or_panic(v[11] == 220); + assert_or_panic(v[12] == 221); + assert_or_panic(v[13] == 222); + assert_or_panic(v[14] == 223); + assert_or_panic(v[15] == 224); + assert_or_panic(v[16] == 225); + assert_or_panic(v[17] == 226); + assert_or_panic(v[18] == 227); + assert_or_panic(v[19] == 228); + assert_or_panic(v[20] == 229); + assert_or_panic(v[21] == 230); + assert_or_panic(v[22] == 231); + assert_or_panic(v[23] == 232); + zig_vector_24_u32((Vector_24_u32){ + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, + }, 24); +} + +typedef uint32_t Vector_32_u32 __attribute__((vector_size(32 * sizeof(uint32_t)))); + +Vector_32_u32 zig_ret_vector_32_u32(void); +void zig_vector_32_u32(Vector_32_u32, size_t); + +Vector_32_u32 c_ret_vector_32_u32(void) { + return (Vector_32_u32){ + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + }; +} +void c_vector_32_u32(Vector_32_u32 v, size_t i) { + assert_or_panic(v[0] == 401); + assert_or_panic(v[1] == 402); + assert_or_panic(v[2] == 403); + assert_or_panic(v[3] == 404); + assert_or_panic(v[4] == 405); + assert_or_panic(v[5] == 406); + assert_or_panic(v[6] == 407); + assert_or_panic(v[7] == 408); + assert_or_panic(v[8] == 409); + assert_or_panic(v[9] == 410); + assert_or_panic(v[10] == 411); + assert_or_panic(v[11] == 412); + assert_or_panic(v[12] == 413); + assert_or_panic(v[13] == 414); + assert_or_panic(v[14] == 415); + assert_or_panic(v[15] == 416); + assert_or_panic(v[16] == 417); + assert_or_panic(v[17] == 418); + assert_or_panic(v[18] == 419); + assert_or_panic(v[19] == 420); + assert_or_panic(v[20] == 421); + assert_or_panic(v[21] == 422); + assert_or_panic(v[22] == 423); + assert_or_panic(v[23] == 424); + assert_or_panic(v[24] == 425); + assert_or_panic(v[25] == 426); + assert_or_panic(v[26] == 427); + assert_or_panic(v[27] == 428); + assert_or_panic(v[28] == 429); + assert_or_panic(v[29] == 430); + assert_or_panic(v[30] == 431); + assert_or_panic(v[31] == 432); + assert_or_panic(i == 32); +} +void c_test_vector_32_u32(void) { + Vector_32_u32 v = zig_ret_vector_32_u32(); + assert_or_panic(v[0] == 305); + assert_or_panic(v[1] == 306); + assert_or_panic(v[2] == 307); + assert_or_panic(v[3] == 308); + assert_or_panic(v[4] == 309); + assert_or_panic(v[5] == 310); + assert_or_panic(v[6] == 311); + assert_or_panic(v[7] == 312); + assert_or_panic(v[8] == 313); + assert_or_panic(v[9] == 314); + assert_or_panic(v[10] == 315); + assert_or_panic(v[11] == 316); + assert_or_panic(v[12] == 317); + assert_or_panic(v[13] == 318); + assert_or_panic(v[14] == 319); + assert_or_panic(v[15] == 320); + assert_or_panic(v[16] == 321); + assert_or_panic(v[17] == 322); + assert_or_panic(v[18] == 323); + assert_or_panic(v[19] == 324); + assert_or_panic(v[20] == 325); + assert_or_panic(v[21] == 326); + assert_or_panic(v[22] == 327); + assert_or_panic(v[23] == 328); + assert_or_panic(v[24] == 329); + assert_or_panic(v[25] == 330); + assert_or_panic(v[26] == 331); + assert_or_panic(v[27] == 332); + assert_or_panic(v[28] == 333); + assert_or_panic(v[29] == 334); + assert_or_panic(v[30] == 335); + assert_or_panic(v[31] == 336); + zig_vector_32_u32((Vector_32_u32){ + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + }, 32); +} + +typedef uint32_t Vector_48_u32 __attribute__((vector_size(48 * sizeof(uint32_t)))); + +Vector_48_u32 zig_ret_vector_48_u32(void); +void zig_vector_48_u32(Vector_48_u32, size_t); + +Vector_48_u32 c_ret_vector_48_u32(void) { + return (Vector_48_u32){ + 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, + 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, + }; +} +void c_vector_48_u32(Vector_48_u32 v, size_t i) { + assert_or_panic(v[0] == 577); + assert_or_panic(v[1] == 578); + assert_or_panic(v[2] == 579); + assert_or_panic(v[3] == 580); + assert_or_panic(v[4] == 581); + assert_or_panic(v[5] == 582); + assert_or_panic(v[6] == 583); + assert_or_panic(v[7] == 584); + assert_or_panic(v[8] == 585); + assert_or_panic(v[9] == 586); + assert_or_panic(v[10] == 587); + assert_or_panic(v[11] == 588); + assert_or_panic(v[12] == 589); + assert_or_panic(v[13] == 590); + assert_or_panic(v[14] == 591); + assert_or_panic(v[15] == 592); + assert_or_panic(v[16] == 593); + assert_or_panic(v[17] == 594); + assert_or_panic(v[18] == 595); + assert_or_panic(v[19] == 596); + assert_or_panic(v[20] == 597); + assert_or_panic(v[21] == 598); + assert_or_panic(v[22] == 599); + assert_or_panic(v[23] == 600); + assert_or_panic(v[24] == 601); + assert_or_panic(v[25] == 602); + assert_or_panic(v[26] == 603); + assert_or_panic(v[27] == 604); + assert_or_panic(v[28] == 605); + assert_or_panic(v[29] == 606); + assert_or_panic(v[30] == 607); + assert_or_panic(v[31] == 608); + assert_or_panic(v[32] == 609); + assert_or_panic(v[33] == 610); + assert_or_panic(v[34] == 611); + assert_or_panic(v[35] == 612); + assert_or_panic(v[36] == 613); + assert_or_panic(v[37] == 614); + assert_or_panic(v[38] == 615); + assert_or_panic(v[39] == 616); + assert_or_panic(v[40] == 617); + assert_or_panic(v[41] == 618); + assert_or_panic(v[42] == 619); + assert_or_panic(v[43] == 620); + assert_or_panic(v[44] == 621); + assert_or_panic(v[45] == 622); + assert_or_panic(v[46] == 623); + assert_or_panic(v[47] == 624); + assert_or_panic(i == 48); +} +void c_test_vector_48_u32(void) { + Vector_48_u32 v = zig_ret_vector_48_u32(); + assert_or_panic(v[0] == 433); + assert_or_panic(v[1] == 434); + assert_or_panic(v[2] == 435); + assert_or_panic(v[3] == 436); + assert_or_panic(v[4] == 437); + assert_or_panic(v[5] == 438); + assert_or_panic(v[6] == 439); + assert_or_panic(v[7] == 440); + assert_or_panic(v[8] == 441); + assert_or_panic(v[9] == 442); + assert_or_panic(v[10] == 443); + assert_or_panic(v[11] == 444); + assert_or_panic(v[12] == 445); + assert_or_panic(v[13] == 446); + assert_or_panic(v[14] == 447); + assert_or_panic(v[15] == 448); + assert_or_panic(v[16] == 449); + assert_or_panic(v[17] == 450); + assert_or_panic(v[18] == 451); + assert_or_panic(v[19] == 452); + assert_or_panic(v[20] == 453); + assert_or_panic(v[21] == 454); + assert_or_panic(v[22] == 455); + assert_or_panic(v[23] == 456); + assert_or_panic(v[24] == 457); + assert_or_panic(v[25] == 458); + assert_or_panic(v[26] == 459); + assert_or_panic(v[27] == 460); + assert_or_panic(v[28] == 461); + assert_or_panic(v[29] == 462); + assert_or_panic(v[30] == 463); + assert_or_panic(v[31] == 464); + assert_or_panic(v[32] == 465); + assert_or_panic(v[33] == 466); + assert_or_panic(v[34] == 467); + assert_or_panic(v[35] == 468); + assert_or_panic(v[36] == 469); + assert_or_panic(v[37] == 470); + assert_or_panic(v[38] == 471); + assert_or_panic(v[39] == 472); + assert_or_panic(v[40] == 473); + assert_or_panic(v[41] == 474); + assert_or_panic(v[42] == 475); + assert_or_panic(v[43] == 476); + assert_or_panic(v[44] == 477); + assert_or_panic(v[45] == 478); + assert_or_panic(v[46] == 479); + assert_or_panic(v[47] == 480); + zig_vector_48_u32((Vector_48_u32){ + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, + }, 48); +} + +typedef uint32_t Vector_64_u32 __attribute__((vector_size(64 * sizeof(uint32_t)))); + +Vector_64_u32 zig_ret_vector_64_u32(void); +void zig_vector_64_u32(Vector_64_u32, size_t); + +Vector_64_u32 c_ret_vector_64_u32(void) { + return (Vector_64_u32){ + 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, + 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, + }; +} +void c_vector_64_u32(Vector_64_u32 v, size_t i) { + assert_or_panic(v[0] == 817); + assert_or_panic(v[1] == 818); + assert_or_panic(v[2] == 819); + assert_or_panic(v[3] == 820); + assert_or_panic(v[4] == 821); + assert_or_panic(v[5] == 822); + assert_or_panic(v[6] == 823); + assert_or_panic(v[7] == 824); + assert_or_panic(v[8] == 825); + assert_or_panic(v[9] == 826); + assert_or_panic(v[10] == 827); + assert_or_panic(v[11] == 828); + assert_or_panic(v[12] == 829); + assert_or_panic(v[13] == 830); + assert_or_panic(v[14] == 831); + assert_or_panic(v[15] == 832); + assert_or_panic(v[16] == 833); + assert_or_panic(v[17] == 834); + assert_or_panic(v[18] == 835); + assert_or_panic(v[19] == 836); + assert_or_panic(v[20] == 837); + assert_or_panic(v[21] == 838); + assert_or_panic(v[22] == 839); + assert_or_panic(v[23] == 840); + assert_or_panic(v[24] == 841); + assert_or_panic(v[25] == 842); + assert_or_panic(v[26] == 843); + assert_or_panic(v[27] == 844); + assert_or_panic(v[28] == 845); + assert_or_panic(v[29] == 846); + assert_or_panic(v[30] == 847); + assert_or_panic(v[31] == 848); + assert_or_panic(v[32] == 849); + assert_or_panic(v[33] == 850); + assert_or_panic(v[34] == 851); + assert_or_panic(v[35] == 852); + assert_or_panic(v[36] == 853); + assert_or_panic(v[37] == 854); + assert_or_panic(v[38] == 855); + assert_or_panic(v[39] == 856); + assert_or_panic(v[40] == 857); + assert_or_panic(v[41] == 858); + assert_or_panic(v[42] == 859); + assert_or_panic(v[43] == 860); + assert_or_panic(v[44] == 861); + assert_or_panic(v[45] == 862); + assert_or_panic(v[46] == 863); + assert_or_panic(v[47] == 864); + assert_or_panic(v[48] == 865); + assert_or_panic(v[49] == 866); + assert_or_panic(v[50] == 867); + assert_or_panic(v[51] == 868); + assert_or_panic(v[52] == 869); + assert_or_panic(v[53] == 870); + assert_or_panic(v[54] == 871); + assert_or_panic(v[55] == 872); + assert_or_panic(v[56] == 873); + assert_or_panic(v[57] == 874); + assert_or_panic(v[58] == 875); + assert_or_panic(v[59] == 876); + assert_or_panic(v[60] == 877); + assert_or_panic(v[61] == 878); + assert_or_panic(v[62] == 879); + assert_or_panic(v[63] == 880); + assert_or_panic(i == 64); +} +void c_test_vector_64_u32(void) { + Vector_64_u32 v = zig_ret_vector_64_u32(); + assert_or_panic(v[0] == 625); + assert_or_panic(v[1] == 626); + assert_or_panic(v[2] == 627); + assert_or_panic(v[3] == 628); + assert_or_panic(v[4] == 629); + assert_or_panic(v[5] == 630); + assert_or_panic(v[6] == 631); + assert_or_panic(v[7] == 632); + assert_or_panic(v[8] == 633); + assert_or_panic(v[9] == 634); + assert_or_panic(v[10] == 635); + assert_or_panic(v[11] == 636); + assert_or_panic(v[12] == 637); + assert_or_panic(v[13] == 638); + assert_or_panic(v[14] == 639); + assert_or_panic(v[15] == 640); + assert_or_panic(v[16] == 641); + assert_or_panic(v[17] == 642); + assert_or_panic(v[18] == 643); + assert_or_panic(v[19] == 644); + assert_or_panic(v[20] == 645); + assert_or_panic(v[21] == 646); + assert_or_panic(v[22] == 647); + assert_or_panic(v[23] == 648); + assert_or_panic(v[24] == 649); + assert_or_panic(v[25] == 650); + assert_or_panic(v[26] == 651); + assert_or_panic(v[27] == 652); + assert_or_panic(v[28] == 653); + assert_or_panic(v[29] == 654); + assert_or_panic(v[30] == 655); + assert_or_panic(v[31] == 656); + assert_or_panic(v[32] == 657); + assert_or_panic(v[33] == 658); + assert_or_panic(v[34] == 659); + assert_or_panic(v[35] == 660); + assert_or_panic(v[36] == 661); + assert_or_panic(v[37] == 662); + assert_or_panic(v[38] == 663); + assert_or_panic(v[39] == 664); + assert_or_panic(v[40] == 665); + assert_or_panic(v[41] == 666); + assert_or_panic(v[42] == 667); + assert_or_panic(v[43] == 668); + assert_or_panic(v[44] == 669); + assert_or_panic(v[45] == 670); + assert_or_panic(v[46] == 671); + assert_or_panic(v[47] == 672); + assert_or_panic(v[48] == 673); + assert_or_panic(v[49] == 674); + assert_or_panic(v[50] == 675); + assert_or_panic(v[51] == 676); + assert_or_panic(v[52] == 677); + assert_or_panic(v[53] == 678); + assert_or_panic(v[54] == 679); + assert_or_panic(v[55] == 680); + assert_or_panic(v[56] == 681); + assert_or_panic(v[57] == 682); + assert_or_panic(v[58] == 683); + assert_or_panic(v[59] == 684); + assert_or_panic(v[60] == 685); + assert_or_panic(v[61] == 686); + assert_or_panic(v[62] == 687); + assert_or_panic(v[63] == 688); + zig_vector_64_u32((Vector_64_u32){ + 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, + 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, + }, 64); +} + +typedef uint32_t Vector_96_u32 __attribute__((vector_size(96 * sizeof(uint32_t)))); + +Vector_96_u32 zig_ret_vector_96_u32(void); +void zig_vector_96_u32(Vector_96_u32, size_t); + +Vector_96_u32 c_ret_vector_96_u32(void) { + return (Vector_96_u32){ + 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, + 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, + 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, + 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, + 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, + 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, + }; +} +void c_vector_96_u32(Vector_96_u32 v, size_t i) { + assert_or_panic(v[0] == 1178); + assert_or_panic(v[1] == 1179); + assert_or_panic(v[2] == 1180); + assert_or_panic(v[3] == 1181); + assert_or_panic(v[4] == 1182); + assert_or_panic(v[5] == 1183); + assert_or_panic(v[6] == 1184); + assert_or_panic(v[7] == 1185); + assert_or_panic(v[8] == 1186); + assert_or_panic(v[9] == 1187); + assert_or_panic(v[10] == 1188); + assert_or_panic(v[11] == 1189); + assert_or_panic(v[12] == 1190); + assert_or_panic(v[13] == 1191); + assert_or_panic(v[14] == 1192); + assert_or_panic(v[15] == 1193); + assert_or_panic(v[16] == 1194); + assert_or_panic(v[17] == 1195); + assert_or_panic(v[18] == 1196); + assert_or_panic(v[19] == 1197); + assert_or_panic(v[20] == 1198); + assert_or_panic(v[21] == 1199); + assert_or_panic(v[22] == 1200); + assert_or_panic(v[23] == 1201); + assert_or_panic(v[24] == 1202); + assert_or_panic(v[25] == 1203); + assert_or_panic(v[26] == 1204); + assert_or_panic(v[27] == 1205); + assert_or_panic(v[28] == 1206); + assert_or_panic(v[29] == 1207); + assert_or_panic(v[30] == 1208); + assert_or_panic(v[31] == 1209); + assert_or_panic(v[32] == 1210); + assert_or_panic(v[33] == 1211); + assert_or_panic(v[34] == 1212); + assert_or_panic(v[35] == 1213); + assert_or_panic(v[36] == 1214); + assert_or_panic(v[37] == 1215); + assert_or_panic(v[38] == 1216); + assert_or_panic(v[39] == 1217); + assert_or_panic(v[40] == 1218); + assert_or_panic(v[41] == 1219); + assert_or_panic(v[42] == 1220); + assert_or_panic(v[43] == 1221); + assert_or_panic(v[44] == 1222); + assert_or_panic(v[45] == 1223); + assert_or_panic(v[46] == 1224); + assert_or_panic(v[47] == 1225); + assert_or_panic(v[48] == 1226); + assert_or_panic(v[49] == 1227); + assert_or_panic(v[50] == 1228); + assert_or_panic(v[51] == 1229); + assert_or_panic(v[52] == 1230); + assert_or_panic(v[53] == 1231); + assert_or_panic(v[54] == 1232); + assert_or_panic(v[55] == 1233); + assert_or_panic(v[56] == 1234); + assert_or_panic(v[57] == 1235); + assert_or_panic(v[58] == 1236); + assert_or_panic(v[59] == 1237); + assert_or_panic(v[60] == 1238); + assert_or_panic(v[61] == 1239); + assert_or_panic(v[62] == 1240); + assert_or_panic(v[63] == 1241); + assert_or_panic(v[64] == 1242); + assert_or_panic(v[65] == 1243); + assert_or_panic(v[66] == 1244); + assert_or_panic(v[67] == 1245); + assert_or_panic(v[68] == 1246); + assert_or_panic(v[69] == 1247); + assert_or_panic(v[70] == 1248); + assert_or_panic(v[71] == 1249); + assert_or_panic(v[72] == 1250); + assert_or_panic(v[73] == 1251); + assert_or_panic(v[74] == 1252); + assert_or_panic(v[75] == 1253); + assert_or_panic(v[76] == 1254); + assert_or_panic(v[77] == 1255); + assert_or_panic(v[80] == 1258); + assert_or_panic(v[81] == 1259); + assert_or_panic(v[82] == 1260); + assert_or_panic(v[83] == 1261); + assert_or_panic(v[84] == 1262); + assert_or_panic(v[85] == 1263); + assert_or_panic(v[86] == 1264); + assert_or_panic(v[87] == 1265); + assert_or_panic(v[88] == 1266); + assert_or_panic(v[89] == 1267); + assert_or_panic(v[90] == 1268); + assert_or_panic(v[91] == 1269); + assert_or_panic(v[92] == 1270); + assert_or_panic(v[93] == 1271); + assert_or_panic(v[94] == 1272); + assert_or_panic(v[95] == 1273); + assert_or_panic(i == 96); +} +void c_test_vector_96_u32(void) { + Vector_96_u32 v = zig_ret_vector_96_u32(); + assert_or_panic(v[0] == 890); + assert_or_panic(v[1] == 891); + assert_or_panic(v[2] == 892); + assert_or_panic(v[3] == 893); + assert_or_panic(v[4] == 894); + assert_or_panic(v[5] == 895); + assert_or_panic(v[6] == 896); + assert_or_panic(v[7] == 897); + assert_or_panic(v[8] == 898); + assert_or_panic(v[9] == 899); + assert_or_panic(v[10] == 900); + assert_or_panic(v[11] == 901); + assert_or_panic(v[12] == 902); + assert_or_panic(v[13] == 903); + assert_or_panic(v[14] == 904); + assert_or_panic(v[15] == 905); + assert_or_panic(v[16] == 906); + assert_or_panic(v[17] == 907); + assert_or_panic(v[18] == 908); + assert_or_panic(v[19] == 909); + assert_or_panic(v[20] == 910); + assert_or_panic(v[21] == 911); + assert_or_panic(v[22] == 912); + assert_or_panic(v[23] == 913); + assert_or_panic(v[24] == 914); + assert_or_panic(v[25] == 915); + assert_or_panic(v[26] == 916); + assert_or_panic(v[27] == 917); + assert_or_panic(v[28] == 918); + assert_or_panic(v[29] == 919); + assert_or_panic(v[30] == 920); + assert_or_panic(v[31] == 921); + assert_or_panic(v[32] == 922); + assert_or_panic(v[33] == 923); + assert_or_panic(v[34] == 924); + assert_or_panic(v[35] == 925); + assert_or_panic(v[36] == 926); + assert_or_panic(v[37] == 927); + assert_or_panic(v[38] == 928); + assert_or_panic(v[39] == 929); + assert_or_panic(v[40] == 930); + assert_or_panic(v[41] == 931); + assert_or_panic(v[42] == 932); + assert_or_panic(v[43] == 933); + assert_or_panic(v[44] == 934); + assert_or_panic(v[45] == 935); + assert_or_panic(v[46] == 936); + assert_or_panic(v[47] == 937); + assert_or_panic(v[48] == 938); + assert_or_panic(v[49] == 939); + assert_or_panic(v[50] == 940); + assert_or_panic(v[51] == 941); + assert_or_panic(v[52] == 942); + assert_or_panic(v[53] == 943); + assert_or_panic(v[54] == 944); + assert_or_panic(v[55] == 945); + assert_or_panic(v[56] == 946); + assert_or_panic(v[57] == 947); + assert_or_panic(v[58] == 948); + assert_or_panic(v[59] == 949); + assert_or_panic(v[60] == 950); + assert_or_panic(v[61] == 951); + assert_or_panic(v[62] == 952); + assert_or_panic(v[63] == 953); + assert_or_panic(v[64] == 954); + assert_or_panic(v[65] == 955); + assert_or_panic(v[66] == 956); + assert_or_panic(v[67] == 957); + assert_or_panic(v[68] == 958); + assert_or_panic(v[69] == 959); + assert_or_panic(v[70] == 960); + assert_or_panic(v[71] == 961); + assert_or_panic(v[72] == 962); + assert_or_panic(v[73] == 963); + assert_or_panic(v[74] == 964); + assert_or_panic(v[75] == 965); + assert_or_panic(v[76] == 966); + assert_or_panic(v[77] == 967); + assert_or_panic(v[78] == 968); + assert_or_panic(v[79] == 969); + assert_or_panic(v[80] == 970); + assert_or_panic(v[81] == 971); + assert_or_panic(v[82] == 972); + assert_or_panic(v[83] == 973); + assert_or_panic(v[84] == 974); + assert_or_panic(v[85] == 975); + assert_or_panic(v[86] == 976); + assert_or_panic(v[87] == 977); + assert_or_panic(v[88] == 978); + assert_or_panic(v[89] == 979); + assert_or_panic(v[90] == 980); + assert_or_panic(v[91] == 981); + assert_or_panic(v[92] == 982); + assert_or_panic(v[93] == 983); + assert_or_panic(v[94] == 984); + assert_or_panic(v[95] == 985); + zig_vector_96_u32((Vector_96_u32){ + 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, + 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, + 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, + 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, + 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, + 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, + }, 96); +} + +typedef uint32_t Vector_128_u32 __attribute__((vector_size(128 * sizeof(uint32_t)))); + +Vector_128_u32 zig_ret_vector_128_u32(void); +void zig_vector_128_u32(Vector_128_u32, size_t); + +Vector_128_u32 c_ret_vector_128_u32(void) { + return (Vector_128_u32){ + 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, + 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, + 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, + 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, + 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, + 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, + 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, + 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, + }; +} +void c_vector_128_u32(Vector_128_u32 v, size_t i) { + assert_or_panic(v[0] == 1658); + assert_or_panic(v[1] == 1659); + assert_or_panic(v[2] == 1660); + assert_or_panic(v[3] == 1661); + assert_or_panic(v[4] == 1662); + assert_or_panic(v[5] == 1663); + assert_or_panic(v[6] == 1664); + assert_or_panic(v[7] == 1665); + assert_or_panic(v[8] == 1666); + assert_or_panic(v[9] == 1667); + assert_or_panic(v[10] == 1668); + assert_or_panic(v[11] == 1669); + assert_or_panic(v[12] == 1670); + assert_or_panic(v[13] == 1671); + assert_or_panic(v[14] == 1672); + assert_or_panic(v[15] == 1673); + assert_or_panic(v[16] == 1674); + assert_or_panic(v[17] == 1675); + assert_or_panic(v[18] == 1676); + assert_or_panic(v[19] == 1677); + assert_or_panic(v[20] == 1678); + assert_or_panic(v[21] == 1679); + assert_or_panic(v[22] == 1680); + assert_or_panic(v[23] == 1681); + assert_or_panic(v[24] == 1682); + assert_or_panic(v[25] == 1683); + assert_or_panic(v[26] == 1684); + assert_or_panic(v[27] == 1685); + assert_or_panic(v[28] == 1686); + assert_or_panic(v[29] == 1687); + assert_or_panic(v[30] == 1688); + assert_or_panic(v[31] == 1689); + assert_or_panic(v[32] == 1690); + assert_or_panic(v[33] == 1691); + assert_or_panic(v[34] == 1692); + assert_or_panic(v[35] == 1693); + assert_or_panic(v[36] == 1694); + assert_or_panic(v[37] == 1695); + assert_or_panic(v[38] == 1696); + assert_or_panic(v[39] == 1697); + assert_or_panic(v[40] == 1698); + assert_or_panic(v[41] == 1699); + assert_or_panic(v[42] == 1700); + assert_or_panic(v[43] == 1701); + assert_or_panic(v[44] == 1702); + assert_or_panic(v[45] == 1703); + assert_or_panic(v[46] == 1704); + assert_or_panic(v[47] == 1705); + assert_or_panic(v[48] == 1706); + assert_or_panic(v[49] == 1707); + assert_or_panic(v[50] == 1708); + assert_or_panic(v[51] == 1709); + assert_or_panic(v[52] == 1710); + assert_or_panic(v[53] == 1711); + assert_or_panic(v[54] == 1712); + assert_or_panic(v[55] == 1713); + assert_or_panic(v[56] == 1714); + assert_or_panic(v[57] == 1715); + assert_or_panic(v[58] == 1716); + assert_or_panic(v[59] == 1717); + assert_or_panic(v[60] == 1718); + assert_or_panic(v[61] == 1719); + assert_or_panic(v[62] == 1720); + assert_or_panic(v[63] == 1721); + assert_or_panic(v[64] == 1722); + assert_or_panic(v[65] == 1723); + assert_or_panic(v[66] == 1724); + assert_or_panic(v[67] == 1725); + assert_or_panic(v[68] == 1726); + assert_or_panic(v[69] == 1727); + assert_or_panic(v[70] == 1728); + assert_or_panic(v[71] == 1729); + assert_or_panic(v[72] == 1730); + assert_or_panic(v[73] == 1731); + assert_or_panic(v[74] == 1732); + assert_or_panic(v[75] == 1733); + assert_or_panic(v[76] == 1734); + assert_or_panic(v[77] == 1735); + assert_or_panic(v[78] == 1736); + assert_or_panic(v[79] == 1737); + assert_or_panic(v[80] == 1738); + assert_or_panic(v[81] == 1739); + assert_or_panic(v[82] == 1740); + assert_or_panic(v[83] == 1741); + assert_or_panic(v[84] == 1742); + assert_or_panic(v[85] == 1743); + assert_or_panic(v[86] == 1744); + assert_or_panic(v[87] == 1745); + assert_or_panic(v[88] == 1746); + assert_or_panic(v[89] == 1747); + assert_or_panic(v[90] == 1748); + assert_or_panic(v[91] == 1749); + assert_or_panic(v[92] == 1750); + assert_or_panic(v[93] == 1751); + assert_or_panic(v[94] == 1752); + assert_or_panic(v[95] == 1753); + assert_or_panic(v[96] == 1754); + assert_or_panic(v[97] == 1755); + assert_or_panic(v[98] == 1756); + assert_or_panic(v[99] == 1757); + assert_or_panic(v[100] == 1758); + assert_or_panic(v[101] == 1759); + assert_or_panic(v[102] == 1760); + assert_or_panic(v[103] == 1761); + assert_or_panic(v[104] == 1762); + assert_or_panic(v[105] == 1763); + assert_or_panic(v[106] == 1764); + assert_or_panic(v[107] == 1765); + assert_or_panic(v[108] == 1766); + assert_or_panic(v[109] == 1767); + assert_or_panic(v[110] == 1768); + assert_or_panic(v[111] == 1769); + assert_or_panic(v[112] == 1770); + assert_or_panic(v[113] == 1771); + assert_or_panic(v[114] == 1772); + assert_or_panic(v[115] == 1773); + assert_or_panic(v[116] == 1774); + assert_or_panic(v[117] == 1775); + assert_or_panic(v[118] == 1776); + assert_or_panic(v[119] == 1777); + assert_or_panic(v[120] == 1778); + assert_or_panic(v[121] == 1779); + assert_or_panic(v[122] == 1780); + assert_or_panic(v[123] == 1781); + assert_or_panic(v[124] == 1782); + assert_or_panic(v[125] == 1783); + assert_or_panic(v[126] == 1784); + assert_or_panic(v[127] == 1785); + assert_or_panic(i == 128); +} +void c_test_vector_128_u32(void) { + Vector_128_u32 v = zig_ret_vector_128_u32(); + assert_or_panic(v[0] == 1274); + assert_or_panic(v[1] == 1275); + assert_or_panic(v[2] == 1276); + assert_or_panic(v[3] == 1277); + assert_or_panic(v[4] == 1278); + assert_or_panic(v[5] == 1279); + assert_or_panic(v[6] == 1280); + assert_or_panic(v[7] == 1281); + assert_or_panic(v[8] == 1282); + assert_or_panic(v[9] == 1283); + assert_or_panic(v[10] == 1284); + assert_or_panic(v[11] == 1285); + assert_or_panic(v[12] == 1286); + assert_or_panic(v[13] == 1287); + assert_or_panic(v[14] == 1288); + assert_or_panic(v[15] == 1289); + assert_or_panic(v[16] == 1290); + assert_or_panic(v[17] == 1291); + assert_or_panic(v[18] == 1292); + assert_or_panic(v[19] == 1293); + assert_or_panic(v[20] == 1294); + assert_or_panic(v[21] == 1295); + assert_or_panic(v[22] == 1296); + assert_or_panic(v[23] == 1297); + assert_or_panic(v[24] == 1298); + assert_or_panic(v[25] == 1299); + assert_or_panic(v[26] == 1300); + assert_or_panic(v[27] == 1301); + assert_or_panic(v[28] == 1302); + assert_or_panic(v[29] == 1303); + assert_or_panic(v[30] == 1304); + assert_or_panic(v[31] == 1305); + assert_or_panic(v[32] == 1306); + assert_or_panic(v[33] == 1307); + assert_or_panic(v[34] == 1308); + assert_or_panic(v[35] == 1309); + assert_or_panic(v[36] == 1310); + assert_or_panic(v[37] == 1311); + assert_or_panic(v[38] == 1312); + assert_or_panic(v[39] == 1313); + assert_or_panic(v[40] == 1314); + assert_or_panic(v[41] == 1315); + assert_or_panic(v[42] == 1316); + assert_or_panic(v[43] == 1317); + assert_or_panic(v[44] == 1318); + assert_or_panic(v[45] == 1319); + assert_or_panic(v[46] == 1320); + assert_or_panic(v[47] == 1321); + assert_or_panic(v[48] == 1322); + assert_or_panic(v[49] == 1323); + assert_or_panic(v[50] == 1324); + assert_or_panic(v[51] == 1325); + assert_or_panic(v[52] == 1326); + assert_or_panic(v[53] == 1327); + assert_or_panic(v[54] == 1328); + assert_or_panic(v[55] == 1329); + assert_or_panic(v[56] == 1330); + assert_or_panic(v[57] == 1331); + assert_or_panic(v[58] == 1332); + assert_or_panic(v[59] == 1333); + assert_or_panic(v[60] == 1334); + assert_or_panic(v[61] == 1335); + assert_or_panic(v[62] == 1336); + assert_or_panic(v[63] == 1337); + assert_or_panic(v[64] == 1338); + assert_or_panic(v[65] == 1339); + assert_or_panic(v[66] == 1340); + assert_or_panic(v[67] == 1341); + assert_or_panic(v[68] == 1342); + assert_or_panic(v[69] == 1343); + assert_or_panic(v[70] == 1344); + assert_or_panic(v[71] == 1345); + assert_or_panic(v[72] == 1346); + assert_or_panic(v[73] == 1347); + assert_or_panic(v[74] == 1348); + assert_or_panic(v[75] == 1349); + assert_or_panic(v[76] == 1350); + assert_or_panic(v[77] == 1351); + assert_or_panic(v[78] == 1352); + assert_or_panic(v[79] == 1353); + assert_or_panic(v[80] == 1354); + assert_or_panic(v[81] == 1355); + assert_or_panic(v[82] == 1356); + assert_or_panic(v[83] == 1357); + assert_or_panic(v[84] == 1358); + assert_or_panic(v[85] == 1359); + assert_or_panic(v[86] == 1360); + assert_or_panic(v[87] == 1361); + assert_or_panic(v[88] == 1362); + assert_or_panic(v[89] == 1363); + assert_or_panic(v[90] == 1364); + assert_or_panic(v[91] == 1365); + assert_or_panic(v[92] == 1366); + assert_or_panic(v[93] == 1367); + assert_or_panic(v[94] == 1368); + assert_or_panic(v[95] == 1369); + assert_or_panic(v[96] == 1370); + assert_or_panic(v[97] == 1371); + assert_or_panic(v[98] == 1372); + assert_or_panic(v[99] == 1373); + assert_or_panic(v[100] == 1374); + assert_or_panic(v[101] == 1375); + assert_or_panic(v[102] == 1376); + assert_or_panic(v[103] == 1377); + assert_or_panic(v[104] == 1378); + assert_or_panic(v[105] == 1379); + assert_or_panic(v[106] == 1380); + assert_or_panic(v[107] == 1381); + assert_or_panic(v[108] == 1382); + assert_or_panic(v[109] == 1383); + assert_or_panic(v[110] == 1384); + assert_or_panic(v[111] == 1385); + assert_or_panic(v[112] == 1386); + assert_or_panic(v[113] == 1387); + assert_or_panic(v[114] == 1388); + assert_or_panic(v[115] == 1389); + assert_or_panic(v[116] == 1390); + assert_or_panic(v[117] == 1391); + assert_or_panic(v[118] == 1392); + assert_or_panic(v[119] == 1393); + assert_or_panic(v[120] == 1394); + assert_or_panic(v[121] == 1395); + assert_or_panic(v[122] == 1396); + assert_or_panic(v[123] == 1397); + assert_or_panic(v[124] == 1398); + assert_or_panic(v[125] == 1399); + assert_or_panic(v[126] == 1400); + assert_or_panic(v[127] == 1401); + zig_vector_128_u32((Vector_128_u32){ + 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, + 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, + 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, + 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, + 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, + 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, + 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, + 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, + }, 128); +} + +typedef uint64_t Vector_1_u64 __attribute__((vector_size(1 * sizeof(uint64_t)))); + +Vector_1_u64 zig_ret_vector_1_u64(void); +void zig_vector_1_u64(Vector_1_u64, size_t); + +Vector_1_u64 c_ret_vector_1_u64(void) { + return (Vector_1_u64){ 3 }; +} +void c_vector_1_u64(Vector_1_u64 v, size_t i) { + assert_or_panic(v[0] == 4); + assert_or_panic(i == 1); +} +void c_test_vector_1_u64(void) { + Vector_1_u64 v = zig_ret_vector_1_u64(); + assert_or_panic(v[0] == 1); + zig_vector_1_u64((Vector_1_u64){ 2 }, 1); +} + +typedef uint64_t Vector_2_u64 __attribute__((vector_size(2 * sizeof(uint64_t)))); + +Vector_2_u64 zig_ret_vector_2_u64(void); +void zig_vector_2_u64(Vector_2_u64, size_t); + +Vector_2_u64 c_ret_vector_2_u64(void) { + return (Vector_2_u64){ 9, 10 }; +} +void c_vector_2_u64(Vector_2_u64 v, size_t i) { + assert_or_panic(v[0] == 11); + assert_or_panic(v[1] == 12); + assert_or_panic(i == 2); +} +void c_test_vector_2_u64(void) { + Vector_2_u64 v = zig_ret_vector_2_u64(); + assert_or_panic(v[0] == 5); + assert_or_panic(v[1] == 6); + zig_vector_2_u64((Vector_2_u64){ 7, 8 }, 2); +} + +typedef uint64_t Vector_3_u64 __attribute__((vector_size(3 * sizeof(uint64_t)))); + +Vector_3_u64 zig_ret_vector_3_u64(void); +void zig_vector_3_u64(Vector_3_u64, size_t); + +Vector_3_u64 c_ret_vector_3_u64(void) { + return (Vector_3_u64){ 19, 20, 21 }; +} +void c_vector_3_u64(Vector_3_u64 v, size_t i) { + assert_or_panic(v[0] == 22); + assert_or_panic(v[1] == 23); + assert_or_panic(v[2] == 24); + assert_or_panic(i == 3); +} +void c_test_vector_3_u64(void) { + Vector_3_u64 v = zig_ret_vector_3_u64(); + assert_or_panic(v[0] == 13); + assert_or_panic(v[1] == 14); + assert_or_panic(v[2] == 15); + zig_vector_3_u64((Vector_3_u64){ 16, 17, 18 }, 3); +} + +typedef uint64_t Vector_4_u64 __attribute__((vector_size(4 * sizeof(uint64_t)))); + +Vector_4_u64 zig_ret_vector_4_u64(void); +void zig_vector_4_u64(Vector_4_u64, size_t); + +Vector_4_u64 c_ret_vector_4_u64(void) { + return (Vector_4_u64){ 33, 34, 35, 36 }; +} +void c_vector_4_u64(Vector_4_u64 v, size_t i) { + assert_or_panic(v[0] == 37); + assert_or_panic(v[1] == 38); + assert_or_panic(v[2] == 39); + assert_or_panic(v[3] == 40); + assert_or_panic(i == 4); +} +void c_test_vector_4_u64(void) { + Vector_4_u64 v = zig_ret_vector_4_u64(); + assert_or_panic(v[0] == 25); + assert_or_panic(v[1] == 26); + assert_or_panic(v[2] == 27); + assert_or_panic(v[3] == 28); + zig_vector_4_u64((Vector_4_u64){ 29, 30, 31, 32 }, 4); +} + +typedef uint64_t Vector_6_u64 __attribute__((vector_size(6 * sizeof(uint64_t)))); + +Vector_6_u64 zig_ret_vector_6_u64(void); +void zig_vector_6_u64(Vector_6_u64, size_t); + +Vector_6_u64 c_ret_vector_6_u64(void) { + return (Vector_6_u64){ 53, 54, 55, 56, 57, 58 }; +} +void c_vector_6_u64(Vector_6_u64 v, size_t i) { + assert_or_panic(v[0] == 59); + assert_or_panic(v[1] == 60); + assert_or_panic(v[2] == 61); + assert_or_panic(v[3] == 62); + assert_or_panic(v[4] == 63); + assert_or_panic(v[5] == 64); + assert_or_panic(i == 6); +} +void c_test_vector_6_u64(void) { + Vector_6_u64 v = zig_ret_vector_6_u64(); + assert_or_panic(v[0] == 41); + assert_or_panic(v[1] == 42); + assert_or_panic(v[2] == 43); + assert_or_panic(v[3] == 44); + assert_or_panic(v[4] == 45); + assert_or_panic(v[5] == 46); + zig_vector_6_u64((Vector_6_u64){ 47, 48, 49, 50, 51, 52 }, 6); +} + +typedef uint64_t Vector_8_u64 __attribute__((vector_size(8 * sizeof(uint64_t)))); + +Vector_8_u64 zig_ret_vector_8_u64(void); +void zig_vector_8_u64(Vector_8_u64, size_t); + +Vector_8_u64 c_ret_vector_8_u64(void) { + return (Vector_8_u64){ 81, 82, 83, 84, 85, 86, 87, 88 }; +} +void c_vector_8_u64(Vector_8_u64 v, size_t i) { + assert_or_panic(v[0] == 89); + assert_or_panic(v[1] == 90); + assert_or_panic(v[2] == 91); + assert_or_panic(v[3] == 92); + assert_or_panic(v[4] == 93); + assert_or_panic(v[5] == 94); + assert_or_panic(v[6] == 95); + assert_or_panic(v[7] == 96); + assert_or_panic(i == 8); +} +void c_test_vector_8_u64(void) { + Vector_8_u64 v = zig_ret_vector_8_u64(); + assert_or_panic(v[0] == 65); + assert_or_panic(v[1] == 66); + assert_or_panic(v[2] == 67); + assert_or_panic(v[3] == 68); + assert_or_panic(v[4] == 69); + assert_or_panic(v[5] == 70); + assert_or_panic(v[6] == 71); + assert_or_panic(v[7] == 72); + zig_vector_8_u64((Vector_8_u64){ 73, 74, 75, 76, 77, 78, 79, 80 }, 8); +} + +typedef uint64_t Vector_12_u64 __attribute__((vector_size(12 * sizeof(uint64_t)))); + +Vector_12_u64 zig_ret_vector_12_u64(void); +void zig_vector_12_u64(Vector_12_u64, size_t); + +Vector_12_u64 c_ret_vector_12_u64(void) { + return (Vector_12_u64){ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132 }; +} +void c_vector_12_u64(Vector_12_u64 v, size_t i) { + assert_or_panic(v[0] == 133); + assert_or_panic(v[1] == 134); + assert_or_panic(v[2] == 135); + assert_or_panic(v[3] == 136); + assert_or_panic(v[4] == 137); + assert_or_panic(v[5] == 138); + assert_or_panic(v[6] == 139); + assert_or_panic(v[7] == 140); + assert_or_panic(v[8] == 141); + assert_or_panic(v[9] == 142); + assert_or_panic(v[10] == 143); + assert_or_panic(v[11] == 144); + assert_or_panic(i == 12); +} +void c_test_vector_12_u64(void) { + Vector_12_u64 v = zig_ret_vector_12_u64(); + assert_or_panic(v[0] == 97); + assert_or_panic(v[1] == 98); + assert_or_panic(v[2] == 99); + assert_or_panic(v[3] == 100); + assert_or_panic(v[4] == 101); + assert_or_panic(v[5] == 102); + assert_or_panic(v[6] == 103); + assert_or_panic(v[7] == 104); + assert_or_panic(v[8] == 105); + assert_or_panic(v[9] == 106); + assert_or_panic(v[10] == 107); + assert_or_panic(v[11] == 108); + zig_vector_12_u64((Vector_12_u64){ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 }, 12); +} + +typedef uint64_t Vector_16_u64 __attribute__((vector_size(16 * sizeof(uint64_t)))); + +Vector_16_u64 zig_ret_vector_16_u64(void); +void zig_vector_16_u64(Vector_16_u64, size_t); + +Vector_16_u64 c_ret_vector_16_u64(void) { + return (Vector_16_u64){ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192 }; +} +void c_vector_16_u64(Vector_16_u64 v, size_t i) { + assert_or_panic(v[0] == 193); + assert_or_panic(v[1] == 194); + assert_or_panic(v[2] == 195); + assert_or_panic(v[3] == 196); + assert_or_panic(v[4] == 197); + assert_or_panic(v[5] == 198); + assert_or_panic(v[6] == 199); + assert_or_panic(v[7] == 200); + assert_or_panic(v[8] == 201); + assert_or_panic(v[9] == 202); + assert_or_panic(v[10] == 203); + assert_or_panic(v[11] == 204); + assert_or_panic(v[12] == 205); + assert_or_panic(v[13] == 206); + assert_or_panic(v[14] == 207); + assert_or_panic(v[15] == 208); + assert_or_panic(i == 16); +} +void c_test_vector_16_u64(void) { + Vector_16_u64 v = zig_ret_vector_16_u64(); + assert_or_panic(v[0] == 145); + assert_or_panic(v[1] == 146); + assert_or_panic(v[2] == 147); + assert_or_panic(v[3] == 148); + assert_or_panic(v[4] == 149); + assert_or_panic(v[5] == 150); + assert_or_panic(v[6] == 151); + assert_or_panic(v[7] == 152); + assert_or_panic(v[8] == 153); + assert_or_panic(v[9] == 154); + assert_or_panic(v[10] == 155); + assert_or_panic(v[11] == 156); + assert_or_panic(v[12] == 157); + assert_or_panic(v[13] == 158); + assert_or_panic(v[14] == 159); + assert_or_panic(v[15] == 160); + zig_vector_16_u64((Vector_16_u64){ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176 }, 16); +} + +typedef uint64_t Vector_24_u64 __attribute__((vector_size(24 * sizeof(uint64_t)))); + +Vector_24_u64 zig_ret_vector_24_u64(void); +void zig_vector_24_u64(Vector_24_u64, size_t); + +Vector_24_u64 c_ret_vector_24_u64(void) { + return (Vector_24_u64){ + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + }; +} +void c_vector_24_u64(Vector_24_u64 v, size_t i) { + assert_or_panic(v[0] == 281); + assert_or_panic(v[1] == 282); + assert_or_panic(v[2] == 283); + assert_or_panic(v[3] == 284); + assert_or_panic(v[4] == 285); + assert_or_panic(v[5] == 286); + assert_or_panic(v[6] == 287); + assert_or_panic(v[7] == 288); + assert_or_panic(v[8] == 289); + assert_or_panic(v[9] == 290); + assert_or_panic(v[10] == 291); + assert_or_panic(v[11] == 292); + assert_or_panic(v[12] == 293); + assert_or_panic(v[13] == 294); + assert_or_panic(v[14] == 295); + assert_or_panic(v[15] == 296); + assert_or_panic(v[16] == 297); + assert_or_panic(v[17] == 298); + assert_or_panic(v[18] == 299); + assert_or_panic(v[19] == 300); + assert_or_panic(v[20] == 301); + assert_or_panic(v[21] == 302); + assert_or_panic(v[22] == 303); + assert_or_panic(v[23] == 304); + assert_or_panic(i == 24); +} +void c_test_vector_24_u64(void) { + Vector_24_u64 v = zig_ret_vector_24_u64(); + assert_or_panic(v[0] == 209); + assert_or_panic(v[1] == 210); + assert_or_panic(v[2] == 211); + assert_or_panic(v[3] == 212); + assert_or_panic(v[4] == 213); + assert_or_panic(v[5] == 214); + assert_or_panic(v[6] == 215); + assert_or_panic(v[7] == 216); + assert_or_panic(v[8] == 217); + assert_or_panic(v[9] == 218); + assert_or_panic(v[10] == 219); + assert_or_panic(v[11] == 220); + assert_or_panic(v[12] == 221); + assert_or_panic(v[13] == 222); + assert_or_panic(v[14] == 223); + assert_or_panic(v[15] == 224); + assert_or_panic(v[16] == 225); + assert_or_panic(v[17] == 226); + assert_or_panic(v[18] == 227); + assert_or_panic(v[19] == 228); + assert_or_panic(v[20] == 229); + assert_or_panic(v[21] == 230); + assert_or_panic(v[22] == 231); + assert_or_panic(v[23] == 232); + zig_vector_24_u64((Vector_24_u64){ + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, + }, 24); +} + +typedef uint64_t Vector_32_u64 __attribute__((vector_size(32 * sizeof(uint64_t)))); + +Vector_32_u64 zig_ret_vector_32_u64(void); +void zig_vector_32_u64(Vector_32_u64, size_t); + +Vector_32_u64 c_ret_vector_32_u64(void) { + return (Vector_32_u64){ + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + }; +} +void c_vector_32_u64(Vector_32_u64 v, size_t i) { + assert_or_panic(v[0] == 401); + assert_or_panic(v[1] == 402); + assert_or_panic(v[2] == 403); + assert_or_panic(v[3] == 404); + assert_or_panic(v[4] == 405); + assert_or_panic(v[5] == 406); + assert_or_panic(v[6] == 407); + assert_or_panic(v[7] == 408); + assert_or_panic(v[8] == 409); + assert_or_panic(v[9] == 410); + assert_or_panic(v[10] == 411); + assert_or_panic(v[11] == 412); + assert_or_panic(v[12] == 413); + assert_or_panic(v[13] == 414); + assert_or_panic(v[14] == 415); + assert_or_panic(v[15] == 416); + assert_or_panic(v[16] == 417); + assert_or_panic(v[17] == 418); + assert_or_panic(v[18] == 419); + assert_or_panic(v[19] == 420); + assert_or_panic(v[20] == 421); + assert_or_panic(v[21] == 422); + assert_or_panic(v[22] == 423); + assert_or_panic(v[23] == 424); + assert_or_panic(v[24] == 425); + assert_or_panic(v[25] == 426); + assert_or_panic(v[26] == 427); + assert_or_panic(v[27] == 428); + assert_or_panic(v[28] == 429); + assert_or_panic(v[29] == 430); + assert_or_panic(v[30] == 431); + assert_or_panic(v[31] == 432); + assert_or_panic(i == 32); +} +void c_test_vector_32_u64(void) { + Vector_32_u64 v = zig_ret_vector_32_u64(); + assert_or_panic(v[0] == 305); + assert_or_panic(v[1] == 306); + assert_or_panic(v[2] == 307); + assert_or_panic(v[3] == 308); + assert_or_panic(v[4] == 309); + assert_or_panic(v[5] == 310); + assert_or_panic(v[6] == 311); + assert_or_panic(v[7] == 312); + assert_or_panic(v[8] == 313); + assert_or_panic(v[9] == 314); + assert_or_panic(v[10] == 315); + assert_or_panic(v[11] == 316); + assert_or_panic(v[12] == 317); + assert_or_panic(v[13] == 318); + assert_or_panic(v[14] == 319); + assert_or_panic(v[15] == 320); + assert_or_panic(v[16] == 321); + assert_or_panic(v[17] == 322); + assert_or_panic(v[18] == 323); + assert_or_panic(v[19] == 324); + assert_or_panic(v[20] == 325); + assert_or_panic(v[21] == 326); + assert_or_panic(v[22] == 327); + assert_or_panic(v[23] == 328); + assert_or_panic(v[24] == 329); + assert_or_panic(v[25] == 330); + assert_or_panic(v[26] == 331); + assert_or_panic(v[27] == 332); + assert_or_panic(v[28] == 333); + assert_or_panic(v[29] == 334); + assert_or_panic(v[30] == 335); + assert_or_panic(v[31] == 336); + zig_vector_32_u64((Vector_32_u64){ + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + }, 32); +} + +typedef uint64_t Vector_48_u64 __attribute__((vector_size(48 * sizeof(uint64_t)))); + +Vector_48_u64 zig_ret_vector_48_u64(void); +void zig_vector_48_u64(Vector_48_u64, size_t); + +Vector_48_u64 c_ret_vector_48_u64(void) { + return (Vector_48_u64){ + 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, + 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, + }; +} +void c_vector_48_u64(Vector_48_u64 v, size_t i) { + assert_or_panic(v[0] == 577); + assert_or_panic(v[1] == 578); + assert_or_panic(v[2] == 579); + assert_or_panic(v[3] == 580); + assert_or_panic(v[4] == 581); + assert_or_panic(v[5] == 582); + assert_or_panic(v[6] == 583); + assert_or_panic(v[7] == 584); + assert_or_panic(v[8] == 585); + assert_or_panic(v[9] == 586); + assert_or_panic(v[10] == 587); + assert_or_panic(v[11] == 588); + assert_or_panic(v[12] == 589); + assert_or_panic(v[13] == 590); + assert_or_panic(v[14] == 591); + assert_or_panic(v[15] == 592); + assert_or_panic(v[16] == 593); + assert_or_panic(v[17] == 594); + assert_or_panic(v[18] == 595); + assert_or_panic(v[19] == 596); + assert_or_panic(v[20] == 597); + assert_or_panic(v[21] == 598); + assert_or_panic(v[22] == 599); + assert_or_panic(v[23] == 600); + assert_or_panic(v[24] == 601); + assert_or_panic(v[25] == 602); + assert_or_panic(v[26] == 603); + assert_or_panic(v[27] == 604); + assert_or_panic(v[28] == 605); + assert_or_panic(v[29] == 606); + assert_or_panic(v[30] == 607); + assert_or_panic(v[31] == 608); + assert_or_panic(v[32] == 609); + assert_or_panic(v[33] == 610); + assert_or_panic(v[34] == 611); + assert_or_panic(v[35] == 612); + assert_or_panic(v[36] == 613); + assert_or_panic(v[37] == 614); + assert_or_panic(v[38] == 615); + assert_or_panic(v[39] == 616); + assert_or_panic(v[40] == 617); + assert_or_panic(v[41] == 618); + assert_or_panic(v[42] == 619); + assert_or_panic(v[43] == 620); + assert_or_panic(v[44] == 621); + assert_or_panic(v[45] == 622); + assert_or_panic(v[46] == 623); + assert_or_panic(v[47] == 624); + assert_or_panic(i == 48); +} +void c_test_vector_48_u64(void) { + Vector_48_u64 v = zig_ret_vector_48_u64(); + assert_or_panic(v[0] == 433); + assert_or_panic(v[1] == 434); + assert_or_panic(v[2] == 435); + assert_or_panic(v[3] == 436); + assert_or_panic(v[4] == 437); + assert_or_panic(v[5] == 438); + assert_or_panic(v[6] == 439); + assert_or_panic(v[7] == 440); + assert_or_panic(v[8] == 441); + assert_or_panic(v[9] == 442); + assert_or_panic(v[10] == 443); + assert_or_panic(v[11] == 444); + assert_or_panic(v[12] == 445); + assert_or_panic(v[13] == 446); + assert_or_panic(v[14] == 447); + assert_or_panic(v[15] == 448); + assert_or_panic(v[16] == 449); + assert_or_panic(v[17] == 450); + assert_or_panic(v[18] == 451); + assert_or_panic(v[19] == 452); + assert_or_panic(v[20] == 453); + assert_or_panic(v[21] == 454); + assert_or_panic(v[22] == 455); + assert_or_panic(v[23] == 456); + assert_or_panic(v[24] == 457); + assert_or_panic(v[25] == 458); + assert_or_panic(v[26] == 459); + assert_or_panic(v[27] == 460); + assert_or_panic(v[28] == 461); + assert_or_panic(v[29] == 462); + assert_or_panic(v[30] == 463); + assert_or_panic(v[31] == 464); + assert_or_panic(v[32] == 465); + assert_or_panic(v[33] == 466); + assert_or_panic(v[34] == 467); + assert_or_panic(v[35] == 468); + assert_or_panic(v[36] == 469); + assert_or_panic(v[37] == 470); + assert_or_panic(v[38] == 471); + assert_or_panic(v[39] == 472); + assert_or_panic(v[40] == 473); + assert_or_panic(v[41] == 474); + assert_or_panic(v[42] == 475); + assert_or_panic(v[43] == 476); + assert_or_panic(v[44] == 477); + assert_or_panic(v[45] == 478); + assert_or_panic(v[46] == 479); + assert_or_panic(v[47] == 480); + zig_vector_48_u64((Vector_48_u64){ + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, + }, 48); +} + +typedef uint64_t Vector_64_u64 __attribute__((vector_size(64 * sizeof(uint64_t)))); + +Vector_64_u64 zig_ret_vector_64_u64(void); +void zig_vector_64_u64(Vector_64_u64, size_t); + +Vector_64_u64 c_ret_vector_64_u64(void) { + return (Vector_64_u64){ + 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, + 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, + }; +} +void c_vector_64_u64(Vector_64_u64 v, size_t i) { + assert_or_panic(v[0] == 817); + assert_or_panic(v[1] == 818); + assert_or_panic(v[2] == 819); + assert_or_panic(v[3] == 820); + assert_or_panic(v[4] == 821); + assert_or_panic(v[5] == 822); + assert_or_panic(v[6] == 823); + assert_or_panic(v[7] == 824); + assert_or_panic(v[8] == 825); + assert_or_panic(v[9] == 826); + assert_or_panic(v[10] == 827); + assert_or_panic(v[11] == 828); + assert_or_panic(v[12] == 829); + assert_or_panic(v[13] == 830); + assert_or_panic(v[14] == 831); + assert_or_panic(v[15] == 832); + assert_or_panic(v[16] == 833); + assert_or_panic(v[17] == 834); + assert_or_panic(v[18] == 835); + assert_or_panic(v[19] == 836); + assert_or_panic(v[20] == 837); + assert_or_panic(v[21] == 838); + assert_or_panic(v[22] == 839); + assert_or_panic(v[23] == 840); + assert_or_panic(v[24] == 841); + assert_or_panic(v[25] == 842); + assert_or_panic(v[26] == 843); + assert_or_panic(v[27] == 844); + assert_or_panic(v[28] == 845); + assert_or_panic(v[29] == 846); + assert_or_panic(v[30] == 847); + assert_or_panic(v[31] == 848); + assert_or_panic(v[32] == 849); + assert_or_panic(v[33] == 850); + assert_or_panic(v[34] == 851); + assert_or_panic(v[35] == 852); + assert_or_panic(v[36] == 853); + assert_or_panic(v[37] == 854); + assert_or_panic(v[38] == 855); + assert_or_panic(v[39] == 856); + assert_or_panic(v[40] == 857); + assert_or_panic(v[41] == 858); + assert_or_panic(v[42] == 859); + assert_or_panic(v[43] == 860); + assert_or_panic(v[44] == 861); + assert_or_panic(v[45] == 862); + assert_or_panic(v[46] == 863); + assert_or_panic(v[47] == 864); + assert_or_panic(v[48] == 865); + assert_or_panic(v[49] == 866); + assert_or_panic(v[50] == 867); + assert_or_panic(v[51] == 868); + assert_or_panic(v[52] == 869); + assert_or_panic(v[53] == 870); + assert_or_panic(v[54] == 871); + assert_or_panic(v[55] == 872); + assert_or_panic(v[56] == 873); + assert_or_panic(v[57] == 874); + assert_or_panic(v[58] == 875); + assert_or_panic(v[59] == 876); + assert_or_panic(v[60] == 877); + assert_or_panic(v[61] == 878); + assert_or_panic(v[62] == 879); + assert_or_panic(v[63] == 880); + assert_or_panic(i == 64); +} +void c_test_vector_64_u64(void) { + Vector_64_u64 v = zig_ret_vector_64_u64(); + assert_or_panic(v[0] == 625); + assert_or_panic(v[1] == 626); + assert_or_panic(v[2] == 627); + assert_or_panic(v[3] == 628); + assert_or_panic(v[4] == 629); + assert_or_panic(v[5] == 630); + assert_or_panic(v[6] == 631); + assert_or_panic(v[7] == 632); + assert_or_panic(v[8] == 633); + assert_or_panic(v[9] == 634); + assert_or_panic(v[10] == 635); + assert_or_panic(v[11] == 636); + assert_or_panic(v[12] == 637); + assert_or_panic(v[13] == 638); + assert_or_panic(v[14] == 639); + assert_or_panic(v[15] == 640); + assert_or_panic(v[16] == 641); + assert_or_panic(v[17] == 642); + assert_or_panic(v[18] == 643); + assert_or_panic(v[19] == 644); + assert_or_panic(v[20] == 645); + assert_or_panic(v[21] == 646); + assert_or_panic(v[22] == 647); + assert_or_panic(v[23] == 648); + assert_or_panic(v[24] == 649); + assert_or_panic(v[25] == 650); + assert_or_panic(v[26] == 651); + assert_or_panic(v[27] == 652); + assert_or_panic(v[28] == 653); + assert_or_panic(v[29] == 654); + assert_or_panic(v[30] == 655); + assert_or_panic(v[31] == 656); + assert_or_panic(v[32] == 657); + assert_or_panic(v[33] == 658); + assert_or_panic(v[34] == 659); + assert_or_panic(v[35] == 660); + assert_or_panic(v[36] == 661); + assert_or_panic(v[37] == 662); + assert_or_panic(v[38] == 663); + assert_or_panic(v[39] == 664); + assert_or_panic(v[40] == 665); + assert_or_panic(v[41] == 666); + assert_or_panic(v[42] == 667); + assert_or_panic(v[43] == 668); + assert_or_panic(v[44] == 669); + assert_or_panic(v[45] == 670); + assert_or_panic(v[46] == 671); + assert_or_panic(v[47] == 672); + assert_or_panic(v[48] == 673); + assert_or_panic(v[49] == 674); + assert_or_panic(v[50] == 675); + assert_or_panic(v[51] == 676); + assert_or_panic(v[52] == 677); + assert_or_panic(v[53] == 678); + assert_or_panic(v[54] == 679); + assert_or_panic(v[55] == 680); + assert_or_panic(v[56] == 681); + assert_or_panic(v[57] == 682); + assert_or_panic(v[58] == 683); + assert_or_panic(v[59] == 684); + assert_or_panic(v[60] == 685); + assert_or_panic(v[61] == 686); + assert_or_panic(v[62] == 687); + assert_or_panic(v[63] == 688); + zig_vector_64_u64((Vector_64_u64){ + 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, + 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, + }, 64); +} + +typedef float Vector_1_f32 __attribute__((vector_size(1 * sizeof(float)))); + +Vector_1_f32 zig_ret_vector_1_f32(void); +void zig_vector_1_f32(Vector_1_f32, size_t); + +Vector_1_f32 c_ret_vector_1_f32(void) { + return (Vector_1_f32){ 3 }; +} +void c_vector_1_f32(Vector_1_f32 v, size_t i) { + assert_or_panic(v[0] == 4); + assert_or_panic(i == 1); +} +void c_test_vector_1_f32(void) { + Vector_1_f32 v = zig_ret_vector_1_f32(); + assert_or_panic(v[0] == 1); + zig_vector_1_f32((Vector_1_f32){ 2 }, 1); +} + +typedef float Vector_2_f32 __attribute__((vector_size(2 * sizeof(float)))); + +Vector_2_f32 zig_ret_vector_2_f32(void); +void zig_vector_2_f32(Vector_2_f32, size_t); + +Vector_2_f32 c_ret_vector_2_f32(void) { + return (Vector_2_f32){ 9, 10 }; +} +void c_vector_2_f32(Vector_2_f32 v, size_t i) { + assert_or_panic(v[0] == 11); + assert_or_panic(v[1] == 12); + assert_or_panic(i == 2); +} +void c_test_vector_2_f32(void) { + Vector_2_f32 v = zig_ret_vector_2_f32(); + assert_or_panic(v[0] == 5); + assert_or_panic(v[1] == 6); + zig_vector_2_f32((Vector_2_f32){ 7, 8 }, 2); +} + +typedef float Vector_3_f32 __attribute__((vector_size(3 * sizeof(float)))); + +Vector_3_f32 zig_ret_vector_3_f32(void); +void zig_vector_3_f32(Vector_3_f32, size_t); + +Vector_3_f32 c_ret_vector_3_f32(void) { + return (Vector_3_f32){ 19, 20, 21 }; +} +void c_vector_3_f32(Vector_3_f32 v, size_t i) { + assert_or_panic(v[0] == 22); + assert_or_panic(v[1] == 23); + assert_or_panic(v[2] == 24); + assert_or_panic(i == 32); +} +void c_test_vector_3_f32(void) { + Vector_3_f32 v = zig_ret_vector_3_f32(); + assert_or_panic(v[0] == 13); + assert_or_panic(v[1] == 14); + assert_or_panic(v[2] == 15); + zig_vector_3_f32((Vector_3_f32){ 16, 17, 18 }, 3); +} + +typedef float Vector_4_f32 __attribute__((vector_size(4 * sizeof(float)))); + +Vector_4_f32 zig_ret_vector_4_f32(void); +void zig_vector_4_f32(Vector_4_f32, size_t); +void zig_vector_4_f32_vector_4_f32(Vector_4_f32, Vector_4_f32, size_t); + +Vector_4_f32 c_ret_vector_4_f32(void) { + return (Vector_4_f32){ 41, 42, 43, 44 }; +} +void c_vector_4_f32(Vector_4_f32 v, size_t i) { + assert_or_panic(v[0] == 45); + assert_or_panic(v[1] == 46); + assert_or_panic(v[2] == 47); + assert_or_panic(v[3] == 48); + assert_or_panic(i == 4); +} +void c_vector_4_f32_vector_4_f32(Vector_4_f32 v0, Vector_4_f32 v1, size_t i) { + assert_or_panic(v0[0] == 49); + assert_or_panic(v0[1] == 50); + assert_or_panic(v0[2] == 51); + assert_or_panic(v0[3] == 52); + assert_or_panic(v1[0] == 53); + assert_or_panic(v1[1] == 54); + assert_or_panic(v1[2] == 55); + assert_or_panic(v1[3] == 56); + assert_or_panic(i == 8); +} +void c_test_vector_4_f32(void) { + Vector_4_f32 v = zig_ret_vector_4_f32(); + assert_or_panic(v[0] == 25); + assert_or_panic(v[1] == 26); + assert_or_panic(v[2] == 27); + assert_or_panic(v[3] == 28); + zig_vector_4_f32((Vector_4_f32){ 29, 30, 31, 32 }, 4); + zig_vector_4_f32_vector_4_f32((Vector_4_f32){ 33, 34, 35, 36 }, (Vector_4_f32){ 37, 38, 39, 40 }, 8); +} + +typedef float Vector_6_f32 __attribute__((vector_size(6 * sizeof(float)))); + +Vector_6_f32 zig_ret_vector_6_f32(void); +void zig_vector_6_f32(Vector_6_f32, size_t); + +Vector_6_f32 c_ret_vector_6_f32(void) { + return (Vector_6_f32){ 53, 54, 55, 56, 57, 58 }; +} +void c_vector_6_f32(Vector_6_f32 v, size_t i) { + assert_or_panic(v[0] == 59); + assert_or_panic(v[1] == 60); + assert_or_panic(v[2] == 61); + assert_or_panic(v[3] == 62); + assert_or_panic(v[4] == 63); + assert_or_panic(v[5] == 64); + assert_or_panic(i == 6); +} +void c_test_vector_6_f32(void) { + Vector_6_f32 v = zig_ret_vector_6_f32(); + assert_or_panic(v[0] == 41); + assert_or_panic(v[1] == 42); + assert_or_panic(v[2] == 43); + assert_or_panic(v[3] == 44); + assert_or_panic(v[4] == 45); + assert_or_panic(v[5] == 46); + zig_vector_6_f32((Vector_6_f32){ 47, 48, 49, 50, 51, 52 }, 6); +} + +typedef float Vector_8_f32 __attribute__((vector_size(8 * sizeof(float)))); + +Vector_8_f32 zig_ret_vector_8_f32(void); +void zig_vector_8_f32(Vector_8_f32, size_t); + +Vector_8_f32 c_ret_vector_8_f32(void) { + return (Vector_8_f32){ 81, 82, 83, 84, 85, 86, 87, 88 }; +} +void c_vector_8_f32(Vector_8_f32 v, size_t i) { + assert_or_panic(v[0] == 89); + assert_or_panic(v[1] == 90); + assert_or_panic(v[2] == 91); + assert_or_panic(v[3] == 92); + assert_or_panic(v[4] == 93); + assert_or_panic(v[5] == 94); + assert_or_panic(v[6] == 95); + assert_or_panic(v[7] == 96); + assert_or_panic(i == 8); +} +void c_test_vector_8_f32(void) { + Vector_8_f32 v = zig_ret_vector_8_f32(); + assert_or_panic(v[0] == 65); + assert_or_panic(v[1] == 66); + assert_or_panic(v[2] == 67); + assert_or_panic(v[3] == 68); + assert_or_panic(v[4] == 69); + assert_or_panic(v[5] == 70); + assert_or_panic(v[6] == 71); + assert_or_panic(v[7] == 72); + zig_vector_8_f32((Vector_8_f32){ 73, 74, 75, 76, 77, 78, 79, 80 }, 8); +} + +typedef float Vector_12_f32 __attribute__((vector_size(12 * sizeof(float)))); + +Vector_12_f32 zig_ret_vector_12_f32(void); +void zig_vector_12_f32(Vector_12_f32, size_t); + +Vector_12_f32 c_ret_vector_12_f32(void) { + return (Vector_12_f32){ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132 }; +} +void c_vector_12_f32(Vector_12_f32 v, size_t i) { + assert_or_panic(v[0] == 133); + assert_or_panic(v[1] == 134); + assert_or_panic(v[2] == 135); + assert_or_panic(v[3] == 136); + assert_or_panic(v[4] == 137); + assert_or_panic(v[5] == 138); + assert_or_panic(v[6] == 139); + assert_or_panic(v[7] == 140); + assert_or_panic(v[8] == 141); + assert_or_panic(v[9] == 142); + assert_or_panic(v[10] == 143); + assert_or_panic(v[11] == 144); + assert_or_panic(i == 12); +} +void c_test_vector_12_f32(void) { + Vector_12_f32 v = zig_ret_vector_12_f32(); + assert_or_panic(v[0] == 97); + assert_or_panic(v[1] == 98); + assert_or_panic(v[2] == 99); + assert_or_panic(v[3] == 100); + assert_or_panic(v[4] == 101); + assert_or_panic(v[5] == 102); + assert_or_panic(v[6] == 103); + assert_or_panic(v[7] == 104); + assert_or_panic(v[8] == 105); + assert_or_panic(v[9] == 106); + assert_or_panic(v[10] == 107); + assert_or_panic(v[11] == 108); + zig_vector_12_f32((Vector_12_f32){ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 }, 12); +} + +typedef float Vector_16_f32 __attribute__((vector_size(16 * sizeof(float)))); + +Vector_16_f32 zig_ret_vector_16_f32(void); +void zig_vector_16_f32(Vector_16_f32, size_t); + +Vector_16_f32 c_ret_vector_16_f32(void) { + return (Vector_16_f32){ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192 }; +} +void c_vector_16_f32(Vector_16_f32 v, size_t i) { + assert_or_panic(v[0] == 193); + assert_or_panic(v[1] == 194); + assert_or_panic(v[2] == 195); + assert_or_panic(v[3] == 196); + assert_or_panic(v[4] == 197); + assert_or_panic(v[5] == 198); + assert_or_panic(v[6] == 199); + assert_or_panic(v[7] == 200); + assert_or_panic(v[8] == 201); + assert_or_panic(v[9] == 202); + assert_or_panic(v[10] == 203); + assert_or_panic(v[11] == 204); + assert_or_panic(v[12] == 205); + assert_or_panic(v[13] == 206); + assert_or_panic(v[14] == 207); + assert_or_panic(v[15] == 208); + assert_or_panic(i == 16); +} +void c_test_vector_16_f32(void) { + Vector_16_f32 v = zig_ret_vector_16_f32(); + assert_or_panic(v[0] == 145); + assert_or_panic(v[1] == 146); + assert_or_panic(v[2] == 147); + assert_or_panic(v[3] == 148); + assert_or_panic(v[4] == 149); + assert_or_panic(v[5] == 150); + assert_or_panic(v[6] == 151); + assert_or_panic(v[7] == 152); + assert_or_panic(v[8] == 153); + assert_or_panic(v[9] == 154); + assert_or_panic(v[10] == 155); + assert_or_panic(v[11] == 156); + assert_or_panic(v[12] == 157); + assert_or_panic(v[13] == 158); + assert_or_panic(v[14] == 159); + assert_or_panic(v[15] == 160); + zig_vector_16_f32((Vector_16_f32){ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176 }, 16); +} + +typedef float Vector_24_f32 __attribute__((vector_size(24 * sizeof(float)))); + +Vector_24_f32 zig_ret_vector_24_f32(void); +void zig_vector_24_f32(Vector_24_f32, size_t); + +Vector_24_f32 c_ret_vector_24_f32(void) { + return (Vector_24_f32){ + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + }; +} +void c_vector_24_f32(Vector_24_f32 v, size_t i) { + assert_or_panic(v[0] == 281); + assert_or_panic(v[1] == 282); + assert_or_panic(v[2] == 283); + assert_or_panic(v[3] == 284); + assert_or_panic(v[4] == 285); + assert_or_panic(v[5] == 286); + assert_or_panic(v[6] == 287); + assert_or_panic(v[7] == 288); + assert_or_panic(v[8] == 289); + assert_or_panic(v[9] == 290); + assert_or_panic(v[10] == 291); + assert_or_panic(v[11] == 292); + assert_or_panic(v[12] == 293); + assert_or_panic(v[13] == 294); + assert_or_panic(v[14] == 295); + assert_or_panic(v[15] == 296); + assert_or_panic(v[16] == 297); + assert_or_panic(v[17] == 298); + assert_or_panic(v[18] == 299); + assert_or_panic(v[19] == 300); + assert_or_panic(v[20] == 301); + assert_or_panic(v[21] == 302); + assert_or_panic(v[22] == 303); + assert_or_panic(v[23] == 304); + assert_or_panic(i == 24); +} +void c_test_vector_24_f32(void) { + Vector_24_f32 v = zig_ret_vector_24_f32(); + assert_or_panic(v[0] == 209); + assert_or_panic(v[1] == 210); + assert_or_panic(v[2] == 211); + assert_or_panic(v[3] == 212); + assert_or_panic(v[4] == 213); + assert_or_panic(v[5] == 214); + assert_or_panic(v[6] == 215); + assert_or_panic(v[7] == 216); + assert_or_panic(v[8] == 217); + assert_or_panic(v[9] == 218); + assert_or_panic(v[10] == 219); + assert_or_panic(v[11] == 220); + assert_or_panic(v[12] == 221); + assert_or_panic(v[13] == 222); + assert_or_panic(v[14] == 223); + assert_or_panic(v[15] == 224); + assert_or_panic(v[16] == 225); + assert_or_panic(v[17] == 226); + assert_or_panic(v[18] == 227); + assert_or_panic(v[19] == 228); + assert_or_panic(v[20] == 229); + assert_or_panic(v[21] == 230); + assert_or_panic(v[22] == 231); + assert_or_panic(v[23] == 232); + zig_vector_24_f32((Vector_24_f32){ + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, + }, 24); +} + +typedef float Vector_32_f32 __attribute__((vector_size(32 * sizeof(float)))); + +Vector_32_f32 zig_ret_vector_32_f32(void); +void zig_vector_32_f32(Vector_32_f32, size_t); + +Vector_32_f32 c_ret_vector_32_f32(void) { + return (Vector_32_f32){ + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + }; +} +void c_vector_32_f32(Vector_32_f32 v, size_t i) { + assert_or_panic(v[0] == 401); + assert_or_panic(v[1] == 402); + assert_or_panic(v[2] == 403); + assert_or_panic(v[3] == 404); + assert_or_panic(v[4] == 405); + assert_or_panic(v[5] == 406); + assert_or_panic(v[6] == 407); + assert_or_panic(v[7] == 408); + assert_or_panic(v[8] == 409); + assert_or_panic(v[9] == 410); + assert_or_panic(v[10] == 411); + assert_or_panic(v[11] == 412); + assert_or_panic(v[12] == 413); + assert_or_panic(v[13] == 414); + assert_or_panic(v[14] == 415); + assert_or_panic(v[15] == 416); + assert_or_panic(v[16] == 417); + assert_or_panic(v[17] == 418); + assert_or_panic(v[18] == 419); + assert_or_panic(v[19] == 420); + assert_or_panic(v[20] == 421); + assert_or_panic(v[21] == 422); + assert_or_panic(v[22] == 423); + assert_or_panic(v[23] == 424); + assert_or_panic(v[24] == 425); + assert_or_panic(v[25] == 426); + assert_or_panic(v[26] == 427); + assert_or_panic(v[27] == 428); + assert_or_panic(v[28] == 429); + assert_or_panic(v[29] == 430); + assert_or_panic(v[30] == 431); + assert_or_panic(v[31] == 432); + assert_or_panic(i == 32); +} +void c_test_vector_32_f32(void) { + Vector_32_f32 v = zig_ret_vector_32_f32(); + assert_or_panic(v[0] == 305); + assert_or_panic(v[1] == 306); + assert_or_panic(v[2] == 307); + assert_or_panic(v[3] == 308); + assert_or_panic(v[4] == 309); + assert_or_panic(v[5] == 310); + assert_or_panic(v[6] == 311); + assert_or_panic(v[7] == 312); + assert_or_panic(v[8] == 313); + assert_or_panic(v[9] == 314); + assert_or_panic(v[10] == 315); + assert_or_panic(v[11] == 316); + assert_or_panic(v[12] == 317); + assert_or_panic(v[13] == 318); + assert_or_panic(v[14] == 319); + assert_or_panic(v[15] == 320); + assert_or_panic(v[16] == 321); + assert_or_panic(v[17] == 322); + assert_or_panic(v[18] == 323); + assert_or_panic(v[19] == 324); + assert_or_panic(v[20] == 325); + assert_or_panic(v[21] == 326); + assert_or_panic(v[22] == 327); + assert_or_panic(v[23] == 328); + assert_or_panic(v[24] == 329); + assert_or_panic(v[25] == 330); + assert_or_panic(v[26] == 331); + assert_or_panic(v[27] == 332); + assert_or_panic(v[28] == 333); + assert_or_panic(v[29] == 334); + assert_or_panic(v[30] == 335); + assert_or_panic(v[31] == 336); + zig_vector_32_f32((Vector_32_f32){ + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + }, 32); +} + +typedef float Vector_48_f32 __attribute__((vector_size(48 * sizeof(float)))); + +Vector_48_f32 zig_ret_vector_48_f32(void); +void zig_vector_48_f32(Vector_48_f32, size_t); + +Vector_48_f32 c_ret_vector_48_f32(void) { + return (Vector_48_f32){ + 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, + 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, + }; +} +void c_vector_48_f32(Vector_48_f32 v, size_t i) { + assert_or_panic(v[0] == 577); + assert_or_panic(v[1] == 578); + assert_or_panic(v[2] == 579); + assert_or_panic(v[3] == 580); + assert_or_panic(v[4] == 581); + assert_or_panic(v[5] == 582); + assert_or_panic(v[6] == 583); + assert_or_panic(v[7] == 584); + assert_or_panic(v[8] == 585); + assert_or_panic(v[9] == 586); + assert_or_panic(v[10] == 587); + assert_or_panic(v[11] == 588); + assert_or_panic(v[12] == 589); + assert_or_panic(v[13] == 590); + assert_or_panic(v[14] == 591); + assert_or_panic(v[15] == 592); + assert_or_panic(v[16] == 593); + assert_or_panic(v[17] == 594); + assert_or_panic(v[18] == 595); + assert_or_panic(v[19] == 596); + assert_or_panic(v[20] == 597); + assert_or_panic(v[21] == 598); + assert_or_panic(v[22] == 599); + assert_or_panic(v[23] == 600); + assert_or_panic(v[24] == 601); + assert_or_panic(v[25] == 602); + assert_or_panic(v[26] == 603); + assert_or_panic(v[27] == 604); + assert_or_panic(v[28] == 605); + assert_or_panic(v[29] == 606); + assert_or_panic(v[30] == 607); + assert_or_panic(v[31] == 608); + assert_or_panic(v[32] == 609); + assert_or_panic(v[33] == 610); + assert_or_panic(v[34] == 611); + assert_or_panic(v[35] == 612); + assert_or_panic(v[36] == 613); + assert_or_panic(v[37] == 614); + assert_or_panic(v[38] == 615); + assert_or_panic(v[39] == 616); + assert_or_panic(v[40] == 617); + assert_or_panic(v[41] == 618); + assert_or_panic(v[42] == 619); + assert_or_panic(v[43] == 620); + assert_or_panic(v[44] == 621); + assert_or_panic(v[45] == 622); + assert_or_panic(v[46] == 623); + assert_or_panic(v[47] == 624); + assert_or_panic(i == 48); +} +void c_test_vector_48_f32(void) { + Vector_48_f32 v = zig_ret_vector_48_f32(); + assert_or_panic(v[0] == 433); + assert_or_panic(v[1] == 434); + assert_or_panic(v[2] == 435); + assert_or_panic(v[3] == 436); + assert_or_panic(v[4] == 437); + assert_or_panic(v[5] == 438); + assert_or_panic(v[6] == 439); + assert_or_panic(v[7] == 440); + assert_or_panic(v[8] == 441); + assert_or_panic(v[9] == 442); + assert_or_panic(v[10] == 443); + assert_or_panic(v[11] == 444); + assert_or_panic(v[12] == 445); + assert_or_panic(v[13] == 446); + assert_or_panic(v[14] == 447); + assert_or_panic(v[15] == 448); + assert_or_panic(v[16] == 449); + assert_or_panic(v[17] == 450); + assert_or_panic(v[18] == 451); + assert_or_panic(v[19] == 452); + assert_or_panic(v[20] == 453); + assert_or_panic(v[21] == 454); + assert_or_panic(v[22] == 455); + assert_or_panic(v[23] == 456); + assert_or_panic(v[24] == 457); + assert_or_panic(v[25] == 458); + assert_or_panic(v[26] == 459); + assert_or_panic(v[27] == 460); + assert_or_panic(v[28] == 461); + assert_or_panic(v[29] == 462); + assert_or_panic(v[30] == 463); + assert_or_panic(v[31] == 464); + assert_or_panic(v[32] == 465); + assert_or_panic(v[33] == 466); + assert_or_panic(v[34] == 467); + assert_or_panic(v[35] == 468); + assert_or_panic(v[36] == 469); + assert_or_panic(v[37] == 470); + assert_or_panic(v[38] == 471); + assert_or_panic(v[39] == 472); + assert_or_panic(v[40] == 473); + assert_or_panic(v[41] == 474); + assert_or_panic(v[42] == 475); + assert_or_panic(v[43] == 476); + assert_or_panic(v[44] == 477); + assert_or_panic(v[45] == 478); + assert_or_panic(v[46] == 479); + assert_or_panic(v[47] == 480); + zig_vector_48_f32((Vector_48_f32){ + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, + }, 48); +} + +typedef float Vector_64_f32 __attribute__((vector_size(64 * sizeof(float)))); + +Vector_64_f32 zig_ret_vector_64_f32(void); +void zig_vector_64_f32(Vector_64_f32, size_t); + +Vector_64_f32 c_ret_vector_64_f32(void) { + return (Vector_64_f32){ + 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, + 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, + }; +} +void c_vector_64_f32(Vector_64_f32 v, size_t i) { + assert_or_panic(v[0] == 817); + assert_or_panic(v[1] == 818); + assert_or_panic(v[2] == 819); + assert_or_panic(v[3] == 820); + assert_or_panic(v[4] == 821); + assert_or_panic(v[5] == 822); + assert_or_panic(v[6] == 823); + assert_or_panic(v[7] == 824); + assert_or_panic(v[8] == 825); + assert_or_panic(v[9] == 826); + assert_or_panic(v[10] == 827); + assert_or_panic(v[11] == 828); + assert_or_panic(v[12] == 829); + assert_or_panic(v[13] == 830); + assert_or_panic(v[14] == 831); + assert_or_panic(v[15] == 832); + assert_or_panic(v[16] == 833); + assert_or_panic(v[17] == 834); + assert_or_panic(v[18] == 835); + assert_or_panic(v[19] == 836); + assert_or_panic(v[20] == 837); + assert_or_panic(v[21] == 838); + assert_or_panic(v[22] == 839); + assert_or_panic(v[23] == 840); + assert_or_panic(v[24] == 841); + assert_or_panic(v[25] == 842); + assert_or_panic(v[26] == 843); + assert_or_panic(v[27] == 844); + assert_or_panic(v[28] == 845); + assert_or_panic(v[29] == 846); + assert_or_panic(v[30] == 847); + assert_or_panic(v[31] == 848); + assert_or_panic(v[32] == 849); + assert_or_panic(v[33] == 850); + assert_or_panic(v[34] == 851); + assert_or_panic(v[35] == 852); + assert_or_panic(v[36] == 853); + assert_or_panic(v[37] == 854); + assert_or_panic(v[38] == 855); + assert_or_panic(v[39] == 856); + assert_or_panic(v[40] == 857); + assert_or_panic(v[41] == 858); + assert_or_panic(v[42] == 859); + assert_or_panic(v[43] == 860); + assert_or_panic(v[44] == 861); + assert_or_panic(v[45] == 862); + assert_or_panic(v[46] == 863); + assert_or_panic(v[47] == 864); + assert_or_panic(v[48] == 865); + assert_or_panic(v[49] == 866); + assert_or_panic(v[50] == 867); + assert_or_panic(v[51] == 868); + assert_or_panic(v[52] == 869); + assert_or_panic(v[53] == 870); + assert_or_panic(v[54] == 871); + assert_or_panic(v[55] == 872); + assert_or_panic(v[56] == 873); + assert_or_panic(v[57] == 874); + assert_or_panic(v[58] == 875); + assert_or_panic(v[59] == 876); + assert_or_panic(v[60] == 877); + assert_or_panic(v[61] == 878); + assert_or_panic(v[62] == 879); + assert_or_panic(v[63] == 880); + assert_or_panic(i == 64); +} +void c_test_vector_64_f32(void) { + Vector_64_f32 v = zig_ret_vector_64_f32(); + assert_or_panic(v[0] == 625); + assert_or_panic(v[1] == 626); + assert_or_panic(v[2] == 627); + assert_or_panic(v[3] == 628); + assert_or_panic(v[4] == 629); + assert_or_panic(v[5] == 630); + assert_or_panic(v[6] == 631); + assert_or_panic(v[7] == 632); + assert_or_panic(v[8] == 633); + assert_or_panic(v[9] == 634); + assert_or_panic(v[10] == 635); + assert_or_panic(v[11] == 636); + assert_or_panic(v[12] == 637); + assert_or_panic(v[13] == 638); + assert_or_panic(v[14] == 639); + assert_or_panic(v[15] == 640); + assert_or_panic(v[16] == 641); + assert_or_panic(v[17] == 642); + assert_or_panic(v[18] == 643); + assert_or_panic(v[19] == 644); + assert_or_panic(v[20] == 645); + assert_or_panic(v[21] == 646); + assert_or_panic(v[22] == 647); + assert_or_panic(v[23] == 648); + assert_or_panic(v[24] == 649); + assert_or_panic(v[25] == 650); + assert_or_panic(v[26] == 651); + assert_or_panic(v[27] == 652); + assert_or_panic(v[28] == 653); + assert_or_panic(v[29] == 654); + assert_or_panic(v[30] == 655); + assert_or_panic(v[31] == 656); + assert_or_panic(v[32] == 657); + assert_or_panic(v[33] == 658); + assert_or_panic(v[34] == 659); + assert_or_panic(v[35] == 660); + assert_or_panic(v[36] == 661); + assert_or_panic(v[37] == 662); + assert_or_panic(v[38] == 663); + assert_or_panic(v[39] == 664); + assert_or_panic(v[40] == 665); + assert_or_panic(v[41] == 666); + assert_or_panic(v[42] == 667); + assert_or_panic(v[43] == 668); + assert_or_panic(v[44] == 669); + assert_or_panic(v[45] == 670); + assert_or_panic(v[46] == 671); + assert_or_panic(v[47] == 672); + assert_or_panic(v[48] == 673); + assert_or_panic(v[49] == 674); + assert_or_panic(v[50] == 675); + assert_or_panic(v[51] == 676); + assert_or_panic(v[52] == 677); + assert_or_panic(v[53] == 678); + assert_or_panic(v[54] == 679); + assert_or_panic(v[55] == 680); + assert_or_panic(v[56] == 681); + assert_or_panic(v[57] == 682); + assert_or_panic(v[58] == 683); + assert_or_panic(v[59] == 684); + assert_or_panic(v[60] == 685); + assert_or_panic(v[61] == 686); + assert_or_panic(v[62] == 687); + assert_or_panic(v[63] == 688); + zig_vector_64_f32((Vector_64_f32){ + 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, + 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, + }, 64); +} + +typedef float Vector_96_f32 __attribute__((vector_size(96 * sizeof(float)))); + +Vector_96_f32 zig_ret_vector_96_f32(void); +void zig_vector_96_f32(Vector_96_f32, size_t); + +Vector_96_f32 c_ret_vector_96_f32(void) { + return (Vector_96_f32){ + 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, + 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, + 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, + 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, + 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, + 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, + }; +} +void c_vector_96_f32(Vector_96_f32 v, size_t i) { + assert_or_panic(v[0] == 1178); + assert_or_panic(v[1] == 1179); + assert_or_panic(v[2] == 1180); + assert_or_panic(v[3] == 1181); + assert_or_panic(v[4] == 1182); + assert_or_panic(v[5] == 1183); + assert_or_panic(v[6] == 1184); + assert_or_panic(v[7] == 1185); + assert_or_panic(v[8] == 1186); + assert_or_panic(v[9] == 1187); + assert_or_panic(v[10] == 1188); + assert_or_panic(v[11] == 1189); + assert_or_panic(v[12] == 1190); + assert_or_panic(v[13] == 1191); + assert_or_panic(v[14] == 1192); + assert_or_panic(v[15] == 1193); + assert_or_panic(v[16] == 1194); + assert_or_panic(v[17] == 1195); + assert_or_panic(v[18] == 1196); + assert_or_panic(v[19] == 1197); + assert_or_panic(v[20] == 1198); + assert_or_panic(v[21] == 1199); + assert_or_panic(v[22] == 1200); + assert_or_panic(v[23] == 1201); + assert_or_panic(v[24] == 1202); + assert_or_panic(v[25] == 1203); + assert_or_panic(v[26] == 1204); + assert_or_panic(v[27] == 1205); + assert_or_panic(v[28] == 1206); + assert_or_panic(v[29] == 1207); + assert_or_panic(v[30] == 1208); + assert_or_panic(v[31] == 1209); + assert_or_panic(v[32] == 1210); + assert_or_panic(v[33] == 1211); + assert_or_panic(v[34] == 1212); + assert_or_panic(v[35] == 1213); + assert_or_panic(v[36] == 1214); + assert_or_panic(v[37] == 1215); + assert_or_panic(v[38] == 1216); + assert_or_panic(v[39] == 1217); + assert_or_panic(v[40] == 1218); + assert_or_panic(v[41] == 1219); + assert_or_panic(v[42] == 1220); + assert_or_panic(v[43] == 1221); + assert_or_panic(v[44] == 1222); + assert_or_panic(v[45] == 1223); + assert_or_panic(v[46] == 1224); + assert_or_panic(v[47] == 1225); + assert_or_panic(v[48] == 1226); + assert_or_panic(v[49] == 1227); + assert_or_panic(v[50] == 1228); + assert_or_panic(v[51] == 1229); + assert_or_panic(v[52] == 1230); + assert_or_panic(v[53] == 1231); + assert_or_panic(v[54] == 1232); + assert_or_panic(v[55] == 1233); + assert_or_panic(v[56] == 1234); + assert_or_panic(v[57] == 1235); + assert_or_panic(v[58] == 1236); + assert_or_panic(v[59] == 1237); + assert_or_panic(v[60] == 1238); + assert_or_panic(v[61] == 1239); + assert_or_panic(v[62] == 1240); + assert_or_panic(v[63] == 1241); + assert_or_panic(v[64] == 1242); + assert_or_panic(v[65] == 1243); + assert_or_panic(v[66] == 1244); + assert_or_panic(v[67] == 1245); + assert_or_panic(v[68] == 1246); + assert_or_panic(v[69] == 1247); + assert_or_panic(v[70] == 1248); + assert_or_panic(v[71] == 1249); + assert_or_panic(v[72] == 1250); + assert_or_panic(v[73] == 1251); + assert_or_panic(v[74] == 1252); + assert_or_panic(v[75] == 1253); + assert_or_panic(v[76] == 1254); + assert_or_panic(v[77] == 1255); + assert_or_panic(v[80] == 1258); + assert_or_panic(v[81] == 1259); + assert_or_panic(v[82] == 1260); + assert_or_panic(v[83] == 1261); + assert_or_panic(v[84] == 1262); + assert_or_panic(v[85] == 1263); + assert_or_panic(v[86] == 1264); + assert_or_panic(v[87] == 1265); + assert_or_panic(v[88] == 1266); + assert_or_panic(v[89] == 1267); + assert_or_panic(v[90] == 1268); + assert_or_panic(v[91] == 1269); + assert_or_panic(v[92] == 1270); + assert_or_panic(v[93] == 1271); + assert_or_panic(v[94] == 1272); + assert_or_panic(v[95] == 1273); + assert_or_panic(i == 96); +} +void c_test_vector_96_f32(void) { + Vector_96_f32 v = zig_ret_vector_96_f32(); + assert_or_panic(v[0] == 890); + assert_or_panic(v[1] == 891); + assert_or_panic(v[2] == 892); + assert_or_panic(v[3] == 893); + assert_or_panic(v[4] == 894); + assert_or_panic(v[5] == 895); + assert_or_panic(v[6] == 896); + assert_or_panic(v[7] == 897); + assert_or_panic(v[8] == 898); + assert_or_panic(v[9] == 899); + assert_or_panic(v[10] == 900); + assert_or_panic(v[11] == 901); + assert_or_panic(v[12] == 902); + assert_or_panic(v[13] == 903); + assert_or_panic(v[14] == 904); + assert_or_panic(v[15] == 905); + assert_or_panic(v[16] == 906); + assert_or_panic(v[17] == 907); + assert_or_panic(v[18] == 908); + assert_or_panic(v[19] == 909); + assert_or_panic(v[20] == 910); + assert_or_panic(v[21] == 911); + assert_or_panic(v[22] == 912); + assert_or_panic(v[23] == 913); + assert_or_panic(v[24] == 914); + assert_or_panic(v[25] == 915); + assert_or_panic(v[26] == 916); + assert_or_panic(v[27] == 917); + assert_or_panic(v[28] == 918); + assert_or_panic(v[29] == 919); + assert_or_panic(v[30] == 920); + assert_or_panic(v[31] == 921); + assert_or_panic(v[32] == 922); + assert_or_panic(v[33] == 923); + assert_or_panic(v[34] == 924); + assert_or_panic(v[35] == 925); + assert_or_panic(v[36] == 926); + assert_or_panic(v[37] == 927); + assert_or_panic(v[38] == 928); + assert_or_panic(v[39] == 929); + assert_or_panic(v[40] == 930); + assert_or_panic(v[41] == 931); + assert_or_panic(v[42] == 932); + assert_or_panic(v[43] == 933); + assert_or_panic(v[44] == 934); + assert_or_panic(v[45] == 935); + assert_or_panic(v[46] == 936); + assert_or_panic(v[47] == 937); + assert_or_panic(v[48] == 938); + assert_or_panic(v[49] == 939); + assert_or_panic(v[50] == 940); + assert_or_panic(v[51] == 941); + assert_or_panic(v[52] == 942); + assert_or_panic(v[53] == 943); + assert_or_panic(v[54] == 944); + assert_or_panic(v[55] == 945); + assert_or_panic(v[56] == 946); + assert_or_panic(v[57] == 947); + assert_or_panic(v[58] == 948); + assert_or_panic(v[59] == 949); + assert_or_panic(v[60] == 950); + assert_or_panic(v[61] == 951); + assert_or_panic(v[62] == 952); + assert_or_panic(v[63] == 953); + assert_or_panic(v[64] == 954); + assert_or_panic(v[65] == 955); + assert_or_panic(v[66] == 956); + assert_or_panic(v[67] == 957); + assert_or_panic(v[68] == 958); + assert_or_panic(v[69] == 959); + assert_or_panic(v[70] == 960); + assert_or_panic(v[71] == 961); + assert_or_panic(v[72] == 962); + assert_or_panic(v[73] == 963); + assert_or_panic(v[74] == 964); + assert_or_panic(v[75] == 965); + assert_or_panic(v[76] == 966); + assert_or_panic(v[77] == 967); + assert_or_panic(v[78] == 968); + assert_or_panic(v[79] == 969); + assert_or_panic(v[80] == 970); + assert_or_panic(v[81] == 971); + assert_or_panic(v[82] == 972); + assert_or_panic(v[83] == 973); + assert_or_panic(v[84] == 974); + assert_or_panic(v[85] == 975); + assert_or_panic(v[86] == 976); + assert_or_panic(v[87] == 977); + assert_or_panic(v[88] == 978); + assert_or_panic(v[89] == 979); + assert_or_panic(v[90] == 980); + assert_or_panic(v[91] == 981); + assert_or_panic(v[92] == 982); + assert_or_panic(v[93] == 983); + assert_or_panic(v[94] == 984); + assert_or_panic(v[95] == 985); + zig_vector_96_f32((Vector_96_f32){ + 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, + 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, + 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, + 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, + 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, + 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, + }, 96); +} + +typedef float Vector_128_f32 __attribute__((vector_size(128 * sizeof(float)))); + +Vector_128_f32 zig_ret_vector_128_f32(void); +void zig_vector_128_f32(Vector_128_f32, size_t); + +Vector_128_f32 c_ret_vector_128_f32(void) { + return (Vector_128_f32){ + 1530, 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, + 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, + 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, + 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, + 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, + 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624, 1625, + 1626, 1627, 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, 1636, 1637, 1638, 1639, 1640, 1641, + 1642, 1643, 1644, 1645, 1646, 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1654, 1655, 1656, 1657, + }; +} +void c_vector_128_f32(Vector_128_f32 v, size_t i) { + assert_or_panic(v[0] == 1658); + assert_or_panic(v[1] == 1659); + assert_or_panic(v[2] == 1660); + assert_or_panic(v[3] == 1661); + assert_or_panic(v[4] == 1662); + assert_or_panic(v[5] == 1663); + assert_or_panic(v[6] == 1664); + assert_or_panic(v[7] == 1665); + assert_or_panic(v[8] == 1666); + assert_or_panic(v[9] == 1667); + assert_or_panic(v[10] == 1668); + assert_or_panic(v[11] == 1669); + assert_or_panic(v[12] == 1670); + assert_or_panic(v[13] == 1671); + assert_or_panic(v[14] == 1672); + assert_or_panic(v[15] == 1673); + assert_or_panic(v[16] == 1674); + assert_or_panic(v[17] == 1675); + assert_or_panic(v[18] == 1676); + assert_or_panic(v[19] == 1677); + assert_or_panic(v[20] == 1678); + assert_or_panic(v[21] == 1679); + assert_or_panic(v[22] == 1680); + assert_or_panic(v[23] == 1681); + assert_or_panic(v[24] == 1682); + assert_or_panic(v[25] == 1683); + assert_or_panic(v[26] == 1684); + assert_or_panic(v[27] == 1685); + assert_or_panic(v[28] == 1686); + assert_or_panic(v[29] == 1687); + assert_or_panic(v[30] == 1688); + assert_or_panic(v[31] == 1689); + assert_or_panic(v[32] == 1690); + assert_or_panic(v[33] == 1691); + assert_or_panic(v[34] == 1692); + assert_or_panic(v[35] == 1693); + assert_or_panic(v[36] == 1694); + assert_or_panic(v[37] == 1695); + assert_or_panic(v[38] == 1696); + assert_or_panic(v[39] == 1697); + assert_or_panic(v[40] == 1698); + assert_or_panic(v[41] == 1699); + assert_or_panic(v[42] == 1700); + assert_or_panic(v[43] == 1701); + assert_or_panic(v[44] == 1702); + assert_or_panic(v[45] == 1703); + assert_or_panic(v[46] == 1704); + assert_or_panic(v[47] == 1705); + assert_or_panic(v[48] == 1706); + assert_or_panic(v[49] == 1707); + assert_or_panic(v[50] == 1708); + assert_or_panic(v[51] == 1709); + assert_or_panic(v[52] == 1710); + assert_or_panic(v[53] == 1711); + assert_or_panic(v[54] == 1712); + assert_or_panic(v[55] == 1713); + assert_or_panic(v[56] == 1714); + assert_or_panic(v[57] == 1715); + assert_or_panic(v[58] == 1716); + assert_or_panic(v[59] == 1717); + assert_or_panic(v[60] == 1718); + assert_or_panic(v[61] == 1719); + assert_or_panic(v[62] == 1720); + assert_or_panic(v[63] == 1721); + assert_or_panic(v[64] == 1722); + assert_or_panic(v[65] == 1723); + assert_or_panic(v[66] == 1724); + assert_or_panic(v[67] == 1725); + assert_or_panic(v[68] == 1726); + assert_or_panic(v[69] == 1727); + assert_or_panic(v[70] == 1728); + assert_or_panic(v[71] == 1729); + assert_or_panic(v[72] == 1730); + assert_or_panic(v[73] == 1731); + assert_or_panic(v[74] == 1732); + assert_or_panic(v[75] == 1733); + assert_or_panic(v[76] == 1734); + assert_or_panic(v[77] == 1735); + assert_or_panic(v[78] == 1736); + assert_or_panic(v[79] == 1737); + assert_or_panic(v[80] == 1738); + assert_or_panic(v[81] == 1739); + assert_or_panic(v[82] == 1740); + assert_or_panic(v[83] == 1741); + assert_or_panic(v[84] == 1742); + assert_or_panic(v[85] == 1743); + assert_or_panic(v[86] == 1744); + assert_or_panic(v[87] == 1745); + assert_or_panic(v[88] == 1746); + assert_or_panic(v[89] == 1747); + assert_or_panic(v[90] == 1748); + assert_or_panic(v[91] == 1749); + assert_or_panic(v[92] == 1750); + assert_or_panic(v[93] == 1751); + assert_or_panic(v[94] == 1752); + assert_or_panic(v[95] == 1753); + assert_or_panic(v[96] == 1754); + assert_or_panic(v[97] == 1755); + assert_or_panic(v[98] == 1756); + assert_or_panic(v[99] == 1757); + assert_or_panic(v[100] == 1758); + assert_or_panic(v[101] == 1759); + assert_or_panic(v[102] == 1760); + assert_or_panic(v[103] == 1761); + assert_or_panic(v[104] == 1762); + assert_or_panic(v[105] == 1763); + assert_or_panic(v[106] == 1764); + assert_or_panic(v[107] == 1765); + assert_or_panic(v[108] == 1766); + assert_or_panic(v[109] == 1767); + assert_or_panic(v[110] == 1768); + assert_or_panic(v[111] == 1769); + assert_or_panic(v[112] == 1770); + assert_or_panic(v[113] == 1771); + assert_or_panic(v[114] == 1772); + assert_or_panic(v[115] == 1773); + assert_or_panic(v[116] == 1774); + assert_or_panic(v[117] == 1775); + assert_or_panic(v[118] == 1776); + assert_or_panic(v[119] == 1777); + assert_or_panic(v[120] == 1778); + assert_or_panic(v[121] == 1779); + assert_or_panic(v[122] == 1780); + assert_or_panic(v[123] == 1781); + assert_or_panic(v[124] == 1782); + assert_or_panic(v[125] == 1783); + assert_or_panic(v[126] == 1784); + assert_or_panic(v[127] == 1785); + assert_or_panic(i == 128); +} +void c_test_vector_128_f32(void) { + Vector_128_f32 v = zig_ret_vector_128_f32(); + assert_or_panic(v[0] == 1274); + assert_or_panic(v[1] == 1275); + assert_or_panic(v[2] == 1276); + assert_or_panic(v[3] == 1277); + assert_or_panic(v[4] == 1278); + assert_or_panic(v[5] == 1279); + assert_or_panic(v[6] == 1280); + assert_or_panic(v[7] == 1281); + assert_or_panic(v[8] == 1282); + assert_or_panic(v[9] == 1283); + assert_or_panic(v[10] == 1284); + assert_or_panic(v[11] == 1285); + assert_or_panic(v[12] == 1286); + assert_or_panic(v[13] == 1287); + assert_or_panic(v[14] == 1288); + assert_or_panic(v[15] == 1289); + assert_or_panic(v[16] == 1290); + assert_or_panic(v[17] == 1291); + assert_or_panic(v[18] == 1292); + assert_or_panic(v[19] == 1293); + assert_or_panic(v[20] == 1294); + assert_or_panic(v[21] == 1295); + assert_or_panic(v[22] == 1296); + assert_or_panic(v[23] == 1297); + assert_or_panic(v[24] == 1298); + assert_or_panic(v[25] == 1299); + assert_or_panic(v[26] == 1300); + assert_or_panic(v[27] == 1301); + assert_or_panic(v[28] == 1302); + assert_or_panic(v[29] == 1303); + assert_or_panic(v[30] == 1304); + assert_or_panic(v[31] == 1305); + assert_or_panic(v[32] == 1306); + assert_or_panic(v[33] == 1307); + assert_or_panic(v[34] == 1308); + assert_or_panic(v[35] == 1309); + assert_or_panic(v[36] == 1310); + assert_or_panic(v[37] == 1311); + assert_or_panic(v[38] == 1312); + assert_or_panic(v[39] == 1313); + assert_or_panic(v[40] == 1314); + assert_or_panic(v[41] == 1315); + assert_or_panic(v[42] == 1316); + assert_or_panic(v[43] == 1317); + assert_or_panic(v[44] == 1318); + assert_or_panic(v[45] == 1319); + assert_or_panic(v[46] == 1320); + assert_or_panic(v[47] == 1321); + assert_or_panic(v[48] == 1322); + assert_or_panic(v[49] == 1323); + assert_or_panic(v[50] == 1324); + assert_or_panic(v[51] == 1325); + assert_or_panic(v[52] == 1326); + assert_or_panic(v[53] == 1327); + assert_or_panic(v[54] == 1328); + assert_or_panic(v[55] == 1329); + assert_or_panic(v[56] == 1330); + assert_or_panic(v[57] == 1331); + assert_or_panic(v[58] == 1332); + assert_or_panic(v[59] == 1333); + assert_or_panic(v[60] == 1334); + assert_or_panic(v[61] == 1335); + assert_or_panic(v[62] == 1336); + assert_or_panic(v[63] == 1337); + assert_or_panic(v[64] == 1338); + assert_or_panic(v[65] == 1339); + assert_or_panic(v[66] == 1340); + assert_or_panic(v[67] == 1341); + assert_or_panic(v[68] == 1342); + assert_or_panic(v[69] == 1343); + assert_or_panic(v[70] == 1344); + assert_or_panic(v[71] == 1345); + assert_or_panic(v[72] == 1346); + assert_or_panic(v[73] == 1347); + assert_or_panic(v[74] == 1348); + assert_or_panic(v[75] == 1349); + assert_or_panic(v[76] == 1350); + assert_or_panic(v[77] == 1351); + assert_or_panic(v[78] == 1352); + assert_or_panic(v[79] == 1353); + assert_or_panic(v[80] == 1354); + assert_or_panic(v[81] == 1355); + assert_or_panic(v[82] == 1356); + assert_or_panic(v[83] == 1357); + assert_or_panic(v[84] == 1358); + assert_or_panic(v[85] == 1359); + assert_or_panic(v[86] == 1360); + assert_or_panic(v[87] == 1361); + assert_or_panic(v[88] == 1362); + assert_or_panic(v[89] == 1363); + assert_or_panic(v[90] == 1364); + assert_or_panic(v[91] == 1365); + assert_or_panic(v[92] == 1366); + assert_or_panic(v[93] == 1367); + assert_or_panic(v[94] == 1368); + assert_or_panic(v[95] == 1369); + assert_or_panic(v[96] == 1370); + assert_or_panic(v[97] == 1371); + assert_or_panic(v[98] == 1372); + assert_or_panic(v[99] == 1373); + assert_or_panic(v[100] == 1374); + assert_or_panic(v[101] == 1375); + assert_or_panic(v[102] == 1376); + assert_or_panic(v[103] == 1377); + assert_or_panic(v[104] == 1378); + assert_or_panic(v[105] == 1379); + assert_or_panic(v[106] == 1380); + assert_or_panic(v[107] == 1381); + assert_or_panic(v[108] == 1382); + assert_or_panic(v[109] == 1383); + assert_or_panic(v[110] == 1384); + assert_or_panic(v[111] == 1385); + assert_or_panic(v[112] == 1386); + assert_or_panic(v[113] == 1387); + assert_or_panic(v[114] == 1388); + assert_or_panic(v[115] == 1389); + assert_or_panic(v[116] == 1390); + assert_or_panic(v[117] == 1391); + assert_or_panic(v[118] == 1392); + assert_or_panic(v[119] == 1393); + assert_or_panic(v[120] == 1394); + assert_or_panic(v[121] == 1395); + assert_or_panic(v[122] == 1396); + assert_or_panic(v[123] == 1397); + assert_or_panic(v[124] == 1398); + assert_or_panic(v[125] == 1399); + assert_or_panic(v[126] == 1400); + assert_or_panic(v[127] == 1401); + zig_vector_128_f32((Vector_128_f32){ + 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 1417, + 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1430, 1431, 1432, 1433, + 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, + 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, 1462, 1463, 1464, 1465, + 1466, 1467, 1468, 1469, 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, 1478, 1479, 1480, 1481, + 1482, 1483, 1484, 1485, 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, + 1498, 1499, 1500, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510, 1511, 1512, 1513, + 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, 1526, 1527, 1528, 1529, + }, 128); +} + +typedef double Vector_1_f64 __attribute__((vector_size(1 * sizeof(double)))); + +Vector_1_f64 zig_ret_vector_1_f64(void); +void zig_vector_1_f64(Vector_1_f64, size_t); + +Vector_1_f64 c_ret_vector_1_f64(void) { + return (Vector_1_f64){ 3 }; +} +void c_vector_1_f64(Vector_1_f64 v, size_t i) { + assert_or_panic(v[0] == 4); + assert_or_panic(i == 1); +} +void c_test_vector_1_f64(void) { + Vector_1_f64 v = zig_ret_vector_1_f64(); + assert_or_panic(v[0] == 1); + zig_vector_1_f64((Vector_1_f64){ 2 }, 1); +} + +typedef double Vector_2_f64 __attribute__((vector_size(2 * sizeof(double)))); + +Vector_2_f64 zig_ret_vector_2_f64(void); +void zig_vector_2_f64(Vector_2_f64, size_t); + +Vector_2_f64 c_ret_vector_2_f64(void) { + return (Vector_2_f64){ 9, 10 }; +} +void c_vector_2_f64(Vector_2_f64 v, size_t i) { + assert_or_panic(v[0] == 11); + assert_or_panic(v[1] == 12); + assert_or_panic(i == 2); +} +void c_test_vector_2_f64(void) { + Vector_2_f64 v = zig_ret_vector_2_f64(); + assert_or_panic(v[0] == 5); + assert_or_panic(v[1] == 6); + zig_vector_2_f64((Vector_2_f64){ 7, 8 }, 2); +} + +typedef double Vector_3_f64 __attribute__((vector_size(3 * sizeof(double)))); + +Vector_3_f64 zig_ret_vector_3_f64(void); +void zig_vector_3_f64(Vector_3_f64, size_t); + +Vector_3_f64 c_ret_vector_3_f64(void) { + return (Vector_3_f64){ 19, 20, 21 }; +} +void c_vector_3_f64(Vector_3_f64 v, size_t i) { + assert_or_panic(v[0] == 22); + assert_or_panic(v[1] == 23); + assert_or_panic(v[2] == 24); + assert_or_panic(i == 3); +} +void c_test_vector_3_f64(void) { + Vector_3_f64 v = zig_ret_vector_3_f64(); + assert_or_panic(v[0] == 13); + assert_or_panic(v[1] == 14); + assert_or_panic(v[2] == 15); + zig_vector_3_f64((Vector_3_f64){ 16, 17, 18 }, 3); +} + +typedef double Vector_4_f64 __attribute__((vector_size(4 * sizeof(double)))); + +Vector_4_f64 zig_ret_vector_4_f64(void); +void zig_vector_4_f64(Vector_4_f64, size_t); + +Vector_4_f64 c_ret_vector_4_f64(void) { + return (Vector_4_f64){ 33, 34, 35, 36 }; +} +void c_vector_4_f64(Vector_4_f64 v, size_t i) { + assert_or_panic(v[0] == 37); + assert_or_panic(v[1] == 38); + assert_or_panic(v[2] == 39); + assert_or_panic(v[3] == 40); + assert_or_panic(i == 4); +} +void c_test_vector_4_f64(void) { + Vector_4_f64 v = zig_ret_vector_4_f64(); + assert_or_panic(v[0] == 25); + assert_or_panic(v[1] == 26); + assert_or_panic(v[2] == 27); + assert_or_panic(v[3] == 28); + zig_vector_4_f64((Vector_4_f64){ 29, 30, 31, 32 }, 4); +} + +typedef double Vector_6_f64 __attribute__((vector_size(6 * sizeof(double)))); + +Vector_6_f64 zig_ret_vector_6_f64(void); +void zig_vector_6_f64(Vector_6_f64, size_t); + +Vector_6_f64 c_ret_vector_6_f64(void) { + return (Vector_6_f64){ 53, 54, 55, 56, 57, 58 }; +} +void c_vector_6_f64(Vector_6_f64 v, size_t i) { + assert_or_panic(v[0] == 59); + assert_or_panic(v[1] == 60); + assert_or_panic(v[2] == 61); + assert_or_panic(v[3] == 62); + assert_or_panic(v[4] == 63); + assert_or_panic(v[5] == 64); + assert_or_panic(i == 6); +} +void c_test_vector_6_f64(void) { + Vector_6_f64 v = zig_ret_vector_6_f64(); + assert_or_panic(v[0] == 41); + assert_or_panic(v[1] == 42); + assert_or_panic(v[2] == 43); + assert_or_panic(v[3] == 44); + assert_or_panic(v[4] == 45); + assert_or_panic(v[5] == 46); + zig_vector_6_f64((Vector_6_f64){ 47, 48, 49, 50, 51, 52 }, 6); +} + +typedef double Vector_8_f64 __attribute__((vector_size(8 * sizeof(double)))); + +Vector_8_f64 zig_ret_vector_8_f64(void); +void zig_vector_8_f64(Vector_8_f64, size_t); + +Vector_8_f64 c_ret_vector_8_f64(void) { + return (Vector_8_f64){ 81, 82, 83, 84, 85, 86, 87, 88 }; +} +void c_vector_8_f64(Vector_8_f64 v, size_t i) { + assert_or_panic(v[0] == 89); + assert_or_panic(v[1] == 90); + assert_or_panic(v[2] == 91); + assert_or_panic(v[3] == 92); + assert_or_panic(v[4] == 93); + assert_or_panic(v[5] == 94); + assert_or_panic(v[6] == 95); + assert_or_panic(v[7] == 96); + assert_or_panic(i == 8); +} +void c_test_vector_8_f64(void) { + Vector_8_f64 v = zig_ret_vector_8_f64(); + assert_or_panic(v[0] == 65); + assert_or_panic(v[1] == 66); + assert_or_panic(v[2] == 67); + assert_or_panic(v[3] == 68); + assert_or_panic(v[4] == 69); + assert_or_panic(v[5] == 70); + assert_or_panic(v[6] == 71); + assert_or_panic(v[7] == 72); + zig_vector_8_f64((Vector_8_f64){ 73, 74, 75, 76, 77, 78, 79, 80 }, 8); +} + +typedef double Vector_12_f64 __attribute__((vector_size(12 * sizeof(double)))); + +Vector_12_f64 zig_ret_vector_12_f64(void); +void zig_vector_12_f64(Vector_12_f64, size_t); + +Vector_12_f64 c_ret_vector_12_f64(void) { + return (Vector_12_f64){ 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132 }; +} +void c_vector_12_f64(Vector_12_f64 v, size_t i) { + assert_or_panic(v[0] == 133); + assert_or_panic(v[1] == 134); + assert_or_panic(v[2] == 135); + assert_or_panic(v[3] == 136); + assert_or_panic(v[4] == 137); + assert_or_panic(v[5] == 138); + assert_or_panic(v[6] == 139); + assert_or_panic(v[7] == 140); + assert_or_panic(v[8] == 141); + assert_or_panic(v[9] == 142); + assert_or_panic(v[10] == 143); + assert_or_panic(v[11] == 144); + assert_or_panic(i == 12); +} +void c_test_vector_12_f64(void) { + Vector_12_f64 v = zig_ret_vector_12_f64(); + assert_or_panic(v[0] == 97); + assert_or_panic(v[1] == 98); + assert_or_panic(v[2] == 99); + assert_or_panic(v[3] == 100); + assert_or_panic(v[4] == 101); + assert_or_panic(v[5] == 102); + assert_or_panic(v[6] == 103); + assert_or_panic(v[7] == 104); + assert_or_panic(v[8] == 105); + assert_or_panic(v[9] == 106); + assert_or_panic(v[10] == 107); + assert_or_panic(v[11] == 108); + zig_vector_12_f64((Vector_12_f64){ 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 }, 12); +} + +typedef double Vector_16_f64 __attribute__((vector_size(16 * sizeof(double)))); + +Vector_16_f64 zig_ret_vector_16_f64(void); +void zig_vector_16_f64(Vector_16_f64, size_t); + +Vector_16_f64 c_ret_vector_16_f64(void) { + return (Vector_16_f64){ 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192 }; +} +void c_vector_16_f64(Vector_16_f64 v, size_t i) { + assert_or_panic(v[0] == 193); + assert_or_panic(v[1] == 194); + assert_or_panic(v[2] == 195); + assert_or_panic(v[3] == 196); + assert_or_panic(v[4] == 197); + assert_or_panic(v[5] == 198); + assert_or_panic(v[6] == 199); + assert_or_panic(v[7] == 200); + assert_or_panic(v[8] == 201); + assert_or_panic(v[9] == 202); + assert_or_panic(v[10] == 203); + assert_or_panic(v[11] == 204); + assert_or_panic(v[12] == 205); + assert_or_panic(v[13] == 206); + assert_or_panic(v[14] == 207); + assert_or_panic(v[15] == 208); + assert_or_panic(i == 16); +} +void c_test_vector_16_f64(void) { + Vector_16_f64 v = zig_ret_vector_16_f64(); + assert_or_panic(v[0] == 145); + assert_or_panic(v[1] == 146); + assert_or_panic(v[2] == 147); + assert_or_panic(v[3] == 148); + assert_or_panic(v[4] == 149); + assert_or_panic(v[5] == 150); + assert_or_panic(v[6] == 151); + assert_or_panic(v[7] == 152); + assert_or_panic(v[8] == 153); + assert_or_panic(v[9] == 154); + assert_or_panic(v[10] == 155); + assert_or_panic(v[11] == 156); + assert_or_panic(v[12] == 157); + assert_or_panic(v[13] == 158); + assert_or_panic(v[14] == 159); + assert_or_panic(v[15] == 160); + zig_vector_16_f64((Vector_16_f64){ 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176 }, 16); +} + +typedef double Vector_24_f64 __attribute__((vector_size(24 * sizeof(double)))); + +Vector_24_f64 zig_ret_vector_24_f64(void); +void zig_vector_24_f64(Vector_24_f64, size_t); + +Vector_24_f64 c_ret_vector_24_f64(void) { + return (Vector_24_f64){ + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, + 273, 274, 275, 276, 277, 278, 279, 280, + }; +} +void c_vector_24_f64(Vector_24_f64 v, size_t i) { + assert_or_panic(v[0] == 281); + assert_or_panic(v[1] == 282); + assert_or_panic(v[2] == 283); + assert_or_panic(v[3] == 284); + assert_or_panic(v[4] == 285); + assert_or_panic(v[5] == 286); + assert_or_panic(v[6] == 287); + assert_or_panic(v[7] == 288); + assert_or_panic(v[8] == 289); + assert_or_panic(v[9] == 290); + assert_or_panic(v[10] == 291); + assert_or_panic(v[11] == 292); + assert_or_panic(v[12] == 293); + assert_or_panic(v[13] == 294); + assert_or_panic(v[14] == 295); + assert_or_panic(v[15] == 296); + assert_or_panic(v[16] == 297); + assert_or_panic(v[17] == 298); + assert_or_panic(v[18] == 299); + assert_or_panic(v[19] == 300); + assert_or_panic(v[20] == 301); + assert_or_panic(v[21] == 302); + assert_or_panic(v[22] == 303); + assert_or_panic(v[23] == 304); + assert_or_panic(i == 24); +} +void c_test_vector_24_f64(void) { + Vector_24_f64 v = zig_ret_vector_24_f64(); + assert_or_panic(v[0] == 209); + assert_or_panic(v[1] == 210); + assert_or_panic(v[2] == 211); + assert_or_panic(v[3] == 212); + assert_or_panic(v[4] == 213); + assert_or_panic(v[5] == 214); + assert_or_panic(v[6] == 215); + assert_or_panic(v[7] == 216); + assert_or_panic(v[8] == 217); + assert_or_panic(v[9] == 218); + assert_or_panic(v[10] == 219); + assert_or_panic(v[11] == 220); + assert_or_panic(v[12] == 221); + assert_or_panic(v[13] == 222); + assert_or_panic(v[14] == 223); + assert_or_panic(v[15] == 224); + assert_or_panic(v[16] == 225); + assert_or_panic(v[17] == 226); + assert_or_panic(v[18] == 227); + assert_or_panic(v[19] == 228); + assert_or_panic(v[20] == 229); + assert_or_panic(v[21] == 230); + assert_or_panic(v[22] == 231); + assert_or_panic(v[23] == 232); + zig_vector_24_f64((Vector_24_f64){ + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, + }, 24); +} + +typedef double Vector_32_f64 __attribute__((vector_size(32 * sizeof(double)))); + +Vector_32_f64 zig_ret_vector_32_f64(void); +void zig_vector_32_f64(Vector_32_f64, size_t); + +Vector_32_f64 c_ret_vector_32_f64(void) { + return (Vector_32_f64){ + 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, + 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, + }; +} +void c_vector_32_f64(Vector_32_f64 v, size_t i) { + assert_or_panic(v[0] == 401); + assert_or_panic(v[1] == 402); + assert_or_panic(v[2] == 403); + assert_or_panic(v[3] == 404); + assert_or_panic(v[4] == 405); + assert_or_panic(v[5] == 406); + assert_or_panic(v[6] == 407); + assert_or_panic(v[7] == 408); + assert_or_panic(v[8] == 409); + assert_or_panic(v[9] == 410); + assert_or_panic(v[10] == 411); + assert_or_panic(v[11] == 412); + assert_or_panic(v[12] == 413); + assert_or_panic(v[13] == 414); + assert_or_panic(v[14] == 415); + assert_or_panic(v[15] == 416); + assert_or_panic(v[16] == 417); + assert_or_panic(v[17] == 418); + assert_or_panic(v[18] == 419); + assert_or_panic(v[19] == 420); + assert_or_panic(v[20] == 421); + assert_or_panic(v[21] == 422); + assert_or_panic(v[22] == 423); + assert_or_panic(v[23] == 424); + assert_or_panic(v[24] == 425); + assert_or_panic(v[25] == 426); + assert_or_panic(v[26] == 427); + assert_or_panic(v[27] == 428); + assert_or_panic(v[28] == 429); + assert_or_panic(v[29] == 430); + assert_or_panic(v[30] == 431); + assert_or_panic(v[31] == 432); + assert_or_panic(i == 32); +} +void c_test_vector_32_f64(void) { + Vector_32_f64 v = zig_ret_vector_32_f64(); + assert_or_panic(v[0] == 305); + assert_or_panic(v[1] == 306); + assert_or_panic(v[2] == 307); + assert_or_panic(v[3] == 308); + assert_or_panic(v[4] == 309); + assert_or_panic(v[5] == 310); + assert_or_panic(v[6] == 311); + assert_or_panic(v[7] == 312); + assert_or_panic(v[8] == 313); + assert_or_panic(v[9] == 314); + assert_or_panic(v[10] == 315); + assert_or_panic(v[11] == 316); + assert_or_panic(v[12] == 317); + assert_or_panic(v[13] == 318); + assert_or_panic(v[14] == 319); + assert_or_panic(v[15] == 320); + assert_or_panic(v[16] == 321); + assert_or_panic(v[17] == 322); + assert_or_panic(v[18] == 323); + assert_or_panic(v[19] == 324); + assert_or_panic(v[20] == 325); + assert_or_panic(v[21] == 326); + assert_or_panic(v[22] == 327); + assert_or_panic(v[23] == 328); + assert_or_panic(v[24] == 329); + assert_or_panic(v[25] == 330); + assert_or_panic(v[26] == 331); + assert_or_panic(v[27] == 332); + assert_or_panic(v[28] == 333); + assert_or_panic(v[29] == 334); + assert_or_panic(v[30] == 335); + assert_or_panic(v[31] == 336); + zig_vector_32_f64((Vector_32_f64){ + 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, + 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, + }, 32); +} + +typedef double Vector_48_f64 __attribute__((vector_size(48 * sizeof(double)))); + +Vector_48_f64 zig_ret_vector_48_f64(void); +void zig_vector_48_f64(Vector_48_f64, size_t); + +Vector_48_f64 c_ret_vector_48_f64(void) { + return (Vector_48_f64){ + 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, + 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, + }; +} +void c_vector_48_f64(Vector_48_f64 v, size_t i) { + assert_or_panic(v[0] == 577); + assert_or_panic(v[1] == 578); + assert_or_panic(v[2] == 579); + assert_or_panic(v[3] == 580); + assert_or_panic(v[4] == 581); + assert_or_panic(v[5] == 582); + assert_or_panic(v[6] == 583); + assert_or_panic(v[7] == 584); + assert_or_panic(v[8] == 585); + assert_or_panic(v[9] == 586); + assert_or_panic(v[10] == 587); + assert_or_panic(v[11] == 588); + assert_or_panic(v[12] == 589); + assert_or_panic(v[13] == 590); + assert_or_panic(v[14] == 591); + assert_or_panic(v[15] == 592); + assert_or_panic(v[16] == 593); + assert_or_panic(v[17] == 594); + assert_or_panic(v[18] == 595); + assert_or_panic(v[19] == 596); + assert_or_panic(v[20] == 597); + assert_or_panic(v[21] == 598); + assert_or_panic(v[22] == 599); + assert_or_panic(v[23] == 600); + assert_or_panic(v[24] == 601); + assert_or_panic(v[25] == 602); + assert_or_panic(v[26] == 603); + assert_or_panic(v[27] == 604); + assert_or_panic(v[28] == 605); + assert_or_panic(v[29] == 606); + assert_or_panic(v[30] == 607); + assert_or_panic(v[31] == 608); + assert_or_panic(v[32] == 609); + assert_or_panic(v[33] == 610); + assert_or_panic(v[34] == 611); + assert_or_panic(v[35] == 612); + assert_or_panic(v[36] == 613); + assert_or_panic(v[37] == 614); + assert_or_panic(v[38] == 615); + assert_or_panic(v[39] == 616); + assert_or_panic(v[40] == 617); + assert_or_panic(v[41] == 618); + assert_or_panic(v[42] == 619); + assert_or_panic(v[43] == 620); + assert_or_panic(v[44] == 621); + assert_or_panic(v[45] == 622); + assert_or_panic(v[46] == 623); + assert_or_panic(v[47] == 624); + assert_or_panic(i == 48); +} +void c_test_vector_48_f64(void) { + Vector_48_f64 v = zig_ret_vector_48_f64(); + assert_or_panic(v[0] == 433); + assert_or_panic(v[1] == 434); + assert_or_panic(v[2] == 435); + assert_or_panic(v[3] == 436); + assert_or_panic(v[4] == 437); + assert_or_panic(v[5] == 438); + assert_or_panic(v[6] == 439); + assert_or_panic(v[7] == 440); + assert_or_panic(v[8] == 441); + assert_or_panic(v[9] == 442); + assert_or_panic(v[10] == 443); + assert_or_panic(v[11] == 444); + assert_or_panic(v[12] == 445); + assert_or_panic(v[13] == 446); + assert_or_panic(v[14] == 447); + assert_or_panic(v[15] == 448); + assert_or_panic(v[16] == 449); + assert_or_panic(v[17] == 450); + assert_or_panic(v[18] == 451); + assert_or_panic(v[19] == 452); + assert_or_panic(v[20] == 453); + assert_or_panic(v[21] == 454); + assert_or_panic(v[22] == 455); + assert_or_panic(v[23] == 456); + assert_or_panic(v[24] == 457); + assert_or_panic(v[25] == 458); + assert_or_panic(v[26] == 459); + assert_or_panic(v[27] == 460); + assert_or_panic(v[28] == 461); + assert_or_panic(v[29] == 462); + assert_or_panic(v[30] == 463); + assert_or_panic(v[31] == 464); + assert_or_panic(v[32] == 465); + assert_or_panic(v[33] == 466); + assert_or_panic(v[34] == 467); + assert_or_panic(v[35] == 468); + assert_or_panic(v[36] == 469); + assert_or_panic(v[37] == 470); + assert_or_panic(v[38] == 471); + assert_or_panic(v[39] == 472); + assert_or_panic(v[40] == 473); + assert_or_panic(v[41] == 474); + assert_or_panic(v[42] == 475); + assert_or_panic(v[43] == 476); + assert_or_panic(v[44] == 477); + assert_or_panic(v[45] == 478); + assert_or_panic(v[46] == 479); + assert_or_panic(v[47] == 480); + zig_vector_48_f64((Vector_48_f64){ + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, + 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, + }, 48); +} + +typedef double Vector_64_f64 __attribute__((vector_size(64 * sizeof(double)))); + +Vector_64_f64 zig_ret_vector_64_f64(void); +void zig_vector_64_f64(Vector_64_f64, size_t); + +Vector_64_f64 c_ret_vector_64_f64(void) { + return (Vector_64_f64){ + 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, + 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, }; } +void c_vector_64_f64(Vector_64_f64 v, size_t i) { + assert_or_panic(v[0] == 817); + assert_or_panic(v[1] == 818); + assert_or_panic(v[2] == 819); + assert_or_panic(v[3] == 820); + assert_or_panic(v[4] == 821); + assert_or_panic(v[5] == 822); + assert_or_panic(v[6] == 823); + assert_or_panic(v[7] == 824); + assert_or_panic(v[8] == 825); + assert_or_panic(v[9] == 826); + assert_or_panic(v[10] == 827); + assert_or_panic(v[11] == 828); + assert_or_panic(v[12] == 829); + assert_or_panic(v[13] == 830); + assert_or_panic(v[14] == 831); + assert_or_panic(v[15] == 832); + assert_or_panic(v[16] == 833); + assert_or_panic(v[17] == 834); + assert_or_panic(v[18] == 835); + assert_or_panic(v[19] == 836); + assert_or_panic(v[20] == 837); + assert_or_panic(v[21] == 838); + assert_or_panic(v[22] == 839); + assert_or_panic(v[23] == 840); + assert_or_panic(v[24] == 841); + assert_or_panic(v[25] == 842); + assert_or_panic(v[26] == 843); + assert_or_panic(v[27] == 844); + assert_or_panic(v[28] == 845); + assert_or_panic(v[29] == 846); + assert_or_panic(v[30] == 847); + assert_or_panic(v[31] == 848); + assert_or_panic(v[32] == 849); + assert_or_panic(v[33] == 850); + assert_or_panic(v[34] == 851); + assert_or_panic(v[35] == 852); + assert_or_panic(v[36] == 853); + assert_or_panic(v[37] == 854); + assert_or_panic(v[38] == 855); + assert_or_panic(v[39] == 856); + assert_or_panic(v[40] == 857); + assert_or_panic(v[41] == 858); + assert_or_panic(v[42] == 859); + assert_or_panic(v[43] == 860); + assert_or_panic(v[44] == 861); + assert_or_panic(v[45] == 862); + assert_or_panic(v[46] == 863); + assert_or_panic(v[47] == 864); + assert_or_panic(v[48] == 865); + assert_or_panic(v[49] == 866); + assert_or_panic(v[50] == 867); + assert_or_panic(v[51] == 868); + assert_or_panic(v[52] == 869); + assert_or_panic(v[53] == 870); + assert_or_panic(v[54] == 871); + assert_or_panic(v[55] == 872); + assert_or_panic(v[56] == 873); + assert_or_panic(v[57] == 874); + assert_or_panic(v[58] == 875); + assert_or_panic(v[59] == 876); + assert_or_panic(v[60] == 877); + assert_or_panic(v[61] == 878); + assert_or_panic(v[62] == 879); + assert_or_panic(v[63] == 880); + assert_or_panic(i == 64); +} +void c_test_vector_64_f64(void) { + Vector_64_f64 v = zig_ret_vector_64_f64(); + assert_or_panic(v[0] == 625); + assert_or_panic(v[1] == 626); + assert_or_panic(v[2] == 627); + assert_or_panic(v[3] == 628); + assert_or_panic(v[4] == 629); + assert_or_panic(v[5] == 630); + assert_or_panic(v[6] == 631); + assert_or_panic(v[7] == 632); + assert_or_panic(v[8] == 633); + assert_or_panic(v[9] == 634); + assert_or_panic(v[10] == 635); + assert_or_panic(v[11] == 636); + assert_or_panic(v[12] == 637); + assert_or_panic(v[13] == 638); + assert_or_panic(v[14] == 639); + assert_or_panic(v[15] == 640); + assert_or_panic(v[16] == 641); + assert_or_panic(v[17] == 642); + assert_or_panic(v[18] == 643); + assert_or_panic(v[19] == 644); + assert_or_panic(v[20] == 645); + assert_or_panic(v[21] == 646); + assert_or_panic(v[22] == 647); + assert_or_panic(v[23] == 648); + assert_or_panic(v[24] == 649); + assert_or_panic(v[25] == 650); + assert_or_panic(v[26] == 651); + assert_or_panic(v[27] == 652); + assert_or_panic(v[28] == 653); + assert_or_panic(v[29] == 654); + assert_or_panic(v[30] == 655); + assert_or_panic(v[31] == 656); + assert_or_panic(v[32] == 657); + assert_or_panic(v[33] == 658); + assert_or_panic(v[34] == 659); + assert_or_panic(v[35] == 660); + assert_or_panic(v[36] == 661); + assert_or_panic(v[37] == 662); + assert_or_panic(v[38] == 663); + assert_or_panic(v[39] == 664); + assert_or_panic(v[40] == 665); + assert_or_panic(v[41] == 666); + assert_or_panic(v[42] == 667); + assert_or_panic(v[43] == 668); + assert_or_panic(v[44] == 669); + assert_or_panic(v[45] == 670); + assert_or_panic(v[46] == 671); + assert_or_panic(v[47] == 672); + assert_or_panic(v[48] == 673); + assert_or_panic(v[49] == 674); + assert_or_panic(v[50] == 675); + assert_or_panic(v[51] == 676); + assert_or_panic(v[52] == 677); + assert_or_panic(v[53] == 678); + assert_or_panic(v[54] == 679); + assert_or_panic(v[55] == 680); + assert_or_panic(v[56] == 681); + assert_or_panic(v[57] == 682); + assert_or_panic(v[58] == 683); + assert_or_panic(v[59] == 684); + assert_or_panic(v[60] == 685); + assert_or_panic(v[61] == 686); + assert_or_panic(v[62] == 687); + assert_or_panic(v[63] == 688); + zig_vector_64_f64((Vector_64_f64){ + 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, + 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, + }, 64); +} + +struct Struct_u8 { + uint8_t a; +}; + +struct Struct_u8 zig_ret_struct_u8(void); +void zig_struct_u8(struct Struct_u8, size_t); + +struct Struct_u8 c_ret_struct_u8(void) { + return (struct Struct_u8){ .a = 4 }; +} +void c_struct_u8(struct Struct_u8 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_u8(void) { + struct Struct_u8 s = zig_ret_struct_u8(); + assert_or_panic(s.a == 1); + zig_struct_u8((struct Struct_u8){ .a = 2 }, 3); +} + +struct Struct_u8_u8 { + uint8_t a, b; +}; + +struct Struct_u8_u8 zig_ret_struct_u8_u8(void); +void zig_struct_u8_u8(struct Struct_u8_u8, size_t); + +struct Struct_u8_u8 c_ret_struct_u8_u8(void) { + return (struct Struct_u8_u8){ .a = 6, .b = 7 }; +} +void c_struct_u8_u8(struct Struct_u8_u8 s, size_t i) { + assert_or_panic(s.a == 8); + assert_or_panic(s.b == 9); + assert_or_panic(i == 10); +} +void c_test_struct_u8_u8(void) { + struct Struct_u8_u8 s = zig_ret_struct_u8_u8(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + zig_struct_u8_u8((struct Struct_u8_u8){ .a = 3, .b = 4 }, 5); +} + +struct Struct_u8_u8_u8 { + uint8_t a, b, c; +}; + +struct Struct_u8_u8_u8 zig_ret_struct_u8_u8_u8(void); +void zig_struct_u8_u8_u8(struct Struct_u8_u8_u8, size_t); + +struct Struct_u8_u8_u8 c_ret_struct_u8_u8_u8(void) { + return (struct Struct_u8_u8_u8){ .a = 8, .b = 9, .c = 10 }; +} +void c_struct_u8_u8_u8(struct Struct_u8_u8_u8 s, size_t i) { + assert_or_panic(s.a == 11); + assert_or_panic(s.b == 12); + assert_or_panic(s.c == 13); + assert_or_panic(i == 14); +} +void c_test_struct_u8_u8_u8(void) { + struct Struct_u8_u8_u8 s = zig_ret_struct_u8_u8_u8(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + zig_struct_u8_u8_u8((struct Struct_u8_u8_u8){ .a = 4, .b = 5, .c = 6 }, 7); +} + +struct Struct_u8_u8_u8_u8 { + uint8_t a, b, c, d; +}; + +struct Struct_u8_u8_u8_u8 zig_ret_struct_u8_u8_u8_u8(void); +void zig_struct_u8_u8_u8_u8(struct Struct_u8_u8_u8_u8, size_t); + +struct Struct_u8_u8_u8_u8 c_ret_struct_u8_u8_u8_u8(void) { + return (struct Struct_u8_u8_u8_u8){ .a = 10, .b = 11, .c = 12, .d = 13 }; +} +void c_struct_u8_u8_u8_u8(struct Struct_u8_u8_u8_u8 s, size_t i) { + assert_or_panic(s.a == 14); + assert_or_panic(s.b == 15); + assert_or_panic(s.c == 16); + assert_or_panic(s.d == 17); + assert_or_panic(i == 18); +} +void c_test_struct_u8_u8_u8_u8(void) { + struct Struct_u8_u8_u8_u8 s = zig_ret_struct_u8_u8_u8_u8(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + zig_struct_u8_u8_u8_u8((struct Struct_u8_u8_u8_u8){ .a = 5, .b = 6, .c = 7, .d = 8 }, 9); +} + +struct Struct_u16 { + uint16_t a; +}; + +struct Struct_u16 zig_ret_struct_u16(void); +void zig_struct_u16(struct Struct_u16, size_t); + +struct Struct_u16 c_ret_struct_u16(void) { + return (struct Struct_u16){ .a = 4 }; +} +void c_struct_u16(struct Struct_u16 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_u16(void) { + struct Struct_u16 s = zig_ret_struct_u16(); + assert_or_panic(s.a == 1); + zig_struct_u16((struct Struct_u16){ .a = 2 }, 3); +} + +struct Struct_u16_u16 { + uint16_t a, b; +}; + +struct Struct_u16_u16 zig_ret_struct_u16_u16(void); +void zig_struct_u16_u16(struct Struct_u16_u16, size_t); + +struct Struct_u16_u16 c_ret_struct_u16_u16(void) { + return (struct Struct_u16_u16){ .a = 6, .b = 7 }; +} +void c_struct_u16_u16(struct Struct_u16_u16 s, size_t i) { + assert_or_panic(s.a == 8); + assert_or_panic(s.b == 9); + assert_or_panic(i == 10); +} +void c_test_struct_u16_u16(void) { + struct Struct_u16_u16 s = zig_ret_struct_u16_u16(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + zig_struct_u16_u16((struct Struct_u16_u16){ .a = 3, .b = 4 }, 5); +} + +struct Struct_u16_u16_u16 { + uint16_t a, b, c; +}; + +struct Struct_u16_u16_u16 zig_ret_struct_u16_u16_u16(void); +void zig_struct_u16_u16_u16(struct Struct_u16_u16_u16, size_t); + +struct Struct_u16_u16_u16 c_ret_struct_u16_u16_u16(void) { + return (struct Struct_u16_u16_u16){ .a = 8, .b = 9, .c = 10 }; +} +void c_struct_u16_u16_u16(struct Struct_u16_u16_u16 s, size_t i) { + assert_or_panic(s.a == 11); + assert_or_panic(s.b == 12); + assert_or_panic(s.c == 13); + assert_or_panic(i == 14); +} +void c_test_struct_u16_u16_u16(void) { + struct Struct_u16_u16_u16 s = zig_ret_struct_u16_u16_u16(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + zig_struct_u16_u16_u16((struct Struct_u16_u16_u16){ .a = 4, .b = 5, .c = 6 }, 7); +} + +struct Struct_u16_u16_u16_u16 { + uint16_t a, b, c, d; +}; + +struct Struct_u16_u16_u16_u16 zig_ret_struct_u16_u16_u16_u16(void); +void zig_struct_u16_u16_u16_u16(struct Struct_u16_u16_u16_u16, size_t); + +struct Struct_u16_u16_u16_u16 c_ret_struct_u16_u16_u16_u16(void) { + return (struct Struct_u16_u16_u16_u16){ .a = 10, .b = 11, .c = 12, .d = 13 }; +} +void c_struct_u16_u16_u16_u16(struct Struct_u16_u16_u16_u16 s, size_t i) { + assert_or_panic(s.a == 14); + assert_or_panic(s.b == 15); + assert_or_panic(s.c == 16); + assert_or_panic(s.d == 17); + assert_or_panic(i == 18); +} +void c_test_struct_u16_u16_u16_u16(void) { + struct Struct_u16_u16_u16_u16 s = zig_ret_struct_u16_u16_u16_u16(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + zig_struct_u16_u16_u16_u16((struct Struct_u16_u16_u16_u16){ .a = 5, .b = 6, .c = 7, .d = 8 }, 9); +} + +struct Struct_u32 { + uint32_t a; +}; + +struct Struct_u32 zig_ret_struct_u32(void); +void zig_struct_u32(struct Struct_u32, size_t); + +struct Struct_u32 c_ret_struct_u32(void) { + return (struct Struct_u32){ .a = 4 }; +} +void c_struct_u32(struct Struct_u32 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_u32(void) { + struct Struct_u32 s = zig_ret_struct_u32(); + assert_or_panic(s.a == 1); + zig_struct_u32((struct Struct_u32){ .a = 2 }, 3); +} + +struct Struct_u32_u32 { + uint32_t a, b; +}; + +struct Struct_u32_u32 zig_ret_struct_u32_u32(void); +void zig_struct_u32_u32(struct Struct_u32_u32, size_t); + +struct Struct_u32_u32 c_ret_struct_u32_u32(void) { + return (struct Struct_u32_u32){ .a = 6, .b = 7 }; +} +void c_struct_u32_u32(struct Struct_u32_u32 s, size_t i) { + assert_or_panic(s.a == 8); + assert_or_panic(s.b == 9); + assert_or_panic(i == 10); +} +void c_test_struct_u32_u32(void) { + struct Struct_u32_u32 s = zig_ret_struct_u32_u32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + zig_struct_u32_u32((struct Struct_u32_u32){ .a = 3, .b = 4 }, 5); +} + +struct Struct_u32_u32_u32 { + uint32_t a, b, c; +}; + +struct Struct_u32_u32_u32 zig_ret_struct_u32_u32_u32(void); +void zig_struct_u32_u32_u32(struct Struct_u32_u32_u32, size_t); + +struct Struct_u32_u32_u32 c_ret_struct_u32_u32_u32(void) { + return (struct Struct_u32_u32_u32){ .a = 8, .b = 9, .c = 10 }; +} +void c_struct_u32_u32_u32(struct Struct_u32_u32_u32 s, size_t i) { + assert_or_panic(s.a == 11); + assert_or_panic(s.b == 12); + assert_or_panic(s.c == 13); + assert_or_panic(i == 14); +} +void c_test_struct_u32_u32_u32(void) { + struct Struct_u32_u32_u32 s = zig_ret_struct_u32_u32_u32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + zig_struct_u32_u32_u32((struct Struct_u32_u32_u32){ .a = 4, .b = 5, .c = 6 }, 7); +} + +struct Struct_u32_u32_u32_u32 { + uint32_t a, b, c, d; +}; + +struct Struct_u32_u32_u32_u32 zig_ret_struct_u32_u32_u32_u32(void); +void zig_struct_u32_u32_u32_u32(struct Struct_u32_u32_u32_u32, size_t); + +struct Struct_u32_u32_u32_u32 c_ret_struct_u32_u32_u32_u32(void) { + return (struct Struct_u32_u32_u32_u32){ .a = 10, .b = 11, .c = 12, .d = 13 }; +} +void c_struct_u32_u32_u32_u32(struct Struct_u32_u32_u32_u32 s, size_t i) { + assert_or_panic(s.a == 14); + assert_or_panic(s.b == 15); + assert_or_panic(s.c == 16); + assert_or_panic(s.d == 17); + assert_or_panic(i == 18); +} +void c_test_struct_u32_u32_u32_u32(void) { + struct Struct_u32_u32_u32_u32 s = zig_ret_struct_u32_u32_u32_u32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + zig_struct_u32_u32_u32_u32((struct Struct_u32_u32_u32_u32){ .a = 5, .b = 6, .c = 7, .d = 8 }, 9); +} + +struct Struct_u64 { + uint64_t a; +}; + +struct Struct_u64 zig_ret_struct_u64(void); +void zig_struct_u64(struct Struct_u64, size_t); + +struct Struct_u64 c_ret_struct_u64(void) { + return (struct Struct_u64){ .a = 4 }; +} +void c_struct_u64(struct Struct_u64 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_u64(void) { + struct Struct_u64 s = zig_ret_struct_u64(); + assert_or_panic(s.a == 1); + zig_struct_u64((struct Struct_u64){ .a = 2 }, 3); +} + +struct Struct_u64_u64 { + uint64_t a; + uint64_t b; +}; + +struct Struct_u64_u64 zig_ret_struct_u64_u64(void); +void zig_struct_u64_u64(struct Struct_u64_u64, size_t); +void zig_1_struct_u64_u64(size_t, struct Struct_u64_u64, size_t); +void zig_2_struct_u64_u64(size_t, size_t, struct Struct_u64_u64, size_t); +void zig_3_struct_u64_u64(size_t, size_t, size_t, struct Struct_u64_u64, size_t); +void zig_4_struct_u64_u64(size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); +void zig_5_struct_u64_u64(size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); +void zig_6_struct_u64_u64(size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); +void zig_7_struct_u64_u64(size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); +void zig_8_struct_u64_u64(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t); + +struct Struct_u64_u64 c_ret_struct_u64_u64(void) { + return (struct Struct_u64_u64){ .a = 21, .b = 22 }; +} +void c_struct_u64_u64(struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 23); + assert_or_panic(s.b == 24); + assert_or_panic(i == 1); +} +void c_1_struct_u64_u64(size_t a0, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 25); + assert_or_panic(s.b == 26); + assert_or_panic(i == 2); +} +void c_2_struct_u64_u64(size_t a0, size_t a1, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 27); + assert_or_panic(s.b == 28); + assert_or_panic(i == 3); +} +void c_3_struct_u64_u64(size_t a0, size_t a1, size_t a2, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 29); + assert_or_panic(s.b == 30); + assert_or_panic(i == 4); +} +void c_4_struct_u64_u64(size_t a0, size_t a1, size_t a2, size_t a3, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 31); + assert_or_panic(s.b == 32); + assert_or_panic(i == 5); +} +void c_5_struct_u64_u64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 33); + assert_or_panic(s.b == 34); + assert_or_panic(i == 6); +} +void c_6_struct_u64_u64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 35); + assert_or_panic(s.b == 36); + assert_or_panic(i == 7); +} +void c_7_struct_u64_u64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 37); + assert_or_panic(s.b == 38); + assert_or_panic(i == 8); +} +void c_8_struct_u64_u64(size_t a0, size_t a1, size_t a2, size_t a3, size_t a4, size_t a5, size_t a6, size_t a7, struct Struct_u64_u64 s, size_t i) { + assert_or_panic(s.a == 39); + assert_or_panic(s.b == 40); + assert_or_panic(i == 9); +} +void c_test_struct_u64_u64(void) { + struct Struct_u64_u64 s = zig_ret_struct_u64_u64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + zig_struct_u64_u64((struct Struct_u64_u64){ .a = 3, .b = 4 }, 1); + zig_1_struct_u64_u64(0, (struct Struct_u64_u64){ .a = 5, .b = 6 }, 2); + zig_2_struct_u64_u64(0, 1, (struct Struct_u64_u64){ .a = 7, .b = 8 }, 3); + zig_3_struct_u64_u64(0, 1, 2, (struct Struct_u64_u64){ .a = 9, .b = 10 }, 4); + zig_4_struct_u64_u64(0, 1, 2, 3, (struct Struct_u64_u64){ .a = 11, .b = 12 }, 5); + zig_5_struct_u64_u64(0, 1, 2, 3, 4, (struct Struct_u64_u64){ .a = 13, .b = 14 }, 6); + zig_6_struct_u64_u64(0, 1, 2, 3, 4, 5, (struct Struct_u64_u64){ .a = 15, .b = 16 }, 7); + zig_7_struct_u64_u64(0, 1, 2, 3, 4, 5, 6, (struct Struct_u64_u64){ .a = 17, .b = 18 }, 8); + zig_8_struct_u64_u64(0, 1, 2, 3, 4, 5, 6, 7, (struct Struct_u64_u64){ .a = 19, .b = 20 }, 9); +} + +struct Struct_u64_u64_u64 { + uint64_t a, b, c; +}; + +struct Struct_u64_u64_u64 zig_ret_struct_u64_u64_u64(void); +void zig_struct_u64_u64_u64(struct Struct_u64_u64_u64, size_t); + +struct Struct_u64_u64_u64 c_ret_struct_u64_u64_u64(void) { + return (struct Struct_u64_u64_u64){ .a = 8, .b = 9, .c = 10 }; +} +void c_struct_u64_u64_u64(struct Struct_u64_u64_u64 s, size_t i) { + assert_or_panic(s.a == 11); + assert_or_panic(s.b == 12); + assert_or_panic(s.c == 13); + assert_or_panic(i == 14); +} +void c_test_struct_u64_u64_u64(void) { + struct Struct_u64_u64_u64 s = zig_ret_struct_u64_u64_u64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + zig_struct_u64_u64_u64((struct Struct_u64_u64_u64){ .a = 4, .b = 5, .c = 6 }, 7); +} + +struct Struct_u64_u64_u64_u64 { + uint64_t a, b, c, d; +}; + +struct Struct_u64_u64_u64_u64 zig_ret_struct_u64_u64_u64_u64(void); +void zig_struct_u64_u64_u64_u64(struct Struct_u64_u64_u64_u64, size_t); + +struct Struct_u64_u64_u64_u64 c_ret_struct_u64_u64_u64_u64(void) { + return (struct Struct_u64_u64_u64_u64){ .a = 10, .b = 11, .c = 12, .d = 13 }; +} +void c_struct_u64_u64_u64_u64(struct Struct_u64_u64_u64_u64 s, size_t i) { + assert_or_panic(s.a == 14); + assert_or_panic(s.b == 15); + assert_or_panic(s.c == 16); + assert_or_panic(s.d == 17); + assert_or_panic(i == 18); +} +void c_test_struct_u64_u64_u64_u64(void) { + struct Struct_u64_u64_u64_u64 s = zig_ret_struct_u64_u64_u64_u64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + zig_struct_u64_u64_u64_u64((struct Struct_u64_u64_u64_u64){ .a = 5, .b = 6, .c = 7, .d = 8 }, 9); +} + +struct Struct_f32 { + float a; +}; + +struct Struct_f32 zig_ret_struct_f32(void); +void zig_struct_f32(struct Struct_f32, size_t); + +struct Struct_f32 c_ret_struct_f32(void) { + return (struct Struct_f32){ .a = 4 }; +} +void c_struct_f32(struct Struct_f32 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_f32(void) { + struct Struct_f32 s = zig_ret_struct_f32(); + assert_or_panic(s.a == 1); + zig_struct_f32((struct Struct_f32){ .a = 2 }, 3); +} + +struct Struct_f32_f32 { + float a, b; +}; + +struct Struct_f32_f32 zig_ret_struct_f32_f32(void); +void zig_struct_f32_f32(struct Struct_f32_f32, size_t); + +struct Struct_f32_f32 c_ret_struct_f32_f32(void) { + return (struct Struct_f32_f32){ .a = 6, .b = 7 }; +} +void c_struct_f32_f32(struct Struct_f32_f32 s, size_t i) { + assert_or_panic(s.a == 8); + assert_or_panic(s.b == 9); + assert_or_panic(i == 10); +} +void c_test_struct_f32_f32(void) { + struct Struct_f32_f32 s = zig_ret_struct_f32_f32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + zig_struct_f32_f32((struct Struct_f32_f32){ .a = 3, .b = 4 }, 5); +} + +struct Struct_f32_f32_f32 { + float a, b, c; +}; + +struct Struct_f32_f32_f32 zig_ret_struct_f32_f32_f32(void); +void zig_struct_f32_f32_f32(struct Struct_f32_f32_f32, size_t); + +struct Struct_f32_f32_f32 c_ret_struct_f32_f32_f32(void) { + return (struct Struct_f32_f32_f32){ .a = 8, .b = 9, .c = 10 }; +} +void c_struct_f32_f32_f32(struct Struct_f32_f32_f32 s, size_t i) { + assert_or_panic(s.a == 11); + assert_or_panic(s.b == 12); + assert_or_panic(s.c == 13); + assert_or_panic(i == 14); +} +void c_test_struct_f32_f32_f32(void) { + struct Struct_f32_f32_f32 s = zig_ret_struct_f32_f32_f32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + zig_struct_f32_f32_f32((struct Struct_f32_f32_f32){ .a = 4, .b = 5, .c = 6 }, 7); +} + +struct Struct_f32_f32_f32_f32 { + float a, b, c, d; +}; + +struct Struct_f32_f32_f32_f32 zig_ret_struct_f32_f32_f32_f32(void); +void zig_struct_f32_f32_f32_f32(struct Struct_f32_f32_f32_f32, size_t); + +struct Struct_f32_f32_f32_f32 c_ret_struct_f32_f32_f32_f32(void) { + return (struct Struct_f32_f32_f32_f32){ .a = 10, .b = 11, .c = 12, .d = 13 }; +} +void c_struct_f32_f32_f32_f32(struct Struct_f32_f32_f32_f32 s, size_t i) { + assert_or_panic(s.a == 14); + assert_or_panic(s.b == 15); + assert_or_panic(s.c == 16); + assert_or_panic(s.d == 17); + assert_or_panic(i == 18); +} +void c_test_struct_f32_f32_f32_f32(void) { + struct Struct_f32_f32_f32_f32 s = zig_ret_struct_f32_f32_f32_f32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + zig_struct_f32_f32_f32_f32((struct Struct_f32_f32_f32_f32){ .a = 5, .b = 6, .c = 7, .d = 8 }, 9); +} + +struct Struct_f32_f32_f32_f32_f32 { + float a, b, c, d, e; +}; + +struct Struct_f32_f32_f32_f32_f32 zig_ret_struct_f32_f32_f32_f32_f32(void); +void zig_struct_f32_f32_f32_f32_f32(struct Struct_f32_f32_f32_f32_f32, size_t); + +struct Struct_f32_f32_f32_f32_f32 c_ret_struct_f32_f32_f32_f32_f32(void) { + return (struct Struct_f32_f32_f32_f32_f32){ .a = 12, .b = 13, .c = 14, .d = 15, .e = 16 }; +} +void c_struct_f32_f32_f32_f32_f32(struct Struct_f32_f32_f32_f32_f32 s, size_t i) { + assert_or_panic(s.a == 17); + assert_or_panic(s.b == 18); + assert_or_panic(s.c == 19); + assert_or_panic(s.d == 20); + assert_or_panic(s.e == 21); + assert_or_panic(i == 22); +} +void c_test_struct_f32_f32_f32_f32_f32(void) { + struct Struct_f32_f32_f32_f32_f32 s = zig_ret_struct_f32_f32_f32_f32_f32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + assert_or_panic(s.e == 5); + 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_f32a8 { + alignas(8) float a; +}; + +struct Struct_f32a8 zig_ret_struct_f32a8(void); +void zig_struct_f32a8(struct Struct_f32a8, float); + +struct Struct_f32a8 c_ret_struct_f32a8(void) { + return (struct Struct_f32a8){ .a = 4.125f }; +} +void c_struct_f32a8(struct Struct_f32a8 s, float f) { + assert_or_panic(s.a == 5.375f); + assert_or_panic(f == 6.5f); +} +void c_test_struct_f32a8(void) { + struct Struct_f32a8 s = zig_ret_struct_f32a8(); + assert_or_panic(s.a == 1.25f); + zig_struct_f32a8((struct Struct_f32a8){ .a = 2.75f }, 3.5f); +} + +struct Struct_f32a8_f32a8 { + alignas(8) float a; + alignas(8) float b; +}; + +struct Struct_f32a8_f32a8 zig_ret_struct_f32a8_f32a8(void); +void zig_struct_f32a8_f32a8(struct Struct_f32a8_f32a8, float); + +struct Struct_f32a8_f32a8 c_ret_struct_f32a8_f32a8(void) { + return (struct Struct_f32a8_f32a8){ .a = 6.625f, .b = 7.875f }; +} +void c_struct_f32a8_f32a8(struct Struct_f32a8_f32a8 s, float f) { + assert_or_panic(s.a == 8.0625f); + assert_or_panic(s.b == 9.1875f); + assert_or_panic(f == 10.5f); +} +void c_test_struct_f32a8_f32a8(void) { + struct Struct_f32a8_f32a8 s = zig_ret_struct_f32a8_f32a8(); + assert_or_panic(s.a == 1.25f); + assert_or_panic(s.b == 2.75f); + zig_struct_f32a8_f32a8((struct Struct_f32a8_f32a8){ .a = 3.125f, .b = 4.375f }, 5.5f); +} + +struct Struct_f32f32_f32 { + struct { + float b, c; + } a; + float d; +}; + +struct Struct_f32f32_f32 zig_ret_struct_f32f32_f32(void); +void zig_struct_f32f32_f32(struct Struct_f32f32_f32); + +struct Struct_f32f32_f32 c_ret_struct_f32f32_f32(void) { + return (struct Struct_f32f32_f32){ .a = { .b = 1.0f, .c = 2.0f }, .d = 3.0f }; +} +void c_struct_f32f32_f32(struct Struct_f32f32_f32 s) { + assert_or_panic(s.a.b == 1.0f); + assert_or_panic(s.a.c == 2.0f); + assert_or_panic(s.d == 3.0f); +} +void c_test_struct_f32f32_f32(void) { + struct Struct_f32f32_f32 s = zig_ret_struct_f32f32_f32(); + assert_or_panic(s.a.b == 1.0f); + assert_or_panic(s.a.c == 2.0f); + assert_or_panic(s.d == 3.0f); + zig_struct_f32f32_f32((struct Struct_f32f32_f32){ .a = { .b = 1.0f, .c = 2.0f }, .d = 3.0f }); +} + +struct Struct_f32_f32f32 { + float a; + struct { + float c, d; + } b; +}; + +struct Struct_f32_f32f32 zig_ret_struct_f32_f32f32(void); +void zig_struct_f32_f32f32(struct Struct_f32_f32f32); + +struct Struct_f32_f32f32 c_ret_struct_f32_f32f32(void) { + return (struct Struct_f32_f32f32){ .a = 1.0f, .b = { .c = 2.0f, .d = 3.0f } }; +} +void c_struct_f32_f32f32(struct Struct_f32_f32f32 s) { + assert_or_panic(s.a == 1.0f); + assert_or_panic(s.b.c == 2.0f); + assert_or_panic(s.b.d == 3.0f); +} +void c_test_struct_f32_f32f32(void) { + struct Struct_f32_f32f32 s = zig_ret_struct_f32_f32f32(); + assert_or_panic(s.a == 1.0f); + assert_or_panic(s.b.c == 2.0f); + assert_or_panic(s.b.d == 3.0f); + zig_struct_f32_f32f32((struct Struct_f32_f32f32){ .a = 1.0f, .b = { .c = 2.0f, .d = 3.0f } }); +} + +struct Struct_f64 { + double a; +}; + +struct Struct_f64 zig_ret_struct_f64(void); +void zig_struct_f64(struct Struct_f64, size_t); + +struct Struct_f64 c_ret_struct_f64(void) { + return (struct Struct_f64){ .a = 4 }; +} +void c_struct_f64(struct Struct_f64 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_f64(void) { + struct Struct_f64 s = zig_ret_struct_f64(); + assert_or_panic(s.a == 1); + zig_struct_f64((struct Struct_f64){ .a = 2 }, 3); +} + +struct Struct_f64_f64 { + double a, b; +}; + +struct Struct_f64_f64 zig_ret_struct_f64_f64(void); +void zig_struct_f64_f64(struct Struct_f64_f64, size_t); + +struct Struct_f64_f64 c_ret_struct_f64_f64(void) { + return (struct Struct_f64_f64){ .a = 6, .b = 7 }; +} +void c_struct_f64_f64(struct Struct_f64_f64 s, size_t i) { + assert_or_panic(s.a == 8); + assert_or_panic(s.b == 9); + assert_or_panic(i == 10); +} +void c_test_struct_f64_f64(void) { + struct Struct_f64_f64 s = zig_ret_struct_f64_f64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + zig_struct_f64_f64((struct Struct_f64_f64){ .a = 3, .b = 4 }, 5); +} + +struct Struct_f64_f64_f64 { + double a, b, c; +}; -void zig_vector_2_bool(Vector2Bool vec); -void zig_vector_4_bool(Vector4Bool vec); -void zig_vector_8_bool(Vector8Bool vec); -void zig_vector_16_bool(Vector16Bool vec); -void zig_vector_32_bool(Vector32Bool vec); -void zig_vector_64_bool(Vector64Bool vec); -void zig_vector_128_bool(Vector128Bool vec); -void zig_vector_256_bool(Vector256Bool vec); -void zig_vector_512_bool(Vector512Bool vec); - -Vector2Bool zig_ret_vector_2_bool(void); -Vector4Bool zig_ret_vector_4_bool(void); -Vector8Bool zig_ret_vector_8_bool(void); -Vector16Bool zig_ret_vector_16_bool(void); -Vector32Bool zig_ret_vector_32_bool(void); -Vector64Bool zig_ret_vector_64_bool(void); -Vector128Bool zig_ret_vector_128_bool(void); -Vector256Bool zig_ret_vector_256_bool(void); -Vector512Bool zig_ret_vector_512_bool(void); +struct Struct_f64_f64_f64 zig_ret_struct_f64_f64_f64(void); +void zig_struct_f64_f64_f64(struct Struct_f64_f64_f64, size_t); +struct Struct_f64_f64_f64 c_ret_struct_f64_f64_f64(void) { + return (struct Struct_f64_f64_f64){ .a = 8, .b = 9, .c = 10 }; +} +void c_struct_f64_f64_f64(struct Struct_f64_f64_f64 s, size_t i) { + assert_or_panic(s.a == 11); + assert_or_panic(s.b == 12); + assert_or_panic(s.c == 13); + assert_or_panic(i == 14); +} +void c_test_struct_f64_f64_f64(void) { + struct Struct_f64_f64_f64 s = zig_ret_struct_f64_f64_f64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + zig_struct_f64_f64_f64((struct Struct_f64_f64_f64){ .a = 4, .b = 5, .c = 6 }, 7); +} + +struct Struct_f64_f64_f64_f64 { + double a, b, c, d; +}; + +struct Struct_f64_f64_f64_f64 zig_ret_struct_f64_f64_f64_f64(void); +void zig_struct_f64_f64_f64_f64(struct Struct_f64_f64_f64_f64, size_t); + +struct Struct_f64_f64_f64_f64 c_ret_struct_f64_f64_f64_f64(void) { + return (struct Struct_f64_f64_f64_f64){ .a = 10, .b = 11, .c = 12, .d = 13 }; +} +void c_struct_f64_f64_f64_f64(struct Struct_f64_f64_f64_f64 s, size_t i) { + assert_or_panic(s.a == 14); + assert_or_panic(s.b == 15); + assert_or_panic(s.c == 16); + assert_or_panic(s.d == 17); + assert_or_panic(i == 18); +} +void c_test_struct_f64_f64_f64_f64(void) { + struct Struct_f64_f64_f64_f64 s = zig_ret_struct_f64_f64_f64_f64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + zig_struct_f64_f64_f64_f64((struct Struct_f64_f64_f64_f64){ .a = 5, .b = 6, .c = 7, .d = 8 }, 9); +} + +struct Struct_f64_f64_f64_f64_f64 { + double a, b, c, d, e; +}; + +struct Struct_f64_f64_f64_f64_f64 zig_ret_struct_f64_f64_f64_f64_f64(void); +void zig_struct_f64_f64_f64_f64_f64(struct Struct_f64_f64_f64_f64_f64, size_t); + +struct Struct_f64_f64_f64_f64_f64 c_ret_struct_f64_f64_f64_f64_f64(void) { + return (struct Struct_f64_f64_f64_f64_f64){ .a = 12, .b = 13, .c = 14, .d = 15, .e = 16 }; +} +void c_struct_f64_f64_f64_f64_f64(struct Struct_f64_f64_f64_f64_f64 s, size_t i) { + assert_or_panic(s.a == 17); + assert_or_panic(s.b == 18); + assert_or_panic(s.c == 19); + assert_or_panic(s.d == 20); + assert_or_panic(s.e == 21); + assert_or_panic(i == 22); +} +void c_test_struct_f64_f64_f64_f64_f64(void) { + struct Struct_f64_f64_f64_f64_f64 s = zig_ret_struct_f64_f64_f64_f64_f64(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + assert_or_panic(s.d == 4); + assert_or_panic(s.e == 5); + 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_u32_Union_u32_u32u32 { + uint32_t a; + union { + struct { + uint32_t d, e; + } c; + } b; +}; + +struct Struct_u32_Union_u32_u32u32 zig_ret_struct_u32_union_u32_u32u32(void); +void zig_struct_u32_union_u32_u32u32(struct Struct_u32_Union_u32_u32u32); + +struct Struct_u32_Union_u32_u32u32 c_ret_struct_u32_union_u32_u32u32(void) { + struct Struct_u32_Union_u32_u32u32 s; + s.a = 1; + s.b.c.d = 2; + s.b.c.e = 3; + return s; +} +void c_struct_u32_union_u32_u32u32(struct Struct_u32_Union_u32_u32u32 s) { + assert_or_panic(s.a == 1); + assert_or_panic(s.b.c.d == 2); + assert_or_panic(s.b.c.e == 3); +} +void c_test_struct_u32_union_u32_u32u32(void) { + struct Struct_u32_Union_u32_u32u32 s = zig_ret_struct_u32_union_u32_u32u32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b.c.d == 2); + assert_or_panic(s.b.c.e == 3); + zig_struct_u32_union_u32_u32u32(s); +} + +struct Struct_i32_i32 { + int32_t a; + int32_t b; +}; + +void zig_struct_i32_i32(struct Struct_i32_i32); + +struct BigStruct { + uint64_t a; + uint64_t b; + uint64_t c; + uint64_t d; + uint8_t e; +}; + +void zig_big_struct(struct BigStruct); + +union BigUnion { + struct BigStruct a; +}; + +void zig_big_union(union BigUnion); + +struct MedStructMixed { + uint32_t a; + float b; + float c; + uint32_t d; +}; + +void zig_med_struct_mixed(struct MedStructMixed); +struct MedStructMixed zig_ret_med_struct_mixed(); + +void zig_small_packed_struct(uint8_t); +#ifndef ZIG_NO_I128 +void zig_big_packed_struct(__int128); #endif -typedef struct Vector3 { - float x; - float y; - float z; -} Vector3; - -typedef struct Vector5 { - float x; - float y; - float z; - float w; - float q; -} Vector5; - -typedef struct Rect { - uint32_t left; - uint32_t right; - uint32_t top; - uint32_t bottom; -} Rect; - -void zig_multiple_struct_ints(struct Rect, struct Rect); - -typedef struct FloatRect { - float left; - float right; - float top; - float bottom; -} FloatRect; - -void zig_multiple_struct_floats(struct FloatRect, struct FloatRect); +struct SplitStructInts { + uint64_t a; + uint8_t b; + uint32_t c; +}; +void zig_split_struct_ints(struct SplitStructInts); + +struct SplitStructMixed { + uint64_t a; + uint8_t b; + float c; +}; +void zig_split_struct_mixed(struct SplitStructMixed); +struct SplitStructMixed zig_ret_split_struct_mixed(); + +struct BigStruct zig_big_struct_both(struct BigStruct); void run_c_tests(void) { zig_u8(0xff); @@ -2843,202 +15374,34 @@ void run_c_tests(void) { } #endif -#if !defined(__mips64) -#if !defined(ZIG_PPC32) -#if !defined(__s390x__) -#if !(defined(_WIN32) && defined(__i386__)) - { - struct Struct_u8 s = zig_ret_struct_u8(); - assert_or_panic(s.a == 1); - zig_struct_u8((struct Struct_u8){ .a = 2 }, 3); - } -#endif -#endif -#endif -#endif - -#if !defined(__mips64) -#if !defined(ZIG_PPC32) -#if !defined(__s390x__) -#if !(defined(_WIN32) && defined(__i386__)) - { - struct Struct_u16 s = zig_ret_struct_u16(); - assert_or_panic(s.a == 7); - zig_struct_u16((struct Struct_u16){ .a = 8 }, 9); - } -#endif -#endif -#endif -#endif - -#if !defined(__mips64) -#if !defined(ZIG_PPC32) -#if !defined(__s390x__) -#if !(defined(_WIN32) && defined(__i386__)) - { - struct Struct_u32 s = zig_ret_struct_u32(); - assert_or_panic(s.a == 13); - zig_struct_u32((struct Struct_u32){ .a = 14 }, 15); - } -#endif -#endif -#endif -#endif - -#if !defined(ZIG_PPC32) -#if !defined(ZIG_RISCV32) -#if !defined(__s390x__) -#if !(defined(_WIN32) && defined(__i386__)) - { - struct Struct_u64 s = zig_ret_struct_u64(); - assert_or_panic(s.a == 19); - zig_struct_u64((struct Struct_u64){ .a = 20 }, 21); - } -#endif -#endif -#endif -#endif - -#if !defined(ZIG_PPC32) && !defined(__hexagon__) && !defined(__s390x__) - { - struct Struct_u64_u64 s = zig_ret_struct_u64_u64(); - assert_or_panic(s.a == 1); - assert_or_panic(s.b == 2); - zig_struct_u64_u64_0((struct Struct_u64_u64){ .a = 3, .b = 4 }, 1); - zig_struct_u64_u64_1(0, (struct Struct_u64_u64){ .a = 5, .b = 6 }, 2); - zig_struct_u64_u64_2(0, 1, (struct Struct_u64_u64){ .a = 7, .b = 8 }, 3); - zig_struct_u64_u64_3(0, 1, 2, (struct Struct_u64_u64){ .a = 9, .b = 10 }, 4); - zig_struct_u64_u64_4(0, 1, 2, 3, (struct Struct_u64_u64){ .a = 11, .b = 12 }, 5); - zig_struct_u64_u64_5(0, 1, 2, 3, 4, (struct Struct_u64_u64){ .a = 13, .b = 14 }, 6); - zig_struct_u64_u64_6(0, 1, 2, 3, 4, 5, (struct Struct_u64_u64){ .a = 15, .b = 16 }, 7); - zig_struct_u64_u64_7(0, 1, 2, 3, 4, 5, 6, (struct Struct_u64_u64){ .a = 17, .b = 18 }, 8); - zig_struct_u64_u64_8(0, 1, 2, 3, 4, 5, 6, 7, (struct Struct_u64_u64){ .a = 19, .b = 20 }, 9); - } - -#if !defined(__mips64__) -#if !(defined(_WIN32) && defined(__i386__)) - { - struct Struct_f32 s = zig_ret_struct_f32(); - assert_or_panic(s.a == 2.5f); - zig_struct_f32((struct Struct_f32){ .a = 2.5f }); - } -#endif -#endif - -#if !(defined(__arm__) && defined(__SOFTFP__)) -#if !defined(ZIG_RISCV32) -#if !(defined(_WIN32) && defined(__i386__)) - { - struct Struct_f64 s = zig_ret_struct_f64(); - assert_or_panic(s.a == 2.5); - zig_struct_f64((struct Struct_f64){ .a = 2.5 }); - } -#endif -#endif -#endif - -#if !defined(__arm__) -#if !defined(__loongarch__) -#if !defined(__mips64__) -#if !defined(__powerpc__) -#if !defined(ZIG_RISCV32) -#if !defined(__s390x__) -#if !defined(__i386__) - { - struct Struct_f32a8 s = zig_ret_struct_f32a8(); - assert_or_panic(s.a == 1.25f); - zig_struct_f32a8((struct Struct_f32a8){ .a = 2.75f }, 3.5f); - } -#endif -#endif -#endif -#endif -#endif -#endif -#endif - -#if !defined(__arm__) -#if !defined(__loongarch__) -#if !defined(__mips64__) -#if !defined(__powerpc__) -#if !defined(__riscv) -#if !defined(__s390x__) -#if !defined(__i386__) - { - struct Struct_f32a8_f32a8 s = zig_ret_struct_f32a8_f32a8(); - assert_or_panic(s.a == 1.25f); - assert_or_panic(s.b == 2.75f); - zig_struct_f32a8_f32a8((struct Struct_f32a8_f32a8){ .a = 3.125f, .b = 4.375f }, 5.5f); - } -#endif -#endif -#endif -#endif -#endif -#endif -#endif - -#if !(defined(__arm__) && defined(__SOFTFP__)) -#if !defined(__loongarch__) && !defined(__mips64__) - { - struct Struct_f32f32_f32 s = zig_ret_struct_f32f32_f32(); - assert_or_panic(s.a.b == 1.0f); - assert_or_panic(s.a.c == 2.0f); - assert_or_panic(s.d == 3.0f); - zig_struct_f32f32_f32((struct Struct_f32f32_f32){ .a = { .b = 1.0f, .c = 2.0f }, .d = 3.0f }); - } - - { - struct Struct_f32_f32f32 s = zig_ret_struct_f32_f32f32(); - assert_or_panic(s.a == 1.0f); - assert_or_panic(s.b.c == 2.0f); - assert_or_panic(s.b.d == 3.0f); - zig_struct_f32_f32f32((struct Struct_f32_f32f32){ .a = 1.0f, .b = { .c = 2.0f, .d = 3.0f } }); - } -#endif -#endif - -#if !defined(__powerpc__) && !defined(__loongarch__) && !defined(__mips64__) -#if !(defined(_WIN32) && defined(__i386__)) - { - struct Struct_u32_Union_u32_u32u32 s = zig_ret_struct_u32_union_u32_u32u32(); - assert_or_panic(s.a == 1); - assert_or_panic(s.b.c.d == 2); - assert_or_panic(s.b.c.e == 3); - zig_struct_u32_union_u32_u32u32(s); - } - +#if !(defined(__i386__) && defined(_WIN32)) +#ifndef __loongarch__ +#ifndef ZIG_MIPS64 +#ifndef __powerpc__ +#ifndef __s390x__ { struct Struct_i32_i32 s = {1, 2}; zig_struct_i32_i32(s); } #endif #endif +#endif +#endif +#endif -#if !defined(__powerpc64__) && !defined(__loongarch__) && !defined(__mips64__) +#ifndef __hexagon__ +#ifndef __loongarch__ +#ifndef ZIG_MIPS64 +#ifndef __powerpc__ +#ifndef __s390x__ { struct BigStruct s = {1, 2, 3, 4, 5}; zig_big_struct(s); } #endif #endif - -#if !defined __i386__ && !defined __arm__ && \ - !defined __powerpc__ && !defined(__loongarch__) && \ - !defined(__mips64__) && !defined(__hexagon__) && !defined(__s390x__) - { - struct SmallStructInts s = {1, 2, 3, 4}; - zig_small_struct_ints(s); - } #endif - -#if !defined __arm__ && \ - !defined __powerpc__ && !defined(__loongarch__) && \ - !defined(__mips64__) && !defined(__hexagon__) && !defined(__s390x__) - { - struct MedStructInts s = {1, 2, 3}; - zig_med_struct_ints(s); - } +#endif #endif #ifndef ZIG_NO_I128 @@ -3059,34 +15422,60 @@ void run_c_tests(void) { zig_small_packed_struct(s); } -#if !defined __i386__ && !defined __arm__ && \ - !defined ZIG_PPC32 && !defined _ARCH_PPC64 && !defined(__loongarch__) && \ - !defined(__mips64__) && !defined(__hexagon__) && !defined(__s390x__) +#ifndef __hexagon__ +#ifndef __i386__ +#ifndef __loongarch__ +#ifndef ZIG_MIPS64 +#ifndef __powerpc__ +#ifndef __s390x__ { struct SplitStructInts s = {1234, 100, 1337}; zig_split_struct_ints(s); } #endif +#endif +#endif +#endif +#endif +#endif -#if !defined __arm__ && !defined ZIG_PPC32 && !defined _ARCH_PPC64 && !defined(__loongarch__) && \ - !defined(__mips64__) && !defined(__hexagon__) && !defined(__s390x__) +#ifndef __hexagon__ +#ifndef __loongarch__ +#ifndef ZIG_MIPS64 +#ifndef __powerpc__ +#ifndef __s390x__ { struct MedStructMixed s = {1234, 100.0f, 1337.0f}; zig_med_struct_mixed(s); } #endif +#endif +#endif +#endif +#endif -#if !defined __i386__ && !defined __arm__ && \ - !defined ZIG_PPC32 && !defined _ARCH_PPC64 && !defined(__loongarch__) && \ - !defined(__mips64__) && !defined(__hexagon__) && !defined(__s390x__) +#ifndef __hexagon__ +#ifndef __i386__ +#ifndef __loongarch__ +#ifndef ZIG_MIPS64 +#ifndef __powerpc__ +#ifndef __s390x__ { struct SplitStructMixed s = {1234, 100, 1337.0f}; zig_split_struct_mixed(s); } #endif +#endif +#endif +#endif +#endif +#endif -#if !defined(__powerpc__) && !defined(__loongarch__) && !defined(__mips64__) && !defined(__hexagon__) && \ - !defined(__s390x__) +#ifndef __hexagon__ +#ifndef __loongarch__ +#ifndef ZIG_MIPS64 +#ifndef __powerpc__ +#ifndef __s390x__ { struct BigStruct s = {30, 31, 32, 33, 34}; struct BigStruct res = zig_big_struct_both(s); @@ -3097,23 +15486,9 @@ void run_c_tests(void) { assert_or_panic(res.e == 24); } #endif - -#if !defined ZIG_PPC32 && !defined _ARCH_PPC64 && !defined(__loongarch__) && !defined(__mips64__) && \ - !defined(__hexagon__) && !defined(__s390x__) - { - struct Rect r1 = {1, 21, 16, 4}; - struct Rect r2 = {178, 189, 21, 15}; - zig_multiple_struct_ints(r1, r2); - } #endif - -#if !defined ZIG_PPC32 && !defined(__loongarch__) && !defined(__mips64__) && !defined(__hexagon__) && \ - !defined(__s390x__) - { - struct FloatRect r1 = {1, 21, 16, 4}; - struct FloatRect r2 = {178, 189, 21, 15}; - zig_multiple_struct_floats(r1, r2); - } +#endif +#endif #endif { @@ -3129,2107 +15504,6 @@ void run_c_tests(void) { assert_or_panic(zig_ret_i32() == -1); assert_or_panic(zig_ret_i64() == -1); } - -#if defined(ZIG_BACKEND_STAGE2_X86_64) || defined(ZIG_PPC32) - { - zig_vector_2_bool((Vector2Bool){ - false, - true, - }); - - Vector2Bool vec = zig_ret_vector_2_bool(); - assert_or_panic(vec[0] == false); - assert_or_panic(vec[1] == false); - } - { - zig_vector_4_bool((Vector4Bool){ - false, - false, - false, - false, - }); - - Vector4Bool vec = zig_ret_vector_4_bool(); - assert_or_panic(vec[0] == false); - assert_or_panic(vec[1] == true); - assert_or_panic(vec[2] == true); - assert_or_panic(vec[3] == true); - } - { - zig_vector_8_bool((Vector8Bool){ - true, - true, - false, - true, - false, - true, - true, - false, - }); - - Vector8Bool vec = zig_ret_vector_8_bool(); - assert_or_panic(vec[0] == false); - assert_or_panic(vec[1] == false); - assert_or_panic(vec[2] == false); - assert_or_panic(vec[3] == false); - assert_or_panic(vec[4] == true); - assert_or_panic(vec[5] == false); - assert_or_panic(vec[6] == false); - assert_or_panic(vec[7] == false); - } - { - zig_vector_16_bool((Vector16Bool){ - true, - false, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - }); - - Vector16Bool vec = zig_ret_vector_16_bool(); - assert_or_panic(vec[0] == false); - assert_or_panic(vec[1] == true); - assert_or_panic(vec[2] == false); - assert_or_panic(vec[3] == false); - assert_or_panic(vec[4] == false); - assert_or_panic(vec[5] == true); - assert_or_panic(vec[6] == false); - assert_or_panic(vec[7] == false); - assert_or_panic(vec[8] == true); - assert_or_panic(vec[9] == false); - assert_or_panic(vec[10] == false); - assert_or_panic(vec[11] == false); - assert_or_panic(vec[12] == false); - assert_or_panic(vec[13] == true); - assert_or_panic(vec[14] == false); - assert_or_panic(vec[15] == false); - } - { - zig_vector_32_bool((Vector32Bool){ - false, - false, - false, - true, - true, - false, - false, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - false, - false, - true, - true, - false, - true, - true, - false, - true, - }); - - Vector32Bool vec = zig_ret_vector_32_bool(); - assert_or_panic(vec[0] == false); - assert_or_panic(vec[1] == true); - assert_or_panic(vec[2] == false); - assert_or_panic(vec[3] == false); - assert_or_panic(vec[4] == true); - assert_or_panic(vec[5] == false); - assert_or_panic(vec[6] == true); - assert_or_panic(vec[7] == true); - assert_or_panic(vec[8] == true); - assert_or_panic(vec[9] == true); - assert_or_panic(vec[10] == true); - assert_or_panic(vec[11] == true); - assert_or_panic(vec[12] == false); - assert_or_panic(vec[13] == false); - assert_or_panic(vec[14] == false); - assert_or_panic(vec[15] == false); - assert_or_panic(vec[16] == false); - assert_or_panic(vec[17] == false); - assert_or_panic(vec[18] == true); - assert_or_panic(vec[19] == true); - assert_or_panic(vec[20] == true); - assert_or_panic(vec[21] == false); - assert_or_panic(vec[22] == true); - assert_or_panic(vec[23] == false); - assert_or_panic(vec[24] == true); - assert_or_panic(vec[25] == false); - assert_or_panic(vec[26] == false); - assert_or_panic(vec[27] == true); - assert_or_panic(vec[28] == false); - assert_or_panic(vec[29] == false); - assert_or_panic(vec[30] == true); - assert_or_panic(vec[31] == true); - } - { - zig_vector_64_bool((Vector64Bool){ - true, - true, - false, - true, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - true, - true, - false, - true, - true, - true, - true, - false, - false, - true, - false, - false, - true, - false, - true, - false, - true, - true, - false, - true, - true, - false, - false, - true, - true, - true, - true, - true, - false, - true, - false, - false, - false, - false, - false, - true, - false, - false, - true, - true, - false, - false, - false, - true, - true, - true, - true, - }); - - Vector64Bool vec = zig_ret_vector_64_bool(); - assert_or_panic(vec[0] == true); - assert_or_panic(vec[1] == false); - assert_or_panic(vec[2] == true); - assert_or_panic(vec[3] == false); - assert_or_panic(vec[4] == false); - assert_or_panic(vec[5] == true); - assert_or_panic(vec[6] == false); - assert_or_panic(vec[7] == true); - assert_or_panic(vec[8] == true); - assert_or_panic(vec[9] == false); - assert_or_panic(vec[10] == true); - assert_or_panic(vec[11] == false); - assert_or_panic(vec[12] == true); - assert_or_panic(vec[13] == false); - assert_or_panic(vec[14] == false); - assert_or_panic(vec[15] == true); - assert_or_panic(vec[16] == false); - assert_or_panic(vec[17] == false); - assert_or_panic(vec[18] == true); - assert_or_panic(vec[19] == true); - assert_or_panic(vec[20] == false); - assert_or_panic(vec[21] == false); - assert_or_panic(vec[22] == true); - assert_or_panic(vec[23] == false); - assert_or_panic(vec[24] == false); - assert_or_panic(vec[25] == true); - assert_or_panic(vec[26] == true); - assert_or_panic(vec[27] == true); - assert_or_panic(vec[28] == true); - assert_or_panic(vec[29] == true); - assert_or_panic(vec[30] == false); - assert_or_panic(vec[31] == false); - assert_or_panic(vec[32] == true); - assert_or_panic(vec[33] == true); - assert_or_panic(vec[34] == true); - assert_or_panic(vec[35] == true); - assert_or_panic(vec[36] == false); - assert_or_panic(vec[37] == true); - assert_or_panic(vec[38] == false); - assert_or_panic(vec[39] == true); - assert_or_panic(vec[40] == true); - assert_or_panic(vec[41] == true); - assert_or_panic(vec[42] == true); - assert_or_panic(vec[43] == true); - assert_or_panic(vec[44] == false); - assert_or_panic(vec[45] == false); - assert_or_panic(vec[46] == false); - assert_or_panic(vec[47] == true); - assert_or_panic(vec[48] == true); - assert_or_panic(vec[49] == true); - assert_or_panic(vec[50] == false); - assert_or_panic(vec[51] == true); - assert_or_panic(vec[52] == true); - assert_or_panic(vec[53] == true); - assert_or_panic(vec[54] == false); - assert_or_panic(vec[55] == false); - assert_or_panic(vec[56] == false); - assert_or_panic(vec[57] == true); - assert_or_panic(vec[58] == false); - assert_or_panic(vec[59] == false); - assert_or_panic(vec[60] == true); - assert_or_panic(vec[61] == false); - assert_or_panic(vec[62] == true); - assert_or_panic(vec[63] == false); - } - { - zig_vector_128_bool((Vector128Bool){ - true, - true, - false, - true, - true, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - true, - false, - true, - false, - false, - false, - true, - false, - true, - true, - false, - true, - false, - true, - true, - false, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - true, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - true, - true, - false, - true, - false, - }); - - Vector128Bool vec = zig_ret_vector_128_bool(); - assert_or_panic(vec[0] == true); - assert_or_panic(vec[1] == true); - assert_or_panic(vec[2] == false); - assert_or_panic(vec[3] == false); - assert_or_panic(vec[4] == false); - assert_or_panic(vec[5] == true); - assert_or_panic(vec[6] == true); - assert_or_panic(vec[7] == false); - assert_or_panic(vec[8] == false); - assert_or_panic(vec[9] == true); - assert_or_panic(vec[10] == false); - assert_or_panic(vec[11] == false); - assert_or_panic(vec[12] == false); - assert_or_panic(vec[13] == true); - assert_or_panic(vec[14] == false); - assert_or_panic(vec[15] == true); - assert_or_panic(vec[16] == true); - assert_or_panic(vec[17] == false); - assert_or_panic(vec[18] == false); - assert_or_panic(vec[19] == true); - assert_or_panic(vec[20] == true); - assert_or_panic(vec[21] == true); - assert_or_panic(vec[22] == true); - assert_or_panic(vec[23] == true); - assert_or_panic(vec[24] == false); - assert_or_panic(vec[25] == false); - assert_or_panic(vec[26] == true); - assert_or_panic(vec[27] == true); - assert_or_panic(vec[28] == true); - assert_or_panic(vec[29] == false); - assert_or_panic(vec[30] == false); - assert_or_panic(vec[31] == true); - assert_or_panic(vec[32] == true); - assert_or_panic(vec[33] == false); - assert_or_panic(vec[34] == true); - assert_or_panic(vec[35] == true); - assert_or_panic(vec[36] == true); - assert_or_panic(vec[37] == false); - assert_or_panic(vec[38] == true); - assert_or_panic(vec[39] == true); - assert_or_panic(vec[40] == true); - assert_or_panic(vec[41] == false); - assert_or_panic(vec[42] == true); - assert_or_panic(vec[43] == true); - assert_or_panic(vec[44] == false); - assert_or_panic(vec[45] == false); - assert_or_panic(vec[46] == false); - assert_or_panic(vec[47] == true); - assert_or_panic(vec[48] == false); - assert_or_panic(vec[49] == false); - assert_or_panic(vec[50] == false); - assert_or_panic(vec[51] == false); - assert_or_panic(vec[52] == true); - assert_or_panic(vec[53] == false); - assert_or_panic(vec[54] == true); - assert_or_panic(vec[55] == false); - assert_or_panic(vec[56] == true); - assert_or_panic(vec[57] == false); - assert_or_panic(vec[58] == false); - assert_or_panic(vec[59] == true); - assert_or_panic(vec[60] == true); - assert_or_panic(vec[61] == true); - assert_or_panic(vec[62] == true); - assert_or_panic(vec[63] == true); - assert_or_panic(vec[64] == false); - assert_or_panic(vec[65] == false); - assert_or_panic(vec[66] == false); - assert_or_panic(vec[67] == true); - assert_or_panic(vec[68] == true); - assert_or_panic(vec[69] == false); - assert_or_panic(vec[70] == true); - assert_or_panic(vec[71] == true); - assert_or_panic(vec[72] == false); - assert_or_panic(vec[73] == true); - assert_or_panic(vec[74] == true); - assert_or_panic(vec[75] == false); - assert_or_panic(vec[76] == false); - assert_or_panic(vec[77] == true); - assert_or_panic(vec[78] == false); - assert_or_panic(vec[79] == true); - assert_or_panic(vec[80] == false); - assert_or_panic(vec[81] == false); - assert_or_panic(vec[82] == true); - assert_or_panic(vec[83] == true); - assert_or_panic(vec[84] == false); - assert_or_panic(vec[85] == true); - assert_or_panic(vec[86] == false); - assert_or_panic(vec[87] == false); - assert_or_panic(vec[88] == true); - assert_or_panic(vec[89] == true); - assert_or_panic(vec[90] == true); - assert_or_panic(vec[91] == true); - assert_or_panic(vec[92] == true); - assert_or_panic(vec[93] == false); - assert_or_panic(vec[94] == false); - assert_or_panic(vec[95] == true); - assert_or_panic(vec[96] == false); - assert_or_panic(vec[97] == false); - assert_or_panic(vec[98] == true); - assert_or_panic(vec[99] == true); - assert_or_panic(vec[100] == true); - assert_or_panic(vec[101] == true); - assert_or_panic(vec[102] == true); - assert_or_panic(vec[103] == true); - assert_or_panic(vec[104] == true); - assert_or_panic(vec[105] == false); - assert_or_panic(vec[106] == false); - assert_or_panic(vec[107] == true); - assert_or_panic(vec[108] == false); - assert_or_panic(vec[109] == false); - assert_or_panic(vec[110] == true); - assert_or_panic(vec[111] == false); - assert_or_panic(vec[112] == false); - assert_or_panic(vec[113] == true); - assert_or_panic(vec[114] == false); - assert_or_panic(vec[115] == false); - assert_or_panic(vec[116] == false); - assert_or_panic(vec[117] == false); - assert_or_panic(vec[118] == false); - assert_or_panic(vec[119] == false); - assert_or_panic(vec[120] == true); - assert_or_panic(vec[121] == true); - assert_or_panic(vec[122] == true); - assert_or_panic(vec[123] == false); - assert_or_panic(vec[124] == true); - assert_or_panic(vec[125] == false); - assert_or_panic(vec[126] == false); - assert_or_panic(vec[127] == true); - } - { - zig_vector_256_bool((Vector256Bool){ - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - false, - false, - false, - true, - true, - true, - false, - true, - true, - false, - true, - false, - false, - true, - true, - true, - false, - true, - false, - true, - false, - false, - false, - true, - false, - false, - true, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - true, - true, - true, - false, - false, - true, - true, - false, - false, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - false, - true, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - true, - false, - true, - false, - true, - false, - true, - true, - true, - true, - false, - true, - false, - true, - true, - false, - false, - true, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - true, - false, - false, - false, - false, - true, - true, - true, - false, - false, - true, - false, - false, - true, - true, - false, - true, - false, - true, - false, - false, - false, - true, - true, - false, - false, - false, - true, - false, - true, - true, - true, - false, - true, - false, - true, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - false, - true, - true, - true, - false, - false, - true, - false, - false, - false, - true, - false, - false, - true, - true, - true, - true, - }); - - Vector256Bool vec = zig_ret_vector_256_bool(); - assert_or_panic(vec[0] == true); - assert_or_panic(vec[1] == true); - assert_or_panic(vec[2] == true); - assert_or_panic(vec[3] == false); - assert_or_panic(vec[4] == true); - assert_or_panic(vec[5] == false); - assert_or_panic(vec[6] == false); - assert_or_panic(vec[7] == true); - assert_or_panic(vec[8] == false); - assert_or_panic(vec[9] == false); - assert_or_panic(vec[10] == false); - assert_or_panic(vec[11] == false); - assert_or_panic(vec[12] == false); - assert_or_panic(vec[13] == false); - assert_or_panic(vec[14] == false); - assert_or_panic(vec[15] == false); - assert_or_panic(vec[16] == true); - assert_or_panic(vec[17] == false); - assert_or_panic(vec[18] == true); - assert_or_panic(vec[19] == false); - assert_or_panic(vec[20] == false); - assert_or_panic(vec[21] == true); - assert_or_panic(vec[22] == true); - assert_or_panic(vec[23] == false); - assert_or_panic(vec[24] == false); - assert_or_panic(vec[25] == true); - assert_or_panic(vec[26] == true); - assert_or_panic(vec[27] == false); - assert_or_panic(vec[28] == true); - assert_or_panic(vec[29] == true); - assert_or_panic(vec[30] == true); - assert_or_panic(vec[31] == false); - assert_or_panic(vec[32] == true); - assert_or_panic(vec[33] == false); - assert_or_panic(vec[34] == true); - assert_or_panic(vec[35] == false); - assert_or_panic(vec[36] == true); - assert_or_panic(vec[37] == false); - assert_or_panic(vec[38] == true); - assert_or_panic(vec[39] == false); - assert_or_panic(vec[40] == false); - assert_or_panic(vec[41] == false); - assert_or_panic(vec[42] == true); - assert_or_panic(vec[43] == true); - assert_or_panic(vec[44] == true); - assert_or_panic(vec[45] == false); - assert_or_panic(vec[46] == false); - assert_or_panic(vec[47] == false); - assert_or_panic(vec[48] == true); - assert_or_panic(vec[49] == false); - assert_or_panic(vec[50] == true); - assert_or_panic(vec[51] == false); - assert_or_panic(vec[52] == true); - assert_or_panic(vec[53] == false); - assert_or_panic(vec[54] == true); - assert_or_panic(vec[55] == true); - assert_or_panic(vec[56] == false); - assert_or_panic(vec[57] == false); - assert_or_panic(vec[58] == false); - assert_or_panic(vec[59] == true); - assert_or_panic(vec[60] == true); - assert_or_panic(vec[61] == true); - assert_or_panic(vec[62] == false); - assert_or_panic(vec[63] == true); - assert_or_panic(vec[64] == false); - assert_or_panic(vec[65] == true); - assert_or_panic(vec[66] == false); - assert_or_panic(vec[67] == true); - assert_or_panic(vec[68] == true); - assert_or_panic(vec[69] == false); - assert_or_panic(vec[70] == true); - assert_or_panic(vec[71] == false); - assert_or_panic(vec[72] == true); - assert_or_panic(vec[73] == true); - assert_or_panic(vec[74] == false); - assert_or_panic(vec[75] == false); - assert_or_panic(vec[76] == false); - assert_or_panic(vec[77] == false); - assert_or_panic(vec[78] == false); - assert_or_panic(vec[79] == false); - assert_or_panic(vec[80] == false); - assert_or_panic(vec[81] == false); - assert_or_panic(vec[82] == false); - assert_or_panic(vec[83] == true); - assert_or_panic(vec[84] == false); - assert_or_panic(vec[85] == false); - assert_or_panic(vec[86] == false); - assert_or_panic(vec[87] == true); - assert_or_panic(vec[88] == false); - assert_or_panic(vec[89] == true); - assert_or_panic(vec[90] == true); - assert_or_panic(vec[91] == false); - assert_or_panic(vec[92] == false); - assert_or_panic(vec[93] == true); - assert_or_panic(vec[94] == true); - assert_or_panic(vec[95] == false); - assert_or_panic(vec[96] == false); - assert_or_panic(vec[97] == true); - assert_or_panic(vec[98] == false); - assert_or_panic(vec[99] == false); - assert_or_panic(vec[100] == false); - assert_or_panic(vec[101] == false); - assert_or_panic(vec[102] == false); - assert_or_panic(vec[103] == false); - assert_or_panic(vec[104] == false); - assert_or_panic(vec[105] == true); - assert_or_panic(vec[106] == true); - assert_or_panic(vec[107] == false); - assert_or_panic(vec[108] == true); - assert_or_panic(vec[109] == false); - assert_or_panic(vec[110] == true); - assert_or_panic(vec[111] == true); - assert_or_panic(vec[112] == false); - assert_or_panic(vec[113] == false); - assert_or_panic(vec[114] == false); - assert_or_panic(vec[115] == false); - assert_or_panic(vec[116] == false); - assert_or_panic(vec[117] == false); - assert_or_panic(vec[118] == false); - assert_or_panic(vec[119] == true); - assert_or_panic(vec[120] == true); - assert_or_panic(vec[121] == true); - assert_or_panic(vec[122] == false); - assert_or_panic(vec[123] == true); - assert_or_panic(vec[124] == true); - assert_or_panic(vec[125] == false); - assert_or_panic(vec[126] == false); - assert_or_panic(vec[127] == true); - assert_or_panic(vec[128] == true); - assert_or_panic(vec[129] == true); - assert_or_panic(vec[130] == true); - assert_or_panic(vec[131] == true); - assert_or_panic(vec[132] == false); - assert_or_panic(vec[133] == true); - assert_or_panic(vec[134] == true); - assert_or_panic(vec[135] == false); - assert_or_panic(vec[136] == false); - assert_or_panic(vec[137] == true); - assert_or_panic(vec[138] == true); - assert_or_panic(vec[139] == false); - assert_or_panic(vec[140] == true); - assert_or_panic(vec[141] == false); - assert_or_panic(vec[142] == true); - assert_or_panic(vec[143] == false); - assert_or_panic(vec[144] == true); - assert_or_panic(vec[145] == true); - assert_or_panic(vec[146] == true); - assert_or_panic(vec[147] == true); - assert_or_panic(vec[148] == false); - assert_or_panic(vec[149] == false); - assert_or_panic(vec[150] == false); - assert_or_panic(vec[151] == true); - assert_or_panic(vec[152] == false); - assert_or_panic(vec[153] == true); - assert_or_panic(vec[154] == false); - assert_or_panic(vec[155] == true); - assert_or_panic(vec[156] == true); - assert_or_panic(vec[157] == false); - assert_or_panic(vec[158] == true); - assert_or_panic(vec[159] == true); - assert_or_panic(vec[160] == true); - assert_or_panic(vec[161] == true); - assert_or_panic(vec[162] == true); - assert_or_panic(vec[163] == false); - assert_or_panic(vec[164] == false); - assert_or_panic(vec[165] == true); - assert_or_panic(vec[166] == false); - assert_or_panic(vec[167] == true); - assert_or_panic(vec[168] == true); - assert_or_panic(vec[169] == true); - assert_or_panic(vec[170] == true); - assert_or_panic(vec[171] == false); - assert_or_panic(vec[172] == true); - assert_or_panic(vec[173] == true); - assert_or_panic(vec[174] == true); - assert_or_panic(vec[175] == true); - assert_or_panic(vec[176] == true); - assert_or_panic(vec[177] == true); - assert_or_panic(vec[178] == true); - assert_or_panic(vec[179] == false); - assert_or_panic(vec[180] == true); - assert_or_panic(vec[181] == false); - assert_or_panic(vec[182] == false); - assert_or_panic(vec[183] == false); - assert_or_panic(vec[184] == true); - assert_or_panic(vec[185] == false); - assert_or_panic(vec[186] == true); - assert_or_panic(vec[187] == true); - assert_or_panic(vec[188] == false); - assert_or_panic(vec[189] == true); - assert_or_panic(vec[190] == false); - assert_or_panic(vec[191] == true); - assert_or_panic(vec[192] == false); - assert_or_panic(vec[193] == true); - assert_or_panic(vec[194] == false); - assert_or_panic(vec[195] == false); - assert_or_panic(vec[196] == true); - assert_or_panic(vec[197] == true); - assert_or_panic(vec[198] == true); - assert_or_panic(vec[199] == true); - assert_or_panic(vec[200] == true); - assert_or_panic(vec[201] == true); - assert_or_panic(vec[202] == true); - assert_or_panic(vec[203] == false); - assert_or_panic(vec[204] == true); - assert_or_panic(vec[205] == false); - assert_or_panic(vec[206] == false); - assert_or_panic(vec[207] == true); - assert_or_panic(vec[208] == true); - assert_or_panic(vec[209] == false); - assert_or_panic(vec[210] == false); - assert_or_panic(vec[211] == false); - assert_or_panic(vec[212] == true); - assert_or_panic(vec[213] == true); - assert_or_panic(vec[214] == true); - assert_or_panic(vec[215] == false); - assert_or_panic(vec[216] == false); - assert_or_panic(vec[217] == true); - assert_or_panic(vec[218] == true); - assert_or_panic(vec[219] == true); - assert_or_panic(vec[220] == true); - assert_or_panic(vec[221] == false); - assert_or_panic(vec[222] == true); - assert_or_panic(vec[223] == false); - assert_or_panic(vec[224] == true); - assert_or_panic(vec[225] == true); - assert_or_panic(vec[226] == true); - assert_or_panic(vec[227] == false); - assert_or_panic(vec[228] == false); - assert_or_panic(vec[229] == false); - assert_or_panic(vec[230] == false); - assert_or_panic(vec[231] == false); - assert_or_panic(vec[232] == true); - assert_or_panic(vec[233] == true); - assert_or_panic(vec[234] == false); - assert_or_panic(vec[235] == false); - assert_or_panic(vec[236] == false); - assert_or_panic(vec[237] == true); - assert_or_panic(vec[238] == true); - assert_or_panic(vec[239] == false); - assert_or_panic(vec[240] == true); - assert_or_panic(vec[241] == true); - assert_or_panic(vec[242] == true); - assert_or_panic(vec[243] == false); - assert_or_panic(vec[244] == true); - assert_or_panic(vec[245] == true); - assert_or_panic(vec[246] == false); - assert_or_panic(vec[247] == true); - assert_or_panic(vec[248] == false); - assert_or_panic(vec[249] == false); - assert_or_panic(vec[250] == true); - assert_or_panic(vec[251] == true); - assert_or_panic(vec[252] == false); - assert_or_panic(vec[253] == true); - assert_or_panic(vec[254] == false); - assert_or_panic(vec[255] == true); - } - { - zig_vector_512_bool((Vector512Bool){ - false, - true, - true, - false, - true, - false, - true, - false, - false, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - true, - false, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - false, - true, - false, - false, - true, - false, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - true, - false, - true, - true, - false, - false, - true, - false, - false, - false, - true, - true, - true, - false, - false, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - false, - true, - true, - false, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - true, - false, - false, - false, - false, - true, - true, - false, - true, - false, - true, - false, - false, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - false, - false, - false, - true, - true, - false, - false, - true, - false, - true, - true, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - true, - true, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - false, - false, - true, - true, - true, - false, - false, - true, - false, - true, - true, - true, - true, - false, - true, - false, - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - false, - true, - true, - false, - true, - false, - true, - true, - false, - false, - false, - false, - true, - false, - true, - true, - false, - false, - true, - true, - true, - false, - true, - false, - false, - true, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - true, - false, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - true, - false, - true, - true, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - true, - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - true, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - true, - false, - true, - true, - true, - false, - false, - true, - false, - false, - false, - true, - true, - true, - false, - true, - false, - false, - false, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - true, - true, - false, - false, - false, - false, - true, - false, - true, - false, - false, - false, - false, - true, - false, - false, - true, - true, - true, - false, - true, - true, - false, - true, - false, - true, - false, - false, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - }); - - Vector512Bool vec = zig_ret_vector_512_bool(); - assert_or_panic(vec[0] == true); - assert_or_panic(vec[1] == true); - assert_or_panic(vec[2] == true); - assert_or_panic(vec[3] == true); - assert_or_panic(vec[4] == false); - assert_or_panic(vec[5] == true); - assert_or_panic(vec[6] == false); - assert_or_panic(vec[7] == true); - assert_or_panic(vec[8] == true); - assert_or_panic(vec[9] == true); - assert_or_panic(vec[10] == false); - assert_or_panic(vec[11] == true); - assert_or_panic(vec[12] == false); - assert_or_panic(vec[13] == false); - assert_or_panic(vec[14] == false); - assert_or_panic(vec[15] == true); - assert_or_panic(vec[16] == true); - assert_or_panic(vec[17] == false); - assert_or_panic(vec[18] == false); - assert_or_panic(vec[19] == false); - assert_or_panic(vec[20] == true); - assert_or_panic(vec[21] == true); - assert_or_panic(vec[22] == false); - assert_or_panic(vec[23] == false); - assert_or_panic(vec[24] == false); - assert_or_panic(vec[25] == false); - assert_or_panic(vec[26] == true); - assert_or_panic(vec[27] == false); - assert_or_panic(vec[28] == false); - assert_or_panic(vec[29] == false); - assert_or_panic(vec[30] == true); - assert_or_panic(vec[31] == true); - assert_or_panic(vec[32] == true); - assert_or_panic(vec[33] == true); - assert_or_panic(vec[34] == false); - assert_or_panic(vec[35] == false); - assert_or_panic(vec[36] == false); - assert_or_panic(vec[37] == true); - assert_or_panic(vec[38] == true); - assert_or_panic(vec[39] == true); - assert_or_panic(vec[40] == false); - assert_or_panic(vec[41] == false); - assert_or_panic(vec[42] == true); - assert_or_panic(vec[43] == false); - assert_or_panic(vec[44] == false); - assert_or_panic(vec[45] == true); - assert_or_panic(vec[46] == false); - assert_or_panic(vec[47] == false); - assert_or_panic(vec[48] == true); - assert_or_panic(vec[49] == true); - assert_or_panic(vec[50] == true); - assert_or_panic(vec[51] == true); - assert_or_panic(vec[52] == false); - assert_or_panic(vec[53] == false); - assert_or_panic(vec[54] == false); - assert_or_panic(vec[55] == true); - assert_or_panic(vec[56] == false); - assert_or_panic(vec[57] == true); - assert_or_panic(vec[58] == false); - assert_or_panic(vec[59] == true); - assert_or_panic(vec[60] == true); - assert_or_panic(vec[61] == false); - assert_or_panic(vec[62] == false); - assert_or_panic(vec[63] == true); - assert_or_panic(vec[64] == true); - assert_or_panic(vec[65] == false); - assert_or_panic(vec[66] == true); - assert_or_panic(vec[67] == false); - assert_or_panic(vec[68] == false); - assert_or_panic(vec[69] == false); - assert_or_panic(vec[70] == true); - assert_or_panic(vec[71] == true); - assert_or_panic(vec[72] == true); - assert_or_panic(vec[73] == true); - assert_or_panic(vec[74] == true); - assert_or_panic(vec[75] == false); - assert_or_panic(vec[76] == true); - assert_or_panic(vec[77] == false); - assert_or_panic(vec[78] == true); - assert_or_panic(vec[79] == true); - assert_or_panic(vec[80] == true); - assert_or_panic(vec[81] == true); - assert_or_panic(vec[82] == true); - assert_or_panic(vec[83] == false); - assert_or_panic(vec[84] == true); - assert_or_panic(vec[85] == true); - assert_or_panic(vec[86] == false); - assert_or_panic(vec[87] == true); - assert_or_panic(vec[88] == false); - assert_or_panic(vec[89] == false); - assert_or_panic(vec[90] == true); - assert_or_panic(vec[91] == false); - assert_or_panic(vec[92] == true); - assert_or_panic(vec[93] == false); - assert_or_panic(vec[94] == false); - assert_or_panic(vec[95] == false); - assert_or_panic(vec[96] == true); - assert_or_panic(vec[97] == true); - assert_or_panic(vec[98] == false); - assert_or_panic(vec[99] == true); - assert_or_panic(vec[100] == true); - assert_or_panic(vec[101] == false); - assert_or_panic(vec[102] == true); - assert_or_panic(vec[103] == false); - assert_or_panic(vec[104] == true); - assert_or_panic(vec[105] == false); - assert_or_panic(vec[106] == true); - assert_or_panic(vec[107] == false); - assert_or_panic(vec[108] == false); - assert_or_panic(vec[109] == true); - assert_or_panic(vec[110] == false); - assert_or_panic(vec[111] == false); - assert_or_panic(vec[112] == true); - assert_or_panic(vec[113] == false); - assert_or_panic(vec[114] == true); - assert_or_panic(vec[115] == false); - assert_or_panic(vec[116] == true); - assert_or_panic(vec[117] == false); - assert_or_panic(vec[118] == false); - assert_or_panic(vec[119] == true); - assert_or_panic(vec[120] == true); - assert_or_panic(vec[121] == true); - assert_or_panic(vec[122] == false); - assert_or_panic(vec[123] == true); - assert_or_panic(vec[124] == false); - assert_or_panic(vec[125] == false); - assert_or_panic(vec[126] == true); - assert_or_panic(vec[127] == true); - assert_or_panic(vec[128] == false); - assert_or_panic(vec[129] == true); - assert_or_panic(vec[130] == true); - assert_or_panic(vec[131] == false); - assert_or_panic(vec[132] == true); - assert_or_panic(vec[133] == true); - assert_or_panic(vec[134] == false); - assert_or_panic(vec[135] == true); - assert_or_panic(vec[136] == true); - assert_or_panic(vec[137] == false); - assert_or_panic(vec[138] == false); - assert_or_panic(vec[139] == false); - assert_or_panic(vec[140] == true); - assert_or_panic(vec[141] == false); - assert_or_panic(vec[142] == true); - assert_or_panic(vec[143] == false); - assert_or_panic(vec[144] == false); - assert_or_panic(vec[145] == false); - assert_or_panic(vec[146] == true); - assert_or_panic(vec[147] == false); - assert_or_panic(vec[148] == true); - assert_or_panic(vec[149] == false); - assert_or_panic(vec[150] == false); - assert_or_panic(vec[151] == true); - assert_or_panic(vec[152] == false); - assert_or_panic(vec[153] == true); - assert_or_panic(vec[154] == true); - assert_or_panic(vec[155] == false); - assert_or_panic(vec[156] == true); - assert_or_panic(vec[157] == true); - assert_or_panic(vec[158] == false); - assert_or_panic(vec[159] == true); - assert_or_panic(vec[160] == true); - assert_or_panic(vec[161] == false); - assert_or_panic(vec[162] == false); - assert_or_panic(vec[163] == false); - assert_or_panic(vec[164] == true); - assert_or_panic(vec[165] == false); - assert_or_panic(vec[166] == true); - assert_or_panic(vec[167] == true); - assert_or_panic(vec[168] == true); - assert_or_panic(vec[169] == true); - assert_or_panic(vec[170] == false); - assert_or_panic(vec[171] == true); - assert_or_panic(vec[172] == false); - assert_or_panic(vec[173] == false); - assert_or_panic(vec[174] == true); - assert_or_panic(vec[175] == true); - assert_or_panic(vec[176] == true); - assert_or_panic(vec[177] == false); - assert_or_panic(vec[178] == false); - assert_or_panic(vec[179] == false); - assert_or_panic(vec[180] == true); - assert_or_panic(vec[181] == false); - assert_or_panic(vec[182] == false); - assert_or_panic(vec[183] == true); - assert_or_panic(vec[184] == true); - assert_or_panic(vec[185] == false); - assert_or_panic(vec[186] == true); - assert_or_panic(vec[187] == false); - assert_or_panic(vec[188] == true); - assert_or_panic(vec[189] == true); - assert_or_panic(vec[190] == true); - assert_or_panic(vec[191] == true); - assert_or_panic(vec[192] == true); - assert_or_panic(vec[193] == true); - assert_or_panic(vec[194] == true); - assert_or_panic(vec[195] == false); - assert_or_panic(vec[196] == false); - assert_or_panic(vec[197] == false); - assert_or_panic(vec[198] == false); - assert_or_panic(vec[199] == false); - assert_or_panic(vec[200] == true); - assert_or_panic(vec[201] == false); - assert_or_panic(vec[202] == true); - assert_or_panic(vec[203] == false); - assert_or_panic(vec[204] == true); - assert_or_panic(vec[205] == true); - assert_or_panic(vec[206] == false); - assert_or_panic(vec[207] == false); - assert_or_panic(vec[208] == false); - assert_or_panic(vec[209] == true); - assert_or_panic(vec[210] == true); - assert_or_panic(vec[211] == true); - assert_or_panic(vec[212] == false); - assert_or_panic(vec[213] == false); - assert_or_panic(vec[214] == true); - assert_or_panic(vec[215] == true); - assert_or_panic(vec[216] == true); - assert_or_panic(vec[217] == false); - assert_or_panic(vec[218] == false); - assert_or_panic(vec[219] == true); - assert_or_panic(vec[220] == false); - assert_or_panic(vec[221] == true); - assert_or_panic(vec[222] == true); - assert_or_panic(vec[223] == false); - assert_or_panic(vec[224] == true); - assert_or_panic(vec[225] == false); - assert_or_panic(vec[226] == false); - assert_or_panic(vec[227] == true); - assert_or_panic(vec[228] == false); - assert_or_panic(vec[229] == false); - assert_or_panic(vec[230] == true); - assert_or_panic(vec[231] == true); - assert_or_panic(vec[232] == false); - assert_or_panic(vec[233] == true); - assert_or_panic(vec[234] == true); - assert_or_panic(vec[235] == true); - assert_or_panic(vec[236] == true); - assert_or_panic(vec[237] == true); - assert_or_panic(vec[238] == false); - assert_or_panic(vec[239] == true); - assert_or_panic(vec[240] == false); - assert_or_panic(vec[241] == false); - assert_or_panic(vec[242] == true); - assert_or_panic(vec[243] == false); - assert_or_panic(vec[244] == true); - assert_or_panic(vec[245] == false); - assert_or_panic(vec[246] == true); - assert_or_panic(vec[247] == false); - assert_or_panic(vec[248] == true); - assert_or_panic(vec[249] == true); - assert_or_panic(vec[250] == true); - assert_or_panic(vec[251] == true); - assert_or_panic(vec[252] == true); - assert_or_panic(vec[253] == false); - assert_or_panic(vec[254] == false); - assert_or_panic(vec[255] == false); - assert_or_panic(vec[256] == false); - assert_or_panic(vec[257] == false); - assert_or_panic(vec[258] == false); - assert_or_panic(vec[259] == true); - assert_or_panic(vec[260] == true); - assert_or_panic(vec[261] == true); - assert_or_panic(vec[262] == true); - assert_or_panic(vec[263] == false); - assert_or_panic(vec[264] == false); - assert_or_panic(vec[265] == false); - assert_or_panic(vec[266] == true); - assert_or_panic(vec[267] == false); - assert_or_panic(vec[268] == true); - assert_or_panic(vec[269] == false); - assert_or_panic(vec[270] == true); - assert_or_panic(vec[271] == true); - assert_or_panic(vec[272] == true); - assert_or_panic(vec[273] == true); - assert_or_panic(vec[274] == true); - assert_or_panic(vec[275] == true); - assert_or_panic(vec[276] == false); - assert_or_panic(vec[277] == false); - assert_or_panic(vec[278] == true); - assert_or_panic(vec[279] == true); - assert_or_panic(vec[280] == false); - assert_or_panic(vec[281] == false); - assert_or_panic(vec[282] == false); - assert_or_panic(vec[283] == false); - assert_or_panic(vec[284] == true); - assert_or_panic(vec[285] == true); - assert_or_panic(vec[286] == true); - assert_or_panic(vec[287] == false); - assert_or_panic(vec[288] == false); - assert_or_panic(vec[289] == false); - assert_or_panic(vec[290] == true); - assert_or_panic(vec[291] == false); - assert_or_panic(vec[292] == true); - assert_or_panic(vec[293] == true); - assert_or_panic(vec[294] == false); - assert_or_panic(vec[295] == true); - assert_or_panic(vec[296] == true); - assert_or_panic(vec[297] == true); - assert_or_panic(vec[298] == false); - assert_or_panic(vec[299] == true); - assert_or_panic(vec[300] == true); - assert_or_panic(vec[301] == false); - assert_or_panic(vec[302] == false); - assert_or_panic(vec[303] == true); - assert_or_panic(vec[304] == false); - assert_or_panic(vec[305] == false); - assert_or_panic(vec[306] == true); - assert_or_panic(vec[307] == true); - assert_or_panic(vec[308] == true); - assert_or_panic(vec[309] == true); - assert_or_panic(vec[310] == false); - assert_or_panic(vec[311] == false); - assert_or_panic(vec[312] == false); - assert_or_panic(vec[313] == false); - assert_or_panic(vec[314] == false); - assert_or_panic(vec[315] == true); - assert_or_panic(vec[316] == false); - assert_or_panic(vec[317] == false); - assert_or_panic(vec[318] == true); - assert_or_panic(vec[319] == false); - assert_or_panic(vec[320] == false); - assert_or_panic(vec[321] == true); - assert_or_panic(vec[322] == true); - assert_or_panic(vec[323] == true); - assert_or_panic(vec[324] == true); - assert_or_panic(vec[325] == false); - assert_or_panic(vec[326] == false); - assert_or_panic(vec[327] == false); - assert_or_panic(vec[328] == true); - assert_or_panic(vec[329] == true); - assert_or_panic(vec[330] == false); - assert_or_panic(vec[331] == true); - assert_or_panic(vec[332] == true); - assert_or_panic(vec[333] == false); - assert_or_panic(vec[334] == false); - assert_or_panic(vec[335] == true); - assert_or_panic(vec[336] == true); - assert_or_panic(vec[337] == false); - assert_or_panic(vec[338] == true); - assert_or_panic(vec[339] == true); - assert_or_panic(vec[340] == true); - assert_or_panic(vec[341] == false); - assert_or_panic(vec[342] == false); - assert_or_panic(vec[343] == false); - assert_or_panic(vec[344] == true); - assert_or_panic(vec[345] == true); - assert_or_panic(vec[346] == false); - assert_or_panic(vec[347] == true); - assert_or_panic(vec[348] == false); - assert_or_panic(vec[349] == true); - assert_or_panic(vec[350] == false); - assert_or_panic(vec[351] == false); - assert_or_panic(vec[352] == true); - assert_or_panic(vec[353] == false); - assert_or_panic(vec[354] == true); - assert_or_panic(vec[355] == false); - assert_or_panic(vec[356] == false); - assert_or_panic(vec[357] == false); - assert_or_panic(vec[358] == false); - assert_or_panic(vec[359] == false); - assert_or_panic(vec[360] == true); - assert_or_panic(vec[361] == true); - assert_or_panic(vec[362] == false); - assert_or_panic(vec[363] == false); - assert_or_panic(vec[364] == false); - assert_or_panic(vec[365] == false); - assert_or_panic(vec[366] == true); - assert_or_panic(vec[367] == false); - assert_or_panic(vec[368] == true); - assert_or_panic(vec[369] == false); - assert_or_panic(vec[370] == true); - assert_or_panic(vec[371] == true); - assert_or_panic(vec[372] == false); - assert_or_panic(vec[373] == true); - assert_or_panic(vec[374] == true); - assert_or_panic(vec[375] == true); - assert_or_panic(vec[376] == true); - assert_or_panic(vec[377] == true); - assert_or_panic(vec[378] == false); - assert_or_panic(vec[379] == true); - assert_or_panic(vec[380] == false); - assert_or_panic(vec[381] == true); - assert_or_panic(vec[382] == true); - assert_or_panic(vec[383] == true); - assert_or_panic(vec[384] == true); - assert_or_panic(vec[385] == true); - assert_or_panic(vec[386] == false); - assert_or_panic(vec[387] == true); - assert_or_panic(vec[388] == true); - assert_or_panic(vec[389] == false); - assert_or_panic(vec[390] == true); - assert_or_panic(vec[391] == false); - assert_or_panic(vec[392] == true); - assert_or_panic(vec[393] == false); - assert_or_panic(vec[394] == true); - assert_or_panic(vec[395] == false); - assert_or_panic(vec[396] == true); - assert_or_panic(vec[397] == false); - assert_or_panic(vec[398] == false); - assert_or_panic(vec[399] == true); - assert_or_panic(vec[400] == true); - assert_or_panic(vec[401] == true); - assert_or_panic(vec[402] == true); - assert_or_panic(vec[403] == false); - assert_or_panic(vec[404] == false); - assert_or_panic(vec[405] == true); - assert_or_panic(vec[406] == false); - assert_or_panic(vec[407] == false); - assert_or_panic(vec[408] == false); - assert_or_panic(vec[409] == true); - assert_or_panic(vec[410] == false); - assert_or_panic(vec[411] == true); - assert_or_panic(vec[412] == true); - assert_or_panic(vec[413] == false); - assert_or_panic(vec[414] == true); - assert_or_panic(vec[415] == true); - assert_or_panic(vec[416] == false); - assert_or_panic(vec[417] == true); - assert_or_panic(vec[418] == true); - assert_or_panic(vec[419] == false); - assert_or_panic(vec[420] == false); - assert_or_panic(vec[421] == true); - assert_or_panic(vec[422] == false); - assert_or_panic(vec[423] == false); - assert_or_panic(vec[424] == true); - assert_or_panic(vec[425] == false); - assert_or_panic(vec[426] == true); - assert_or_panic(vec[427] == false); - assert_or_panic(vec[428] == false); - assert_or_panic(vec[429] == true); - assert_or_panic(vec[430] == false); - assert_or_panic(vec[431] == true); - assert_or_panic(vec[432] == true); - assert_or_panic(vec[433] == false); - assert_or_panic(vec[434] == true); - assert_or_panic(vec[435] == false); - assert_or_panic(vec[436] == true); - assert_or_panic(vec[437] == false); - assert_or_panic(vec[438] == true); - assert_or_panic(vec[439] == false); - assert_or_panic(vec[440] == false); - assert_or_panic(vec[441] == true); - assert_or_panic(vec[442] == true); - assert_or_panic(vec[443] == false); - assert_or_panic(vec[444] == true); - assert_or_panic(vec[445] == true); - assert_or_panic(vec[446] == false); - assert_or_panic(vec[447] == true); - assert_or_panic(vec[448] == true); - assert_or_panic(vec[449] == false); - assert_or_panic(vec[450] == false); - assert_or_panic(vec[451] == false); - assert_or_panic(vec[452] == false); - assert_or_panic(vec[453] == false); - assert_or_panic(vec[454] == true); - assert_or_panic(vec[455] == false); - assert_or_panic(vec[456] == false); - assert_or_panic(vec[457] == true); - assert_or_panic(vec[458] == false); - assert_or_panic(vec[459] == true); - assert_or_panic(vec[460] == false); - assert_or_panic(vec[461] == false); - assert_or_panic(vec[462] == false); - assert_or_panic(vec[463] == true); - assert_or_panic(vec[464] == false); - assert_or_panic(vec[465] == true); - assert_or_panic(vec[466] == false); - assert_or_panic(vec[467] == false); - assert_or_panic(vec[468] == false); - assert_or_panic(vec[469] == false); - assert_or_panic(vec[470] == true); - assert_or_panic(vec[471] == true); - assert_or_panic(vec[472] == false); - assert_or_panic(vec[473] == true); - assert_or_panic(vec[474] == true); - assert_or_panic(vec[475] == false); - assert_or_panic(vec[476] == false); - assert_or_panic(vec[477] == true); - assert_or_panic(vec[478] == true); - assert_or_panic(vec[479] == true); - assert_or_panic(vec[480] == false); - assert_or_panic(vec[481] == false); - assert_or_panic(vec[482] == true); - assert_or_panic(vec[483] == false); - assert_or_panic(vec[484] == false); - assert_or_panic(vec[485] == false); - assert_or_panic(vec[486] == true); - assert_or_panic(vec[487] == true); - assert_or_panic(vec[488] == false); - assert_or_panic(vec[489] == false); - assert_or_panic(vec[490] == false); - assert_or_panic(vec[491] == false); - assert_or_panic(vec[492] == false); - assert_or_panic(vec[493] == true); - assert_or_panic(vec[494] == true); - assert_or_panic(vec[495] == true); - assert_or_panic(vec[496] == true); - assert_or_panic(vec[497] == false); - assert_or_panic(vec[498] == false); - assert_or_panic(vec[499] == false); - assert_or_panic(vec[500] == true); - assert_or_panic(vec[501] == false); - assert_or_panic(vec[502] == true); - assert_or_panic(vec[503] == true); - assert_or_panic(vec[504] == true); - assert_or_panic(vec[505] == true); - assert_or_panic(vec[506] == false); - assert_or_panic(vec[507] == false); - assert_or_panic(vec[508] == true); - assert_or_panic(vec[509] == true); - assert_or_panic(vec[510] == false); - assert_or_panic(vec[511] == false); - } -#endif } void c_u8(uint8_t x) { @@ -5312,6 +15586,7 @@ void c_five_floats(float a, float b, float c, float d, float e) { assert_or_panic(e == 5.0); } +#ifndef ZIG_NO_COMPLEX float complex c_cmultf_comp(float a_r, float a_i, float b_r, float b_i) { assert_or_panic(a_r == 1.25f); assert_or_panic(a_i == 2.6f); @@ -5347,6 +15622,7 @@ double complex c_cmultd(double complex a, double complex b) { return 1.5 + I * 13.5; } +#endif struct Struct_i32_i32 c_mut_struct_i32_i32(struct Struct_i32_i32 s) { assert_or_panic(s.a == 1); @@ -5378,51 +15654,6 @@ void c_big_union(union BigUnion x) { assert_or_panic(x.a.d == 4); } -void c_small_struct_ints(struct SmallStructInts x) { - assert_or_panic(x.a == 1); - assert_or_panic(x.b == 2); - assert_or_panic(x.c == 3); - assert_or_panic(x.d == 4); - - struct SmallStructInts y = zig_ret_small_struct_ints(); - - assert_or_panic(y.a == 1); - assert_or_panic(y.b == 2); - assert_or_panic(y.c == 3); - assert_or_panic(y.d == 4); -} - -struct SmallStructInts c_ret_small_struct_ints() { - struct SmallStructInts s = { - .a = 1, - .b = 2, - .c = 3, - .d = 4, - }; - return s; -} - -void c_med_struct_ints(struct MedStructInts s) { - assert_or_panic(s.x == 1); - assert_or_panic(s.y == 2); - assert_or_panic(s.z == 3); - - struct MedStructInts s2 = zig_ret_med_struct_ints(); - - assert_or_panic(s2.x == 1); - assert_or_panic(s2.y == 2); - assert_or_panic(s2.z == 3); -} - -struct MedStructInts c_ret_med_struct_ints() { - struct MedStructInts s = { - .x = 1, - .y = 2, - .z = 3, - }; - return s; -} - void c_med_struct_mixed(struct MedStructMixed x) { assert_or_panic(x.a == 1234); assert_or_panic(x.b == 100.0f); @@ -5435,7 +15666,7 @@ void c_med_struct_mixed(struct MedStructMixed x) { assert_or_panic(y.c == 1337.0f); } -struct MedStructMixed c_ret_med_struct_mixed() { +struct MedStructMixed c_ret_med_struct_mixed(void) { struct MedStructMixed s = { .a = 1234, .b = 100.0, @@ -5461,7 +15692,7 @@ void c_split_struct_mixed(struct SplitStructMixed x) { assert_or_panic(y.c == 1337.0f); } -uint8_t c_ret_small_packed_struct() { +uint8_t c_ret_small_packed_struct(void) { uint8_t s = 0; s |= 0 << 0; s |= 1 << 2; @@ -5478,7 +15709,7 @@ void c_small_packed_struct(uint8_t x) { } #ifndef ZIG_NO_I128 -__int128 c_ret_big_packed_struct() { +__int128 c_ret_big_packed_struct(void) { __int128 s = 0; s |= 1 << 0; s |= (__int128)2 << 64; @@ -5491,7 +15722,7 @@ void c_big_packed_struct(__int128 x) { } #endif -struct SplitStructMixed c_ret_split_struct_mixed() { +struct SplitStructMixed c_ret_split_struct_mixed(void) { struct SplitStructMixed s = { .a = 1234, .b = 100, @@ -5510,74 +15741,31 @@ struct BigStruct c_big_struct_both(struct BigStruct x) { return y; } -void c_small_struct_floats(Vector3 vec) { - assert_or_panic(vec.x == 3.0); - assert_or_panic(vec.y == 6.0); - assert_or_panic(vec.z == 12.0); -} - -void c_small_struct_floats_extra(Vector3 vec, const char *str) { - assert_or_panic(vec.x == 3.0); - assert_or_panic(vec.y == 6.0); - assert_or_panic(vec.z == 12.0); - assert_or_panic(!strcmp(str, "hello")); -} - -void c_big_struct_floats(Vector5 vec) { - assert_or_panic(vec.x == 76.0); - assert_or_panic(vec.y == -1.0); - assert_or_panic(vec.z == -12.0); - assert_or_panic(vec.w == 69); - assert_or_panic(vec.q == 55); -} - -void c_multiple_struct_ints(Rect x, Rect y) { - assert_or_panic(x.left == 1); - assert_or_panic(x.right == 21); - assert_or_panic(x.top == 16); - assert_or_panic(x.bottom == 4); - assert_or_panic(y.left == 178); - assert_or_panic(y.right == 189); - assert_or_panic(y.top == 21); - assert_or_panic(y.bottom == 15); -} - -void c_multiple_struct_floats(FloatRect x, FloatRect y) { - assert_or_panic(x.left == 1); - assert_or_panic(x.right == 21); - assert_or_panic(x.top == 16); - assert_or_panic(x.bottom == 4); - assert_or_panic(y.left == 178); - assert_or_panic(y.right == 189); - assert_or_panic(y.top == 21); - assert_or_panic(y.bottom == 15); -} - -bool c_ret_bool() { +bool c_ret_bool(void) { return 1; } -uint8_t c_ret_u8() { +uint8_t c_ret_u8(void) { return 0xff; } -uint16_t c_ret_u16() { +uint16_t c_ret_u16(void) { return 0xffff; } -uint32_t c_ret_u32() { +uint32_t c_ret_u32(void) { return 0xffffffff; } -uint64_t c_ret_u64() { +uint64_t c_ret_u64(void) { return 0xffffffffffffffff; } -int8_t c_ret_i8() { +int8_t c_ret_i8(void) { return -1; } -int16_t c_ret_i16() { +int16_t c_ret_i16(void) { return -1; } -int32_t c_ret_i32() { +int32_t c_ret_i32(void) { return -1; } -int64_t c_ret_i64() { +int64_t c_ret_i64(void) { return -1; } @@ -5592,7 +15780,7 @@ void c_struct_with_array(StructWithArray x) { assert_or_panic(x.b == 2); } -StructWithArray c_ret_struct_with_array() { +StructWithArray c_ret_struct_with_array(void) { return (StructWithArray){4, {}, 155}; } @@ -5614,7 +15802,7 @@ void c_float_array_struct(FloatArrayStruct x) { assert_or_panic(x.size.height == 8); } -FloatArrayStruct c_ret_float_array_struct() { +FloatArrayStruct c_ret_float_array_struct(void) { FloatArrayStruct x; x.origin.x = 1; x.origin.y = 2; @@ -5792,7 +15980,7 @@ f16_struct c_f16_struct(f16_struct a) { return (f16_struct){34}; } -#if defined __x86_64__ || defined __i386__ +#if (defined __x86_64__ || defined __i386__) && !defined _MSC_VER typedef long double f80; f80 c_f80(f80 a) { assert_or_panic((double)a == 12.34); @@ -5890,7 +16078,6 @@ struct ByRef __attribute__((sysv_abi)) c_explict_sys_v(struct ByRef in) { } #endif - struct byval_tail_callsite_attr_Point { double x; double y; @@ -5907,7 +16094,7 @@ double c_byval_tail_callsite_attr(struct byval_tail_callsite_attr_Rect in) { return in.size.width; } -#ifdef __i386__ +#if defined(__i386__) && defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) void __attribute__((fastcall)) zig_fastcall_check(int a, float b, void *c, double d, int e); void __attribute__((fastcall)) c_fastcall_check(int a, float b, void *c, double d, int e) { assert_or_panic(a == 1); @@ -5915,7 +16102,98 @@ void __attribute__((fastcall)) c_fastcall_check(int a, float b, void *c, double assert_or_panic((uintptr_t)c == 3); assert_or_panic(d == 4.0); assert_or_panic(e == 5); - zig_fastcall_check(a, b, c, d, e); +} + +typedef struct { + int a; + int b; + int c; +} FastcallSRet; +FastcallSRet __attribute__((fastcall)) zig_fastcall_sret(void); +FastcallSRet __attribute__((fastcall)) c_fastcall_sret(void) { + return (FastcallSRet){ + .a = 1, + .b = 2, + .c = 3 + }; +} + +typedef struct { + char a; + short b; +} FastcallNoSRet; +FastcallNoSRet __attribute__((fastcall)) zig_fastcall_no_sret(void); +FastcallNoSRet __attribute__((fastcall)) c_fastcall_no_sret(void) { + return (FastcallNoSRet){ + .a = 1, + .b = 2 + }; +} + +typedef struct { + float a; + float b; +} FastcallNoSRetF32F32; +FastcallNoSRetF32F32 __attribute__((fastcall)) zig_fastcall_no_sret_f32_f32(void); +FastcallNoSRetF32F32 __attribute__((fastcall)) c_fastcall_no_sret_f32_f32(void) { + return (FastcallNoSRetF32F32){ + .a = 1, + .b = 2 + }; +} + +typedef struct { + double a; +} FastcallNoSRetF64; +FastcallNoSRetF64 __attribute__((fastcall)) zig_fastcall_no_sret_f64(void); +FastcallNoSRetF64 __attribute__((fastcall)) c_fastcall_no_sret_f64(void) { + return (FastcallNoSRetF64){ + .a = 1 + }; +} + +float __attribute__((fastcall)) zig_fastcall_ret_f32(void); +float __attribute__((fastcall)) c_fastcall_ret_f32(void) { + return 1; +} + +double __attribute__((fastcall)) zig_fastcall_ret_f64(void); +double __attribute__((fastcall)) c_fastcall_ret_f64(void) { + return 1; +} + +void run_c_fastcall_tests(void) { + { + zig_fastcall_check(1, 2, (void*)3, 4, 5); + } + { + const FastcallSRet s = zig_fastcall_sret(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + assert_or_panic(s.c == 3); + } + { + const FastcallNoSRet s = zig_fastcall_no_sret(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + } + { + const FastcallNoSRetF32F32 s = zig_fastcall_no_sret_f32_f32(); + assert_or_panic(s.a == 1); + assert_or_panic(s.b == 2); + } + { + const FastcallNoSRetF64 s = zig_fastcall_no_sret_f64(); + assert_or_panic(s.a == 1); + } + { + const float s = zig_fastcall_ret_f32(); + assert_or_panic(s == 1); + } + { + const double s = zig_fastcall_ret_f64(); + assert_or_panic(s == 1); + } } void __attribute__((vectorcall)) zig_vectorcall_check(int a, float b, double c, void *d, float e, double f, double g, float h, float i, int j); @@ -5933,3 +16211,18 @@ void __attribute__((vectorcall)) c_vectorcall_check(int a, float b, double c, vo zig_vectorcall_check(a, b, c, d, e, f, g, h, i, j); } #endif + +#if defined(__x86_64__) && defined(_WIN64) +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); + assert_or_panic(c == UINT64_C(0x4008000000000000)); + assert_or_panic(d == 4.0); +} +void c_win64_varargs_f64_u64_f64_u64(double a, uint64_t b, double c, uint64_t d) { + assert_or_panic(a == 5.0); + assert_or_panic(b == UINT64_C(0x4018000000000000)); + 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 ff6ecbea9a4bd4a318fa8cbbd6cdcca73528b1ce..1fd570b4ed40b6a50d2085c8d65a32fa941b36fc 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -15,16 +15,15 @@ const have_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isArm() and builtin.cpu.arch != .hexagon and builtin.cpu.arch != .s390x; // https://github.com/llvm/llvm-project/issues/168460 -const have_f128 = builtin.cpu.arch.isWasm() or (builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin()); -const have_f80 = builtin.cpu.arch.isX86(); - -extern fn run_c_tests() void; +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; export fn zig_panic() noreturn { @panic("zig_panic called from C"); } -test "C importing Zig ABI Tests" { +extern fn run_c_tests() void; +test run_c_tests { run_c_tests(); } @@ -50,7 +49,7 @@ export fn zig_five_integers(a: i32, b: i32, c: i32, d: i32, e: i32) void { expect(e == 90) catch @panic("test failure: zig_five_integers 90"); } -test "C ABI integers" { +test "integers" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; c_u8(0xff); @@ -120,13 +119,13 @@ export fn zig_five_floats(a: f32, b: f32, c: f32, d: f32, e: f32) void { expect(e == 5.0) catch @panic("test failure: zig_five_floats 5.0"); } -test "C ABI floats" { +test "floats" { c_f32(12.34); c_f64(56.78); c_five_floats(1.0, 2.0, 3.0, 4.0, 5.0); } -test "C ABI long double" { +test "long double" { if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; c_long_double(12.34); @@ -145,7 +144,7 @@ export fn zig_longdouble(x: c_longdouble) void { extern fn c_ptr(*anyopaque) void; -test "C ABI pointer" { +test "pointer" { c_ptr(@as(*anyopaque, @ptrFromInt(0xdeadbeef))); } @@ -155,7 +154,7 @@ export fn zig_ptr(x: *anyopaque) void { extern fn c_bool(bool) void; -test "C ABI bool" { +test "bool" { c_bool(true); } @@ -190,7 +189,7 @@ const complex_abi_compatible = builtin.cpu.arch != .x86 and !builtin.cpu.arch.is builtin.cpu.arch != .s390x and !(builtin.cpu.arch.isLoongArch() and builtin.abi.float() == .soft); -test "C ABI complex float" { +test "complex float" { if (!complex_abi_compatible) return error.SkipZigTest; const a = ComplexFloat{ .real = 1.25, .imag = 2.6 }; @@ -201,7 +200,7 @@ test "C ABI complex float" { try expect(z.imag == 13.5); } -test "C ABI complex float by component" { +test "complex float by component" { if (!complex_abi_compatible) return error.SkipZigTest; const a = ComplexFloat{ .real = 1.25, .imag = 2.6 }; @@ -212,7 +211,7 @@ test "C ABI complex float by component" { try expect(z2.imag == 13.5); } -test "C ABI complex double" { +test "complex double" { if (!complex_abi_compatible) return error.SkipZigTest; const a = ComplexDouble{ .real = 1.25, .imag = 2.6 }; @@ -223,7 +222,7 @@ test "C ABI complex double" { try expect(z.imag == 13.5); } -test "C ABI complex double by component" { +test "complex double by component" { if (!complex_abi_compatible) return error.SkipZigTest; const a = ComplexDouble{ .real = 1.25, .imag = 2.6 }; @@ -270,3307 +269,107 @@ 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 }; } -const Struct_u8 = extern struct { - a: u8, -}; - -export fn zig_ret_struct_u8() Struct_u8 { - return .{ .a = 1 }; -} - -export fn zig_struct_u8(s: Struct_u8, i: usize) void { - expect(s.a == 2) catch @panic("test failure"); - expect(i == 3) catch @panic("test failure"); -} - -extern fn c_ret_struct_u8() Struct_u8; - -extern fn c_struct_u8(Struct_u8, usize) void; - -test "C ABI 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(); - try expect(s.a == 4); - c_struct_u8(.{ .a = 5 }, 6); -} - -const Struct_u16 = extern struct { - a: u16, -}; - -export fn zig_ret_struct_u16() Struct_u16 { - return .{ .a = 7 }; -} - -export fn zig_struct_u16(s: Struct_u16, i: usize) void { - expect(s.a == 8) catch @panic("test failure"); - expect(i == 9) catch @panic("test failure"); -} - -extern fn c_ret_struct_u16() Struct_u16; - -extern fn c_struct_u16(Struct_u16, usize) void; - -test "C ABI 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(); - try expect(s.a == 10); - c_struct_u16(.{ .a = 11 }, 12); -} - -const Struct_u32 = extern struct { - a: u32, -}; - -export fn zig_ret_struct_u32() Struct_u32 { - return .{ .a = 13 }; -} - -export fn zig_struct_u32(s: Struct_u32, i: usize) void { - expect(s.a == 14) catch @panic("test failure"); - expect(i == 15) catch @panic("test failure"); -} - -extern fn c_ret_struct_u32() Struct_u32; - -extern fn c_struct_u32(Struct_u32, usize) void; - -test "C ABI 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(); - try expect(s.a == 16); - c_struct_u32(.{ .a = 17 }, 18); -} - -const Struct_u64 = extern struct { - a: u64, -}; - -export fn zig_ret_struct_u64() Struct_u64 { - return .{ .a = 19 }; -} - -export fn zig_struct_u64(s: Struct_u64, i: usize) void { - expect(s.a == 20) catch @panic("test failure"); - expect(i == 21) catch @panic("test failure"); -} - -extern fn c_ret_struct_u64() Struct_u64; - -extern fn c_struct_u64(Struct_u64, usize) void; - -test "C ABI struct u64" { - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .riscv32) 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(); - try expect(s.a == 22); - c_struct_u64(.{ .a = 23 }, 24); -} - -const Struct_u64_u64 = extern struct { - a: u64, - b: u64, -}; - -export fn zig_ret_struct_u64_u64() Struct_u64_u64 { - return .{ .a = 1, .b = 2 }; -} - -export fn zig_struct_u64_u64_0(s: Struct_u64_u64, i: usize) void { - expect(s.a == 3) catch @panic("test failure"); - expect(s.b == 4) catch @panic("test failure"); - expect(i == 1) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_1(_: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 5) catch @panic("test failure"); - expect(s.b == 6) catch @panic("test failure"); - expect(i == 2) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_2(_: usize, _: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 7) catch @panic("test failure"); - expect(s.b == 8) catch @panic("test failure"); - expect(i == 3) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_3(_: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 9) catch @panic("test failure"); - expect(s.b == 10) catch @panic("test failure"); - expect(i == 4) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_4(_: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 11) catch @panic("test failure"); - expect(s.b == 12) catch @panic("test failure"); - expect(i == 5) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_5(_: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 13) catch @panic("test failure"); - expect(s.b == 14) catch @panic("test failure"); - expect(i == 6) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_6(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 15) catch @panic("test failure"); - expect(s.b == 16) catch @panic("test failure"); - expect(i == 7) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_7(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 17) catch @panic("test failure"); - expect(s.b == 18) catch @panic("test failure"); - expect(i == 8) catch @panic("test failure"); -} -export fn zig_struct_u64_u64_8(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { - expect(s.a == 19) catch @panic("test failure"); - expect(s.b == 20) catch @panic("test failure"); - expect(i == 9) catch @panic("test failure"); -} - -extern fn c_ret_struct_u64_u64() Struct_u64_u64; - -extern fn c_struct_u64_u64_0(Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_1(usize, Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_2(usize, usize, Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_3(usize, usize, usize, Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_4(usize, usize, usize, usize, Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_5(usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_6(usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_7(usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; -extern fn c_struct_u64_u64_8(usize, usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; - -test "C ABI struct u64, u64" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - - const s = c_ret_struct_u64_u64(); - try expect(s.a == 21); - try expect(s.b == 22); - c_struct_u64_u64_0(.{ .a = 23, .b = 24 }, 1); - c_struct_u64_u64_1(0, .{ .a = 25, .b = 26 }, 2); - c_struct_u64_u64_2(0, 1, .{ .a = 27, .b = 28 }, 3); - c_struct_u64_u64_3(0, 1, 2, .{ .a = 29, .b = 30 }, 4); - c_struct_u64_u64_4(0, 1, 2, 3, .{ .a = 31, .b = 32 }, 5); - c_struct_u64_u64_5(0, 1, 2, 3, 4, .{ .a = 33, .b = 34 }, 6); - c_struct_u64_u64_6(0, 1, 2, 3, 4, 5, .{ .a = 35, .b = 36 }, 7); - c_struct_u64_u64_7(0, 1, 2, 3, 4, 5, 6, .{ .a = 37, .b = 38 }, 8); - c_struct_u64_u64_8(0, 1, 2, 3, 4, 5, 6, 7, .{ .a = 39, .b = 40 }, 9); -} - -const Struct_f32 = extern struct { - a: f32, -}; - -export fn zig_ret_struct_f32() Struct_f32 { - return .{ .a = 2.5 }; -} - -export fn zig_struct_f32(s: Struct_f32) void { - expect(s.a == 2.5) catch @panic("test failure"); -} - -extern fn c_ret_struct_f32() Struct_f32; - -extern fn c_struct_f32(Struct_f32) void; - -test "C ABI 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 == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; - - const s = c_ret_struct_f32(); - try expect(s.a == 2.5); - c_struct_f32(.{ .a = 2.5 }); -} - -const Struct_f64 = extern struct { - a: f64, -}; - -export fn zig_ret_struct_f64() Struct_f64 { - return .{ .a = 2.5 }; -} - -export fn zig_struct_f64(s: Struct_f64) void { - expect(s.a == 2.5) catch @panic("test failure"); -} - -extern fn c_ret_struct_f64() Struct_f64; - -extern fn c_struct_f64(Struct_f64) void; - -test "C ABI struct f64" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; - if (builtin.cpu.arch == .riscv32) 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(); - try expect(s.a == 2.5); - c_struct_f64(.{ .a = 2.5 }); -} - -const Struct_f32a8 = extern struct { - a: f32 align(8), -}; - -export fn zig_ret_struct_f32a8() Struct_f32a8 { - return .{ .a = 1.25 }; -} - -export fn zig_struct_f32a8(s: Struct_f32a8, f: f32) void { - expect(s.a == 2.75) catch @panic("test failure"); - expect(f == 3.5) catch @panic("test failure"); -} - -extern fn c_ret_struct_f32a8() Struct_f32a8; - -extern fn c_struct_f32a8(Struct_f32a8, f32) void; - -test "C ABI struct f32 align(8)" { - 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.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .riscv32) 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(); - try expect(s.a == 4.125); - c_struct_f32a8(.{ .a = 5.375 }, 6.5); -} - -const Struct_f32a8_f32a8 = extern struct { - a: f32 align(8), - b: f32 align(8), -}; - -export fn zig_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8 { - return .{ .a = 1.25, .b = 2.75 }; -} - -export fn zig_struct_f32a8_f32a8(s: Struct_f32a8_f32a8, f: f32) void { - expect(s.a == 3.125) catch @panic("test failure"); - expect(s.b == 4.375) catch @panic("test failure"); - expect(f == 5.5) catch @panic("test failure"); -} - -extern fn c_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8; - -extern fn c_struct_f32a8_f32a8(Struct_f32a8_f32a8, f32) void; - -test "C ABI struct f32 align(8), f32 align(8)" { - 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.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(); - try expect(s.a == 6.625); - try expect(s.b == 7.875); - c_struct_f32a8_f32a8(.{ .a = 8.0625, .b = 9.1875 }, 10.5); -} - -const Struct_f32f32_f32 = extern struct { - a: extern struct { b: f32, c: f32 }, - d: f32, -}; - -export fn zig_ret_struct_f32f32_f32() Struct_f32f32_f32 { - return .{ .a = .{ .b = 1.0, .c = 2.0 }, .d = 3.0 }; -} - -export fn zig_struct_f32f32_f32(s: Struct_f32f32_f32) void { - expect(s.a.b == 1.0) catch @panic("test failure"); - expect(s.a.c == 2.0) catch @panic("test failure"); - expect(s.d == 3.0) catch @panic("test failure"); -} - -extern fn c_ret_struct_f32f32_f32() Struct_f32f32_f32; - -extern fn c_struct_f32f32_f32(Struct_f32f32_f32) void; - -test "C ABI struct {f32, f32}, f32" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) 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; - - const s = c_ret_struct_f32f32_f32(); - try expect(s.a.b == 1.0); - try expect(s.a.c == 2.0); - try expect(s.d == 3.0); - c_struct_f32f32_f32(.{ .a = .{ .b = 1.0, .c = 2.0 }, .d = 3.0 }); -} - -const Struct_f32_f32f32 = extern struct { - a: f32, - b: extern struct { c: f32, d: f32 }, -}; - -export fn zig_ret_struct_f32_f32f32() Struct_f32_f32f32 { - return .{ .a = 1.0, .b = .{ .c = 2.0, .d = 3.0 } }; -} - -export fn zig_struct_f32_f32f32(s: Struct_f32_f32f32) void { - expect(s.a == 1.0) catch @panic("test failure"); - expect(s.b.c == 2.0) catch @panic("test failure"); - expect(s.b.d == 3.0) catch @panic("test failure"); -} - -extern fn c_ret_struct_f32_f32f32() Struct_f32_f32f32; - -extern fn c_struct_f32_f32f32(Struct_f32_f32f32) void; - -test "C ABI struct f32 {f32,f32}" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest; - if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) 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; - - const s = c_ret_struct_f32_f32f32(); - try expect(s.a == 1.0); - try expect(s.b.c == 2.0); - try expect(s.b.d == 3.0); - c_struct_f32_f32f32(.{ .a = 1.0, .b = .{ .c = 2.0, .d = 3.0 } }); -} - -const Struct_u32_Union_u32_u32u32 = extern struct { - a: u32, - b: extern union { - c: extern struct { - d: u32, - e: u32, - }, - }, -}; - -export fn zig_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32 { - return .{ .a = 1, .b = .{ .c = .{ .d = 2, .e = 3 } } }; -} - -export fn zig_struct_u32_union_u32_u32u32(s: Struct_u32_Union_u32_u32u32) void { - expect(s.a == 1) catch @panic("test failure"); - expect(s.b.c.d == 2) catch @panic("test failure"); - expect(s.b.c.e == 3) catch @panic("test failure"); -} - -extern fn c_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32; - -extern fn c_struct_u32_union_u32_u32u32(Struct_u32_Union_u32_u32u32) void; - -test "C ABI struct{u32,union{u32,struct{u32,u32}}}" { - 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; - - const s = c_ret_struct_u32_union_u32_u32u32(); - try expect(s.a == 1); - try expect(s.b.c.d == 2); - try expect(s.b.c.e == 3); - c_struct_u32_union_u32_u32u32(.{ .a = 1, .b = .{ .c = .{ .d = 2, .e = 3 } } }); -} - -const Struct_i32_i32 = extern struct { - a: i32, - b: i32, -}; -extern fn c_mut_struct_i32_i32(Struct_i32_i32) Struct_i32_i32; -extern fn c_struct_i32_i32(Struct_i32_i32) void; - -test "C ABI struct i32 i32" { - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch == .riscv32) 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 = .{ - .a = 1, - .b = 2, - }; - const mut_res = c_mut_struct_i32_i32(s); - try expect(s.a == 1); - try expect(s.b == 2); - try expect(mut_res.a == 101); - try expect(mut_res.b == 252); - c_struct_i32_i32(s); -} - -export fn zig_struct_i32_i32(s: Struct_i32_i32) void { - expect(s.a == 1) catch @panic("test failure: zig_struct_i32_i32 1"); - expect(s.b == 2) catch @panic("test failure: zig_struct_i32_i32 2"); -} - -const BigStruct = extern struct { - a: u64, - b: u64, - c: u64, - d: u64, - e: u8, -}; -extern fn c_big_struct(BigStruct) void; - -test "C ABI 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; - - const s = BigStruct{ - .a = 1, - .b = 2, - .c = 3, - .d = 4, - .e = 5, - }; - c_big_struct(s); -} - -export fn zig_big_struct(x: BigStruct) void { - expect(x.a == 1) catch @panic("test failure: zig_big_struct 1"); - expect(x.b == 2) catch @panic("test failure: zig_big_struct 2"); - expect(x.c == 3) catch @panic("test failure: zig_big_struct 3"); - expect(x.d == 4) catch @panic("test failure: zig_big_struct 4"); - expect(x.e == 5) catch @panic("test failure: zig_big_struct 5"); -} - -const BigUnion = extern union { - a: BigStruct, -}; -extern fn c_big_union(BigUnion) void; - -test "C 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; - - const x = BigUnion{ - .a = BigStruct{ - .a = 1, - .b = 2, - .c = 3, - .d = 4, - .e = 5, - }, - }; - c_big_union(x); -} - -export fn zig_big_union(x: BigUnion) void { - expect(x.a.a == 1) catch @panic("test failure: zig_big_union a"); - expect(x.a.b == 2) catch @panic("test failure: zig_big_union b"); - expect(x.a.c == 3) catch @panic("test failure: zig_big_union c"); - expect(x.a.d == 4) catch @panic("test failure: zig_big_union d"); - expect(x.a.e == 5) catch @panic("test failure: zig_big_union e"); -} - -const MedStructMixed = extern struct { - a: u32, - b: f32, - c: f32, - d: u32 = 0, -}; -extern fn c_med_struct_mixed(MedStructMixed) void; -extern fn c_ret_med_struct_mixed() MedStructMixed; - -test "C ABI 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; - - const s = MedStructMixed{ - .a = 1234, - .b = 100.0, - .c = 1337.0, - }; - c_med_struct_mixed(s); - const s2 = c_ret_med_struct_mixed(); - try expect(s2.a == 1234); - try expect(s2.b == 100.0); - try expect(s2.c == 1337.0); -} - -export fn zig_med_struct_mixed(x: MedStructMixed) void { - expect(x.a == 1234) catch @panic("test failure"); - expect(x.b == 100.0) catch @panic("test failure"); - expect(x.c == 1337.0) catch @panic("test failure"); -} - -const SmallStructInts = extern struct { - a: u8, - b: u8, - c: u8, - d: u8, -}; -extern fn c_small_struct_ints(SmallStructInts) void; -extern fn c_ret_small_struct_ints() SmallStructInts; - -test "C ABI small 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; - - const s = SmallStructInts{ - .a = 1, - .b = 2, - .c = 3, - .d = 4, - }; - c_small_struct_ints(s); - const s2 = c_ret_small_struct_ints(); - try expect(s2.a == 1); - try expect(s2.b == 2); - try expect(s2.c == 3); - try expect(s2.d == 4); -} - -export fn zig_small_struct_ints(x: SmallStructInts) void { - expect(x.a == 1) catch @panic("test failure"); - expect(x.b == 2) catch @panic("test failure"); - expect(x.c == 3) catch @panic("test failure"); - expect(x.d == 4) catch @panic("test failure"); -} - -const MedStructInts = extern struct { - x: i32, - y: i32, - z: i32, -}; -extern fn c_med_struct_ints(MedStructInts) void; -extern fn c_ret_med_struct_ints() MedStructInts; - -test "C ABI medium struct of ints" { - 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; - - const s = MedStructInts{ - .x = 1, - .y = 2, - .z = 3, - }; - c_med_struct_ints(s); - const s2 = c_ret_med_struct_ints(); - try expect(s2.x == 1); - try expect(s2.y == 2); - try expect(s2.z == 3); -} - -export fn zig_med_struct_ints(s: MedStructInts) void { - expect(s.x == 1) catch @panic("test failure"); - expect(s.y == 2) catch @panic("test failure"); - expect(s.z == 3) catch @panic("test failure"); -} - -const SmallPackedStruct = packed struct(u8) { - a: u2, - b: u2, - c: u2, - d: u2, -}; -extern fn c_small_packed_struct(SmallPackedStruct) void; -extern fn c_ret_small_packed_struct() SmallPackedStruct; - -export fn zig_small_packed_struct(x: SmallPackedStruct) void { - expect(x.a == 0) catch @panic("test failure"); - expect(x.b == 1) catch @panic("test failure"); - expect(x.c == 2) catch @panic("test failure"); - expect(x.d == 3) catch @panic("test failure"); -} - -test "C ABI small packed struct" { - const s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3 }; - c_small_packed_struct(s); - const s2 = c_ret_small_packed_struct(); - try expect(s2.a == 0); - try expect(s2.b == 1); - try expect(s2.c == 2); - try expect(s2.d == 3); -} - -const BigPackedStruct = packed struct(u128) { - a: u64, - b: u64, -}; -extern fn c_big_packed_struct(BigPackedStruct) void; -extern fn c_ret_big_packed_struct() BigPackedStruct; - -export fn zig_big_packed_struct(x: BigPackedStruct) void { - expect(x.a == 1) catch @panic("test failure"); - expect(x.b == 2) catch @panic("test failure"); -} - -test "C ABI big packed struct" { - if (!have_i128) return error.SkipZigTest; - - const s = BigPackedStruct{ .a = 1, .b = 2 }; - c_big_packed_struct(s); - const s2 = c_ret_big_packed_struct(); - try expect(s2.a == 1); - try expect(s2.b == 2); -} - -const SplitStructInt = extern struct { - a: u64, - b: u8, - c: u32, -}; -extern fn c_split_struct_ints(SplitStructInt) void; - -test "C ABI 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; - - const s = SplitStructInt{ - .a = 1234, - .b = 100, - .c = 1337, - }; - c_split_struct_ints(s); -} - -export fn zig_split_struct_ints(x: SplitStructInt) void { - expect(x.a == 1234) catch @panic("test failure"); - expect(x.b == 100) catch @panic("test failure"); - expect(x.c == 1337) catch @panic("test failure"); -} - -const SplitStructMixed = extern struct { - a: u64, - b: u8, - c: f32, -}; -extern fn c_split_struct_mixed(SplitStructMixed) void; -extern fn c_ret_split_struct_mixed() SplitStructMixed; - -test "C ABI 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; - - const s = SplitStructMixed{ - .a = 1234, - .b = 100, - .c = 1337.0, - }; - c_split_struct_mixed(s); - const s2 = c_ret_split_struct_mixed(); - try expect(s2.a == 1234); - try expect(s2.b == 100); - try expect(s2.c == 1337.0); -} - -export fn zig_split_struct_mixed(x: SplitStructMixed) void { - expect(x.a == 1234) catch @panic("test failure"); - expect(x.b == 100) catch @panic("test failure"); - expect(x.c == 1337.0) catch @panic("test failure"); -} - -extern fn c_big_struct_both(BigStruct) BigStruct; - -extern fn c_multiple_struct_ints(Rect, Rect) void; -extern fn c_multiple_struct_floats(FloatRect, FloatRect) void; - -test "C ABI 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; - - const s = BigStruct{ - .a = 1, - .b = 2, - .c = 3, - .d = 4, - .e = 5, - }; - const y = c_big_struct_both(s); - try expect(y.a == 10); - try expect(y.b == 11); - try expect(y.c == 12); - try expect(y.d == 13); - try expect(y.e == 14); -} - -export fn zig_big_struct_both(x: BigStruct) BigStruct { - expect(x.a == 30) catch @panic("test failure"); - expect(x.b == 31) catch @panic("test failure"); - expect(x.c == 32) catch @panic("test failure"); - expect(x.d == 33) catch @panic("test failure"); - expect(x.e == 34) catch @panic("test failure"); - const s = BigStruct{ - .a = 20, - .b = 21, - .c = 22, - .d = 23, - .e = 24, - }; - return s; -} - -const Vector3 = extern struct { - x: f32, - y: f32, - z: f32, -}; -extern fn c_small_struct_floats(Vector3) void; -extern fn c_small_struct_floats_extra(Vector3, ?[*]const u8) void; - -const Vector5 = extern struct { - x: f32, - y: f32, - z: f32, - w: f32, - q: f32, -}; -extern fn c_big_struct_floats(Vector5) void; - -test "C ABI structs of floats as parameter" { - 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; - - const v3 = Vector3{ - .x = 3.0, - .y = 6.0, - .z = 12.0, - }; - c_small_struct_floats(v3); - c_small_struct_floats_extra(v3, "hello"); - - const v5 = Vector5{ - .x = 76.0, - .y = -1.0, - .z = -12.0, - .w = 69.0, - .q = 55, - }; - c_big_struct_floats(v5); -} - -const Rect = extern struct { - left: u32, - right: u32, - top: u32, - bottom: u32, -}; - -export fn zig_multiple_struct_ints(x: Rect, y: Rect) void { - expect(x.left == 1) catch @panic("test failure"); - expect(x.right == 21) catch @panic("test failure"); - expect(x.top == 16) catch @panic("test failure"); - expect(x.bottom == 4) catch @panic("test failure"); - expect(y.left == 178) catch @panic("test failure"); - expect(y.right == 189) catch @panic("test failure"); - expect(y.top == 21) catch @panic("test failure"); - expect(y.bottom == 15) catch @panic("test failure"); -} - -test "C ABI structs of ints as multiple parameters" { - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; - if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - - const r1 = Rect{ - .left = 1, - .right = 21, - .top = 16, - .bottom = 4, - }; - const r2 = Rect{ - .left = 178, - .right = 189, - .top = 21, - .bottom = 15, - }; - c_multiple_struct_ints(r1, r2); -} - -const FloatRect = extern struct { - left: f32, - right: f32, - top: f32, - bottom: f32, -}; - -export fn zig_multiple_struct_floats(x: FloatRect, y: FloatRect) void { - expect(x.left == 1) catch @panic("test failure"); - expect(x.right == 21) catch @panic("test failure"); - expect(x.top == 16) catch @panic("test failure"); - expect(x.bottom == 4) catch @panic("test failure"); - expect(y.left == 178) catch @panic("test failure"); - expect(y.right == 189) catch @panic("test failure"); - expect(y.top == 21) catch @panic("test failure"); - expect(y.bottom == 15) catch @panic("test failure"); -} - -test "C ABI structs of floats as multiple parameters" { - 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; - - const r1 = FloatRect{ - .left = 1, - .right = 21, - .top = 16, - .bottom = 4, - }; - const r2 = FloatRect{ - .left = 178, - .right = 189, - .top = 21, - .bottom = 15, - }; - c_multiple_struct_floats(r1, r2); -} - -export fn zig_ret_bool() bool { - return true; -} -export fn zig_ret_u8() u8 { - return 0xff; -} -export fn zig_ret_u16() u16 { - return 0xffff; -} -export fn zig_ret_u32() u32 { - return 0xffffffff; -} -export fn zig_ret_u64() u64 { - return 0xffffffffffffffff; -} -export fn zig_ret_i8() i8 { - return -1; -} -export fn zig_ret_i16() i16 { - return -1; -} -export fn zig_ret_i32() i32 { - return -1; -} -export fn zig_ret_i64() i64 { - return -1; -} - -export fn zig_ret_small_struct_ints() SmallStructInts { - return .{ - .a = 1, - .b = 2, - .c = 3, - .d = 4, - }; -} - -export fn zig_ret_med_struct_ints() MedStructInts { - return .{ - .x = 1, - .y = 2, - .z = 3, - }; -} - -export fn zig_ret_med_struct_mixed() MedStructMixed { - return .{ - .a = 1234, - .b = 100.0, - .c = 1337.0, - }; -} - -export fn zig_ret_split_struct_mixed() SplitStructMixed { - return .{ - .a = 1234, - .b = 100, - .c = 1337.0, - }; -} - -extern fn c_ret_bool() bool; -extern fn c_ret_u8() u8; -extern fn c_ret_u16() u16; -extern fn c_ret_u32() u32; -extern fn c_ret_u64() u64; -extern fn c_ret_i8() i8; -extern fn c_ret_i16() i16; -extern fn c_ret_i32() i32; -extern fn c_ret_i64() i64; - -test "C ABI integer return types" { - try expect(c_ret_bool() == true); - - try expect(c_ret_u8() == 0xff); - try expect(c_ret_u16() == 0xffff); - try expect(c_ret_u32() == 0xffffffff); - try expect(c_ret_u64() == 0xffffffffffffffff); - - try expect(c_ret_i8() == -1); - try expect(c_ret_i16() == -1); - try expect(c_ret_i32() == -1); - try expect(c_ret_i64() == -1); -} - -const StructWithArray = extern struct { - a: i32, - padding: [4]u8, - b: i64, -}; -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; - - c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 }); - - const x = c_ret_struct_with_array(); - try expect(x.a == 4); - try expect(x.b == 155); -} - -const FloatArrayStruct = extern struct { - origin: extern struct { - x: f64, - y: f64, - }, - size: extern struct { - width: f64, - height: f64, - }, -}; - -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; - - c_float_array_struct(.{ - .origin = .{ - .x = 5, - .y = 6, - }, - .size = .{ - .width = 7, - .height = 8, - }, - }); - - const x = c_ret_float_array_struct(); - try expect(x.origin.x == 1); - try expect(x.origin.y == 2); - try expect(x.size.width == 3); - try expect(x.size.height == 4); -} - -const SmallVec = @Vector(2, u32); - -extern fn c_small_vec(SmallVec) void; -extern fn c_ret_small_vec() SmallVec; - -test "small simd vector" { - if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - - c_small_vec(.{ 1, 2 }); - - const x = c_ret_small_vec(); - try expect(x[0] == 3); - try expect(x[1] == 4); -} - -const MediumVec = @Vector(4, usize); - -extern fn c_medium_vec(MediumVec) void; -extern fn c_ret_medium_vec() MediumVec; - -test "medium simd vector" { - if (builtin.zig_backend == .stage2_x86_64 and !comptime builtin.cpu.has(.x86, .avx)) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - - c_medium_vec(.{ 1, 2, 3, 4 }); - - const x = c_ret_medium_vec(); - try expect(x[0] == 5); - try expect(x[1] == 6); - try expect(x[2] == 7); - try expect(x[3] == 8); -} - -const BigVec = @Vector(8, usize); - -extern fn c_big_vec(BigVec) void; -extern fn c_ret_big_vec() BigVec; - -test "big simd vector" { - if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - - if (builtin.cpu.arch.isMIPS64() and builtin.mode != .Debug) return error.SkipZigTest; - if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and builtin.os.tag.isDarwin() and builtin.mode != .Debug) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - - c_big_vec(.{ 1, 2, 3, 4, 5, 6, 7, 8 }); - - const x = c_ret_big_vec(); - try expect(x[0] == 9); - try expect(x[1] == 10); - try expect(x[2] == 11); - try expect(x[3] == 12); - try expect(x[4] == 13); - try expect(x[5] == 14); - try expect(x[6] == 15); - try expect(x[7] == 16); -} - -const Vector2Float = @Vector(2, f32); -const Vector4Float = @Vector(4, f32); - -extern fn c_vector_2_float(Vector2Float) void; -extern fn c_vector_4_float(Vector4Float) void; - -extern fn c_ret_vector_2_float() Vector2Float; -extern fn c_ret_vector_4_float() Vector4Float; - -test "float simd vectors" { - if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; - if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - - { - c_vector_2_float(.{ 1.0, 2.0 }); - const vec = c_ret_vector_2_float(); - try expect(vec[0] == 1.0); - try expect(vec[1] == 2.0); - } - { - c_vector_4_float(.{ 1.0, 2.0, 3.0, 4.0 }); - const vec = c_ret_vector_4_float(); - try expect(vec[0] == 1.0); - try expect(vec[1] == 2.0); - try expect(vec[2] == 3.0); - try expect(vec[3] == 4.0); - } -} - -const Vector2Bool = @Vector(2, bool); -const Vector4Bool = @Vector(4, bool); -const Vector8Bool = @Vector(8, bool); -const Vector16Bool = @Vector(16, bool); -const Vector32Bool = @Vector(32, bool); -const Vector64Bool = @Vector(64, bool); -const Vector128Bool = @Vector(128, bool); -const Vector256Bool = @Vector(256, bool); -const Vector512Bool = @Vector(512, bool); - -extern fn c_vector_2_bool(Vector2Bool) void; -extern fn c_vector_4_bool(Vector4Bool) void; -extern fn c_vector_8_bool(Vector8Bool) void; -extern fn c_vector_16_bool(Vector16Bool) void; -extern fn c_vector_32_bool(Vector32Bool) void; -extern fn c_vector_64_bool(Vector64Bool) void; -extern fn c_vector_128_bool(Vector128Bool) void; -extern fn c_vector_256_bool(Vector256Bool) void; -extern fn c_vector_512_bool(Vector512Bool) void; - -extern fn c_ret_vector_2_bool() Vector2Bool; -extern fn c_ret_vector_4_bool() Vector4Bool; -extern fn c_ret_vector_8_bool() Vector8Bool; -extern fn c_ret_vector_16_bool() Vector16Bool; -extern fn c_ret_vector_32_bool() Vector32Bool; -extern fn c_ret_vector_64_bool() Vector64Bool; -extern fn c_ret_vector_128_bool() Vector128Bool; -extern fn c_ret_vector_256_bool() Vector256Bool; -extern fn c_ret_vector_512_bool() Vector512Bool; - -test "bool simd vector" { - if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; - - { - c_vector_2_bool(.{ - true, - true, - }); - - const vec = c_ret_vector_2_bool(); - try expect(vec[0] == true); - try expect(vec[1] == false); - } - { - c_vector_4_bool(.{ - true, - true, - false, - true, - }); - - const vec = c_ret_vector_4_bool(); - try expect(vec[0] == true); - try expect(vec[1] == false); - try expect(vec[2] == true); - try expect(vec[3] == false); - } - { - c_vector_8_bool(.{ - true, - false, - true, - true, - true, - true, - false, - true, - }); - - const vec = c_ret_vector_8_bool(); - try expect(vec[0] == false); - try expect(vec[1] == true); - try expect(vec[2] == false); - try expect(vec[3] == false); - try expect(vec[4] == true); - try expect(vec[5] == false); - try expect(vec[6] == false); - try expect(vec[7] == true); - } - { - c_vector_16_bool(.{ - true, - false, - false, - false, - true, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - }); - - const vec = c_ret_vector_16_bool(); - try expect(vec[0] == true); - try expect(vec[1] == true); - try expect(vec[2] == false); - try expect(vec[3] == false); - try expect(vec[4] == false); - try expect(vec[5] == false); - try expect(vec[6] == true); - try expect(vec[7] == false); - try expect(vec[8] == true); - try expect(vec[9] == false); - try expect(vec[10] == false); - try expect(vec[11] == true); - try expect(vec[12] == true); - try expect(vec[13] == false); - try expect(vec[14] == true); - try expect(vec[15] == true); - } - { - c_vector_32_bool(.{ - true, - false, - true, - true, - false, - false, - true, - false, - true, - false, - true, - true, - true, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - false, - true, - true, - false, - }); - - const vec = c_ret_vector_32_bool(); - try expect(vec[0] == true); - try expect(vec[1] == false); - try expect(vec[2] == true); - try expect(vec[3] == true); - try expect(vec[4] == true); - try expect(vec[5] == false); - try expect(vec[6] == true); - try expect(vec[7] == false); - try expect(vec[8] == true); - try expect(vec[9] == true); - try expect(vec[10] == true); - try expect(vec[11] == false); - try expect(vec[12] == true); - try expect(vec[13] == true); - try expect(vec[14] == false); - try expect(vec[15] == false); - try expect(vec[16] == true); - try expect(vec[17] == false); - try expect(vec[18] == false); - try expect(vec[19] == false); - try expect(vec[20] == false); - try expect(vec[21] == true); - try expect(vec[22] == true); - try expect(vec[23] == true); - try expect(vec[24] == false); - try expect(vec[25] == true); - try expect(vec[26] == false); - try expect(vec[27] == false); - try expect(vec[28] == true); - try expect(vec[29] == false); - try expect(vec[30] == false); - try expect(vec[31] == false); - } - { - c_vector_64_bool(.{ - true, - true, - true, - false, - true, - false, - false, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - true, - true, - false, - true, - false, - false, - true, - true, - true, - false, - false, - true, - true, - false, - true, - false, - true, - false, - false, - true, - false, - true, - true, - true, - true, - true, - false, - false, - true, - false, - true, - false, - }); - - const vec = c_ret_vector_64_bool(); - try expect(vec[0] == false); - try expect(vec[1] == true); - try expect(vec[2] == false); - try expect(vec[3] == true); - try expect(vec[4] == true); - try expect(vec[5] == true); - try expect(vec[6] == false); - try expect(vec[7] == true); - try expect(vec[8] == true); - try expect(vec[9] == true); - try expect(vec[10] == true); - try expect(vec[11] == true); - try expect(vec[12] == true); - try expect(vec[13] == false); - try expect(vec[14] == true); - try expect(vec[15] == true); - try expect(vec[16] == true); - try expect(vec[17] == false); - try expect(vec[18] == false); - try expect(vec[19] == false); - try expect(vec[20] == true); - try expect(vec[21] == true); - try expect(vec[22] == false); - try expect(vec[23] == true); - try expect(vec[24] == false); - try expect(vec[25] == true); - try expect(vec[26] == false); - try expect(vec[27] == true); - try expect(vec[28] == false); - try expect(vec[29] == true); - try expect(vec[30] == false); - try expect(vec[31] == true); - try expect(vec[32] == false); - try expect(vec[33] == false); - try expect(vec[34] == true); - try expect(vec[35] == true); - try expect(vec[36] == false); - try expect(vec[37] == false); - try expect(vec[38] == false); - try expect(vec[39] == true); - try expect(vec[40] == true); - try expect(vec[41] == true); - try expect(vec[42] == true); - try expect(vec[43] == false); - try expect(vec[44] == false); - try expect(vec[45] == false); - try expect(vec[46] == true); - try expect(vec[47] == true); - try expect(vec[48] == false); - try expect(vec[49] == false); - try expect(vec[50] == true); - try expect(vec[51] == false); - try expect(vec[52] == false); - try expect(vec[53] == false); - try expect(vec[54] == false); - try expect(vec[55] == true); - try expect(vec[56] == false); - try expect(vec[57] == false); - try expect(vec[58] == false); - try expect(vec[59] == true); - try expect(vec[60] == true); - try expect(vec[61] == true); - try expect(vec[62] == true); - try expect(vec[63] == true); - } - { - c_vector_128_bool(.{ - false, - false, - false, - false, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - true, - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - true, - false, - false, - false, - false, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - false, - true, - false, - false, - true, - true, - false, - true, - true, - false, - true, - false, - false, - true, - true, - false, - true, - true, - true, - false, - true, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - true, - false, - true, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - }); - - const vec = c_ret_vector_128_bool(); - try expect(vec[0] == false); - try expect(vec[1] == true); - try expect(vec[2] == true); - try expect(vec[3] == false); - try expect(vec[4] == true); - try expect(vec[5] == false); - try expect(vec[6] == false); - try expect(vec[7] == true); - try expect(vec[8] == true); - try expect(vec[9] == false); - try expect(vec[10] == true); - try expect(vec[11] == false); - try expect(vec[12] == false); - try expect(vec[13] == false); - try expect(vec[14] == true); - try expect(vec[15] == false); - try expect(vec[16] == true); - try expect(vec[17] == false); - try expect(vec[18] == false); - try expect(vec[19] == true); - try expect(vec[20] == false); - try expect(vec[21] == true); - try expect(vec[22] == false); - try expect(vec[23] == false); - try expect(vec[24] == false); - try expect(vec[25] == true); - try expect(vec[26] == true); - try expect(vec[27] == true); - try expect(vec[28] == false); - try expect(vec[29] == false); - try expect(vec[30] == false); - try expect(vec[31] == false); - try expect(vec[32] == true); - try expect(vec[33] == true); - try expect(vec[34] == true); - try expect(vec[35] == false); - try expect(vec[36] == true); - try expect(vec[37] == true); - try expect(vec[38] == false); - try expect(vec[39] == false); - try expect(vec[40] == false); - try expect(vec[41] == false); - try expect(vec[42] == true); - try expect(vec[43] == true); - try expect(vec[44] == true); - try expect(vec[45] == false); - try expect(vec[46] == false); - try expect(vec[47] == false); - try expect(vec[48] == false); - try expect(vec[49] == true); - try expect(vec[50] == false); - try expect(vec[51] == false); - try expect(vec[52] == true); - try expect(vec[53] == false); - try expect(vec[54] == false); - try expect(vec[55] == false); - try expect(vec[56] == false); - try expect(vec[57] == false); - try expect(vec[58] == true); - try expect(vec[59] == true); - try expect(vec[60] == true); - try expect(vec[61] == false); - try expect(vec[62] == true); - try expect(vec[63] == true); - try expect(vec[64] == false); - try expect(vec[65] == false); - try expect(vec[66] == false); - try expect(vec[67] == false); - try expect(vec[68] == false); - try expect(vec[69] == false); - try expect(vec[70] == false); - try expect(vec[71] == false); - try expect(vec[72] == true); - try expect(vec[73] == true); - try expect(vec[74] == true); - try expect(vec[75] == true); - try expect(vec[76] == true); - try expect(vec[77] == false); - try expect(vec[78] == false); - try expect(vec[79] == false); - try expect(vec[80] == false); - try expect(vec[81] == false); - try expect(vec[82] == false); - try expect(vec[83] == true); - try expect(vec[84] == false); - try expect(vec[85] == true); - try expect(vec[86] == false); - try expect(vec[87] == true); - try expect(vec[88] == false); - try expect(vec[89] == true); - try expect(vec[90] == false); - try expect(vec[91] == true); - try expect(vec[92] == true); - try expect(vec[93] == true); - try expect(vec[94] == true); - try expect(vec[95] == false); - try expect(vec[96] == false); - try expect(vec[97] == true); - try expect(vec[98] == false); - try expect(vec[99] == false); - try expect(vec[100] == true); - try expect(vec[101] == true); - try expect(vec[102] == true); - try expect(vec[103] == true); - try expect(vec[104] == false); - try expect(vec[105] == true); - try expect(vec[106] == true); - try expect(vec[107] == true); - try expect(vec[108] == false); - try expect(vec[109] == false); - try expect(vec[110] == true); - try expect(vec[111] == false); - try expect(vec[112] == false); - try expect(vec[113] == true); - try expect(vec[114] == true); - try expect(vec[115] == false); - try expect(vec[116] == true); - try expect(vec[117] == false); - try expect(vec[118] == true); - try expect(vec[119] == true); - try expect(vec[120] == true); - try expect(vec[121] == true); - try expect(vec[122] == true); - try expect(vec[123] == false); - try expect(vec[124] == false); - try expect(vec[125] == true); - try expect(vec[126] == false); - try expect(vec[127] == true); - } - - { - if (!builtin.target.cpu.arch.isWasm()) c_vector_256_bool(.{ - false, - true, - true, - false, - false, - true, - true, - true, - false, - true, - true, - true, - false, - true, - false, - true, - false, - false, - true, - true, - false, - true, - false, - false, - false, - true, - true, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - false, - false, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - true, - true, - false, - false, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - true, - false, - true, - true, - false, - false, - true, - true, - false, - true, - true, - true, - true, - true, - true, - true, - false, - true, - true, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - true, - false, - true, - true, - true, - true, - false, - true, - true, - false, - false, - true, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - false, - false, - false, - true, - true, - false, - true, - true, - false, - false, - false, - false, - true, - false, - true, - false, - false, - false, - false, - true, - true, - true, - false, - true, - false, - true, - true, - false, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - true, - false, - false, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - true, - false, - false, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - false, - true, - false, - true, - true, - false, - true, - true, - true, - false, - }); - - const vec = c_ret_vector_256_bool(); - try expect(vec[0] == true); - try expect(vec[1] == false); - try expect(vec[2] == true); - try expect(vec[3] == true); - try expect(vec[4] == false); - try expect(vec[5] == false); - try expect(vec[6] == false); - try expect(vec[7] == false); - try expect(vec[8] == false); - try expect(vec[9] == true); - try expect(vec[10] == false); - try expect(vec[11] == true); - try expect(vec[12] == false); - try expect(vec[13] == true); - try expect(vec[14] == false); - try expect(vec[15] == false); - try expect(vec[16] == true); - try expect(vec[17] == true); - try expect(vec[18] == true); - try expect(vec[19] == false); - try expect(vec[20] == false); - try expect(vec[21] == false); - try expect(vec[22] == true); - try expect(vec[23] == false); - try expect(vec[24] == true); - try expect(vec[25] == false); - try expect(vec[26] == false); - try expect(vec[27] == true); - try expect(vec[28] == true); - try expect(vec[29] == true); - try expect(vec[30] == false); - try expect(vec[31] == false); - try expect(vec[32] == true); - try expect(vec[33] == true); - try expect(vec[34] == true); - try expect(vec[35] == false); - try expect(vec[36] == true); - try expect(vec[37] == true); - try expect(vec[38] == true); - try expect(vec[39] == false); - try expect(vec[40] == true); - try expect(vec[41] == false); - try expect(vec[42] == true); - try expect(vec[43] == true); - try expect(vec[44] == false); - try expect(vec[45] == true); - try expect(vec[46] == false); - try expect(vec[47] == true); - try expect(vec[48] == true); - try expect(vec[49] == false); - try expect(vec[50] == false); - try expect(vec[51] == true); - try expect(vec[52] == true); - try expect(vec[53] == false); - try expect(vec[54] == false); - try expect(vec[55] == true); - try expect(vec[56] == false); - try expect(vec[57] == true); - try expect(vec[58] == true); - try expect(vec[59] == true); - try expect(vec[60] == false); - try expect(vec[61] == true); - try expect(vec[62] == true); - try expect(vec[63] == false); - try expect(vec[64] == true); - try expect(vec[65] == true); - try expect(vec[66] == false); - try expect(vec[67] == true); - try expect(vec[68] == false); - try expect(vec[69] == true); - try expect(vec[70] == true); - try expect(vec[71] == true); - try expect(vec[72] == false); - try expect(vec[73] == true); - try expect(vec[74] == true); - try expect(vec[75] == false); - try expect(vec[76] == true); - try expect(vec[77] == true); - try expect(vec[78] == true); - try expect(vec[79] == true); - try expect(vec[80] == false); - try expect(vec[81] == true); - try expect(vec[82] == false); - try expect(vec[83] == true); - try expect(vec[84] == true); - try expect(vec[85] == true); - try expect(vec[86] == false); - try expect(vec[87] == true); - try expect(vec[88] == false); - try expect(vec[89] == true); - try expect(vec[90] == false); - try expect(vec[91] == false); - try expect(vec[92] == true); - try expect(vec[93] == false); - try expect(vec[94] == false); - try expect(vec[95] == false); - try expect(vec[96] == true); - try expect(vec[97] == true); - try expect(vec[98] == false); - try expect(vec[99] == false); - try expect(vec[100] == false); - try expect(vec[101] == true); - try expect(vec[102] == true); - try expect(vec[103] == true); - try expect(vec[104] == false); - try expect(vec[105] == false); - try expect(vec[106] == false); - try expect(vec[107] == true); - try expect(vec[108] == false); - try expect(vec[109] == true); - try expect(vec[110] == true); - try expect(vec[111] == true); - try expect(vec[112] == true); - try expect(vec[113] == true); - try expect(vec[114] == true); - try expect(vec[115] == true); - try expect(vec[116] == true); - try expect(vec[117] == false); - try expect(vec[118] == true); - try expect(vec[119] == false); - try expect(vec[120] == true); - try expect(vec[121] == false); - try expect(vec[122] == false); - try expect(vec[123] == true); - try expect(vec[124] == true); - try expect(vec[125] == false); - try expect(vec[126] == true); - try expect(vec[127] == false); - try expect(vec[128] == false); - try expect(vec[129] == false); - try expect(vec[130] == false); - try expect(vec[131] == true); - try expect(vec[132] == false); - try expect(vec[133] == false); - try expect(vec[134] == true); - try expect(vec[135] == false); - try expect(vec[136] == false); - try expect(vec[137] == false); - try expect(vec[138] == false); - try expect(vec[139] == false); - try expect(vec[140] == false); - try expect(vec[141] == true); - try expect(vec[142] == false); - try expect(vec[143] == true); - try expect(vec[144] == false); - try expect(vec[145] == true); - try expect(vec[146] == true); - try expect(vec[147] == true); - try expect(vec[148] == false); - try expect(vec[149] == true); - try expect(vec[150] == true); - try expect(vec[151] == false); - try expect(vec[152] == true); - try expect(vec[153] == true); - try expect(vec[154] == false); - try expect(vec[155] == true); - try expect(vec[156] == true); - try expect(vec[157] == true); - try expect(vec[158] == true); - try expect(vec[159] == true); - try expect(vec[160] == true); - try expect(vec[161] == true); - try expect(vec[162] == false); - try expect(vec[163] == false); - try expect(vec[164] == false); - try expect(vec[165] == true); - try expect(vec[166] == false); - try expect(vec[167] == false); - try expect(vec[168] == true); - try expect(vec[169] == false); - try expect(vec[170] == true); - try expect(vec[171] == true); - try expect(vec[172] == true); - try expect(vec[173] == false); - try expect(vec[174] == false); - try expect(vec[175] == true); - try expect(vec[176] == true); - try expect(vec[177] == true); - try expect(vec[178] == true); - try expect(vec[179] == false); - try expect(vec[180] == true); - try expect(vec[181] == true); - try expect(vec[182] == false); - try expect(vec[183] == true); - try expect(vec[184] == false); - try expect(vec[185] == false); - try expect(vec[186] == false); - try expect(vec[187] == true); - try expect(vec[188] == true); - try expect(vec[189] == true); - try expect(vec[190] == true); - try expect(vec[191] == true); - try expect(vec[192] == true); - try expect(vec[193] == true); - try expect(vec[194] == true); - try expect(vec[195] == false); - try expect(vec[196] == false); - try expect(vec[197] == true); - try expect(vec[198] == false); - try expect(vec[199] == false); - try expect(vec[200] == false); - try expect(vec[201] == true); - try expect(vec[202] == true); - try expect(vec[203] == true); - try expect(vec[204] == true); - try expect(vec[205] == true); - try expect(vec[206] == true); - try expect(vec[207] == false); - try expect(vec[208] == false); - try expect(vec[209] == false); - try expect(vec[210] == true); - try expect(vec[211] == true); - try expect(vec[212] == true); - try expect(vec[213] == false); - try expect(vec[214] == true); - try expect(vec[215] == false); - try expect(vec[216] == true); - try expect(vec[217] == false); - try expect(vec[218] == true); - try expect(vec[219] == false); - try expect(vec[220] == true); - try expect(vec[221] == true); - try expect(vec[222] == true); - try expect(vec[223] == false); - try expect(vec[224] == true); - try expect(vec[225] == false); - try expect(vec[226] == true); - try expect(vec[227] == false); - try expect(vec[228] == true); - try expect(vec[229] == false); - try expect(vec[230] == true); - try expect(vec[231] == false); - try expect(vec[232] == false); - try expect(vec[233] == true); - try expect(vec[234] == false); - try expect(vec[235] == true); - try expect(vec[236] == true); - try expect(vec[237] == false); - try expect(vec[238] == false); - try expect(vec[239] == true); - try expect(vec[240] == false); - try expect(vec[241] == false); - try expect(vec[242] == false); - try expect(vec[243] == true); - try expect(vec[244] == true); - try expect(vec[245] == false); - try expect(vec[246] == false); - try expect(vec[247] == false); - try expect(vec[248] == false); - try expect(vec[249] == false); - try expect(vec[250] == true); - try expect(vec[251] == false); - try expect(vec[252] == true); - try expect(vec[253] == false); - try expect(vec[254] == false); - try expect(vec[255] == false); - } - { - if (!builtin.target.cpu.arch.isWasm()) c_vector_512_bool(.{ - true, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, - true, - false, - true, - true, - true, - true, - true, - true, - false, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - true, - true, - false, - true, - false, - false, - true, - true, - false, - true, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - true, - false, - true, - false, - false, - false, - true, - false, - true, - true, - false, - true, - true, - true, - false, - true, - true, - false, - true, - false, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - true, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - true, - false, - false, - true, - true, - false, - true, - false, - true, - true, - false, - true, - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - true, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - true, - true, - false, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - true, - true, - false, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - true, - true, - false, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - false, - true, - false, - false, - false, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - false, - true, - false, - false, - false, - false, - true, - true, - true, - true, - false, - true, - false, - false, - false, - true, - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - false, - true, - false, - true, - true, - true, - false, - false, - true, - true, - true, - false, - true, - true, - true, - false, - true, - true, - true, - false, - true, - true, - false, - false, - true, - false, - false, - false, - false, - true, - false, - true, - true, - true, - true, - false, - false, - true, - false, - true, - false, - false, - false, - true, - false, - true, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - false, - true, - false, - true, - false, - true, - true, - false, - false, - true, - true, - true, - true, - false, - false, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - true, - false, - true, - true, - true, - false, - false, - true, - false, - true, - true, - true, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - true, - false, - false, - true, - true, - false, - false, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - true, - false, - false, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - false, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true, - false, - true, - false, - false, - false, - true, - true, - false, - true, - true, - false, - false, - true, - true, - false, - false, - true, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - true, - true, - true, - false, - true, - true, - true, - false, - false, - true, - false, - false, - false, - true, - true, - false, - true, - false, - true, - }); - - const vec = c_ret_vector_512_bool(); - try expect(vec[0] == false); - try expect(vec[1] == true); - try expect(vec[2] == false); - try expect(vec[3] == false); - try expect(vec[4] == false); - try expect(vec[5] == true); - try expect(vec[6] == false); - try expect(vec[7] == false); - try expect(vec[8] == false); - try expect(vec[9] == true); - try expect(vec[10] == false); - try expect(vec[11] == false); - try expect(vec[12] == false); - try expect(vec[13] == true); - try expect(vec[14] == false); - try expect(vec[15] == true); - try expect(vec[16] == false); - try expect(vec[17] == false); - try expect(vec[18] == false); - try expect(vec[19] == false); - try expect(vec[20] == false); - try expect(vec[21] == false); - try expect(vec[22] == true); - try expect(vec[23] == true); - try expect(vec[24] == false); - try expect(vec[25] == false); - try expect(vec[26] == false); - try expect(vec[27] == false); - try expect(vec[28] == true); - try expect(vec[29] == true); - try expect(vec[30] == false); - try expect(vec[31] == true); - try expect(vec[32] == false); - try expect(vec[33] == true); - try expect(vec[34] == true); - try expect(vec[35] == true); - try expect(vec[36] == false); - try expect(vec[37] == false); - try expect(vec[38] == true); - try expect(vec[39] == true); - try expect(vec[40] == false); - try expect(vec[41] == false); - try expect(vec[42] == false); - try expect(vec[43] == false); - try expect(vec[44] == false); - try expect(vec[45] == true); - try expect(vec[46] == false); - try expect(vec[47] == true); - try expect(vec[48] == true); - try expect(vec[49] == false); - try expect(vec[50] == true); - try expect(vec[51] == true); - try expect(vec[52] == true); - try expect(vec[53] == true); - try expect(vec[54] == false); - try expect(vec[55] == false); - try expect(vec[56] == false); - try expect(vec[57] == true); - try expect(vec[58] == true); - try expect(vec[59] == false); - try expect(vec[60] == false); - try expect(vec[61] == false); - try expect(vec[62] == false); - try expect(vec[63] == true); - try expect(vec[64] == true); - try expect(vec[65] == true); - try expect(vec[66] == true); - try expect(vec[67] == true); - try expect(vec[68] == false); - try expect(vec[69] == false); - try expect(vec[70] == false); - try expect(vec[71] == false); - try expect(vec[72] == false); - try expect(vec[73] == true); - try expect(vec[74] == false); - try expect(vec[75] == true); - try expect(vec[76] == false); - try expect(vec[77] == false); - try expect(vec[78] == true); - try expect(vec[79] == true); - try expect(vec[80] == false); - try expect(vec[81] == false); - try expect(vec[82] == false); - try expect(vec[83] == true); - try expect(vec[84] == false); - try expect(vec[85] == true); - try expect(vec[86] == true); - try expect(vec[87] == true); - try expect(vec[88] == false); - try expect(vec[89] == true); - try expect(vec[90] == false); - try expect(vec[91] == false); - try expect(vec[92] == true); - try expect(vec[93] == true); - try expect(vec[94] == false); - try expect(vec[95] == true); - try expect(vec[96] == true); - try expect(vec[97] == false); - try expect(vec[98] == true); - try expect(vec[99] == false); - try expect(vec[100] == true); - try expect(vec[101] == true); - try expect(vec[102] == false); - try expect(vec[103] == true); - try expect(vec[104] == true); - try expect(vec[105] == false); - try expect(vec[106] == false); - try expect(vec[107] == false); - try expect(vec[108] == true); - try expect(vec[109] == false); - try expect(vec[110] == false); - try expect(vec[111] == false); - try expect(vec[112] == true); - try expect(vec[113] == true); - try expect(vec[114] == true); - try expect(vec[115] == false); - try expect(vec[116] == true); - try expect(vec[117] == false); - try expect(vec[118] == true); - try expect(vec[119] == false); - try expect(vec[120] == true); - try expect(vec[121] == true); - try expect(vec[122] == false); - try expect(vec[123] == true); - try expect(vec[124] == false); - try expect(vec[125] == true); - try expect(vec[126] == true); - try expect(vec[127] == true); - try expect(vec[128] == false); - try expect(vec[129] == true); - try expect(vec[130] == false); - try expect(vec[131] == false); - try expect(vec[132] == false); - try expect(vec[133] == false); - try expect(vec[134] == false); - try expect(vec[135] == false); - try expect(vec[136] == true); - try expect(vec[137] == false); - try expect(vec[138] == true); - try expect(vec[139] == false); - try expect(vec[140] == true); - try expect(vec[141] == true); - try expect(vec[142] == false); - try expect(vec[143] == true); - try expect(vec[144] == false); - try expect(vec[145] == false); - try expect(vec[146] == true); - try expect(vec[147] == false); - try expect(vec[148] == false); - try expect(vec[149] == true); - try expect(vec[150] == false); - try expect(vec[151] == true); - try expect(vec[152] == false); - try expect(vec[153] == true); - try expect(vec[154] == false); - try expect(vec[155] == false); - try expect(vec[156] == true); - try expect(vec[157] == false); - try expect(vec[158] == true); - try expect(vec[159] == true); - try expect(vec[160] == true); - try expect(vec[161] == false); - try expect(vec[162] == false); - try expect(vec[163] == true); - try expect(vec[164] == false); - try expect(vec[165] == false); - try expect(vec[166] == false); - try expect(vec[167] == true); - try expect(vec[168] == true); - try expect(vec[169] == true); - try expect(vec[170] == false); - try expect(vec[171] == true); - try expect(vec[172] == false); - try expect(vec[173] == false); - try expect(vec[174] == false); - try expect(vec[175] == false); - try expect(vec[176] == false); - try expect(vec[177] == true); - try expect(vec[178] == true); - try expect(vec[179] == false); - try expect(vec[180] == false); - try expect(vec[181] == true); - try expect(vec[182] == false); - try expect(vec[183] == false); - try expect(vec[184] == false); - try expect(vec[185] == false); - try expect(vec[186] == false); - try expect(vec[187] == true); - try expect(vec[188] == true); - try expect(vec[189] == false); - try expect(vec[190] == false); - try expect(vec[191] == false); - try expect(vec[192] == false); - try expect(vec[193] == false); - try expect(vec[194] == false); - try expect(vec[195] == true); - try expect(vec[196] == true); - try expect(vec[197] == false); - try expect(vec[198] == true); - try expect(vec[199] == true); - try expect(vec[200] == true); - try expect(vec[201] == true); - try expect(vec[202] == true); - try expect(vec[203] == true); - try expect(vec[204] == false); - try expect(vec[205] == false); - try expect(vec[206] == false); - try expect(vec[207] == false); - try expect(vec[208] == true); - try expect(vec[209] == false); - try expect(vec[210] == true); - try expect(vec[211] == true); - try expect(vec[212] == true); - try expect(vec[213] == true); - try expect(vec[214] == false); - try expect(vec[215] == false); - try expect(vec[216] == false); - try expect(vec[217] == true); - try expect(vec[218] == true); - try expect(vec[219] == false); - try expect(vec[220] == true); - try expect(vec[221] == true); - try expect(vec[222] == false); - try expect(vec[223] == false); - try expect(vec[224] == false); - try expect(vec[225] == true); - try expect(vec[226] == true); - try expect(vec[227] == true); - try expect(vec[228] == true); - try expect(vec[229] == false); - try expect(vec[230] == true); - try expect(vec[231] == false); - try expect(vec[232] == true); - try expect(vec[233] == true); - try expect(vec[234] == true); - try expect(vec[235] == true); - try expect(vec[236] == false); - try expect(vec[237] == true); - try expect(vec[238] == false); - try expect(vec[239] == true); - try expect(vec[240] == false); - try expect(vec[241] == true); - try expect(vec[242] == false); - try expect(vec[243] == false); - try expect(vec[244] == false); - try expect(vec[245] == true); - try expect(vec[246] == true); - try expect(vec[247] == false); - try expect(vec[248] == true); - try expect(vec[249] == false); - try expect(vec[250] == false); - try expect(vec[251] == false); - try expect(vec[252] == true); - try expect(vec[253] == true); - try expect(vec[254] == true); - try expect(vec[255] == true); - try expect(vec[256] == true); - try expect(vec[257] == false); - try expect(vec[258] == true); - try expect(vec[259] == true); - try expect(vec[260] == true); - try expect(vec[261] == true); - try expect(vec[262] == false); - try expect(vec[263] == true); - try expect(vec[264] == false); - try expect(vec[265] == false); - try expect(vec[266] == true); - try expect(vec[267] == false); - try expect(vec[268] == true); - try expect(vec[269] == false); - try expect(vec[270] == false); - try expect(vec[271] == true); - try expect(vec[272] == true); - try expect(vec[273] == false); - try expect(vec[274] == true); - try expect(vec[275] == false); - try expect(vec[276] == false); - try expect(vec[277] == true); - try expect(vec[278] == false); - try expect(vec[279] == false); - try expect(vec[280] == true); - try expect(vec[281] == true); - try expect(vec[282] == true); - try expect(vec[283] == false); - try expect(vec[284] == false); - try expect(vec[285] == true); - try expect(vec[286] == true); - try expect(vec[287] == true); - try expect(vec[288] == false); - try expect(vec[289] == false); - try expect(vec[290] == false); - try expect(vec[291] == false); - try expect(vec[292] == false); - try expect(vec[293] == false); - try expect(vec[294] == true); - try expect(vec[295] == false); - try expect(vec[296] == true); - try expect(vec[297] == false); - try expect(vec[298] == true); - try expect(vec[299] == true); - try expect(vec[300] == false); - try expect(vec[301] == false); - try expect(vec[302] == false); - try expect(vec[303] == false); - try expect(vec[304] == true); - try expect(vec[305] == true); - try expect(vec[306] == true); - try expect(vec[307] == true); - try expect(vec[308] == true); - try expect(vec[309] == false); - try expect(vec[310] == true); - try expect(vec[311] == true); - try expect(vec[312] == true); - try expect(vec[313] == true); - try expect(vec[314] == true); - try expect(vec[315] == false); - try expect(vec[316] == true); - try expect(vec[317] == true); - try expect(vec[318] == true); - try expect(vec[319] == false); - try expect(vec[320] == true); - try expect(vec[321] == false); - try expect(vec[322] == true); - try expect(vec[323] == true); - try expect(vec[324] == true); - try expect(vec[325] == false); - try expect(vec[326] == false); - try expect(vec[327] == true); - try expect(vec[328] == true); - try expect(vec[329] == true); - try expect(vec[330] == false); - try expect(vec[331] == false); - try expect(vec[332] == true); - try expect(vec[333] == true); - try expect(vec[334] == false); - try expect(vec[335] == true); - try expect(vec[336] == true); - try expect(vec[337] == true); - try expect(vec[338] == true); - try expect(vec[339] == true); - try expect(vec[340] == true); - try expect(vec[341] == false); - try expect(vec[342] == true); - try expect(vec[343] == false); - try expect(vec[344] == true); - try expect(vec[345] == false); - try expect(vec[346] == false); - try expect(vec[347] == false); - try expect(vec[348] == false); - try expect(vec[349] == true); - try expect(vec[350] == true); - try expect(vec[351] == true); - try expect(vec[352] == true); - try expect(vec[353] == false); - try expect(vec[354] == true); - try expect(vec[355] == false); - try expect(vec[356] == true); - try expect(vec[357] == true); - try expect(vec[358] == false); - try expect(vec[359] == true); - try expect(vec[360] == false); - try expect(vec[361] == false); - try expect(vec[362] == true); - try expect(vec[363] == false); - try expect(vec[364] == false); - try expect(vec[365] == false); - try expect(vec[366] == false); - try expect(vec[367] == false); - try expect(vec[368] == false); - try expect(vec[369] == false); - try expect(vec[370] == true); - try expect(vec[371] == false); - try expect(vec[372] == true); - try expect(vec[373] == true); - try expect(vec[374] == false); - try expect(vec[375] == false); - try expect(vec[376] == true); - try expect(vec[377] == false); - try expect(vec[378] == false); - try expect(vec[379] == true); - try expect(vec[380] == false); - try expect(vec[381] == false); - try expect(vec[382] == true); - try expect(vec[383] == false); - try expect(vec[384] == false); - try expect(vec[385] == false); - try expect(vec[386] == false); - try expect(vec[387] == true); - try expect(vec[388] == true); - try expect(vec[389] == true); - try expect(vec[390] == true); - try expect(vec[391] == true); - try expect(vec[392] == true); - try expect(vec[393] == true); - try expect(vec[394] == false); - try expect(vec[395] == true); - try expect(vec[396] == true); - try expect(vec[397] == false); - try expect(vec[398] == false); - try expect(vec[399] == false); - try expect(vec[400] == true); - try expect(vec[401] == false); - try expect(vec[402] == true); - try expect(vec[403] == true); - try expect(vec[404] == false); - try expect(vec[405] == true); - try expect(vec[406] == true); - try expect(vec[407] == true); - try expect(vec[408] == true); - try expect(vec[409] == false); - try expect(vec[410] == false); - try expect(vec[411] == false); - try expect(vec[412] == true); - try expect(vec[413] == true); - try expect(vec[414] == false); - try expect(vec[415] == true); - try expect(vec[416] == false); - try expect(vec[417] == true); - try expect(vec[418] == false); - try expect(vec[419] == false); - try expect(vec[420] == false); - try expect(vec[421] == false); - try expect(vec[422] == true); - try expect(vec[423] == true); - try expect(vec[424] == true); - try expect(vec[425] == false); - try expect(vec[426] == true); - try expect(vec[427] == false); - try expect(vec[428] == false); - try expect(vec[429] == false); - try expect(vec[430] == true); - try expect(vec[431] == true); - try expect(vec[432] == false); - try expect(vec[433] == true); - try expect(vec[434] == false); - try expect(vec[435] == false); - try expect(vec[436] == true); - try expect(vec[437] == true); - try expect(vec[438] == true); - try expect(vec[439] == true); - try expect(vec[440] == true); - try expect(vec[441] == true); - try expect(vec[442] == false); - try expect(vec[443] == false); - try expect(vec[444] == false); - try expect(vec[445] == true); - try expect(vec[446] == true); - try expect(vec[447] == true); - try expect(vec[448] == false); - try expect(vec[449] == false); - try expect(vec[450] == false); - try expect(vec[451] == false); - try expect(vec[452] == false); - try expect(vec[453] == false); - try expect(vec[454] == false); - try expect(vec[455] == false); - try expect(vec[456] == false); - try expect(vec[457] == false); - try expect(vec[458] == false); - try expect(vec[459] == true); - try expect(vec[460] == false); - try expect(vec[461] == false); - try expect(vec[462] == false); - try expect(vec[463] == true); - try expect(vec[464] == false); - try expect(vec[465] == false); - try expect(vec[466] == false); - try expect(vec[467] == false); - try expect(vec[468] == true); - try expect(vec[469] == true); - try expect(vec[470] == true); - try expect(vec[471] == true); - try expect(vec[472] == true); - try expect(vec[473] == false); - try expect(vec[474] == false); - try expect(vec[475] == true); - try expect(vec[476] == true); - try expect(vec[477] == true); - try expect(vec[478] == false); - try expect(vec[479] == true); - try expect(vec[480] == true); - try expect(vec[481] == true); - try expect(vec[482] == false); - try expect(vec[483] == true); - try expect(vec[484] == false); - try expect(vec[485] == true); - try expect(vec[486] == false); - try expect(vec[487] == true); - try expect(vec[488] == false); - try expect(vec[489] == true); - try expect(vec[490] == true); - try expect(vec[491] == true); - try expect(vec[492] == true); - try expect(vec[493] == false); - try expect(vec[494] == true); - try expect(vec[495] == true); - try expect(vec[496] == false); - try expect(vec[497] == true); - try expect(vec[498] == false); - try expect(vec[499] == false); - try expect(vec[500] == false); - try expect(vec[501] == false); - try expect(vec[502] == false); - try expect(vec[503] == false); - try expect(vec[504] == false); - try expect(vec[505] == false); - try expect(vec[506] == false); - try expect(vec[507] == true); - try expect(vec[508] == true); - try expect(vec[509] == false); - try expect(vec[510] == true); - try expect(vec[511] == false); - } -} - 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; _ = struct { - export fn zig_vector_2_bool(vec: Vector2Bool) void { + export fn zig_ret_vector_2_bool() @Vector(2, bool) { + return .{ + false, + false, + }; + } + export fn zig_vector_2_bool(vec: @Vector(2, bool)) void { expect(vec[0] == false) catch @panic("test failure"); expect(vec[1] == true) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_4_bool(vec: Vector4Bool) void { +extern fn c_ret_vector_2_bool() @Vector(2, bool); +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; + + const vec = c_ret_vector_2_bool(); + try expect(vec[0] == true); + try expect(vec[1] == false); + c_vector_2_bool(.{ + true, + true, + }); + c_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; + + _ = struct { + export fn zig_ret_vector_4_bool() @Vector(4, bool) { + return .{ + false, + true, + true, + true, + }; + } + export fn zig_vector_4_bool(vec: @Vector(4, bool)) void { expect(vec[0] == false) catch @panic("test failure"); expect(vec[1] == false) catch @panic("test failure"); expect(vec[2] == false) catch @panic("test failure"); expect(vec[3] == false) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_8_bool(vec: Vector8Bool) void { +extern fn c_ret_vector_4_bool() @Vector(4, bool); +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; + + const vec = c_ret_vector_4_bool(); + try expect(vec[0] == true); + try expect(vec[1] == false); + try expect(vec[2] == true); + try expect(vec[3] == false); + c_vector_4_bool(.{ + true, + true, + false, + true, + }); + c_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; + + _ = struct { + export fn zig_ret_vector_8_bool() @Vector(8, bool) { + return .{ + false, + false, + false, + false, + true, + false, + false, + false, + }; + } + export fn zig_vector_8_bool(vec: @Vector(8, bool)) void { expect(vec[0] == true) catch @panic("test failure"); expect(vec[1] == true) catch @panic("test failure"); expect(vec[2] == false) catch @panic("test failure"); @@ -3580,8 +379,66 @@ comptime { expect(vec[6] == true) catch @panic("test failure"); expect(vec[7] == false) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_16_bool(vec: Vector16Bool) void { +extern fn c_ret_vector_8_bool() @Vector(8, bool); +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; + + const vec = c_ret_vector_8_bool(); + try expect(vec[0] == false); + try expect(vec[1] == true); + try expect(vec[2] == false); + try expect(vec[3] == false); + try expect(vec[4] == true); + try expect(vec[5] == false); + try expect(vec[6] == false); + try expect(vec[7] == true); + c_vector_8_bool(.{ + true, + false, + true, + true, + true, + true, + false, + true, + }); + c_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; + + _ = struct { + export fn zig_ret_vector_16_bool() @Vector(16, bool) { + return .{ + false, + true, + false, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + true, + false, + false, + }; + } + export fn zig_vector_16_bool(vec: @Vector(16, bool)) void { expect(vec[0] == true) catch @panic("test failure"); expect(vec[1] == false) catch @panic("test failure"); expect(vec[2] == true) catch @panic("test failure"); @@ -3599,8 +456,98 @@ comptime { expect(vec[14] == false) catch @panic("test failure"); expect(vec[15] == true) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_32_bool(vec: Vector32Bool) void { +extern fn c_ret_vector_16_bool() @Vector(16, bool); +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; + + const vec = c_ret_vector_16_bool(); + try expect(vec[0] == true); + try expect(vec[1] == true); + try expect(vec[2] == false); + try expect(vec[3] == false); + try expect(vec[4] == false); + try expect(vec[5] == false); + try expect(vec[6] == true); + try expect(vec[7] == false); + try expect(vec[8] == true); + try expect(vec[9] == false); + try expect(vec[10] == false); + try expect(vec[11] == true); + try expect(vec[12] == true); + try expect(vec[13] == false); + try expect(vec[14] == true); + try expect(vec[15] == true); + c_vector_16_bool(.{ + true, + false, + false, + false, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + }); + c_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; + + _ = struct { + export fn zig_ret_vector_32_bool() @Vector(32, bool) { + return .{ + false, + true, + false, + false, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + }; + } + export fn zig_vector_32_bool(vec: @Vector(32, bool)) void { expect(vec[0] == false) catch @panic("test failure"); expect(vec[1] == false) catch @panic("test failure"); expect(vec[2] == false) catch @panic("test failure"); @@ -3634,8 +581,162 @@ comptime { expect(vec[30] == false) catch @panic("test failure"); expect(vec[31] == true) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_64_bool(vec: Vector64Bool) void { +extern fn c_ret_vector_32_bool() @Vector(32, bool); +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; + + const vec = c_ret_vector_32_bool(); + try expect(vec[0] == true); + try expect(vec[1] == false); + try expect(vec[2] == true); + try expect(vec[3] == true); + try expect(vec[4] == true); + try expect(vec[5] == false); + try expect(vec[6] == true); + try expect(vec[7] == false); + try expect(vec[8] == true); + try expect(vec[9] == true); + try expect(vec[10] == true); + try expect(vec[11] == false); + try expect(vec[12] == true); + try expect(vec[13] == true); + try expect(vec[14] == false); + try expect(vec[15] == false); + try expect(vec[16] == true); + try expect(vec[17] == false); + try expect(vec[18] == false); + try expect(vec[19] == false); + try expect(vec[20] == false); + try expect(vec[21] == true); + try expect(vec[22] == true); + try expect(vec[23] == true); + try expect(vec[24] == false); + try expect(vec[25] == true); + try expect(vec[26] == false); + try expect(vec[27] == false); + try expect(vec[28] == true); + try expect(vec[29] == false); + try expect(vec[30] == false); + try expect(vec[31] == false); + c_vector_32_bool(.{ + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + true, + true, + false, + }); + c_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; + + _ = struct { + export fn zig_ret_vector_64_bool() @Vector(64, bool) { + return .{ + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + false, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + true, + true, + true, + false, + false, + false, + true, + false, + false, + true, + false, + true, + false, + }; + } + export fn zig_vector_64_bool(vec: @Vector(64, bool)) void { expect(vec[0] == true) catch @panic("test failure"); expect(vec[1] == true) catch @panic("test failure"); expect(vec[2] == false) catch @panic("test failure"); @@ -3701,8 +802,290 @@ comptime { expect(vec[62] == true) catch @panic("test failure"); expect(vec[63] == true) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_128_bool(vec: Vector128Bool) void { +extern fn c_ret_vector_64_bool() @Vector(64, bool); +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; + + const vec = c_ret_vector_64_bool(); + try expect(vec[0] == false); + try expect(vec[1] == true); + try expect(vec[2] == false); + try expect(vec[3] == true); + try expect(vec[4] == true); + try expect(vec[5] == true); + try expect(vec[6] == false); + try expect(vec[7] == true); + try expect(vec[8] == true); + try expect(vec[9] == true); + try expect(vec[10] == true); + try expect(vec[11] == true); + try expect(vec[12] == true); + try expect(vec[13] == false); + try expect(vec[14] == true); + try expect(vec[15] == true); + try expect(vec[16] == true); + try expect(vec[17] == false); + try expect(vec[18] == false); + try expect(vec[19] == false); + try expect(vec[20] == true); + try expect(vec[21] == true); + try expect(vec[22] == false); + try expect(vec[23] == true); + try expect(vec[24] == false); + try expect(vec[25] == true); + try expect(vec[26] == false); + try expect(vec[27] == true); + try expect(vec[28] == false); + try expect(vec[29] == true); + try expect(vec[30] == false); + try expect(vec[31] == true); + try expect(vec[32] == false); + try expect(vec[33] == false); + try expect(vec[34] == true); + try expect(vec[35] == true); + try expect(vec[36] == false); + try expect(vec[37] == false); + try expect(vec[38] == false); + try expect(vec[39] == true); + try expect(vec[40] == true); + try expect(vec[41] == true); + try expect(vec[42] == true); + try expect(vec[43] == false); + try expect(vec[44] == false); + try expect(vec[45] == false); + try expect(vec[46] == true); + try expect(vec[47] == true); + try expect(vec[48] == false); + try expect(vec[49] == false); + try expect(vec[50] == true); + try expect(vec[51] == false); + try expect(vec[52] == false); + try expect(vec[53] == false); + try expect(vec[54] == false); + try expect(vec[55] == true); + try expect(vec[56] == false); + try expect(vec[57] == false); + try expect(vec[58] == false); + try expect(vec[59] == true); + try expect(vec[60] == true); + try expect(vec[61] == true); + try expect(vec[62] == true); + try expect(vec[63] == true); + c_vector_64_bool(.{ + true, + true, + true, + false, + true, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + true, + false, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + false, + }); + c_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; + + _ = struct { + export fn zig_ret_vector_128_bool() @Vector(128, bool) { + return .{ + true, + true, + false, + false, + false, + true, + true, + false, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + false, + true, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + false, + false, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + false, + false, + true, + }; + } + export fn zig_vector_128_bool(vec: @Vector(128, bool)) void { expect(vec[0] == true) catch @panic("test failure"); expect(vec[1] == true) catch @panic("test failure"); expect(vec[2] == false) catch @panic("test failure"); @@ -3832,8 +1215,546 @@ comptime { expect(vec[126] == true) catch @panic("test failure"); expect(vec[127] == false) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_256_bool(vec: Vector256Bool) void { +extern fn c_ret_vector_128_bool() @Vector(128, bool); +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; + + const vec = c_ret_vector_128_bool(); + try expect(vec[0] == false); + try expect(vec[1] == true); + try expect(vec[2] == true); + try expect(vec[3] == false); + try expect(vec[4] == true); + try expect(vec[5] == false); + try expect(vec[6] == false); + try expect(vec[7] == true); + try expect(vec[8] == true); + try expect(vec[9] == false); + try expect(vec[10] == true); + try expect(vec[11] == false); + try expect(vec[12] == false); + try expect(vec[13] == false); + try expect(vec[14] == true); + try expect(vec[15] == false); + try expect(vec[16] == true); + try expect(vec[17] == false); + try expect(vec[18] == false); + try expect(vec[19] == true); + try expect(vec[20] == false); + try expect(vec[21] == true); + try expect(vec[22] == false); + try expect(vec[23] == false); + try expect(vec[24] == false); + try expect(vec[25] == true); + try expect(vec[26] == true); + try expect(vec[27] == true); + try expect(vec[28] == false); + try expect(vec[29] == false); + try expect(vec[30] == false); + try expect(vec[31] == false); + try expect(vec[32] == true); + try expect(vec[33] == true); + try expect(vec[34] == true); + try expect(vec[35] == false); + try expect(vec[36] == true); + try expect(vec[37] == true); + try expect(vec[38] == false); + try expect(vec[39] == false); + try expect(vec[40] == false); + try expect(vec[41] == false); + try expect(vec[42] == true); + try expect(vec[43] == true); + try expect(vec[44] == true); + try expect(vec[45] == false); + try expect(vec[46] == false); + try expect(vec[47] == false); + try expect(vec[48] == false); + try expect(vec[49] == true); + try expect(vec[50] == false); + try expect(vec[51] == false); + try expect(vec[52] == true); + try expect(vec[53] == false); + try expect(vec[54] == false); + try expect(vec[55] == false); + try expect(vec[56] == false); + try expect(vec[57] == false); + try expect(vec[58] == true); + try expect(vec[59] == true); + try expect(vec[60] == true); + try expect(vec[61] == false); + try expect(vec[62] == true); + try expect(vec[63] == true); + try expect(vec[64] == false); + try expect(vec[65] == false); + try expect(vec[66] == false); + try expect(vec[67] == false); + try expect(vec[68] == false); + try expect(vec[69] == false); + try expect(vec[70] == false); + try expect(vec[71] == false); + try expect(vec[72] == true); + try expect(vec[73] == true); + try expect(vec[74] == true); + try expect(vec[75] == true); + try expect(vec[76] == true); + try expect(vec[77] == false); + try expect(vec[78] == false); + try expect(vec[79] == false); + try expect(vec[80] == false); + try expect(vec[81] == false); + try expect(vec[82] == false); + try expect(vec[83] == true); + try expect(vec[84] == false); + try expect(vec[85] == true); + try expect(vec[86] == false); + try expect(vec[87] == true); + try expect(vec[88] == false); + try expect(vec[89] == true); + try expect(vec[90] == false); + try expect(vec[91] == true); + try expect(vec[92] == true); + try expect(vec[93] == true); + try expect(vec[94] == true); + try expect(vec[95] == false); + try expect(vec[96] == false); + try expect(vec[97] == true); + try expect(vec[98] == false); + try expect(vec[99] == false); + try expect(vec[100] == true); + try expect(vec[101] == true); + try expect(vec[102] == true); + try expect(vec[103] == true); + try expect(vec[104] == false); + try expect(vec[105] == true); + try expect(vec[106] == true); + try expect(vec[107] == true); + try expect(vec[108] == false); + try expect(vec[109] == false); + try expect(vec[110] == true); + try expect(vec[111] == false); + try expect(vec[112] == false); + try expect(vec[113] == true); + try expect(vec[114] == true); + try expect(vec[115] == false); + try expect(vec[116] == true); + try expect(vec[117] == false); + try expect(vec[118] == true); + try expect(vec[119] == true); + try expect(vec[120] == true); + try expect(vec[121] == true); + try expect(vec[122] == true); + try expect(vec[123] == false); + try expect(vec[124] == false); + try expect(vec[125] == true); + try expect(vec[126] == false); + try expect(vec[127] == true); + c_vector_128_bool(.{ + false, + false, + false, + false, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + true, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false, + true, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + }); + c_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; + + _ = struct { + export fn zig_ret_vector_256_bool() @Vector(256, bool) { + return .{ + true, + true, + true, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + true, + false, + true, + true, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + false, + true, + true, + false, + false, + true, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + true, + true, + true, + false, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + false, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + }; + } + export fn zig_vector_256_bool(vec: @Vector(256, bool)) void { expect(vec[0] == false) catch @panic("test failure"); expect(vec[1] == false) catch @panic("test failure"); expect(vec[2] == false) catch @panic("test failure"); @@ -4091,8 +2012,1058 @@ comptime { expect(vec[254] == true) catch @panic("test failure"); expect(vec[255] == true) catch @panic("test failure"); } + }; + } +} - export fn zig_vector_512_bool(vec: Vector512Bool) void { +extern fn c_ret_vector_256_bool() @Vector(256, bool); +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; + + const vec = c_ret_vector_256_bool(); + try expect(vec[0] == true); + try expect(vec[1] == false); + try expect(vec[2] == true); + try expect(vec[3] == true); + try expect(vec[4] == false); + try expect(vec[5] == false); + try expect(vec[6] == false); + try expect(vec[7] == false); + try expect(vec[8] == false); + try expect(vec[9] == true); + try expect(vec[10] == false); + try expect(vec[11] == true); + try expect(vec[12] == false); + try expect(vec[13] == true); + try expect(vec[14] == false); + try expect(vec[15] == false); + try expect(vec[16] == true); + try expect(vec[17] == true); + try expect(vec[18] == true); + try expect(vec[19] == false); + try expect(vec[20] == false); + try expect(vec[21] == false); + try expect(vec[22] == true); + try expect(vec[23] == false); + try expect(vec[24] == true); + try expect(vec[25] == false); + try expect(vec[26] == false); + try expect(vec[27] == true); + try expect(vec[28] == true); + try expect(vec[29] == true); + try expect(vec[30] == false); + try expect(vec[31] == false); + try expect(vec[32] == true); + try expect(vec[33] == true); + try expect(vec[34] == true); + try expect(vec[35] == false); + try expect(vec[36] == true); + try expect(vec[37] == true); + try expect(vec[38] == true); + try expect(vec[39] == false); + try expect(vec[40] == true); + try expect(vec[41] == false); + try expect(vec[42] == true); + try expect(vec[43] == true); + try expect(vec[44] == false); + try expect(vec[45] == true); + try expect(vec[46] == false); + try expect(vec[47] == true); + try expect(vec[48] == true); + try expect(vec[49] == false); + try expect(vec[50] == false); + try expect(vec[51] == true); + try expect(vec[52] == true); + try expect(vec[53] == false); + try expect(vec[54] == false); + try expect(vec[55] == true); + try expect(vec[56] == false); + try expect(vec[57] == true); + try expect(vec[58] == true); + try expect(vec[59] == true); + try expect(vec[60] == false); + try expect(vec[61] == true); + try expect(vec[62] == true); + try expect(vec[63] == false); + try expect(vec[64] == true); + try expect(vec[65] == true); + try expect(vec[66] == false); + try expect(vec[67] == true); + try expect(vec[68] == false); + try expect(vec[69] == true); + try expect(vec[70] == true); + try expect(vec[71] == true); + try expect(vec[72] == false); + try expect(vec[73] == true); + try expect(vec[74] == true); + try expect(vec[75] == false); + try expect(vec[76] == true); + try expect(vec[77] == true); + try expect(vec[78] == true); + try expect(vec[79] == true); + try expect(vec[80] == false); + try expect(vec[81] == true); + try expect(vec[82] == false); + try expect(vec[83] == true); + try expect(vec[84] == true); + try expect(vec[85] == true); + try expect(vec[86] == false); + try expect(vec[87] == true); + try expect(vec[88] == false); + try expect(vec[89] == true); + try expect(vec[90] == false); + try expect(vec[91] == false); + try expect(vec[92] == true); + try expect(vec[93] == false); + try expect(vec[94] == false); + try expect(vec[95] == false); + try expect(vec[96] == true); + try expect(vec[97] == true); + try expect(vec[98] == false); + try expect(vec[99] == false); + try expect(vec[100] == false); + try expect(vec[101] == true); + try expect(vec[102] == true); + try expect(vec[103] == true); + try expect(vec[104] == false); + try expect(vec[105] == false); + try expect(vec[106] == false); + try expect(vec[107] == true); + try expect(vec[108] == false); + try expect(vec[109] == true); + try expect(vec[110] == true); + try expect(vec[111] == true); + try expect(vec[112] == true); + try expect(vec[113] == true); + try expect(vec[114] == true); + try expect(vec[115] == true); + try expect(vec[116] == true); + try expect(vec[117] == false); + try expect(vec[118] == true); + try expect(vec[119] == false); + try expect(vec[120] == true); + try expect(vec[121] == false); + try expect(vec[122] == false); + try expect(vec[123] == true); + try expect(vec[124] == true); + try expect(vec[125] == false); + try expect(vec[126] == true); + try expect(vec[127] == false); + try expect(vec[128] == false); + try expect(vec[129] == false); + try expect(vec[130] == false); + try expect(vec[131] == true); + try expect(vec[132] == false); + try expect(vec[133] == false); + try expect(vec[134] == true); + try expect(vec[135] == false); + try expect(vec[136] == false); + try expect(vec[137] == false); + try expect(vec[138] == false); + try expect(vec[139] == false); + try expect(vec[140] == false); + try expect(vec[141] == true); + try expect(vec[142] == false); + try expect(vec[143] == true); + try expect(vec[144] == false); + try expect(vec[145] == true); + try expect(vec[146] == true); + try expect(vec[147] == true); + try expect(vec[148] == false); + try expect(vec[149] == true); + try expect(vec[150] == true); + try expect(vec[151] == false); + try expect(vec[152] == true); + try expect(vec[153] == true); + try expect(vec[154] == false); + try expect(vec[155] == true); + try expect(vec[156] == true); + try expect(vec[157] == true); + try expect(vec[158] == true); + try expect(vec[159] == true); + try expect(vec[160] == true); + try expect(vec[161] == true); + try expect(vec[162] == false); + try expect(vec[163] == false); + try expect(vec[164] == false); + try expect(vec[165] == true); + try expect(vec[166] == false); + try expect(vec[167] == false); + try expect(vec[168] == true); + try expect(vec[169] == false); + try expect(vec[170] == true); + try expect(vec[171] == true); + try expect(vec[172] == true); + try expect(vec[173] == false); + try expect(vec[174] == false); + try expect(vec[175] == true); + try expect(vec[176] == true); + try expect(vec[177] == true); + try expect(vec[178] == true); + try expect(vec[179] == false); + try expect(vec[180] == true); + try expect(vec[181] == true); + try expect(vec[182] == false); + try expect(vec[183] == true); + try expect(vec[184] == false); + try expect(vec[185] == false); + try expect(vec[186] == false); + try expect(vec[187] == true); + try expect(vec[188] == true); + try expect(vec[189] == true); + try expect(vec[190] == true); + try expect(vec[191] == true); + try expect(vec[192] == true); + try expect(vec[193] == true); + try expect(vec[194] == true); + try expect(vec[195] == false); + try expect(vec[196] == false); + try expect(vec[197] == true); + try expect(vec[198] == false); + try expect(vec[199] == false); + try expect(vec[200] == false); + try expect(vec[201] == true); + try expect(vec[202] == true); + try expect(vec[203] == true); + try expect(vec[204] == true); + try expect(vec[205] == true); + try expect(vec[206] == true); + try expect(vec[207] == false); + try expect(vec[208] == false); + try expect(vec[209] == false); + try expect(vec[210] == true); + try expect(vec[211] == true); + try expect(vec[212] == true); + try expect(vec[213] == false); + try expect(vec[214] == true); + try expect(vec[215] == false); + try expect(vec[216] == true); + try expect(vec[217] == false); + try expect(vec[218] == true); + try expect(vec[219] == false); + try expect(vec[220] == true); + try expect(vec[221] == true); + try expect(vec[222] == true); + try expect(vec[223] == false); + try expect(vec[224] == true); + try expect(vec[225] == false); + try expect(vec[226] == true); + try expect(vec[227] == false); + try expect(vec[228] == true); + try expect(vec[229] == false); + try expect(vec[230] == true); + try expect(vec[231] == false); + try expect(vec[232] == false); + try expect(vec[233] == true); + try expect(vec[234] == false); + try expect(vec[235] == true); + try expect(vec[236] == true); + try expect(vec[237] == false); + try expect(vec[238] == false); + try expect(vec[239] == true); + try expect(vec[240] == false); + try expect(vec[241] == false); + try expect(vec[242] == false); + try expect(vec[243] == true); + try expect(vec[244] == true); + try expect(vec[245] == false); + try expect(vec[246] == false); + try expect(vec[247] == false); + try expect(vec[248] == false); + try expect(vec[249] == false); + try expect(vec[250] == true); + try expect(vec[251] == false); + try expect(vec[252] == true); + try expect(vec[253] == false); + try expect(vec[254] == false); + try expect(vec[255] == false); + if (!builtin.target.cpu.arch.isWasm()) c_vector_256_bool(.{ + false, + true, + true, + false, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + true, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + true, + false, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + true, + false, + }); + c_test_vector_512_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; + + _ = struct { + export fn zig_ret_vector_512_bool() @Vector(512, bool) { + return .{ + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + false, + true, + true, + false, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + true, + false, + true, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + false, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + true, + true, + false, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + false, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + false, + true, + true, + true, + true, + false, + false, + true, + true, + false, + false, + }; + } + export fn zig_vector_512_bool(vec: @Vector(512, bool)) void { expect(vec[0] == false) catch @panic("test failure"); expect(vec[1] == true) catch @panic("test failure"); expect(vec[2] == true) catch @panic("test failure"); @@ -4606,1095 +3577,13100 @@ comptime { expect(vec[510] == false) catch @panic("test failure"); expect(vec[511] == true) catch @panic("test failure"); } - - export fn zig_ret_vector_2_bool() Vector2Bool { - return .{ - false, - false, - }; - } - - export fn zig_ret_vector_4_bool() Vector4Bool { - return .{ - false, - true, - true, - true, - }; - } - - export fn zig_ret_vector_8_bool() Vector8Bool { - return .{ - false, - false, - false, - false, - true, - false, - false, - false, - }; - } - - export fn zig_ret_vector_16_bool() Vector16Bool { - return .{ - false, - true, - false, - false, - false, - true, - false, - false, - true, - false, - false, - false, - false, - true, - false, - false, - }; - } - - export fn zig_ret_vector_32_bool() Vector32Bool { - return .{ - false, - true, - false, - false, - true, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - }; - } - - export fn zig_ret_vector_64_bool() Vector64Bool { - return .{ - true, - false, - true, - false, - false, - true, - false, - true, - true, - false, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - false, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - false, - true, - true, - true, - false, - false, - false, - true, - false, - false, - true, - false, - true, - false, - }; - } - - export fn zig_ret_vector_128_bool() Vector128Bool { - return .{ - true, - true, - false, - false, - false, - true, - true, - false, - false, - true, - false, - false, - false, - true, - false, - true, - true, - false, - false, - true, - true, - true, - true, - true, - false, - false, - true, - true, - true, - false, - false, - true, - true, - false, - true, - true, - true, - false, - true, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - false, - false, - false, - true, - false, - true, - false, - true, - false, - false, - true, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - false, - true, - false, - true, - false, - false, - true, - true, - false, - true, - false, - false, - true, - true, - true, - true, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - true, - false, - false, - true, - false, - false, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - true, - false, - false, - true, - }; - } - - export fn zig_ret_vector_256_bool() Vector256Bool { - return .{ - true, - true, - true, - false, - true, - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - false, - true, - true, - false, - false, - true, - true, - false, - true, - true, - true, - false, - true, - false, - true, - false, - true, - false, - true, - false, - false, - false, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - true, - false, - true, - true, - false, - false, - false, - true, - true, - true, - false, - true, - false, - true, - false, - true, - true, - false, - true, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - true, - false, - true, - true, - false, - false, - true, - true, - false, - false, - true, - false, - false, - false, - false, - false, - false, - false, - true, - true, - false, - true, - false, - true, - true, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - false, - true, - true, - false, - false, - true, - true, - true, - true, - true, - false, - true, - true, - false, - false, - true, - true, - false, - true, - false, - true, - false, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - true, - true, - false, - true, - true, - true, - true, - true, - false, - false, - true, - false, - true, - true, - true, - true, - false, - true, - true, - true, - true, - true, - true, - true, - false, - true, - false, - false, - false, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - false, - true, - true, - true, - true, - true, - true, - true, - false, - true, - false, - false, - true, - true, - false, - false, - false, - true, - true, - true, - false, - false, - true, - true, - true, - true, - false, - true, - false, - true, - true, - true, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true, - false, - true, - true, - true, - false, - true, - true, - false, - true, - false, - false, - true, - true, - false, - true, - false, - true, - }; - } - - export fn zig_ret_vector_512_bool() Vector512Bool { - return .{ - true, - true, - true, - true, - false, - true, - false, - true, - true, - true, - false, - true, - false, - false, - false, - true, - true, - false, - false, - false, - true, - true, - false, - false, - false, - false, - true, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - true, - false, - false, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - true, - true, - false, - false, - true, - true, - false, - true, - false, - false, - false, - true, - true, - true, - true, - true, - false, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - false, - true, - false, - false, - true, - false, - true, - false, - false, - false, - true, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - false, - true, - false, - false, - true, - false, - true, - false, - true, - false, - false, - true, - true, - true, - false, - true, - false, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - false, - true, - false, - false, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - false, - false, - true, - false, - true, - true, - true, - true, - false, - true, - false, - false, - true, - true, - true, - false, - false, - false, - true, - false, - false, - true, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - false, - true, - false, - true, - true, - false, - false, - false, - true, - true, - true, - false, - false, - true, - true, - true, - false, - false, - true, - false, - true, - true, - false, - true, - false, - false, - true, - false, - false, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - false, - false, - true, - false, - true, - false, - true, - false, - true, - true, - true, - true, - true, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - false, - true, - true, - true, - true, - true, - true, - false, - false, - true, - true, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - true, - false, - true, - true, - false, - true, - true, - true, - false, - true, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - false, - false, - false, - false, - false, - true, - false, - false, - true, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - true, - false, - false, - true, - true, - false, - true, - true, - true, - false, - false, - false, - true, - true, - false, - true, - false, - true, - false, - false, - true, - false, - true, - false, - false, - false, - false, - false, - true, - true, - false, - false, - false, - false, - true, - false, - true, - false, - true, - true, - false, - true, - true, - true, - true, - true, - false, - true, - false, - true, - true, - true, - true, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - true, - false, - false, - true, - true, - true, - true, - false, - false, - true, - false, - false, - false, - true, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - false, - true, - false, - false, - true, - false, - true, - false, - false, - true, - false, - true, - true, - false, - true, - false, - true, - false, - true, - false, - false, - true, - true, - false, - true, - true, - false, - true, - true, - false, - false, - false, - false, - false, - true, - false, - false, - true, - false, - true, - false, - false, - false, - true, - false, - true, - false, - false, - false, - false, - true, - true, - false, - true, - true, - false, - false, - true, - true, - true, - false, - false, - true, - false, - false, - false, - true, - true, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - false, - false, - true, - false, - true, - true, - true, - true, - false, - false, - true, - true, - false, - false, - }; - } }; } } -const Vector2 = extern struct { x: f32, y: f32 }; +extern fn c_ret_vector_512_bool() @Vector(512, bool); +extern fn c_vector_512_bool(@Vector(512, bool)) void; +extern fn c_test_vector_512_bool() void; -extern fn c_ptr_size_float_struct(Vector2) void; -extern fn c_ret_ptr_size_float_struct() Vector2; +test "@Vector(512, bool)" { + if (builtin.zig_backend == .stage2_llvm and (builtin.cpu.arch != .powerpc and builtin.cpu.arch != .wasm32)) return error.SkipZigTest; -test "C ABI pointer sized float struct" { + const vec = c_ret_vector_512_bool(); + try expect(vec[0] == false); + try expect(vec[1] == true); + try expect(vec[2] == false); + try expect(vec[3] == false); + try expect(vec[4] == false); + try expect(vec[5] == true); + try expect(vec[6] == false); + try expect(vec[7] == false); + try expect(vec[8] == false); + try expect(vec[9] == true); + try expect(vec[10] == false); + try expect(vec[11] == false); + try expect(vec[12] == false); + try expect(vec[13] == true); + try expect(vec[14] == false); + try expect(vec[15] == true); + try expect(vec[16] == false); + try expect(vec[17] == false); + try expect(vec[18] == false); + try expect(vec[19] == false); + try expect(vec[20] == false); + try expect(vec[21] == false); + try expect(vec[22] == true); + try expect(vec[23] == true); + try expect(vec[24] == false); + try expect(vec[25] == false); + try expect(vec[26] == false); + try expect(vec[27] == false); + try expect(vec[28] == true); + try expect(vec[29] == true); + try expect(vec[30] == false); + try expect(vec[31] == true); + try expect(vec[32] == false); + try expect(vec[33] == true); + try expect(vec[34] == true); + try expect(vec[35] == true); + try expect(vec[36] == false); + try expect(vec[37] == false); + try expect(vec[38] == true); + try expect(vec[39] == true); + try expect(vec[40] == false); + try expect(vec[41] == false); + try expect(vec[42] == false); + try expect(vec[43] == false); + try expect(vec[44] == false); + try expect(vec[45] == true); + try expect(vec[46] == false); + try expect(vec[47] == true); + try expect(vec[48] == true); + try expect(vec[49] == false); + try expect(vec[50] == true); + try expect(vec[51] == true); + try expect(vec[52] == true); + try expect(vec[53] == true); + try expect(vec[54] == false); + try expect(vec[55] == false); + try expect(vec[56] == false); + try expect(vec[57] == true); + try expect(vec[58] == true); + try expect(vec[59] == false); + try expect(vec[60] == false); + try expect(vec[61] == false); + try expect(vec[62] == false); + try expect(vec[63] == true); + try expect(vec[64] == true); + try expect(vec[65] == true); + try expect(vec[66] == true); + try expect(vec[67] == true); + try expect(vec[68] == false); + try expect(vec[69] == false); + try expect(vec[70] == false); + try expect(vec[71] == false); + try expect(vec[72] == false); + try expect(vec[73] == true); + try expect(vec[74] == false); + try expect(vec[75] == true); + try expect(vec[76] == false); + try expect(vec[77] == false); + try expect(vec[78] == true); + try expect(vec[79] == true); + try expect(vec[80] == false); + try expect(vec[81] == false); + try expect(vec[82] == false); + try expect(vec[83] == true); + try expect(vec[84] == false); + try expect(vec[85] == true); + try expect(vec[86] == true); + try expect(vec[87] == true); + try expect(vec[88] == false); + try expect(vec[89] == true); + try expect(vec[90] == false); + try expect(vec[91] == false); + try expect(vec[92] == true); + try expect(vec[93] == true); + try expect(vec[94] == false); + try expect(vec[95] == true); + try expect(vec[96] == true); + try expect(vec[97] == false); + try expect(vec[98] == true); + try expect(vec[99] == false); + try expect(vec[100] == true); + try expect(vec[101] == true); + try expect(vec[102] == false); + try expect(vec[103] == true); + try expect(vec[104] == true); + try expect(vec[105] == false); + try expect(vec[106] == false); + try expect(vec[107] == false); + try expect(vec[108] == true); + try expect(vec[109] == false); + try expect(vec[110] == false); + try expect(vec[111] == false); + try expect(vec[112] == true); + try expect(vec[113] == true); + try expect(vec[114] == true); + try expect(vec[115] == false); + try expect(vec[116] == true); + try expect(vec[117] == false); + try expect(vec[118] == true); + try expect(vec[119] == false); + try expect(vec[120] == true); + try expect(vec[121] == true); + try expect(vec[122] == false); + try expect(vec[123] == true); + try expect(vec[124] == false); + try expect(vec[125] == true); + try expect(vec[126] == true); + try expect(vec[127] == true); + try expect(vec[128] == false); + try expect(vec[129] == true); + try expect(vec[130] == false); + try expect(vec[131] == false); + try expect(vec[132] == false); + try expect(vec[133] == false); + try expect(vec[134] == false); + try expect(vec[135] == false); + try expect(vec[136] == true); + try expect(vec[137] == false); + try expect(vec[138] == true); + try expect(vec[139] == false); + try expect(vec[140] == true); + try expect(vec[141] == true); + try expect(vec[142] == false); + try expect(vec[143] == true); + try expect(vec[144] == false); + try expect(vec[145] == false); + try expect(vec[146] == true); + try expect(vec[147] == false); + try expect(vec[148] == false); + try expect(vec[149] == true); + try expect(vec[150] == false); + try expect(vec[151] == true); + try expect(vec[152] == false); + try expect(vec[153] == true); + try expect(vec[154] == false); + try expect(vec[155] == false); + try expect(vec[156] == true); + try expect(vec[157] == false); + try expect(vec[158] == true); + try expect(vec[159] == true); + try expect(vec[160] == true); + try expect(vec[161] == false); + try expect(vec[162] == false); + try expect(vec[163] == true); + try expect(vec[164] == false); + try expect(vec[165] == false); + try expect(vec[166] == false); + try expect(vec[167] == true); + try expect(vec[168] == true); + try expect(vec[169] == true); + try expect(vec[170] == false); + try expect(vec[171] == true); + try expect(vec[172] == false); + try expect(vec[173] == false); + try expect(vec[174] == false); + try expect(vec[175] == false); + try expect(vec[176] == false); + try expect(vec[177] == true); + try expect(vec[178] == true); + try expect(vec[179] == false); + try expect(vec[180] == false); + try expect(vec[181] == true); + try expect(vec[182] == false); + try expect(vec[183] == false); + try expect(vec[184] == false); + try expect(vec[185] == false); + try expect(vec[186] == false); + try expect(vec[187] == true); + try expect(vec[188] == true); + try expect(vec[189] == false); + try expect(vec[190] == false); + try expect(vec[191] == false); + try expect(vec[192] == false); + try expect(vec[193] == false); + try expect(vec[194] == false); + try expect(vec[195] == true); + try expect(vec[196] == true); + try expect(vec[197] == false); + try expect(vec[198] == true); + try expect(vec[199] == true); + try expect(vec[200] == true); + try expect(vec[201] == true); + try expect(vec[202] == true); + try expect(vec[203] == true); + try expect(vec[204] == false); + try expect(vec[205] == false); + try expect(vec[206] == false); + try expect(vec[207] == false); + try expect(vec[208] == true); + try expect(vec[209] == false); + try expect(vec[210] == true); + try expect(vec[211] == true); + try expect(vec[212] == true); + try expect(vec[213] == true); + try expect(vec[214] == false); + try expect(vec[215] == false); + try expect(vec[216] == false); + try expect(vec[217] == true); + try expect(vec[218] == true); + try expect(vec[219] == false); + try expect(vec[220] == true); + try expect(vec[221] == true); + try expect(vec[222] == false); + try expect(vec[223] == false); + try expect(vec[224] == false); + try expect(vec[225] == true); + try expect(vec[226] == true); + try expect(vec[227] == true); + try expect(vec[228] == true); + try expect(vec[229] == false); + try expect(vec[230] == true); + try expect(vec[231] == false); + try expect(vec[232] == true); + try expect(vec[233] == true); + try expect(vec[234] == true); + try expect(vec[235] == true); + try expect(vec[236] == false); + try expect(vec[237] == true); + try expect(vec[238] == false); + try expect(vec[239] == true); + try expect(vec[240] == false); + try expect(vec[241] == true); + try expect(vec[242] == false); + try expect(vec[243] == false); + try expect(vec[244] == false); + try expect(vec[245] == true); + try expect(vec[246] == true); + try expect(vec[247] == false); + try expect(vec[248] == true); + try expect(vec[249] == false); + try expect(vec[250] == false); + try expect(vec[251] == false); + try expect(vec[252] == true); + try expect(vec[253] == true); + try expect(vec[254] == true); + try expect(vec[255] == true); + try expect(vec[256] == true); + try expect(vec[257] == false); + try expect(vec[258] == true); + try expect(vec[259] == true); + try expect(vec[260] == true); + try expect(vec[261] == true); + try expect(vec[262] == false); + try expect(vec[263] == true); + try expect(vec[264] == false); + try expect(vec[265] == false); + try expect(vec[266] == true); + try expect(vec[267] == false); + try expect(vec[268] == true); + try expect(vec[269] == false); + try expect(vec[270] == false); + try expect(vec[271] == true); + try expect(vec[272] == true); + try expect(vec[273] == false); + try expect(vec[274] == true); + try expect(vec[275] == false); + try expect(vec[276] == false); + try expect(vec[277] == true); + try expect(vec[278] == false); + try expect(vec[279] == false); + try expect(vec[280] == true); + try expect(vec[281] == true); + try expect(vec[282] == true); + try expect(vec[283] == false); + try expect(vec[284] == false); + try expect(vec[285] == true); + try expect(vec[286] == true); + try expect(vec[287] == true); + try expect(vec[288] == false); + try expect(vec[289] == false); + try expect(vec[290] == false); + try expect(vec[291] == false); + try expect(vec[292] == false); + try expect(vec[293] == false); + try expect(vec[294] == true); + try expect(vec[295] == false); + try expect(vec[296] == true); + try expect(vec[297] == false); + try expect(vec[298] == true); + try expect(vec[299] == true); + try expect(vec[300] == false); + try expect(vec[301] == false); + try expect(vec[302] == false); + try expect(vec[303] == false); + try expect(vec[304] == true); + try expect(vec[305] == true); + try expect(vec[306] == true); + try expect(vec[307] == true); + try expect(vec[308] == true); + try expect(vec[309] == false); + try expect(vec[310] == true); + try expect(vec[311] == true); + try expect(vec[312] == true); + try expect(vec[313] == true); + try expect(vec[314] == true); + try expect(vec[315] == false); + try expect(vec[316] == true); + try expect(vec[317] == true); + try expect(vec[318] == true); + try expect(vec[319] == false); + try expect(vec[320] == true); + try expect(vec[321] == false); + try expect(vec[322] == true); + try expect(vec[323] == true); + try expect(vec[324] == true); + try expect(vec[325] == false); + try expect(vec[326] == false); + try expect(vec[327] == true); + try expect(vec[328] == true); + try expect(vec[329] == true); + try expect(vec[330] == false); + try expect(vec[331] == false); + try expect(vec[332] == true); + try expect(vec[333] == true); + try expect(vec[334] == false); + try expect(vec[335] == true); + try expect(vec[336] == true); + try expect(vec[337] == true); + try expect(vec[338] == true); + try expect(vec[339] == true); + try expect(vec[340] == true); + try expect(vec[341] == false); + try expect(vec[342] == true); + try expect(vec[343] == false); + try expect(vec[344] == true); + try expect(vec[345] == false); + try expect(vec[346] == false); + try expect(vec[347] == false); + try expect(vec[348] == false); + try expect(vec[349] == true); + try expect(vec[350] == true); + try expect(vec[351] == true); + try expect(vec[352] == true); + try expect(vec[353] == false); + try expect(vec[354] == true); + try expect(vec[355] == false); + try expect(vec[356] == true); + try expect(vec[357] == true); + try expect(vec[358] == false); + try expect(vec[359] == true); + try expect(vec[360] == false); + try expect(vec[361] == false); + try expect(vec[362] == true); + try expect(vec[363] == false); + try expect(vec[364] == false); + try expect(vec[365] == false); + try expect(vec[366] == false); + try expect(vec[367] == false); + try expect(vec[368] == false); + try expect(vec[369] == false); + try expect(vec[370] == true); + try expect(vec[371] == false); + try expect(vec[372] == true); + try expect(vec[373] == true); + try expect(vec[374] == false); + try expect(vec[375] == false); + try expect(vec[376] == true); + try expect(vec[377] == false); + try expect(vec[378] == false); + try expect(vec[379] == true); + try expect(vec[380] == false); + try expect(vec[381] == false); + try expect(vec[382] == true); + try expect(vec[383] == false); + try expect(vec[384] == false); + try expect(vec[385] == false); + try expect(vec[386] == false); + try expect(vec[387] == true); + try expect(vec[388] == true); + try expect(vec[389] == true); + try expect(vec[390] == true); + try expect(vec[391] == true); + try expect(vec[392] == true); + try expect(vec[393] == true); + try expect(vec[394] == false); + try expect(vec[395] == true); + try expect(vec[396] == true); + try expect(vec[397] == false); + try expect(vec[398] == false); + try expect(vec[399] == false); + try expect(vec[400] == true); + try expect(vec[401] == false); + try expect(vec[402] == true); + try expect(vec[403] == true); + try expect(vec[404] == false); + try expect(vec[405] == true); + try expect(vec[406] == true); + try expect(vec[407] == true); + try expect(vec[408] == true); + try expect(vec[409] == false); + try expect(vec[410] == false); + try expect(vec[411] == false); + try expect(vec[412] == true); + try expect(vec[413] == true); + try expect(vec[414] == false); + try expect(vec[415] == true); + try expect(vec[416] == false); + try expect(vec[417] == true); + try expect(vec[418] == false); + try expect(vec[419] == false); + try expect(vec[420] == false); + try expect(vec[421] == false); + try expect(vec[422] == true); + try expect(vec[423] == true); + try expect(vec[424] == true); + try expect(vec[425] == false); + try expect(vec[426] == true); + try expect(vec[427] == false); + try expect(vec[428] == false); + try expect(vec[429] == false); + try expect(vec[430] == true); + try expect(vec[431] == true); + try expect(vec[432] == false); + try expect(vec[433] == true); + try expect(vec[434] == false); + try expect(vec[435] == false); + try expect(vec[436] == true); + try expect(vec[437] == true); + try expect(vec[438] == true); + try expect(vec[439] == true); + try expect(vec[440] == true); + try expect(vec[441] == true); + try expect(vec[442] == false); + try expect(vec[443] == false); + try expect(vec[444] == false); + try expect(vec[445] == true); + try expect(vec[446] == true); + try expect(vec[447] == true); + try expect(vec[448] == false); + try expect(vec[449] == false); + try expect(vec[450] == false); + try expect(vec[451] == false); + try expect(vec[452] == false); + try expect(vec[453] == false); + try expect(vec[454] == false); + try expect(vec[455] == false); + try expect(vec[456] == false); + try expect(vec[457] == false); + try expect(vec[458] == false); + try expect(vec[459] == true); + try expect(vec[460] == false); + try expect(vec[461] == false); + try expect(vec[462] == false); + try expect(vec[463] == true); + try expect(vec[464] == false); + try expect(vec[465] == false); + try expect(vec[466] == false); + try expect(vec[467] == false); + try expect(vec[468] == true); + try expect(vec[469] == true); + try expect(vec[470] == true); + try expect(vec[471] == true); + try expect(vec[472] == true); + try expect(vec[473] == false); + try expect(vec[474] == false); + try expect(vec[475] == true); + try expect(vec[476] == true); + try expect(vec[477] == true); + try expect(vec[478] == false); + try expect(vec[479] == true); + try expect(vec[480] == true); + try expect(vec[481] == true); + try expect(vec[482] == false); + try expect(vec[483] == true); + try expect(vec[484] == false); + try expect(vec[485] == true); + try expect(vec[486] == false); + try expect(vec[487] == true); + try expect(vec[488] == false); + try expect(vec[489] == true); + try expect(vec[490] == true); + try expect(vec[491] == true); + try expect(vec[492] == true); + try expect(vec[493] == false); + try expect(vec[494] == true); + try expect(vec[495] == true); + try expect(vec[496] == false); + try expect(vec[497] == true); + try expect(vec[498] == false); + try expect(vec[499] == false); + try expect(vec[500] == false); + try expect(vec[501] == false); + try expect(vec[502] == false); + try expect(vec[503] == false); + try expect(vec[504] == false); + try expect(vec[505] == false); + try expect(vec[506] == false); + try expect(vec[507] == true); + try expect(vec[508] == true); + try expect(vec[509] == false); + try expect(vec[510] == true); + try expect(vec[511] == false); + if (!builtin.target.cpu.arch.isWasm()) c_vector_512_bool(.{ + true, + true, + true, + true, + true, + false, + false, + true, + true, + true, + true, + false, + true, + true, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + true, + false, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + true, + true, + true, + false, + true, + true, + false, + true, + false, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + true, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + false, + false, + false, + true, + true, + false, + false, + false, + true, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + true, + true, + false, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + false, + false, + true, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + true, + true, + false, + true, + false, + true, + true, + false, + true, + false, + true, + false, + true, + false, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + false, + false, + true, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true, + false, + false, + true, + true, + false, + false, + false, + false, + false, + true, + false, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + false, + true, + false, + true, + true, + true, + false, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + true, + true, + false, + true, + true, + false, + false, + true, + false, + false, + false, + false, + true, + false, + true, + true, + true, + true, + false, + false, + true, + false, + true, + false, + false, + false, + true, + false, + true, + false, + false, + true, + true, + true, + true, + false, + false, + false, + true, + true, + false, + true, + false, + false, + true, + false, + true, + false, + true, + true, + false, + false, + true, + true, + true, + true, + false, + false, + true, + false, + true, + true, + false, + true, + true, + false, + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + false, + true, + true, + true, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + true, + false, + false, + true, + true, + false, + false, + false, + false, + true, + true, + true, + true, + true, + false, + false, + false, + true, + false, + false, + false, + false, + true, + false, + true, + false, + true, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + false, + true, + false, + true, + false, + false, + true, + false, + false, + true, + true, + true, + true, + true, + true, + false, + true, + false, + false, + false, + true, + true, + false, + true, + true, + false, + false, + true, + true, + false, + false, + true, + true, + false, + true, + false, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + true, + true, + true, + false, + false, + true, + false, + false, + false, + true, + true, + false, + true, + false, + true, + }); + c_test_vector_512_bool(); +} + +export fn zig_ret_vector_1_u8() @Vector(1, u8) { + return .{1}; +} +export fn zig_vector_1_u8(v: @Vector(1, u8), i: usize) void { + expect(v[0] == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_vector_1_u8() @Vector(1, u8); +extern fn c_vector_1_u8(@Vector(1, u8), usize) void; +extern fn c_test_vector_1_u8() void; + +test "@Vector(1, u8)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + + const v = c_ret_vector_1_u8(); + try expect(v[0] == 3); + c_vector_1_u8(.{4}, 1); + c_test_vector_1_u8(); +} + +export fn zig_ret_vector_2_u8() @Vector(2, u8) { + return .{ 5, 6 }; +} +export fn zig_vector_2_u8(v: @Vector(2, u8), i: usize) void { + expect(v[0] == 7) catch @panic("test failure"); + expect(v[1] == 8) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} + +extern fn c_ret_vector_2_u8() @Vector(2, u8); +extern fn c_vector_2_u8(@Vector(2, u8), usize) void; +extern fn c_test_vector_2_u8() void; + +test "@Vector(2, u8)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) 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.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64) return error.SkipZigTest; + + const v = c_ret_vector_2_u8(); + try expect(v[0] == 9); + try expect(v[1] == 10); + c_vector_2_u8(.{ 11, 12 }, 2); + c_test_vector_2_u8(); +} + +export fn zig_ret_vector_3_u8() @Vector(3, u8) { + return .{ 13, 14, 15 }; +} +export fn zig_vector_3_u8(v: @Vector(3, u8), i: usize) void { + expect(v[0] == 16) catch @panic("test failure"); + expect(v[1] == 17) catch @panic("test failure"); + expect(v[2] == 18) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_vector_3_u8() @Vector(3, u8); +extern fn c_vector_3_u8(@Vector(3, u8), usize) void; +extern fn c_test_vector_3_u8() void; + +test "@Vector(3, u8)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) 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.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); + try expect(v[1] == 20); + try expect(v[2] == 21); + c_vector_3_u8(.{ 22, 23, 24 }, 3); + c_test_vector_3_u8(); +} + +export fn zig_ret_vector_4_u8() @Vector(4, u8) { + return .{ 25, 26, 27, 28 }; +} +export fn zig_vector_4_u8(v: @Vector(4, u8), i: usize) void { + expect(v[0] == 29) catch @panic("test failure"); + expect(v[1] == 30) catch @panic("test failure"); + expect(v[2] == 31) catch @panic("test failure"); + expect(v[3] == 32) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_vector_4_u8_vector_4_u8(v0: @Vector(4, u8), v1: @Vector(4, u8), i: usize) void { + expect(v0[0] == 33) catch @panic("test failure"); + expect(v0[1] == 34) catch @panic("test failure"); + expect(v0[2] == 35) catch @panic("test failure"); + expect(v0[3] == 36) catch @panic("test failure"); + expect(v1[0] == 37) catch @panic("test failure"); + expect(v1[1] == 38) catch @panic("test failure"); + expect(v1[2] == 39) catch @panic("test failure"); + expect(v1[3] == 40) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_4_u8() @Vector(4, u8); +extern fn c_vector_4_u8(@Vector(4, u8), usize) void; +extern fn c_vector_4_u8_vector_4_u8(@Vector(4, u8), @Vector(4, u8), usize) void; +extern fn c_test_vector_4_u8() void; + +test "@Vector(4, u8)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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; + + const v = c_ret_vector_4_u8(); + try expect(v[0] == 41); + try expect(v[1] == 42); + try expect(v[2] == 43); + try expect(v[3] == 44); + c_vector_4_u8(.{ 45, 46, 47, 48 }, 4); + c_vector_4_u8_vector_4_u8(.{ 49, 50, 51, 52 }, .{ 53, 54, 55, 56 }, 8); + c_test_vector_4_u8(); +} + +export fn zig_ret_vector_6_u8() @Vector(6, u8) { + return .{ 41, 42, 43, 44, 45, 46 }; +} +export fn zig_vector_6_u8(v: @Vector(6, u8), i: usize) void { + expect(v[0] == 47) catch @panic("test failure"); + expect(v[1] == 48) catch @panic("test failure"); + expect(v[2] == 49) catch @panic("test failure"); + expect(v[3] == 50) catch @panic("test failure"); + expect(v[4] == 51) catch @panic("test failure"); + expect(v[5] == 52) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} + +extern fn c_ret_vector_6_u8() @Vector(6, u8); +extern fn c_vector_6_u8(@Vector(6, u8), usize) void; +extern fn c_test_vector_6_u8() void; + +test "@Vector(6, u8)" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) 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.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); + try expect(v[1] == 54); + try expect(v[2] == 55); + try expect(v[3] == 56); + try expect(v[4] == 57); + try expect(v[5] == 58); + c_vector_6_u8(.{ 59, 60, 61, 62, 63, 64 }, 6); + c_test_vector_6_u8(); +} + +export fn zig_ret_vector_8_u8() @Vector(8, u8) { + return .{ 65, 66, 67, 68, 69, 70, 71, 72 }; +} +export fn zig_vector_8_u8(v: @Vector(8, u8), i: usize) void { + expect(v[0] == 73) catch @panic("test failure"); + expect(v[1] == 74) catch @panic("test failure"); + expect(v[2] == 75) catch @panic("test failure"); + expect(v[3] == 76) catch @panic("test failure"); + expect(v[4] == 77) catch @panic("test failure"); + expect(v[5] == 78) catch @panic("test failure"); + expect(v[6] == 79) catch @panic("test failure"); + expect(v[7] == 80) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_8_u8() @Vector(8, u8); +extern fn c_vector_8_u8(@Vector(8, u8), usize) void; +extern fn c_test_vector_8_u8() void; + +test "@Vector(8, u8)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) 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_8_u8(); + try expect(v[0] == 81); + try expect(v[1] == 82); + try expect(v[2] == 83); + try expect(v[3] == 84); + try expect(v[4] == 85); + try expect(v[5] == 86); + try expect(v[6] == 87); + try expect(v[7] == 88); + c_vector_8_u8(.{ 89, 90, 91, 92, 93, 94, 95, 96 }, 8); + c_test_vector_8_u8(); +} + +export fn zig_ret_vector_12_u8() @Vector(12, u8) { + return .{ 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8 }; +} +export fn zig_vector_12_u8(v: @Vector(12, u8), i: usize) void { + expect(v[0] == 9) catch @panic("test failure"); + expect(v[1] == 10) catch @panic("test failure"); + expect(v[2] == 11) catch @panic("test failure"); + expect(v[3] == 12) catch @panic("test failure"); + expect(v[4] == 13) catch @panic("test failure"); + expect(v[5] == 14) catch @panic("test failure"); + expect(v[6] == 15) catch @panic("test failure"); + expect(v[7] == 16) catch @panic("test failure"); + expect(v[8] == 17) catch @panic("test failure"); + expect(v[9] == 18) catch @panic("test failure"); + expect(v[10] == 19) catch @panic("test failure"); + expect(v[11] == 20) catch @panic("test failure"); + expect(i == 12) catch @panic("test failure"); +} + +extern fn c_ret_vector_12_u8() @Vector(12, u8); +extern fn c_vector_12_u8(@Vector(12, u8), usize) void; +extern fn c_test_vector_12_u8() void; + +test "@Vector(12, u8)" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + + const v = c_ret_vector_12_u8(); + try expect(v[0] == 21); + try expect(v[1] == 22); + try expect(v[2] == 23); + try expect(v[3] == 24); + try expect(v[4] == 25); + try expect(v[5] == 26); + try expect(v[6] == 27); + try expect(v[7] == 28); + try expect(v[8] == 29); + try expect(v[9] == 30); + try expect(v[10] == 31); + try expect(v[11] == 32); + c_vector_12_u8(.{ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44 }, 12); + c_test_vector_12_u8(); +} + +export fn zig_ret_vector_16_u8() @Vector(16, u8) { + return .{ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 }; +} +export fn zig_vector_16_u8(v: @Vector(16, u8), i: usize) void { + expect(v[0] == 61) catch @panic("test failure"); + expect(v[1] == 62) catch @panic("test failure"); + expect(v[2] == 63) catch @panic("test failure"); + expect(v[3] == 64) catch @panic("test failure"); + expect(v[4] == 65) catch @panic("test failure"); + expect(v[5] == 66) catch @panic("test failure"); + expect(v[6] == 67) catch @panic("test failure"); + expect(v[7] == 68) catch @panic("test failure"); + expect(v[8] == 69) catch @panic("test failure"); + expect(v[9] == 70) catch @panic("test failure"); + expect(v[10] == 71) catch @panic("test failure"); + expect(v[11] == 72) catch @panic("test failure"); + expect(v[12] == 73) catch @panic("test failure"); + expect(v[13] == 74) catch @panic("test failure"); + expect(v[14] == 75) catch @panic("test failure"); + expect(v[15] == 76) catch @panic("test failure"); + expect(i == 16) catch @panic("test failure"); +} + +extern fn c_ret_vector_16_u8() @Vector(16, u8); +extern fn c_vector_16_u8(@Vector(16, u8), usize) void; +extern fn c_test_vector_16_u8() void; + +test "@Vector(16, u8)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + + const v = c_ret_vector_16_u8(); + try expect(v[0] == 77); + try expect(v[1] == 78); + try expect(v[2] == 79); + try expect(v[3] == 80); + try expect(v[4] == 81); + try expect(v[5] == 82); + try expect(v[6] == 83); + try expect(v[7] == 84); + try expect(v[8] == 85); + try expect(v[9] == 86); + try expect(v[10] == 87); + try expect(v[11] == 88); + try expect(v[12] == 89); + try expect(v[13] == 90); + try expect(v[14] == 91); + try expect(v[15] == 92); + c_vector_16_u8(.{ 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8 }, 16); + c_test_vector_16_u8(); +} + +export fn zig_ret_vector_24_u8() @Vector(24, u8) { + return .{ + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, + }; +} +export fn zig_vector_24_u8(v: @Vector(24, u8), i: usize) void { + expect(v[0] == 33) catch @panic("test failure"); + expect(v[1] == 34) catch @panic("test failure"); + expect(v[2] == 35) catch @panic("test failure"); + expect(v[3] == 36) catch @panic("test failure"); + expect(v[4] == 37) catch @panic("test failure"); + expect(v[5] == 38) catch @panic("test failure"); + expect(v[6] == 39) catch @panic("test failure"); + expect(v[7] == 40) catch @panic("test failure"); + expect(v[8] == 41) catch @panic("test failure"); + expect(v[9] == 42) catch @panic("test failure"); + expect(v[10] == 43) catch @panic("test failure"); + expect(v[11] == 44) catch @panic("test failure"); + expect(v[12] == 45) catch @panic("test failure"); + expect(v[13] == 46) catch @panic("test failure"); + expect(v[14] == 47) catch @panic("test failure"); + expect(v[15] == 48) catch @panic("test failure"); + expect(v[16] == 49) catch @panic("test failure"); + expect(v[17] == 50) catch @panic("test failure"); + expect(v[18] == 51) catch @panic("test failure"); + expect(v[19] == 52) catch @panic("test failure"); + expect(v[20] == 53) catch @panic("test failure"); + expect(v[21] == 54) catch @panic("test failure"); + expect(v[22] == 55) catch @panic("test failure"); + expect(v[23] == 56) catch @panic("test failure"); + expect(i == 24) catch @panic("test failure"); +} + +extern fn c_ret_vector_24_u8() @Vector(24, u8); +extern fn c_vector_24_u8(@Vector(24, u8), usize) void; +extern fn c_test_vector_24_u8() void; + +test "@Vector(24, u8)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_24_u8(); + try expect(v[0] == 57); + try expect(v[1] == 58); + try expect(v[2] == 59); + try expect(v[3] == 60); + try expect(v[4] == 61); + try expect(v[5] == 62); + try expect(v[6] == 63); + try expect(v[7] == 64); + try expect(v[8] == 65); + try expect(v[9] == 66); + try expect(v[10] == 67); + try expect(v[11] == 68); + try expect(v[12] == 69); + try expect(v[13] == 70); + try expect(v[14] == 71); + try expect(v[15] == 72); + try expect(v[16] == 73); + try expect(v[17] == 74); + try expect(v[18] == 75); + try expect(v[19] == 76); + try expect(v[20] == 77); + try expect(v[21] == 78); + try expect(v[22] == 79); + try expect(v[23] == 80); + c_vector_24_u8(.{ + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 0, 1, 2, 3, 4, + }, 24); + c_test_vector_24_u8(); +} + +export fn zig_ret_vector_32_u8() @Vector(32, u8) { + return .{ + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + }; +} +export fn zig_vector_32_u8(v: @Vector(32, u8), i: usize) void { + expect(v[0] == 37) catch @panic("test failure"); + expect(v[1] == 38) catch @panic("test failure"); + expect(v[2] == 39) catch @panic("test failure"); + expect(v[3] == 40) catch @panic("test failure"); + expect(v[4] == 41) catch @panic("test failure"); + expect(v[5] == 42) catch @panic("test failure"); + expect(v[6] == 43) catch @panic("test failure"); + expect(v[7] == 44) catch @panic("test failure"); + expect(v[8] == 45) catch @panic("test failure"); + expect(v[9] == 46) catch @panic("test failure"); + expect(v[10] == 47) catch @panic("test failure"); + expect(v[11] == 48) catch @panic("test failure"); + expect(v[12] == 49) catch @panic("test failure"); + expect(v[13] == 50) catch @panic("test failure"); + expect(v[14] == 51) catch @panic("test failure"); + expect(v[15] == 52) catch @panic("test failure"); + expect(v[16] == 53) catch @panic("test failure"); + expect(v[17] == 54) catch @panic("test failure"); + expect(v[18] == 55) catch @panic("test failure"); + expect(v[19] == 56) catch @panic("test failure"); + expect(v[20] == 57) catch @panic("test failure"); + expect(v[21] == 58) catch @panic("test failure"); + expect(v[22] == 59) catch @panic("test failure"); + expect(v[23] == 60) catch @panic("test failure"); + expect(v[24] == 61) catch @panic("test failure"); + expect(v[25] == 62) catch @panic("test failure"); + expect(v[26] == 63) catch @panic("test failure"); + expect(v[27] == 64) catch @panic("test failure"); + expect(v[28] == 65) catch @panic("test failure"); + expect(v[29] == 66) catch @panic("test failure"); + expect(v[30] == 67) catch @panic("test failure"); + expect(v[31] == 68) catch @panic("test failure"); + expect(i == 32) catch @panic("test failure"); +} + +extern fn c_ret_vector_32_u8() @Vector(32, u8); +extern fn c_vector_32_u8(@Vector(32, u8), usize) void; +extern fn c_test_vector_32_u8() void; + +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); + try expect(v[1] == 70); + try expect(v[2] == 71); + try expect(v[3] == 72); + try expect(v[4] == 73); + try expect(v[5] == 74); + try expect(v[6] == 75); + try expect(v[7] == 76); + try expect(v[8] == 77); + try expect(v[9] == 78); + try expect(v[10] == 79); + try expect(v[11] == 80); + try expect(v[12] == 81); + try expect(v[13] == 82); + try expect(v[14] == 83); + try expect(v[15] == 84); + try expect(v[16] == 85); + try expect(v[17] == 86); + try expect(v[18] == 87); + try expect(v[19] == 88); + try expect(v[20] == 89); + try expect(v[21] == 90); + try expect(v[22] == 91); + try expect(v[23] == 92); + try expect(v[24] == 93); + try expect(v[25] == 94); + try expect(v[26] == 95); + try expect(v[27] == 96); + try expect(v[28] == 97); + try expect(v[29] == 98); + try expect(v[30] == 99); + try expect(v[31] == 0); + c_vector_32_u8(.{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + }, 32); + c_test_vector_32_u8(); +} + +export fn zig_ret_vector_48_u8() @Vector(48, u8) { + return .{ + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + }; +} +export fn zig_vector_48_u8(v: @Vector(48, u8), i: usize) void { + expect(v[0] == 81) catch @panic("test failure"); + expect(v[1] == 82) catch @panic("test failure"); + expect(v[2] == 83) catch @panic("test failure"); + expect(v[3] == 84) catch @panic("test failure"); + expect(v[4] == 85) catch @panic("test failure"); + expect(v[5] == 86) catch @panic("test failure"); + expect(v[6] == 87) catch @panic("test failure"); + expect(v[7] == 88) catch @panic("test failure"); + expect(v[8] == 89) catch @panic("test failure"); + expect(v[9] == 90) catch @panic("test failure"); + expect(v[10] == 91) catch @panic("test failure"); + expect(v[11] == 92) catch @panic("test failure"); + expect(v[12] == 93) catch @panic("test failure"); + expect(v[13] == 94) catch @panic("test failure"); + expect(v[14] == 95) catch @panic("test failure"); + expect(v[15] == 96) catch @panic("test failure"); + expect(v[16] == 97) catch @panic("test failure"); + expect(v[17] == 98) catch @panic("test failure"); + expect(v[18] == 99) catch @panic("test failure"); + expect(v[19] == 0) catch @panic("test failure"); + expect(v[20] == 1) catch @panic("test failure"); + expect(v[21] == 2) catch @panic("test failure"); + expect(v[22] == 3) catch @panic("test failure"); + expect(v[23] == 4) catch @panic("test failure"); + expect(v[24] == 5) catch @panic("test failure"); + expect(v[25] == 6) catch @panic("test failure"); + expect(v[26] == 7) catch @panic("test failure"); + expect(v[27] == 8) catch @panic("test failure"); + expect(v[28] == 9) catch @panic("test failure"); + expect(v[29] == 10) catch @panic("test failure"); + expect(v[30] == 11) catch @panic("test failure"); + expect(v[31] == 12) catch @panic("test failure"); + expect(v[32] == 13) catch @panic("test failure"); + expect(v[33] == 14) catch @panic("test failure"); + expect(v[34] == 15) catch @panic("test failure"); + expect(v[35] == 16) catch @panic("test failure"); + expect(v[36] == 17) catch @panic("test failure"); + expect(v[37] == 18) catch @panic("test failure"); + expect(v[38] == 19) catch @panic("test failure"); + expect(v[39] == 20) catch @panic("test failure"); + expect(v[40] == 21) catch @panic("test failure"); + expect(v[41] == 22) catch @panic("test failure"); + expect(v[42] == 23) catch @panic("test failure"); + expect(v[43] == 24) catch @panic("test failure"); + expect(v[44] == 25) catch @panic("test failure"); + expect(v[45] == 26) catch @panic("test failure"); + expect(v[46] == 27) catch @panic("test failure"); + expect(v[47] == 28) catch @panic("test failure"); + expect(i == 48) catch @panic("test failure"); +} + +extern fn c_ret_vector_48_u8() @Vector(48, u8); +extern fn c_vector_48_u8(@Vector(48, u8), usize) void; +extern fn c_test_vector_48_u8() void; + +test "@Vector(48, u8)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_48_u8(); + try expect(v[0] == 29); + try expect(v[1] == 30); + try expect(v[2] == 31); + try expect(v[3] == 32); + try expect(v[4] == 33); + try expect(v[5] == 34); + try expect(v[6] == 35); + try expect(v[7] == 36); + try expect(v[8] == 37); + try expect(v[9] == 38); + try expect(v[10] == 39); + try expect(v[11] == 40); + try expect(v[12] == 41); + try expect(v[13] == 42); + try expect(v[14] == 43); + try expect(v[15] == 44); + try expect(v[16] == 45); + try expect(v[17] == 46); + try expect(v[18] == 47); + try expect(v[19] == 48); + try expect(v[20] == 49); + try expect(v[21] == 50); + try expect(v[22] == 51); + try expect(v[23] == 52); + try expect(v[24] == 53); + try expect(v[25] == 54); + try expect(v[26] == 55); + try expect(v[27] == 56); + try expect(v[28] == 57); + try expect(v[29] == 58); + try expect(v[30] == 59); + try expect(v[31] == 60); + try expect(v[32] == 61); + try expect(v[33] == 62); + try expect(v[34] == 63); + try expect(v[35] == 64); + try expect(v[36] == 65); + try expect(v[37] == 66); + try expect(v[38] == 67); + try expect(v[39] == 68); + try expect(v[40] == 69); + try expect(v[41] == 70); + try expect(v[42] == 71); + try expect(v[43] == 72); + try expect(v[44] == 73); + try expect(v[45] == 74); + try expect(v[46] == 75); + try expect(v[47] == 76); + c_vector_48_u8(.{ + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + }, 48); + c_test_vector_48_u8(); +} + +export fn zig_ret_vector_64_u8() @Vector(64, u8) { + return .{ + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + }; +} +export fn zig_vector_64_u8(v: @Vector(64, u8), i: usize) void { + expect(v[0] == 89) catch @panic("test failure"); + expect(v[1] == 90) catch @panic("test failure"); + expect(v[2] == 91) catch @panic("test failure"); + expect(v[3] == 92) catch @panic("test failure"); + expect(v[4] == 93) catch @panic("test failure"); + expect(v[5] == 94) catch @panic("test failure"); + expect(v[6] == 95) catch @panic("test failure"); + expect(v[7] == 96) catch @panic("test failure"); + expect(v[8] == 97) catch @panic("test failure"); + expect(v[9] == 98) catch @panic("test failure"); + expect(v[10] == 99) catch @panic("test failure"); + expect(v[11] == 0) catch @panic("test failure"); + expect(v[12] == 1) catch @panic("test failure"); + expect(v[13] == 2) catch @panic("test failure"); + expect(v[14] == 3) catch @panic("test failure"); + expect(v[15] == 4) catch @panic("test failure"); + expect(v[16] == 5) catch @panic("test failure"); + expect(v[17] == 6) catch @panic("test failure"); + expect(v[18] == 7) catch @panic("test failure"); + expect(v[19] == 8) catch @panic("test failure"); + expect(v[20] == 9) catch @panic("test failure"); + expect(v[21] == 10) catch @panic("test failure"); + expect(v[22] == 11) catch @panic("test failure"); + expect(v[23] == 12) catch @panic("test failure"); + expect(v[24] == 13) catch @panic("test failure"); + expect(v[25] == 14) catch @panic("test failure"); + expect(v[26] == 15) catch @panic("test failure"); + expect(v[27] == 16) catch @panic("test failure"); + expect(v[28] == 17) catch @panic("test failure"); + expect(v[29] == 18) catch @panic("test failure"); + expect(v[30] == 19) catch @panic("test failure"); + expect(v[31] == 20) catch @panic("test failure"); + expect(v[32] == 21) catch @panic("test failure"); + expect(v[33] == 22) catch @panic("test failure"); + expect(v[34] == 23) catch @panic("test failure"); + expect(v[35] == 24) catch @panic("test failure"); + expect(v[36] == 25) catch @panic("test failure"); + expect(v[37] == 26) catch @panic("test failure"); + expect(v[38] == 27) catch @panic("test failure"); + expect(v[39] == 28) catch @panic("test failure"); + expect(v[40] == 29) catch @panic("test failure"); + expect(v[41] == 30) catch @panic("test failure"); + expect(v[42] == 31) catch @panic("test failure"); + expect(v[43] == 32) catch @panic("test failure"); + expect(v[44] == 33) catch @panic("test failure"); + expect(v[45] == 34) catch @panic("test failure"); + expect(v[46] == 35) catch @panic("test failure"); + expect(v[47] == 36) catch @panic("test failure"); + expect(v[48] == 37) catch @panic("test failure"); + expect(v[49] == 38) catch @panic("test failure"); + expect(v[50] == 39) catch @panic("test failure"); + expect(v[51] == 40) catch @panic("test failure"); + expect(v[52] == 41) catch @panic("test failure"); + expect(v[53] == 42) catch @panic("test failure"); + expect(v[54] == 43) catch @panic("test failure"); + expect(v[55] == 44) catch @panic("test failure"); + expect(v[56] == 45) catch @panic("test failure"); + expect(v[57] == 46) catch @panic("test failure"); + expect(v[58] == 47) catch @panic("test failure"); + expect(v[59] == 48) catch @panic("test failure"); + expect(v[60] == 49) catch @panic("test failure"); + expect(v[61] == 50) catch @panic("test failure"); + expect(v[62] == 51) catch @panic("test failure"); + expect(v[63] == 52) catch @panic("test failure"); + expect(i == 64) catch @panic("test failure"); +} + +extern fn c_ret_vector_64_u8() @Vector(64, u8); +extern fn c_vector_64_u8(@Vector(64, u8), usize) void; +extern fn c_test_vector_64_u8() void; + +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); + try expect(v[1] == 54); + try expect(v[2] == 55); + try expect(v[3] == 56); + try expect(v[4] == 57); + try expect(v[5] == 58); + try expect(v[6] == 59); + try expect(v[7] == 60); + try expect(v[8] == 61); + try expect(v[9] == 62); + try expect(v[10] == 63); + try expect(v[11] == 64); + try expect(v[12] == 65); + try expect(v[13] == 66); + try expect(v[14] == 67); + try expect(v[15] == 68); + try expect(v[16] == 69); + try expect(v[17] == 70); + try expect(v[18] == 71); + try expect(v[19] == 72); + try expect(v[20] == 73); + try expect(v[21] == 74); + try expect(v[22] == 75); + try expect(v[23] == 76); + try expect(v[24] == 77); + try expect(v[25] == 78); + try expect(v[26] == 79); + try expect(v[27] == 80); + try expect(v[28] == 81); + try expect(v[29] == 82); + try expect(v[30] == 83); + try expect(v[31] == 84); + try expect(v[32] == 85); + try expect(v[33] == 86); + try expect(v[34] == 87); + try expect(v[35] == 88); + try expect(v[36] == 89); + try expect(v[37] == 90); + try expect(v[38] == 91); + try expect(v[39] == 92); + try expect(v[40] == 93); + try expect(v[41] == 94); + try expect(v[42] == 95); + try expect(v[43] == 96); + try expect(v[44] == 97); + try expect(v[45] == 98); + try expect(v[46] == 99); + try expect(v[47] == 0); + try expect(v[48] == 1); + try expect(v[49] == 2); + try expect(v[50] == 3); + try expect(v[51] == 4); + try expect(v[52] == 5); + try expect(v[53] == 6); + try expect(v[54] == 7); + try expect(v[55] == 8); + try expect(v[56] == 9); + try expect(v[57] == 10); + try expect(v[58] == 11); + try expect(v[59] == 12); + try expect(v[60] == 13); + try expect(v[61] == 14); + try expect(v[62] == 15); + try expect(v[63] == 16); + c_vector_64_u8(.{ + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + }, 64); + c_test_vector_64_u8(); +} + +export fn zig_ret_vector_96_u8() @Vector(96, u8) { + return .{ + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + }; +} +export fn zig_vector_96_u8(v: @Vector(96, u8), i: usize) void { + expect(v[0] == 86) catch @panic("test failure"); + expect(v[1] == 87) catch @panic("test failure"); + expect(v[2] == 88) catch @panic("test failure"); + expect(v[3] == 89) catch @panic("test failure"); + expect(v[4] == 90) catch @panic("test failure"); + expect(v[5] == 91) catch @panic("test failure"); + expect(v[6] == 92) catch @panic("test failure"); + expect(v[7] == 93) catch @panic("test failure"); + expect(v[8] == 94) catch @panic("test failure"); + expect(v[9] == 95) catch @panic("test failure"); + expect(v[10] == 96) catch @panic("test failure"); + expect(v[11] == 97) catch @panic("test failure"); + expect(v[12] == 98) catch @panic("test failure"); + expect(v[13] == 99) catch @panic("test failure"); + expect(v[14] == 0) catch @panic("test failure"); + expect(v[15] == 1) catch @panic("test failure"); + expect(v[16] == 2) catch @panic("test failure"); + expect(v[17] == 3) catch @panic("test failure"); + expect(v[18] == 4) catch @panic("test failure"); + expect(v[19] == 5) catch @panic("test failure"); + expect(v[20] == 6) catch @panic("test failure"); + expect(v[21] == 7) catch @panic("test failure"); + expect(v[22] == 8) catch @panic("test failure"); + expect(v[23] == 9) catch @panic("test failure"); + expect(v[24] == 10) catch @panic("test failure"); + expect(v[25] == 11) catch @panic("test failure"); + expect(v[26] == 12) catch @panic("test failure"); + expect(v[27] == 13) catch @panic("test failure"); + expect(v[28] == 14) catch @panic("test failure"); + expect(v[29] == 15) catch @panic("test failure"); + expect(v[30] == 16) catch @panic("test failure"); + expect(v[31] == 17) catch @panic("test failure"); + expect(v[32] == 18) catch @panic("test failure"); + expect(v[33] == 19) catch @panic("test failure"); + expect(v[34] == 20) catch @panic("test failure"); + expect(v[35] == 21) catch @panic("test failure"); + expect(v[36] == 22) catch @panic("test failure"); + expect(v[37] == 23) catch @panic("test failure"); + expect(v[38] == 24) catch @panic("test failure"); + expect(v[39] == 25) catch @panic("test failure"); + expect(v[40] == 26) catch @panic("test failure"); + expect(v[41] == 27) catch @panic("test failure"); + expect(v[42] == 28) catch @panic("test failure"); + expect(v[43] == 29) catch @panic("test failure"); + expect(v[44] == 30) catch @panic("test failure"); + expect(v[45] == 31) catch @panic("test failure"); + expect(v[46] == 32) catch @panic("test failure"); + expect(v[47] == 33) catch @panic("test failure"); + expect(v[48] == 34) catch @panic("test failure"); + expect(v[49] == 35) catch @panic("test failure"); + expect(v[50] == 36) catch @panic("test failure"); + expect(v[51] == 37) catch @panic("test failure"); + expect(v[52] == 38) catch @panic("test failure"); + expect(v[53] == 39) catch @panic("test failure"); + expect(v[54] == 40) catch @panic("test failure"); + expect(v[55] == 41) catch @panic("test failure"); + expect(v[56] == 42) catch @panic("test failure"); + expect(v[57] == 43) catch @panic("test failure"); + expect(v[58] == 44) catch @panic("test failure"); + expect(v[59] == 45) catch @panic("test failure"); + expect(v[60] == 46) catch @panic("test failure"); + expect(v[61] == 47) catch @panic("test failure"); + expect(v[62] == 48) catch @panic("test failure"); + expect(v[63] == 49) catch @panic("test failure"); + expect(v[64] == 50) catch @panic("test failure"); + expect(v[65] == 51) catch @panic("test failure"); + expect(v[66] == 52) catch @panic("test failure"); + expect(v[67] == 53) catch @panic("test failure"); + expect(v[68] == 54) catch @panic("test failure"); + expect(v[69] == 55) catch @panic("test failure"); + expect(v[70] == 56) catch @panic("test failure"); + expect(v[71] == 57) catch @panic("test failure"); + expect(v[72] == 58) catch @panic("test failure"); + expect(v[73] == 59) catch @panic("test failure"); + expect(v[74] == 60) catch @panic("test failure"); + expect(v[75] == 61) catch @panic("test failure"); + expect(v[76] == 62) catch @panic("test failure"); + expect(v[77] == 63) catch @panic("test failure"); + expect(v[78] == 64) catch @panic("test failure"); + expect(v[79] == 65) catch @panic("test failure"); + expect(v[80] == 66) catch @panic("test failure"); + expect(v[81] == 67) catch @panic("test failure"); + expect(v[82] == 68) catch @panic("test failure"); + expect(v[83] == 69) catch @panic("test failure"); + expect(v[84] == 70) catch @panic("test failure"); + expect(v[85] == 71) catch @panic("test failure"); + expect(v[86] == 72) catch @panic("test failure"); + expect(v[87] == 73) catch @panic("test failure"); + expect(v[88] == 74) catch @panic("test failure"); + expect(v[89] == 75) catch @panic("test failure"); + expect(v[90] == 76) catch @panic("test failure"); + expect(v[91] == 77) catch @panic("test failure"); + expect(v[92] == 78) catch @panic("test failure"); + expect(v[93] == 79) catch @panic("test failure"); + expect(v[94] == 80) catch @panic("test failure"); + expect(v[95] == 81) catch @panic("test failure"); + expect(i == 96) catch @panic("test failure"); +} + +extern fn c_ret_vector_96_u8() @Vector(96, u8); +extern fn c_vector_96_u8(@Vector(96, u8), usize) void; +extern fn c_test_vector_96_u8() void; + +test "@Vector(96, u8)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_96_u8(); + try expect(v[0] == 82); + try expect(v[1] == 83); + try expect(v[2] == 84); + try expect(v[3] == 85); + try expect(v[4] == 86); + try expect(v[5] == 87); + try expect(v[6] == 88); + try expect(v[7] == 89); + try expect(v[8] == 90); + try expect(v[9] == 91); + try expect(v[10] == 92); + try expect(v[11] == 93); + try expect(v[12] == 94); + try expect(v[13] == 95); + try expect(v[14] == 96); + try expect(v[15] == 97); + try expect(v[16] == 98); + try expect(v[17] == 99); + try expect(v[18] == 0); + try expect(v[19] == 1); + try expect(v[20] == 2); + try expect(v[21] == 3); + try expect(v[22] == 4); + try expect(v[23] == 5); + try expect(v[24] == 6); + try expect(v[25] == 7); + try expect(v[26] == 8); + try expect(v[27] == 9); + try expect(v[28] == 10); + try expect(v[29] == 11); + try expect(v[30] == 12); + try expect(v[31] == 13); + try expect(v[32] == 14); + try expect(v[33] == 15); + try expect(v[34] == 16); + try expect(v[35] == 17); + try expect(v[36] == 18); + try expect(v[37] == 19); + try expect(v[38] == 20); + try expect(v[39] == 21); + try expect(v[40] == 22); + try expect(v[41] == 23); + try expect(v[42] == 24); + try expect(v[43] == 25); + try expect(v[44] == 26); + try expect(v[45] == 27); + try expect(v[46] == 28); + try expect(v[47] == 29); + try expect(v[48] == 30); + try expect(v[49] == 31); + try expect(v[50] == 32); + try expect(v[51] == 33); + try expect(v[52] == 34); + try expect(v[53] == 35); + try expect(v[54] == 36); + try expect(v[55] == 37); + try expect(v[56] == 38); + try expect(v[57] == 39); + try expect(v[58] == 40); + try expect(v[59] == 41); + try expect(v[60] == 42); + try expect(v[61] == 43); + try expect(v[62] == 44); + try expect(v[63] == 45); + try expect(v[64] == 46); + try expect(v[65] == 47); + try expect(v[66] == 48); + try expect(v[67] == 49); + try expect(v[68] == 50); + try expect(v[69] == 51); + try expect(v[70] == 52); + try expect(v[71] == 53); + try expect(v[72] == 54); + try expect(v[73] == 55); + try expect(v[74] == 56); + try expect(v[75] == 57); + try expect(v[76] == 58); + try expect(v[77] == 59); + try expect(v[78] == 60); + try expect(v[79] == 61); + try expect(v[80] == 62); + try expect(v[81] == 63); + try expect(v[82] == 64); + try expect(v[83] == 65); + try expect(v[84] == 66); + try expect(v[85] == 67); + try expect(v[86] == 68); + try expect(v[87] == 69); + try expect(v[88] == 70); + try expect(v[89] == 71); + try expect(v[90] == 72); + try expect(v[91] == 73); + try expect(v[92] == 74); + try expect(v[93] == 75); + try expect(v[94] == 76); + try expect(v[95] == 77); + c_vector_96_u8(.{ + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + }, 96); + c_test_vector_96_u8(); +} + +export fn zig_ret_vector_128_u8() @Vector(128, u8) { + return .{ + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + }; +} +export fn zig_vector_128_u8(v: @Vector(128, u8), i: usize) void { + expect(v[0] == 2) catch @panic("test failure"); + expect(v[1] == 3) catch @panic("test failure"); + expect(v[2] == 4) catch @panic("test failure"); + expect(v[3] == 5) catch @panic("test failure"); + expect(v[4] == 6) catch @panic("test failure"); + expect(v[5] == 7) catch @panic("test failure"); + expect(v[6] == 8) catch @panic("test failure"); + expect(v[7] == 9) catch @panic("test failure"); + expect(v[8] == 10) catch @panic("test failure"); + expect(v[9] == 11) catch @panic("test failure"); + expect(v[10] == 12) catch @panic("test failure"); + expect(v[11] == 13) catch @panic("test failure"); + expect(v[12] == 14) catch @panic("test failure"); + expect(v[13] == 15) catch @panic("test failure"); + expect(v[14] == 16) catch @panic("test failure"); + expect(v[15] == 17) catch @panic("test failure"); + expect(v[16] == 18) catch @panic("test failure"); + expect(v[17] == 19) catch @panic("test failure"); + expect(v[18] == 20) catch @panic("test failure"); + expect(v[19] == 21) catch @panic("test failure"); + expect(v[20] == 22) catch @panic("test failure"); + expect(v[21] == 23) catch @panic("test failure"); + expect(v[22] == 24) catch @panic("test failure"); + expect(v[23] == 25) catch @panic("test failure"); + expect(v[24] == 26) catch @panic("test failure"); + expect(v[25] == 27) catch @panic("test failure"); + expect(v[26] == 28) catch @panic("test failure"); + expect(v[27] == 29) catch @panic("test failure"); + expect(v[28] == 30) catch @panic("test failure"); + expect(v[29] == 31) catch @panic("test failure"); + expect(v[30] == 32) catch @panic("test failure"); + expect(v[31] == 33) catch @panic("test failure"); + expect(v[32] == 34) catch @panic("test failure"); + expect(v[33] == 35) catch @panic("test failure"); + expect(v[34] == 36) catch @panic("test failure"); + expect(v[35] == 37) catch @panic("test failure"); + expect(v[36] == 38) catch @panic("test failure"); + expect(v[37] == 39) catch @panic("test failure"); + expect(v[38] == 40) catch @panic("test failure"); + expect(v[39] == 41) catch @panic("test failure"); + expect(v[40] == 42) catch @panic("test failure"); + expect(v[41] == 43) catch @panic("test failure"); + expect(v[42] == 44) catch @panic("test failure"); + expect(v[43] == 45) catch @panic("test failure"); + expect(v[44] == 46) catch @panic("test failure"); + expect(v[45] == 47) catch @panic("test failure"); + expect(v[46] == 48) catch @panic("test failure"); + expect(v[47] == 49) catch @panic("test failure"); + expect(v[48] == 50) catch @panic("test failure"); + expect(v[49] == 51) catch @panic("test failure"); + expect(v[50] == 52) catch @panic("test failure"); + expect(v[51] == 53) catch @panic("test failure"); + expect(v[52] == 54) catch @panic("test failure"); + expect(v[53] == 55) catch @panic("test failure"); + expect(v[54] == 56) catch @panic("test failure"); + expect(v[55] == 57) catch @panic("test failure"); + expect(v[56] == 58) catch @panic("test failure"); + expect(v[57] == 59) catch @panic("test failure"); + expect(v[58] == 60) catch @panic("test failure"); + expect(v[59] == 61) catch @panic("test failure"); + expect(v[60] == 62) catch @panic("test failure"); + expect(v[61] == 63) catch @panic("test failure"); + expect(v[62] == 64) catch @panic("test failure"); + expect(v[63] == 65) catch @panic("test failure"); + expect(v[64] == 66) catch @panic("test failure"); + expect(v[65] == 67) catch @panic("test failure"); + expect(v[66] == 68) catch @panic("test failure"); + expect(v[67] == 69) catch @panic("test failure"); + expect(v[68] == 70) catch @panic("test failure"); + expect(v[69] == 71) catch @panic("test failure"); + expect(v[70] == 72) catch @panic("test failure"); + expect(v[71] == 73) catch @panic("test failure"); + expect(v[72] == 74) catch @panic("test failure"); + expect(v[73] == 75) catch @panic("test failure"); + expect(v[74] == 76) catch @panic("test failure"); + expect(v[75] == 77) catch @panic("test failure"); + expect(v[76] == 78) catch @panic("test failure"); + expect(v[77] == 79) catch @panic("test failure"); + expect(v[78] == 80) catch @panic("test failure"); + expect(v[79] == 81) catch @panic("test failure"); + expect(v[80] == 82) catch @panic("test failure"); + expect(v[81] == 83) catch @panic("test failure"); + expect(v[82] == 84) catch @panic("test failure"); + expect(v[83] == 85) catch @panic("test failure"); + expect(v[84] == 86) catch @panic("test failure"); + expect(v[85] == 87) catch @panic("test failure"); + expect(v[86] == 88) catch @panic("test failure"); + expect(v[87] == 89) catch @panic("test failure"); + expect(v[88] == 90) catch @panic("test failure"); + expect(v[89] == 91) catch @panic("test failure"); + expect(v[90] == 92) catch @panic("test failure"); + expect(v[91] == 93) catch @panic("test failure"); + expect(v[92] == 94) catch @panic("test failure"); + expect(v[93] == 95) catch @panic("test failure"); + expect(v[94] == 96) catch @panic("test failure"); + expect(v[95] == 97) catch @panic("test failure"); + expect(v[96] == 98) catch @panic("test failure"); + expect(v[97] == 99) catch @panic("test failure"); + expect(v[98] == 0) catch @panic("test failure"); + expect(v[99] == 1) catch @panic("test failure"); + expect(v[100] == 2) catch @panic("test failure"); + expect(v[101] == 3) catch @panic("test failure"); + expect(v[102] == 4) catch @panic("test failure"); + expect(v[103] == 5) catch @panic("test failure"); + expect(v[104] == 6) catch @panic("test failure"); + expect(v[105] == 7) catch @panic("test failure"); + expect(v[106] == 8) catch @panic("test failure"); + expect(v[107] == 9) catch @panic("test failure"); + expect(v[108] == 10) catch @panic("test failure"); + expect(v[109] == 11) catch @panic("test failure"); + expect(v[110] == 12) catch @panic("test failure"); + expect(v[111] == 13) catch @panic("test failure"); + expect(v[112] == 14) catch @panic("test failure"); + expect(v[113] == 15) catch @panic("test failure"); + expect(v[114] == 16) catch @panic("test failure"); + expect(v[115] == 17) catch @panic("test failure"); + expect(v[116] == 18) catch @panic("test failure"); + expect(v[117] == 19) catch @panic("test failure"); + expect(v[118] == 20) catch @panic("test failure"); + expect(v[119] == 21) catch @panic("test failure"); + expect(v[120] == 22) catch @panic("test failure"); + expect(v[121] == 23) catch @panic("test failure"); + expect(v[122] == 24) catch @panic("test failure"); + expect(v[123] == 25) catch @panic("test failure"); + expect(v[124] == 26) catch @panic("test failure"); + expect(v[125] == 27) catch @panic("test failure"); + expect(v[126] == 28) catch @panic("test failure"); + expect(v[127] == 29) catch @panic("test failure"); + expect(i == 128) catch @panic("test failure"); +} + +extern fn c_ret_vector_128_u8() @Vector(128, u8); +extern fn c_vector_128_u8(@Vector(128, u8), usize) void; +extern fn c_test_vector_128_u8() void; + +test "@Vector(128, u8)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 31); + try expect(v[2] == 32); + try expect(v[3] == 33); + try expect(v[4] == 34); + try expect(v[5] == 35); + try expect(v[6] == 36); + try expect(v[7] == 37); + try expect(v[8] == 38); + try expect(v[9] == 39); + try expect(v[10] == 40); + try expect(v[11] == 41); + try expect(v[12] == 42); + try expect(v[13] == 43); + try expect(v[14] == 44); + try expect(v[15] == 45); + try expect(v[16] == 46); + try expect(v[17] == 47); + try expect(v[18] == 48); + try expect(v[19] == 49); + try expect(v[20] == 50); + try expect(v[21] == 51); + try expect(v[22] == 52); + try expect(v[23] == 53); + try expect(v[24] == 54); + try expect(v[25] == 55); + try expect(v[26] == 56); + try expect(v[27] == 57); + try expect(v[28] == 58); + try expect(v[29] == 59); + try expect(v[30] == 60); + try expect(v[31] == 61); + try expect(v[32] == 62); + try expect(v[33] == 63); + try expect(v[34] == 64); + try expect(v[35] == 65); + try expect(v[36] == 66); + try expect(v[37] == 67); + try expect(v[38] == 68); + try expect(v[39] == 69); + try expect(v[40] == 70); + try expect(v[41] == 71); + try expect(v[42] == 72); + try expect(v[43] == 73); + try expect(v[44] == 74); + try expect(v[45] == 75); + try expect(v[46] == 76); + try expect(v[47] == 77); + try expect(v[48] == 78); + try expect(v[49] == 79); + try expect(v[50] == 80); + try expect(v[51] == 81); + try expect(v[52] == 82); + try expect(v[53] == 83); + try expect(v[54] == 84); + try expect(v[55] == 85); + try expect(v[56] == 86); + try expect(v[57] == 87); + try expect(v[58] == 88); + try expect(v[59] == 89); + try expect(v[60] == 90); + try expect(v[61] == 91); + try expect(v[62] == 92); + try expect(v[63] == 93); + try expect(v[64] == 94); + try expect(v[65] == 95); + try expect(v[66] == 96); + try expect(v[67] == 97); + try expect(v[68] == 98); + try expect(v[69] == 99); + try expect(v[70] == 0); + try expect(v[71] == 1); + try expect(v[72] == 2); + try expect(v[73] == 3); + try expect(v[74] == 4); + try expect(v[75] == 5); + try expect(v[76] == 6); + try expect(v[77] == 7); + try expect(v[78] == 8); + try expect(v[79] == 9); + try expect(v[80] == 10); + try expect(v[81] == 11); + try expect(v[82] == 12); + try expect(v[83] == 13); + try expect(v[84] == 14); + try expect(v[85] == 15); + try expect(v[86] == 16); + try expect(v[87] == 17); + try expect(v[88] == 18); + try expect(v[89] == 19); + try expect(v[90] == 20); + try expect(v[91] == 21); + try expect(v[92] == 22); + try expect(v[93] == 23); + try expect(v[94] == 24); + try expect(v[95] == 25); + try expect(v[96] == 26); + try expect(v[97] == 27); + try expect(v[98] == 28); + try expect(v[99] == 29); + try expect(v[100] == 30); + try expect(v[101] == 31); + try expect(v[102] == 32); + try expect(v[103] == 33); + try expect(v[104] == 34); + try expect(v[105] == 35); + try expect(v[106] == 36); + try expect(v[107] == 37); + try expect(v[108] == 38); + try expect(v[109] == 39); + try expect(v[110] == 40); + try expect(v[111] == 41); + try expect(v[112] == 42); + try expect(v[113] == 43); + try expect(v[114] == 44); + try expect(v[115] == 45); + try expect(v[116] == 46); + try expect(v[117] == 47); + try expect(v[118] == 48); + try expect(v[119] == 49); + try expect(v[120] == 50); + try expect(v[121] == 51); + try expect(v[122] == 52); + try expect(v[123] == 53); + try expect(v[124] == 54); + try expect(v[125] == 55); + try expect(v[126] == 56); + try expect(v[127] == 57); + c_vector_128_u8(.{ + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + }, 128); + c_test_vector_128_u8(); +} + +export fn zig_ret_vector_192_u8() @Vector(192, u8) { + return .{ + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + }; +} +export fn zig_vector_192_u8(v: @Vector(192, u8), i: usize) void { + expect(v[0] == 78) catch @panic("test failure"); + expect(v[1] == 79) catch @panic("test failure"); + expect(v[2] == 80) catch @panic("test failure"); + expect(v[3] == 81) catch @panic("test failure"); + expect(v[4] == 82) catch @panic("test failure"); + expect(v[5] == 83) catch @panic("test failure"); + expect(v[6] == 84) catch @panic("test failure"); + expect(v[7] == 85) catch @panic("test failure"); + expect(v[8] == 86) catch @panic("test failure"); + expect(v[9] == 87) catch @panic("test failure"); + expect(v[10] == 88) catch @panic("test failure"); + expect(v[11] == 89) catch @panic("test failure"); + expect(v[12] == 90) catch @panic("test failure"); + expect(v[13] == 91) catch @panic("test failure"); + expect(v[14] == 92) catch @panic("test failure"); + expect(v[15] == 93) catch @panic("test failure"); + expect(v[16] == 94) catch @panic("test failure"); + expect(v[17] == 95) catch @panic("test failure"); + expect(v[18] == 96) catch @panic("test failure"); + expect(v[19] == 97) catch @panic("test failure"); + expect(v[20] == 98) catch @panic("test failure"); + expect(v[21] == 99) catch @panic("test failure"); + expect(v[22] == 0) catch @panic("test failure"); + expect(v[23] == 1) catch @panic("test failure"); + expect(v[24] == 2) catch @panic("test failure"); + expect(v[25] == 3) catch @panic("test failure"); + expect(v[26] == 4) catch @panic("test failure"); + expect(v[27] == 5) catch @panic("test failure"); + expect(v[28] == 6) catch @panic("test failure"); + expect(v[29] == 7) catch @panic("test failure"); + expect(v[30] == 8) catch @panic("test failure"); + expect(v[31] == 9) catch @panic("test failure"); + expect(v[32] == 10) catch @panic("test failure"); + expect(v[33] == 11) catch @panic("test failure"); + expect(v[34] == 12) catch @panic("test failure"); + expect(v[35] == 13) catch @panic("test failure"); + expect(v[36] == 14) catch @panic("test failure"); + expect(v[37] == 15) catch @panic("test failure"); + expect(v[38] == 16) catch @panic("test failure"); + expect(v[39] == 17) catch @panic("test failure"); + expect(v[40] == 18) catch @panic("test failure"); + expect(v[41] == 19) catch @panic("test failure"); + expect(v[42] == 20) catch @panic("test failure"); + expect(v[43] == 21) catch @panic("test failure"); + expect(v[44] == 22) catch @panic("test failure"); + expect(v[45] == 23) catch @panic("test failure"); + expect(v[46] == 24) catch @panic("test failure"); + expect(v[47] == 25) catch @panic("test failure"); + expect(v[48] == 26) catch @panic("test failure"); + expect(v[49] == 27) catch @panic("test failure"); + expect(v[50] == 28) catch @panic("test failure"); + expect(v[51] == 29) catch @panic("test failure"); + expect(v[52] == 30) catch @panic("test failure"); + expect(v[53] == 31) catch @panic("test failure"); + expect(v[54] == 32) catch @panic("test failure"); + expect(v[55] == 33) catch @panic("test failure"); + expect(v[56] == 34) catch @panic("test failure"); + expect(v[57] == 35) catch @panic("test failure"); + expect(v[58] == 36) catch @panic("test failure"); + expect(v[59] == 37) catch @panic("test failure"); + expect(v[60] == 38) catch @panic("test failure"); + expect(v[61] == 39) catch @panic("test failure"); + expect(v[62] == 40) catch @panic("test failure"); + expect(v[63] == 41) catch @panic("test failure"); + expect(v[64] == 42) catch @panic("test failure"); + expect(v[65] == 43) catch @panic("test failure"); + expect(v[66] == 44) catch @panic("test failure"); + expect(v[67] == 45) catch @panic("test failure"); + expect(v[68] == 46) catch @panic("test failure"); + expect(v[69] == 47) catch @panic("test failure"); + expect(v[70] == 48) catch @panic("test failure"); + expect(v[71] == 49) catch @panic("test failure"); + expect(v[72] == 50) catch @panic("test failure"); + expect(v[73] == 51) catch @panic("test failure"); + expect(v[74] == 52) catch @panic("test failure"); + expect(v[75] == 53) catch @panic("test failure"); + expect(v[76] == 54) catch @panic("test failure"); + expect(v[77] == 55) catch @panic("test failure"); + expect(v[78] == 56) catch @panic("test failure"); + expect(v[79] == 57) catch @panic("test failure"); + expect(v[80] == 58) catch @panic("test failure"); + expect(v[81] == 59) catch @panic("test failure"); + expect(v[82] == 60) catch @panic("test failure"); + expect(v[83] == 61) catch @panic("test failure"); + expect(v[84] == 62) catch @panic("test failure"); + expect(v[85] == 63) catch @panic("test failure"); + expect(v[86] == 64) catch @panic("test failure"); + expect(v[87] == 65) catch @panic("test failure"); + expect(v[88] == 66) catch @panic("test failure"); + expect(v[89] == 67) catch @panic("test failure"); + expect(v[90] == 68) catch @panic("test failure"); + expect(v[91] == 69) catch @panic("test failure"); + expect(v[92] == 70) catch @panic("test failure"); + expect(v[93] == 71) catch @panic("test failure"); + expect(v[94] == 72) catch @panic("test failure"); + expect(v[95] == 73) catch @panic("test failure"); + expect(v[96] == 74) catch @panic("test failure"); + expect(v[97] == 75) catch @panic("test failure"); + expect(v[98] == 76) catch @panic("test failure"); + expect(v[99] == 77) catch @panic("test failure"); + expect(v[100] == 78) catch @panic("test failure"); + expect(v[101] == 79) catch @panic("test failure"); + expect(v[102] == 80) catch @panic("test failure"); + expect(v[103] == 81) catch @panic("test failure"); + expect(v[104] == 82) catch @panic("test failure"); + expect(v[105] == 83) catch @panic("test failure"); + expect(v[106] == 84) catch @panic("test failure"); + expect(v[107] == 85) catch @panic("test failure"); + expect(v[108] == 86) catch @panic("test failure"); + expect(v[109] == 87) catch @panic("test failure"); + expect(v[110] == 88) catch @panic("test failure"); + expect(v[111] == 89) catch @panic("test failure"); + expect(v[112] == 90) catch @panic("test failure"); + expect(v[113] == 91) catch @panic("test failure"); + expect(v[114] == 92) catch @panic("test failure"); + expect(v[115] == 93) catch @panic("test failure"); + expect(v[116] == 94) catch @panic("test failure"); + expect(v[117] == 95) catch @panic("test failure"); + expect(v[118] == 96) catch @panic("test failure"); + expect(v[119] == 97) catch @panic("test failure"); + expect(v[120] == 98) catch @panic("test failure"); + expect(v[121] == 99) catch @panic("test failure"); + expect(v[122] == 0) catch @panic("test failure"); + expect(v[123] == 1) catch @panic("test failure"); + expect(v[124] == 2) catch @panic("test failure"); + expect(v[125] == 3) catch @panic("test failure"); + expect(v[126] == 4) catch @panic("test failure"); + expect(v[127] == 5) catch @panic("test failure"); + expect(v[128] == 6) catch @panic("test failure"); + expect(v[129] == 7) catch @panic("test failure"); + expect(v[130] == 8) catch @panic("test failure"); + expect(v[131] == 9) catch @panic("test failure"); + expect(v[132] == 10) catch @panic("test failure"); + expect(v[133] == 11) catch @panic("test failure"); + expect(v[134] == 12) catch @panic("test failure"); + expect(v[135] == 13) catch @panic("test failure"); + expect(v[136] == 14) catch @panic("test failure"); + expect(v[137] == 15) catch @panic("test failure"); + expect(v[138] == 16) catch @panic("test failure"); + expect(v[139] == 17) catch @panic("test failure"); + expect(v[140] == 18) catch @panic("test failure"); + expect(v[141] == 19) catch @panic("test failure"); + expect(v[142] == 20) catch @panic("test failure"); + expect(v[143] == 21) catch @panic("test failure"); + expect(v[144] == 22) catch @panic("test failure"); + expect(v[145] == 23) catch @panic("test failure"); + expect(v[146] == 24) catch @panic("test failure"); + expect(v[147] == 25) catch @panic("test failure"); + expect(v[148] == 26) catch @panic("test failure"); + expect(v[149] == 27) catch @panic("test failure"); + expect(v[150] == 28) catch @panic("test failure"); + expect(v[151] == 29) catch @panic("test failure"); + expect(v[152] == 30) catch @panic("test failure"); + expect(v[153] == 31) catch @panic("test failure"); + expect(v[154] == 32) catch @panic("test failure"); + expect(v[155] == 33) catch @panic("test failure"); + expect(v[156] == 34) catch @panic("test failure"); + expect(v[157] == 35) catch @panic("test failure"); + expect(v[158] == 36) catch @panic("test failure"); + expect(v[159] == 37) catch @panic("test failure"); + expect(v[160] == 38) catch @panic("test failure"); + expect(v[161] == 39) catch @panic("test failure"); + expect(v[162] == 40) catch @panic("test failure"); + expect(v[163] == 41) catch @panic("test failure"); + expect(v[164] == 42) catch @panic("test failure"); + expect(v[165] == 43) catch @panic("test failure"); + expect(v[166] == 44) catch @panic("test failure"); + expect(v[167] == 45) catch @panic("test failure"); + expect(v[168] == 46) catch @panic("test failure"); + expect(v[169] == 47) catch @panic("test failure"); + expect(v[170] == 48) catch @panic("test failure"); + expect(v[171] == 49) catch @panic("test failure"); + expect(v[172] == 50) catch @panic("test failure"); + expect(v[173] == 51) catch @panic("test failure"); + expect(v[174] == 52) catch @panic("test failure"); + expect(v[175] == 53) catch @panic("test failure"); + expect(v[176] == 54) catch @panic("test failure"); + expect(v[177] == 55) catch @panic("test failure"); + expect(v[178] == 56) catch @panic("test failure"); + expect(v[179] == 57) catch @panic("test failure"); + expect(v[180] == 58) catch @panic("test failure"); + expect(v[181] == 59) catch @panic("test failure"); + expect(v[182] == 60) catch @panic("test failure"); + expect(v[183] == 61) catch @panic("test failure"); + expect(v[184] == 62) catch @panic("test failure"); + expect(v[185] == 63) catch @panic("test failure"); + expect(v[186] == 64) catch @panic("test failure"); + expect(v[187] == 65) catch @panic("test failure"); + expect(v[188] == 66) catch @panic("test failure"); + expect(v[189] == 67) catch @panic("test failure"); + expect(v[190] == 68) catch @panic("test failure"); + expect(v[191] == 69) catch @panic("test failure"); + expect(i == 192) catch @panic("test failure"); +} + +extern fn c_ret_vector_192_u8() @Vector(192, u8); +extern fn c_vector_192_u8(@Vector(192, u8), usize) void; +extern fn c_test_vector_192_u8() void; + +test "@Vector(192, u8)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_192_u8(); + try expect(v[0] == 70); + try expect(v[1] == 71); + try expect(v[2] == 72); + try expect(v[3] == 73); + try expect(v[4] == 74); + try expect(v[5] == 75); + try expect(v[6] == 76); + try expect(v[7] == 77); + try expect(v[8] == 78); + try expect(v[9] == 79); + try expect(v[10] == 80); + try expect(v[11] == 81); + try expect(v[12] == 82); + try expect(v[13] == 83); + try expect(v[14] == 84); + try expect(v[15] == 85); + try expect(v[16] == 86); + try expect(v[17] == 87); + try expect(v[18] == 88); + try expect(v[19] == 89); + try expect(v[20] == 90); + try expect(v[21] == 91); + try expect(v[22] == 92); + try expect(v[23] == 93); + try expect(v[24] == 94); + try expect(v[25] == 95); + try expect(v[26] == 96); + try expect(v[27] == 97); + try expect(v[28] == 98); + try expect(v[29] == 99); + try expect(v[30] == 0); + try expect(v[31] == 1); + try expect(v[32] == 2); + try expect(v[33] == 3); + try expect(v[34] == 4); + try expect(v[35] == 5); + try expect(v[36] == 6); + try expect(v[37] == 7); + try expect(v[38] == 8); + try expect(v[39] == 9); + try expect(v[40] == 10); + try expect(v[41] == 11); + try expect(v[42] == 12); + try expect(v[43] == 13); + try expect(v[44] == 14); + try expect(v[45] == 15); + try expect(v[46] == 16); + try expect(v[47] == 17); + try expect(v[48] == 18); + try expect(v[49] == 19); + try expect(v[50] == 20); + try expect(v[51] == 21); + try expect(v[52] == 22); + try expect(v[53] == 23); + try expect(v[54] == 24); + try expect(v[55] == 25); + try expect(v[56] == 26); + try expect(v[57] == 27); + try expect(v[58] == 28); + try expect(v[59] == 29); + try expect(v[60] == 30); + try expect(v[61] == 31); + try expect(v[62] == 32); + try expect(v[63] == 33); + try expect(v[64] == 34); + try expect(v[65] == 35); + try expect(v[66] == 36); + try expect(v[67] == 37); + try expect(v[68] == 38); + try expect(v[69] == 39); + try expect(v[70] == 40); + try expect(v[71] == 41); + try expect(v[72] == 42); + try expect(v[73] == 43); + try expect(v[74] == 44); + try expect(v[75] == 45); + try expect(v[76] == 46); + try expect(v[77] == 47); + try expect(v[78] == 48); + try expect(v[79] == 49); + try expect(v[80] == 50); + try expect(v[81] == 51); + try expect(v[82] == 52); + try expect(v[83] == 53); + try expect(v[84] == 54); + try expect(v[85] == 55); + try expect(v[86] == 56); + try expect(v[87] == 57); + try expect(v[88] == 58); + try expect(v[89] == 59); + try expect(v[90] == 60); + try expect(v[91] == 61); + try expect(v[92] == 62); + try expect(v[93] == 63); + try expect(v[94] == 64); + try expect(v[95] == 65); + try expect(v[96] == 66); + try expect(v[97] == 67); + try expect(v[98] == 68); + try expect(v[99] == 69); + try expect(v[100] == 70); + try expect(v[101] == 71); + try expect(v[102] == 72); + try expect(v[103] == 73); + try expect(v[104] == 74); + try expect(v[105] == 75); + try expect(v[106] == 76); + try expect(v[107] == 77); + try expect(v[108] == 78); + try expect(v[109] == 79); + try expect(v[110] == 80); + try expect(v[111] == 81); + try expect(v[112] == 82); + try expect(v[113] == 83); + try expect(v[114] == 84); + try expect(v[115] == 85); + try expect(v[116] == 86); + try expect(v[117] == 87); + try expect(v[118] == 88); + try expect(v[119] == 89); + try expect(v[120] == 90); + try expect(v[121] == 91); + try expect(v[122] == 92); + try expect(v[123] == 93); + try expect(v[124] == 94); + try expect(v[125] == 95); + try expect(v[126] == 96); + try expect(v[127] == 97); + try expect(v[128] == 98); + try expect(v[129] == 99); + try expect(v[130] == 0); + try expect(v[131] == 1); + try expect(v[132] == 2); + try expect(v[133] == 3); + try expect(v[134] == 4); + try expect(v[135] == 5); + try expect(v[136] == 6); + try expect(v[137] == 7); + try expect(v[138] == 8); + try expect(v[139] == 9); + try expect(v[140] == 10); + try expect(v[141] == 11); + try expect(v[142] == 12); + try expect(v[143] == 13); + try expect(v[144] == 14); + try expect(v[145] == 15); + try expect(v[146] == 16); + try expect(v[147] == 17); + try expect(v[148] == 18); + try expect(v[149] == 19); + try expect(v[150] == 20); + try expect(v[151] == 21); + try expect(v[152] == 22); + try expect(v[153] == 23); + try expect(v[154] == 24); + try expect(v[155] == 25); + try expect(v[156] == 26); + try expect(v[157] == 27); + try expect(v[158] == 28); + try expect(v[159] == 29); + try expect(v[160] == 30); + try expect(v[161] == 31); + try expect(v[162] == 32); + try expect(v[163] == 33); + try expect(v[164] == 34); + try expect(v[165] == 35); + try expect(v[166] == 36); + try expect(v[167] == 37); + try expect(v[168] == 38); + try expect(v[169] == 39); + try expect(v[170] == 40); + try expect(v[171] == 41); + try expect(v[172] == 42); + try expect(v[173] == 43); + try expect(v[174] == 44); + try expect(v[175] == 45); + try expect(v[176] == 46); + try expect(v[177] == 47); + try expect(v[178] == 48); + try expect(v[179] == 49); + try expect(v[180] == 50); + try expect(v[181] == 51); + try expect(v[182] == 52); + try expect(v[183] == 53); + try expect(v[184] == 54); + try expect(v[185] == 55); + try expect(v[186] == 56); + try expect(v[187] == 57); + try expect(v[188] == 58); + try expect(v[189] == 59); + try expect(v[190] == 60); + try expect(v[191] == 61); + c_vector_192_u8(.{ + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + }, 192); + c_test_vector_192_u8(); +} + +export fn zig_ret_vector_256_u8() @Vector(256, u8) { + return .{ + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + }; +} +export fn zig_vector_256_u8(v: @Vector(256, u8), i: usize) void { + expect(v[0] == 10) catch @panic("test failure"); + expect(v[1] == 11) catch @panic("test failure"); + expect(v[2] == 12) catch @panic("test failure"); + expect(v[3] == 13) catch @panic("test failure"); + expect(v[4] == 14) catch @panic("test failure"); + expect(v[5] == 15) catch @panic("test failure"); + expect(v[6] == 16) catch @panic("test failure"); + expect(v[7] == 17) catch @panic("test failure"); + expect(v[8] == 18) catch @panic("test failure"); + expect(v[9] == 19) catch @panic("test failure"); + expect(v[10] == 20) catch @panic("test failure"); + expect(v[11] == 21) catch @panic("test failure"); + expect(v[12] == 22) catch @panic("test failure"); + expect(v[13] == 23) catch @panic("test failure"); + expect(v[14] == 24) catch @panic("test failure"); + expect(v[15] == 25) catch @panic("test failure"); + expect(v[16] == 26) catch @panic("test failure"); + expect(v[17] == 27) catch @panic("test failure"); + expect(v[18] == 28) catch @panic("test failure"); + expect(v[19] == 29) catch @panic("test failure"); + expect(v[20] == 30) catch @panic("test failure"); + expect(v[21] == 31) catch @panic("test failure"); + expect(v[22] == 32) catch @panic("test failure"); + expect(v[23] == 33) catch @panic("test failure"); + expect(v[24] == 34) catch @panic("test failure"); + expect(v[25] == 35) catch @panic("test failure"); + expect(v[26] == 36) catch @panic("test failure"); + expect(v[27] == 37) catch @panic("test failure"); + expect(v[28] == 38) catch @panic("test failure"); + expect(v[29] == 39) catch @panic("test failure"); + expect(v[30] == 40) catch @panic("test failure"); + expect(v[31] == 41) catch @panic("test failure"); + expect(v[32] == 42) catch @panic("test failure"); + expect(v[33] == 43) catch @panic("test failure"); + expect(v[34] == 44) catch @panic("test failure"); + expect(v[35] == 45) catch @panic("test failure"); + expect(v[36] == 46) catch @panic("test failure"); + expect(v[37] == 47) catch @panic("test failure"); + expect(v[38] == 48) catch @panic("test failure"); + expect(v[39] == 49) catch @panic("test failure"); + expect(v[40] == 50) catch @panic("test failure"); + expect(v[41] == 51) catch @panic("test failure"); + expect(v[42] == 52) catch @panic("test failure"); + expect(v[43] == 53) catch @panic("test failure"); + expect(v[44] == 54) catch @panic("test failure"); + expect(v[45] == 55) catch @panic("test failure"); + expect(v[46] == 56) catch @panic("test failure"); + expect(v[47] == 57) catch @panic("test failure"); + expect(v[48] == 58) catch @panic("test failure"); + expect(v[49] == 59) catch @panic("test failure"); + expect(v[50] == 60) catch @panic("test failure"); + expect(v[51] == 61) catch @panic("test failure"); + expect(v[52] == 62) catch @panic("test failure"); + expect(v[53] == 63) catch @panic("test failure"); + expect(v[54] == 64) catch @panic("test failure"); + expect(v[55] == 65) catch @panic("test failure"); + expect(v[56] == 66) catch @panic("test failure"); + expect(v[57] == 67) catch @panic("test failure"); + expect(v[58] == 68) catch @panic("test failure"); + expect(v[59] == 69) catch @panic("test failure"); + expect(v[60] == 70) catch @panic("test failure"); + expect(v[61] == 71) catch @panic("test failure"); + expect(v[62] == 72) catch @panic("test failure"); + expect(v[63] == 73) catch @panic("test failure"); + expect(v[64] == 74) catch @panic("test failure"); + expect(v[65] == 75) catch @panic("test failure"); + expect(v[66] == 76) catch @panic("test failure"); + expect(v[67] == 77) catch @panic("test failure"); + expect(v[68] == 78) catch @panic("test failure"); + expect(v[69] == 79) catch @panic("test failure"); + expect(v[70] == 80) catch @panic("test failure"); + expect(v[71] == 81) catch @panic("test failure"); + expect(v[72] == 82) catch @panic("test failure"); + expect(v[73] == 83) catch @panic("test failure"); + expect(v[74] == 84) catch @panic("test failure"); + expect(v[75] == 85) catch @panic("test failure"); + expect(v[76] == 86) catch @panic("test failure"); + expect(v[77] == 87) catch @panic("test failure"); + expect(v[78] == 88) catch @panic("test failure"); + expect(v[79] == 89) catch @panic("test failure"); + expect(v[80] == 90) catch @panic("test failure"); + expect(v[81] == 91) catch @panic("test failure"); + expect(v[82] == 92) catch @panic("test failure"); + expect(v[83] == 93) catch @panic("test failure"); + expect(v[84] == 94) catch @panic("test failure"); + expect(v[85] == 95) catch @panic("test failure"); + expect(v[86] == 96) catch @panic("test failure"); + expect(v[87] == 97) catch @panic("test failure"); + expect(v[88] == 98) catch @panic("test failure"); + expect(v[89] == 99) catch @panic("test failure"); + expect(v[90] == 0) catch @panic("test failure"); + expect(v[91] == 1) catch @panic("test failure"); + expect(v[92] == 2) catch @panic("test failure"); + expect(v[93] == 3) catch @panic("test failure"); + expect(v[94] == 4) catch @panic("test failure"); + expect(v[95] == 5) catch @panic("test failure"); + expect(v[96] == 6) catch @panic("test failure"); + expect(v[97] == 7) catch @panic("test failure"); + expect(v[98] == 8) catch @panic("test failure"); + expect(v[99] == 9) catch @panic("test failure"); + expect(v[100] == 10) catch @panic("test failure"); + expect(v[101] == 11) catch @panic("test failure"); + expect(v[102] == 12) catch @panic("test failure"); + expect(v[103] == 13) catch @panic("test failure"); + expect(v[104] == 14) catch @panic("test failure"); + expect(v[105] == 15) catch @panic("test failure"); + expect(v[106] == 16) catch @panic("test failure"); + expect(v[107] == 17) catch @panic("test failure"); + expect(v[108] == 18) catch @panic("test failure"); + expect(v[109] == 19) catch @panic("test failure"); + expect(v[110] == 20) catch @panic("test failure"); + expect(v[111] == 21) catch @panic("test failure"); + expect(v[112] == 22) catch @panic("test failure"); + expect(v[113] == 23) catch @panic("test failure"); + expect(v[114] == 24) catch @panic("test failure"); + expect(v[115] == 25) catch @panic("test failure"); + expect(v[116] == 26) catch @panic("test failure"); + expect(v[117] == 27) catch @panic("test failure"); + expect(v[118] == 28) catch @panic("test failure"); + expect(v[119] == 29) catch @panic("test failure"); + expect(v[120] == 30) catch @panic("test failure"); + expect(v[121] == 31) catch @panic("test failure"); + expect(v[122] == 32) catch @panic("test failure"); + expect(v[123] == 33) catch @panic("test failure"); + expect(v[124] == 34) catch @panic("test failure"); + expect(v[125] == 35) catch @panic("test failure"); + expect(v[126] == 36) catch @panic("test failure"); + expect(v[127] == 37) catch @panic("test failure"); + expect(v[128] == 38) catch @panic("test failure"); + expect(v[129] == 39) catch @panic("test failure"); + expect(v[130] == 40) catch @panic("test failure"); + expect(v[131] == 41) catch @panic("test failure"); + expect(v[132] == 42) catch @panic("test failure"); + expect(v[133] == 43) catch @panic("test failure"); + expect(v[134] == 44) catch @panic("test failure"); + expect(v[135] == 45) catch @panic("test failure"); + expect(v[136] == 46) catch @panic("test failure"); + expect(v[137] == 47) catch @panic("test failure"); + expect(v[138] == 48) catch @panic("test failure"); + expect(v[139] == 49) catch @panic("test failure"); + expect(v[140] == 50) catch @panic("test failure"); + expect(v[141] == 51) catch @panic("test failure"); + expect(v[142] == 52) catch @panic("test failure"); + expect(v[143] == 53) catch @panic("test failure"); + expect(v[144] == 54) catch @panic("test failure"); + expect(v[145] == 55) catch @panic("test failure"); + expect(v[146] == 56) catch @panic("test failure"); + expect(v[147] == 57) catch @panic("test failure"); + expect(v[148] == 58) catch @panic("test failure"); + expect(v[149] == 59) catch @panic("test failure"); + expect(v[150] == 60) catch @panic("test failure"); + expect(v[151] == 61) catch @panic("test failure"); + expect(v[152] == 62) catch @panic("test failure"); + expect(v[153] == 63) catch @panic("test failure"); + expect(v[154] == 64) catch @panic("test failure"); + expect(v[155] == 65) catch @panic("test failure"); + expect(v[156] == 66) catch @panic("test failure"); + expect(v[157] == 67) catch @panic("test failure"); + expect(v[158] == 68) catch @panic("test failure"); + expect(v[159] == 69) catch @panic("test failure"); + expect(v[160] == 70) catch @panic("test failure"); + expect(v[161] == 71) catch @panic("test failure"); + expect(v[162] == 72) catch @panic("test failure"); + expect(v[163] == 73) catch @panic("test failure"); + expect(v[164] == 74) catch @panic("test failure"); + expect(v[165] == 75) catch @panic("test failure"); + expect(v[166] == 76) catch @panic("test failure"); + expect(v[167] == 77) catch @panic("test failure"); + expect(v[168] == 78) catch @panic("test failure"); + expect(v[169] == 79) catch @panic("test failure"); + expect(v[170] == 80) catch @panic("test failure"); + expect(v[171] == 81) catch @panic("test failure"); + expect(v[172] == 82) catch @panic("test failure"); + expect(v[173] == 83) catch @panic("test failure"); + expect(v[174] == 84) catch @panic("test failure"); + expect(v[175] == 85) catch @panic("test failure"); + expect(v[176] == 86) catch @panic("test failure"); + expect(v[177] == 87) catch @panic("test failure"); + expect(v[178] == 88) catch @panic("test failure"); + expect(v[179] == 89) catch @panic("test failure"); + expect(v[180] == 90) catch @panic("test failure"); + expect(v[181] == 91) catch @panic("test failure"); + expect(v[182] == 92) catch @panic("test failure"); + expect(v[183] == 93) catch @panic("test failure"); + expect(v[184] == 94) catch @panic("test failure"); + expect(v[185] == 95) catch @panic("test failure"); + expect(v[186] == 96) catch @panic("test failure"); + expect(v[187] == 97) catch @panic("test failure"); + expect(v[188] == 98) catch @panic("test failure"); + expect(v[189] == 99) catch @panic("test failure"); + expect(v[190] == 0) catch @panic("test failure"); + expect(v[191] == 1) catch @panic("test failure"); + expect(v[192] == 2) catch @panic("test failure"); + expect(v[193] == 3) catch @panic("test failure"); + expect(v[194] == 4) catch @panic("test failure"); + expect(v[195] == 5) catch @panic("test failure"); + expect(v[196] == 6) catch @panic("test failure"); + expect(v[197] == 7) catch @panic("test failure"); + expect(v[198] == 8) catch @panic("test failure"); + expect(v[199] == 9) catch @panic("test failure"); + expect(v[200] == 10) catch @panic("test failure"); + expect(v[201] == 11) catch @panic("test failure"); + expect(v[202] == 12) catch @panic("test failure"); + expect(v[203] == 13) catch @panic("test failure"); + expect(v[204] == 14) catch @panic("test failure"); + expect(v[205] == 15) catch @panic("test failure"); + expect(v[206] == 16) catch @panic("test failure"); + expect(v[207] == 17) catch @panic("test failure"); + expect(v[208] == 18) catch @panic("test failure"); + expect(v[209] == 19) catch @panic("test failure"); + expect(v[210] == 20) catch @panic("test failure"); + expect(v[211] == 21) catch @panic("test failure"); + expect(v[212] == 22) catch @panic("test failure"); + expect(v[213] == 23) catch @panic("test failure"); + expect(v[214] == 24) catch @panic("test failure"); + expect(v[215] == 25) catch @panic("test failure"); + expect(v[216] == 26) catch @panic("test failure"); + expect(v[217] == 27) catch @panic("test failure"); + expect(v[218] == 28) catch @panic("test failure"); + expect(v[219] == 29) catch @panic("test failure"); + expect(v[220] == 30) catch @panic("test failure"); + expect(v[221] == 31) catch @panic("test failure"); + expect(v[222] == 32) catch @panic("test failure"); + expect(v[223] == 33) catch @panic("test failure"); + expect(v[224] == 34) catch @panic("test failure"); + expect(v[225] == 35) catch @panic("test failure"); + expect(v[226] == 36) catch @panic("test failure"); + expect(v[227] == 37) catch @panic("test failure"); + expect(v[228] == 38) catch @panic("test failure"); + expect(v[229] == 39) catch @panic("test failure"); + expect(v[230] == 40) catch @panic("test failure"); + expect(v[231] == 41) catch @panic("test failure"); + expect(v[232] == 42) catch @panic("test failure"); + expect(v[233] == 43) catch @panic("test failure"); + expect(v[234] == 44) catch @panic("test failure"); + expect(v[235] == 45) catch @panic("test failure"); + expect(v[236] == 46) catch @panic("test failure"); + expect(v[237] == 47) catch @panic("test failure"); + expect(v[238] == 48) catch @panic("test failure"); + expect(v[239] == 49) catch @panic("test failure"); + expect(v[240] == 50) catch @panic("test failure"); + expect(v[241] == 51) catch @panic("test failure"); + expect(v[242] == 52) catch @panic("test failure"); + expect(v[243] == 53) catch @panic("test failure"); + expect(v[244] == 54) catch @panic("test failure"); + expect(v[245] == 55) catch @panic("test failure"); + expect(v[246] == 56) catch @panic("test failure"); + expect(v[247] == 57) catch @panic("test failure"); + expect(v[248] == 58) catch @panic("test failure"); + expect(v[249] == 59) catch @panic("test failure"); + expect(v[250] == 60) catch @panic("test failure"); + expect(v[251] == 61) catch @panic("test failure"); + expect(v[252] == 62) catch @panic("test failure"); + expect(v[253] == 63) catch @panic("test failure"); + expect(v[254] == 64) catch @panic("test failure"); + expect(v[255] == 65) catch @panic("test failure"); + expect(i == 256) catch @panic("test failure"); +} + +extern fn c_ret_vector_256_u8() @Vector(256, u8); +extern fn c_vector_256_u8(@Vector(256, u8), usize) void; +extern fn c_test_vector_256_u8() void; + +test "@Vector(256, u8)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 67); + try expect(v[2] == 68); + try expect(v[3] == 69); + try expect(v[4] == 70); + try expect(v[5] == 71); + try expect(v[6] == 72); + try expect(v[7] == 73); + try expect(v[8] == 74); + try expect(v[9] == 75); + try expect(v[10] == 76); + try expect(v[11] == 77); + try expect(v[12] == 78); + try expect(v[13] == 79); + try expect(v[14] == 80); + try expect(v[15] == 81); + try expect(v[16] == 82); + try expect(v[17] == 83); + try expect(v[18] == 84); + try expect(v[19] == 85); + try expect(v[20] == 86); + try expect(v[21] == 87); + try expect(v[22] == 88); + try expect(v[23] == 89); + try expect(v[24] == 90); + try expect(v[25] == 91); + try expect(v[26] == 92); + try expect(v[27] == 93); + try expect(v[28] == 94); + try expect(v[29] == 95); + try expect(v[30] == 96); + try expect(v[31] == 97); + try expect(v[32] == 98); + try expect(v[33] == 99); + try expect(v[34] == 0); + try expect(v[35] == 1); + try expect(v[36] == 2); + try expect(v[37] == 3); + try expect(v[38] == 4); + try expect(v[39] == 5); + try expect(v[40] == 6); + try expect(v[41] == 7); + try expect(v[42] == 8); + try expect(v[43] == 9); + try expect(v[44] == 10); + try expect(v[45] == 11); + try expect(v[46] == 12); + try expect(v[47] == 13); + try expect(v[48] == 14); + try expect(v[49] == 15); + try expect(v[50] == 16); + try expect(v[51] == 17); + try expect(v[52] == 18); + try expect(v[53] == 19); + try expect(v[54] == 20); + try expect(v[55] == 21); + try expect(v[56] == 22); + try expect(v[57] == 23); + try expect(v[58] == 24); + try expect(v[59] == 25); + try expect(v[60] == 26); + try expect(v[61] == 27); + try expect(v[62] == 28); + try expect(v[63] == 29); + try expect(v[64] == 30); + try expect(v[65] == 31); + try expect(v[66] == 32); + try expect(v[67] == 33); + try expect(v[68] == 34); + try expect(v[69] == 35); + try expect(v[70] == 36); + try expect(v[71] == 37); + try expect(v[72] == 38); + try expect(v[73] == 39); + try expect(v[74] == 40); + try expect(v[75] == 41); + try expect(v[76] == 42); + try expect(v[77] == 43); + try expect(v[78] == 44); + try expect(v[79] == 45); + try expect(v[80] == 46); + try expect(v[81] == 47); + try expect(v[82] == 48); + try expect(v[83] == 49); + try expect(v[84] == 50); + try expect(v[85] == 51); + try expect(v[86] == 52); + try expect(v[87] == 53); + try expect(v[88] == 54); + try expect(v[89] == 55); + try expect(v[90] == 56); + try expect(v[91] == 57); + try expect(v[92] == 58); + try expect(v[93] == 59); + try expect(v[94] == 60); + try expect(v[95] == 61); + try expect(v[96] == 62); + try expect(v[97] == 63); + try expect(v[98] == 64); + try expect(v[99] == 65); + try expect(v[100] == 66); + try expect(v[101] == 67); + try expect(v[102] == 68); + try expect(v[103] == 69); + try expect(v[104] == 70); + try expect(v[105] == 71); + try expect(v[106] == 72); + try expect(v[107] == 73); + try expect(v[108] == 74); + try expect(v[109] == 75); + try expect(v[110] == 76); + try expect(v[111] == 77); + try expect(v[112] == 78); + try expect(v[113] == 79); + try expect(v[114] == 80); + try expect(v[115] == 81); + try expect(v[116] == 82); + try expect(v[117] == 83); + try expect(v[118] == 84); + try expect(v[119] == 85); + try expect(v[120] == 86); + try expect(v[121] == 87); + try expect(v[122] == 88); + try expect(v[123] == 89); + try expect(v[124] == 90); + try expect(v[125] == 91); + try expect(v[126] == 92); + try expect(v[127] == 93); + try expect(v[128] == 94); + try expect(v[129] == 95); + try expect(v[130] == 96); + try expect(v[131] == 97); + try expect(v[132] == 98); + try expect(v[133] == 99); + try expect(v[134] == 0); + try expect(v[135] == 1); + try expect(v[136] == 2); + try expect(v[137] == 3); + try expect(v[138] == 4); + try expect(v[139] == 5); + try expect(v[140] == 6); + try expect(v[141] == 7); + try expect(v[142] == 8); + try expect(v[143] == 9); + try expect(v[144] == 10); + try expect(v[145] == 11); + try expect(v[146] == 12); + try expect(v[147] == 13); + try expect(v[148] == 14); + try expect(v[149] == 15); + try expect(v[150] == 16); + try expect(v[151] == 17); + try expect(v[152] == 18); + try expect(v[153] == 19); + try expect(v[154] == 20); + try expect(v[155] == 21); + try expect(v[156] == 22); + try expect(v[157] == 23); + try expect(v[158] == 24); + try expect(v[159] == 25); + try expect(v[160] == 26); + try expect(v[161] == 27); + try expect(v[162] == 28); + try expect(v[163] == 29); + try expect(v[164] == 30); + try expect(v[165] == 31); + try expect(v[166] == 32); + try expect(v[167] == 33); + try expect(v[168] == 34); + try expect(v[169] == 35); + try expect(v[170] == 36); + try expect(v[171] == 37); + try expect(v[172] == 38); + try expect(v[173] == 39); + try expect(v[174] == 40); + try expect(v[175] == 41); + try expect(v[176] == 42); + try expect(v[177] == 43); + try expect(v[178] == 44); + try expect(v[179] == 45); + try expect(v[180] == 46); + try expect(v[181] == 47); + try expect(v[182] == 48); + try expect(v[183] == 49); + try expect(v[184] == 50); + try expect(v[185] == 51); + try expect(v[186] == 52); + try expect(v[187] == 53); + try expect(v[188] == 54); + try expect(v[189] == 55); + try expect(v[190] == 56); + try expect(v[191] == 57); + try expect(v[192] == 58); + try expect(v[193] == 59); + try expect(v[194] == 60); + try expect(v[195] == 61); + try expect(v[196] == 62); + try expect(v[197] == 63); + try expect(v[198] == 64); + try expect(v[199] == 65); + try expect(v[200] == 66); + try expect(v[201] == 67); + try expect(v[202] == 68); + try expect(v[203] == 69); + try expect(v[204] == 70); + try expect(v[205] == 71); + try expect(v[206] == 72); + try expect(v[207] == 73); + try expect(v[208] == 74); + try expect(v[209] == 75); + try expect(v[210] == 76); + try expect(v[211] == 77); + try expect(v[212] == 78); + try expect(v[213] == 79); + try expect(v[214] == 80); + try expect(v[215] == 81); + try expect(v[216] == 82); + try expect(v[217] == 83); + try expect(v[218] == 84); + try expect(v[219] == 85); + try expect(v[220] == 86); + try expect(v[221] == 87); + try expect(v[222] == 88); + try expect(v[223] == 89); + try expect(v[224] == 90); + try expect(v[225] == 91); + try expect(v[226] == 92); + try expect(v[227] == 93); + try expect(v[228] == 94); + try expect(v[229] == 95); + try expect(v[230] == 96); + try expect(v[231] == 97); + try expect(v[232] == 98); + try expect(v[233] == 99); + try expect(v[234] == 0); + try expect(v[235] == 1); + try expect(v[236] == 2); + try expect(v[237] == 3); + try expect(v[238] == 4); + try expect(v[239] == 5); + try expect(v[240] == 6); + try expect(v[241] == 7); + try expect(v[242] == 8); + try expect(v[243] == 9); + try expect(v[244] == 10); + try expect(v[245] == 11); + try expect(v[246] == 12); + try expect(v[247] == 13); + try expect(v[248] == 14); + try expect(v[249] == 15); + try expect(v[250] == 16); + try expect(v[251] == 17); + try expect(v[252] == 18); + try expect(v[253] == 19); + try expect(v[254] == 20); + try expect(v[255] == 21); + c_vector_256_u8(.{ + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + }, 256); + c_test_vector_256_u8(); +} + +export fn zig_ret_vector_384_u8() @Vector(384, u8) { + return .{ + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + }; +} +export fn zig_vector_384_u8(v: @Vector(384, u8), i: usize) void { + expect(v[0] == 62) catch @panic("test failure"); + expect(v[1] == 63) catch @panic("test failure"); + expect(v[2] == 64) catch @panic("test failure"); + expect(v[3] == 65) catch @panic("test failure"); + expect(v[4] == 66) catch @panic("test failure"); + expect(v[5] == 67) catch @panic("test failure"); + expect(v[6] == 68) catch @panic("test failure"); + expect(v[7] == 69) catch @panic("test failure"); + expect(v[8] == 70) catch @panic("test failure"); + expect(v[9] == 71) catch @panic("test failure"); + expect(v[10] == 72) catch @panic("test failure"); + expect(v[11] == 73) catch @panic("test failure"); + expect(v[12] == 74) catch @panic("test failure"); + expect(v[13] == 75) catch @panic("test failure"); + expect(v[14] == 76) catch @panic("test failure"); + expect(v[15] == 77) catch @panic("test failure"); + expect(v[16] == 78) catch @panic("test failure"); + expect(v[17] == 79) catch @panic("test failure"); + expect(v[18] == 80) catch @panic("test failure"); + expect(v[19] == 81) catch @panic("test failure"); + expect(v[20] == 82) catch @panic("test failure"); + expect(v[21] == 83) catch @panic("test failure"); + expect(v[22] == 84) catch @panic("test failure"); + expect(v[23] == 85) catch @panic("test failure"); + expect(v[24] == 86) catch @panic("test failure"); + expect(v[25] == 87) catch @panic("test failure"); + expect(v[26] == 88) catch @panic("test failure"); + expect(v[27] == 89) catch @panic("test failure"); + expect(v[28] == 90) catch @panic("test failure"); + expect(v[29] == 91) catch @panic("test failure"); + expect(v[30] == 92) catch @panic("test failure"); + expect(v[31] == 93) catch @panic("test failure"); + expect(v[32] == 94) catch @panic("test failure"); + expect(v[33] == 95) catch @panic("test failure"); + expect(v[34] == 96) catch @panic("test failure"); + expect(v[35] == 97) catch @panic("test failure"); + expect(v[36] == 98) catch @panic("test failure"); + expect(v[37] == 99) catch @panic("test failure"); + expect(v[38] == 0) catch @panic("test failure"); + expect(v[39] == 1) catch @panic("test failure"); + expect(v[40] == 2) catch @panic("test failure"); + expect(v[41] == 3) catch @panic("test failure"); + expect(v[42] == 4) catch @panic("test failure"); + expect(v[43] == 5) catch @panic("test failure"); + expect(v[44] == 6) catch @panic("test failure"); + expect(v[45] == 7) catch @panic("test failure"); + expect(v[46] == 8) catch @panic("test failure"); + expect(v[47] == 9) catch @panic("test failure"); + expect(v[48] == 10) catch @panic("test failure"); + expect(v[49] == 11) catch @panic("test failure"); + expect(v[50] == 12) catch @panic("test failure"); + expect(v[51] == 13) catch @panic("test failure"); + expect(v[52] == 14) catch @panic("test failure"); + expect(v[53] == 15) catch @panic("test failure"); + expect(v[54] == 16) catch @panic("test failure"); + expect(v[55] == 17) catch @panic("test failure"); + expect(v[56] == 18) catch @panic("test failure"); + expect(v[57] == 19) catch @panic("test failure"); + expect(v[58] == 20) catch @panic("test failure"); + expect(v[59] == 21) catch @panic("test failure"); + expect(v[60] == 22) catch @panic("test failure"); + expect(v[61] == 23) catch @panic("test failure"); + expect(v[62] == 24) catch @panic("test failure"); + expect(v[63] == 25) catch @panic("test failure"); + expect(v[64] == 26) catch @panic("test failure"); + expect(v[65] == 27) catch @panic("test failure"); + expect(v[66] == 28) catch @panic("test failure"); + expect(v[67] == 29) catch @panic("test failure"); + expect(v[68] == 30) catch @panic("test failure"); + expect(v[69] == 31) catch @panic("test failure"); + expect(v[70] == 32) catch @panic("test failure"); + expect(v[71] == 33) catch @panic("test failure"); + expect(v[72] == 34) catch @panic("test failure"); + expect(v[73] == 35) catch @panic("test failure"); + expect(v[74] == 36) catch @panic("test failure"); + expect(v[75] == 37) catch @panic("test failure"); + expect(v[76] == 38) catch @panic("test failure"); + expect(v[77] == 39) catch @panic("test failure"); + expect(v[78] == 40) catch @panic("test failure"); + expect(v[79] == 41) catch @panic("test failure"); + expect(v[80] == 42) catch @panic("test failure"); + expect(v[81] == 43) catch @panic("test failure"); + expect(v[82] == 44) catch @panic("test failure"); + expect(v[83] == 45) catch @panic("test failure"); + expect(v[84] == 46) catch @panic("test failure"); + expect(v[85] == 47) catch @panic("test failure"); + expect(v[86] == 48) catch @panic("test failure"); + expect(v[87] == 49) catch @panic("test failure"); + expect(v[88] == 50) catch @panic("test failure"); + expect(v[89] == 51) catch @panic("test failure"); + expect(v[90] == 52) catch @panic("test failure"); + expect(v[91] == 53) catch @panic("test failure"); + expect(v[92] == 54) catch @panic("test failure"); + expect(v[93] == 55) catch @panic("test failure"); + expect(v[94] == 56) catch @panic("test failure"); + expect(v[95] == 57) catch @panic("test failure"); + expect(v[96] == 58) catch @panic("test failure"); + expect(v[97] == 59) catch @panic("test failure"); + expect(v[98] == 60) catch @panic("test failure"); + expect(v[99] == 61) catch @panic("test failure"); + expect(v[100] == 62) catch @panic("test failure"); + expect(v[101] == 63) catch @panic("test failure"); + expect(v[102] == 64) catch @panic("test failure"); + expect(v[103] == 65) catch @panic("test failure"); + expect(v[104] == 66) catch @panic("test failure"); + expect(v[105] == 67) catch @panic("test failure"); + expect(v[106] == 68) catch @panic("test failure"); + expect(v[107] == 69) catch @panic("test failure"); + expect(v[108] == 70) catch @panic("test failure"); + expect(v[109] == 71) catch @panic("test failure"); + expect(v[110] == 72) catch @panic("test failure"); + expect(v[111] == 73) catch @panic("test failure"); + expect(v[112] == 74) catch @panic("test failure"); + expect(v[113] == 75) catch @panic("test failure"); + expect(v[114] == 76) catch @panic("test failure"); + expect(v[115] == 77) catch @panic("test failure"); + expect(v[116] == 78) catch @panic("test failure"); + expect(v[117] == 79) catch @panic("test failure"); + expect(v[118] == 80) catch @panic("test failure"); + expect(v[119] == 81) catch @panic("test failure"); + expect(v[120] == 82) catch @panic("test failure"); + expect(v[121] == 83) catch @panic("test failure"); + expect(v[122] == 84) catch @panic("test failure"); + expect(v[123] == 85) catch @panic("test failure"); + expect(v[124] == 86) catch @panic("test failure"); + expect(v[125] == 87) catch @panic("test failure"); + expect(v[126] == 88) catch @panic("test failure"); + expect(v[127] == 89) catch @panic("test failure"); + expect(v[128] == 90) catch @panic("test failure"); + expect(v[129] == 91) catch @panic("test failure"); + expect(v[130] == 92) catch @panic("test failure"); + expect(v[131] == 93) catch @panic("test failure"); + expect(v[132] == 94) catch @panic("test failure"); + expect(v[133] == 95) catch @panic("test failure"); + expect(v[134] == 96) catch @panic("test failure"); + expect(v[135] == 97) catch @panic("test failure"); + expect(v[136] == 98) catch @panic("test failure"); + expect(v[137] == 99) catch @panic("test failure"); + expect(v[138] == 0) catch @panic("test failure"); + expect(v[139] == 1) catch @panic("test failure"); + expect(v[140] == 2) catch @panic("test failure"); + expect(v[141] == 3) catch @panic("test failure"); + expect(v[142] == 4) catch @panic("test failure"); + expect(v[143] == 5) catch @panic("test failure"); + expect(v[144] == 6) catch @panic("test failure"); + expect(v[145] == 7) catch @panic("test failure"); + expect(v[146] == 8) catch @panic("test failure"); + expect(v[147] == 9) catch @panic("test failure"); + expect(v[148] == 10) catch @panic("test failure"); + expect(v[149] == 11) catch @panic("test failure"); + expect(v[150] == 12) catch @panic("test failure"); + expect(v[151] == 13) catch @panic("test failure"); + expect(v[152] == 14) catch @panic("test failure"); + expect(v[153] == 15) catch @panic("test failure"); + expect(v[154] == 16) catch @panic("test failure"); + expect(v[155] == 17) catch @panic("test failure"); + expect(v[156] == 18) catch @panic("test failure"); + expect(v[157] == 19) catch @panic("test failure"); + expect(v[158] == 20) catch @panic("test failure"); + expect(v[159] == 21) catch @panic("test failure"); + expect(v[160] == 22) catch @panic("test failure"); + expect(v[161] == 23) catch @panic("test failure"); + expect(v[162] == 24) catch @panic("test failure"); + expect(v[163] == 25) catch @panic("test failure"); + expect(v[164] == 26) catch @panic("test failure"); + expect(v[165] == 27) catch @panic("test failure"); + expect(v[166] == 28) catch @panic("test failure"); + expect(v[167] == 29) catch @panic("test failure"); + expect(v[168] == 30) catch @panic("test failure"); + expect(v[169] == 31) catch @panic("test failure"); + expect(v[170] == 32) catch @panic("test failure"); + expect(v[171] == 33) catch @panic("test failure"); + expect(v[172] == 34) catch @panic("test failure"); + expect(v[173] == 35) catch @panic("test failure"); + expect(v[174] == 36) catch @panic("test failure"); + expect(v[175] == 37) catch @panic("test failure"); + expect(v[176] == 38) catch @panic("test failure"); + expect(v[177] == 39) catch @panic("test failure"); + expect(v[178] == 40) catch @panic("test failure"); + expect(v[179] == 41) catch @panic("test failure"); + expect(v[180] == 42) catch @panic("test failure"); + expect(v[181] == 43) catch @panic("test failure"); + expect(v[182] == 44) catch @panic("test failure"); + expect(v[183] == 45) catch @panic("test failure"); + expect(v[184] == 46) catch @panic("test failure"); + expect(v[185] == 47) catch @panic("test failure"); + expect(v[186] == 48) catch @panic("test failure"); + expect(v[187] == 49) catch @panic("test failure"); + expect(v[188] == 50) catch @panic("test failure"); + expect(v[189] == 51) catch @panic("test failure"); + expect(v[190] == 52) catch @panic("test failure"); + expect(v[191] == 53) catch @panic("test failure"); + expect(v[192] == 54) catch @panic("test failure"); + expect(v[193] == 55) catch @panic("test failure"); + expect(v[194] == 56) catch @panic("test failure"); + expect(v[195] == 57) catch @panic("test failure"); + expect(v[196] == 58) catch @panic("test failure"); + expect(v[197] == 59) catch @panic("test failure"); + expect(v[198] == 60) catch @panic("test failure"); + expect(v[199] == 61) catch @panic("test failure"); + expect(v[200] == 62) catch @panic("test failure"); + expect(v[201] == 63) catch @panic("test failure"); + expect(v[202] == 64) catch @panic("test failure"); + expect(v[203] == 65) catch @panic("test failure"); + expect(v[204] == 66) catch @panic("test failure"); + expect(v[205] == 67) catch @panic("test failure"); + expect(v[206] == 68) catch @panic("test failure"); + expect(v[207] == 69) catch @panic("test failure"); + expect(v[208] == 70) catch @panic("test failure"); + expect(v[209] == 71) catch @panic("test failure"); + expect(v[210] == 72) catch @panic("test failure"); + expect(v[211] == 73) catch @panic("test failure"); + expect(v[212] == 74) catch @panic("test failure"); + expect(v[213] == 75) catch @panic("test failure"); + expect(v[214] == 76) catch @panic("test failure"); + expect(v[215] == 77) catch @panic("test failure"); + expect(v[216] == 78) catch @panic("test failure"); + expect(v[217] == 79) catch @panic("test failure"); + expect(v[218] == 80) catch @panic("test failure"); + expect(v[219] == 81) catch @panic("test failure"); + expect(v[220] == 82) catch @panic("test failure"); + expect(v[221] == 83) catch @panic("test failure"); + expect(v[222] == 84) catch @panic("test failure"); + expect(v[223] == 85) catch @panic("test failure"); + expect(v[224] == 86) catch @panic("test failure"); + expect(v[225] == 87) catch @panic("test failure"); + expect(v[226] == 88) catch @panic("test failure"); + expect(v[227] == 89) catch @panic("test failure"); + expect(v[228] == 90) catch @panic("test failure"); + expect(v[229] == 91) catch @panic("test failure"); + expect(v[230] == 92) catch @panic("test failure"); + expect(v[231] == 93) catch @panic("test failure"); + expect(v[232] == 94) catch @panic("test failure"); + expect(v[233] == 95) catch @panic("test failure"); + expect(v[234] == 96) catch @panic("test failure"); + expect(v[235] == 97) catch @panic("test failure"); + expect(v[236] == 98) catch @panic("test failure"); + expect(v[237] == 99) catch @panic("test failure"); + expect(v[238] == 0) catch @panic("test failure"); + expect(v[239] == 1) catch @panic("test failure"); + expect(v[240] == 2) catch @panic("test failure"); + expect(v[241] == 3) catch @panic("test failure"); + expect(v[242] == 4) catch @panic("test failure"); + expect(v[243] == 5) catch @panic("test failure"); + expect(v[244] == 6) catch @panic("test failure"); + expect(v[245] == 7) catch @panic("test failure"); + expect(v[246] == 8) catch @panic("test failure"); + expect(v[247] == 9) catch @panic("test failure"); + expect(v[248] == 10) catch @panic("test failure"); + expect(v[249] == 11) catch @panic("test failure"); + expect(v[250] == 12) catch @panic("test failure"); + expect(v[251] == 13) catch @panic("test failure"); + expect(v[252] == 14) catch @panic("test failure"); + expect(v[253] == 15) catch @panic("test failure"); + expect(v[254] == 16) catch @panic("test failure"); + expect(v[255] == 17) catch @panic("test failure"); + expect(v[256] == 18) catch @panic("test failure"); + expect(v[257] == 19) catch @panic("test failure"); + expect(v[258] == 20) catch @panic("test failure"); + expect(v[259] == 21) catch @panic("test failure"); + expect(v[260] == 22) catch @panic("test failure"); + expect(v[261] == 23) catch @panic("test failure"); + expect(v[262] == 24) catch @panic("test failure"); + expect(v[263] == 25) catch @panic("test failure"); + expect(v[264] == 26) catch @panic("test failure"); + expect(v[265] == 27) catch @panic("test failure"); + expect(v[266] == 28) catch @panic("test failure"); + expect(v[267] == 29) catch @panic("test failure"); + expect(v[268] == 30) catch @panic("test failure"); + expect(v[269] == 31) catch @panic("test failure"); + expect(v[270] == 32) catch @panic("test failure"); + expect(v[271] == 33) catch @panic("test failure"); + expect(v[272] == 34) catch @panic("test failure"); + expect(v[273] == 35) catch @panic("test failure"); + expect(v[274] == 36) catch @panic("test failure"); + expect(v[275] == 37) catch @panic("test failure"); + expect(v[276] == 38) catch @panic("test failure"); + expect(v[277] == 39) catch @panic("test failure"); + expect(v[278] == 40) catch @panic("test failure"); + expect(v[279] == 41) catch @panic("test failure"); + expect(v[280] == 42) catch @panic("test failure"); + expect(v[281] == 43) catch @panic("test failure"); + expect(v[282] == 44) catch @panic("test failure"); + expect(v[283] == 45) catch @panic("test failure"); + expect(v[284] == 46) catch @panic("test failure"); + expect(v[285] == 47) catch @panic("test failure"); + expect(v[286] == 48) catch @panic("test failure"); + expect(v[287] == 49) catch @panic("test failure"); + expect(v[288] == 50) catch @panic("test failure"); + expect(v[289] == 51) catch @panic("test failure"); + expect(v[290] == 52) catch @panic("test failure"); + expect(v[291] == 53) catch @panic("test failure"); + expect(v[292] == 54) catch @panic("test failure"); + expect(v[293] == 55) catch @panic("test failure"); + expect(v[294] == 56) catch @panic("test failure"); + expect(v[295] == 57) catch @panic("test failure"); + expect(v[296] == 58) catch @panic("test failure"); + expect(v[297] == 59) catch @panic("test failure"); + expect(v[298] == 60) catch @panic("test failure"); + expect(v[299] == 61) catch @panic("test failure"); + expect(v[300] == 62) catch @panic("test failure"); + expect(v[301] == 63) catch @panic("test failure"); + expect(v[302] == 64) catch @panic("test failure"); + expect(v[303] == 65) catch @panic("test failure"); + expect(v[304] == 66) catch @panic("test failure"); + expect(v[305] == 67) catch @panic("test failure"); + expect(v[306] == 68) catch @panic("test failure"); + expect(v[307] == 69) catch @panic("test failure"); + expect(v[308] == 70) catch @panic("test failure"); + expect(v[309] == 71) catch @panic("test failure"); + expect(v[310] == 72) catch @panic("test failure"); + expect(v[311] == 73) catch @panic("test failure"); + expect(v[312] == 74) catch @panic("test failure"); + expect(v[313] == 75) catch @panic("test failure"); + expect(v[314] == 76) catch @panic("test failure"); + expect(v[315] == 77) catch @panic("test failure"); + expect(v[316] == 78) catch @panic("test failure"); + expect(v[317] == 79) catch @panic("test failure"); + expect(v[318] == 80) catch @panic("test failure"); + expect(v[319] == 81) catch @panic("test failure"); + expect(v[320] == 82) catch @panic("test failure"); + expect(v[321] == 83) catch @panic("test failure"); + expect(v[322] == 84) catch @panic("test failure"); + expect(v[323] == 85) catch @panic("test failure"); + expect(v[324] == 86) catch @panic("test failure"); + expect(v[325] == 87) catch @panic("test failure"); + expect(v[326] == 88) catch @panic("test failure"); + expect(v[327] == 89) catch @panic("test failure"); + expect(v[328] == 90) catch @panic("test failure"); + expect(v[329] == 91) catch @panic("test failure"); + expect(v[330] == 92) catch @panic("test failure"); + expect(v[331] == 93) catch @panic("test failure"); + expect(v[332] == 94) catch @panic("test failure"); + expect(v[333] == 95) catch @panic("test failure"); + expect(v[334] == 96) catch @panic("test failure"); + expect(v[335] == 97) catch @panic("test failure"); + expect(v[336] == 98) catch @panic("test failure"); + expect(v[337] == 99) catch @panic("test failure"); + expect(v[338] == 0) catch @panic("test failure"); + expect(v[339] == 1) catch @panic("test failure"); + expect(v[340] == 2) catch @panic("test failure"); + expect(v[341] == 3) catch @panic("test failure"); + expect(v[342] == 4) catch @panic("test failure"); + expect(v[343] == 5) catch @panic("test failure"); + expect(v[344] == 6) catch @panic("test failure"); + expect(v[345] == 7) catch @panic("test failure"); + expect(v[346] == 8) catch @panic("test failure"); + expect(v[347] == 9) catch @panic("test failure"); + expect(v[348] == 10) catch @panic("test failure"); + expect(v[349] == 11) catch @panic("test failure"); + expect(v[350] == 12) catch @panic("test failure"); + expect(v[351] == 13) catch @panic("test failure"); + expect(v[352] == 14) catch @panic("test failure"); + expect(v[353] == 15) catch @panic("test failure"); + expect(v[354] == 16) catch @panic("test failure"); + expect(v[355] == 17) catch @panic("test failure"); + expect(v[356] == 18) catch @panic("test failure"); + expect(v[357] == 19) catch @panic("test failure"); + expect(v[358] == 20) catch @panic("test failure"); + expect(v[359] == 21) catch @panic("test failure"); + expect(v[360] == 22) catch @panic("test failure"); + expect(v[361] == 23) catch @panic("test failure"); + expect(v[362] == 24) catch @panic("test failure"); + expect(v[363] == 25) catch @panic("test failure"); + expect(v[364] == 26) catch @panic("test failure"); + expect(v[365] == 27) catch @panic("test failure"); + expect(v[366] == 28) catch @panic("test failure"); + expect(v[367] == 29) catch @panic("test failure"); + expect(v[368] == 30) catch @panic("test failure"); + expect(v[369] == 31) catch @panic("test failure"); + expect(v[370] == 32) catch @panic("test failure"); + expect(v[371] == 33) catch @panic("test failure"); + expect(v[372] == 34) catch @panic("test failure"); + expect(v[373] == 35) catch @panic("test failure"); + expect(v[374] == 36) catch @panic("test failure"); + expect(v[375] == 37) catch @panic("test failure"); + expect(v[376] == 38) catch @panic("test failure"); + expect(v[377] == 39) catch @panic("test failure"); + expect(v[378] == 40) catch @panic("test failure"); + expect(v[379] == 41) catch @panic("test failure"); + expect(v[380] == 42) catch @panic("test failure"); + expect(v[381] == 43) catch @panic("test failure"); + expect(v[382] == 44) catch @panic("test failure"); + expect(v[383] == 45) catch @panic("test failure"); + expect(i == 384) catch @panic("test failure"); +} + +extern fn c_ret_vector_384_u8() @Vector(384, u8); +extern fn c_vector_384_u8(@Vector(384, u8), usize) void; +extern fn c_test_vector_384_u8() void; + +test "@Vector(384, u8)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_384_u8(); + try expect(v[0] == 46); + try expect(v[1] == 47); + try expect(v[2] == 48); + try expect(v[3] == 49); + try expect(v[4] == 50); + try expect(v[5] == 51); + try expect(v[6] == 52); + try expect(v[7] == 53); + try expect(v[8] == 54); + try expect(v[9] == 55); + try expect(v[10] == 56); + try expect(v[11] == 57); + try expect(v[12] == 58); + try expect(v[13] == 59); + try expect(v[14] == 60); + try expect(v[15] == 61); + try expect(v[16] == 62); + try expect(v[17] == 63); + try expect(v[18] == 64); + try expect(v[19] == 65); + try expect(v[20] == 66); + try expect(v[21] == 67); + try expect(v[22] == 68); + try expect(v[23] == 69); + try expect(v[24] == 70); + try expect(v[25] == 71); + try expect(v[26] == 72); + try expect(v[27] == 73); + try expect(v[28] == 74); + try expect(v[29] == 75); + try expect(v[30] == 76); + try expect(v[31] == 77); + try expect(v[32] == 78); + try expect(v[33] == 79); + try expect(v[34] == 80); + try expect(v[35] == 81); + try expect(v[36] == 82); + try expect(v[37] == 83); + try expect(v[38] == 84); + try expect(v[39] == 85); + try expect(v[40] == 86); + try expect(v[41] == 87); + try expect(v[42] == 88); + try expect(v[43] == 89); + try expect(v[44] == 90); + try expect(v[45] == 91); + try expect(v[46] == 92); + try expect(v[47] == 93); + try expect(v[48] == 94); + try expect(v[49] == 95); + try expect(v[50] == 96); + try expect(v[51] == 97); + try expect(v[52] == 98); + try expect(v[53] == 99); + try expect(v[54] == 0); + try expect(v[55] == 1); + try expect(v[56] == 2); + try expect(v[57] == 3); + try expect(v[58] == 4); + try expect(v[59] == 5); + try expect(v[60] == 6); + try expect(v[61] == 7); + try expect(v[62] == 8); + try expect(v[63] == 9); + try expect(v[64] == 10); + try expect(v[65] == 11); + try expect(v[66] == 12); + try expect(v[67] == 13); + try expect(v[68] == 14); + try expect(v[69] == 15); + try expect(v[70] == 16); + try expect(v[71] == 17); + try expect(v[72] == 18); + try expect(v[73] == 19); + try expect(v[74] == 20); + try expect(v[75] == 21); + try expect(v[76] == 22); + try expect(v[77] == 23); + try expect(v[78] == 24); + try expect(v[79] == 25); + try expect(v[80] == 26); + try expect(v[81] == 27); + try expect(v[82] == 28); + try expect(v[83] == 29); + try expect(v[84] == 30); + try expect(v[85] == 31); + try expect(v[86] == 32); + try expect(v[87] == 33); + try expect(v[88] == 34); + try expect(v[89] == 35); + try expect(v[90] == 36); + try expect(v[91] == 37); + try expect(v[92] == 38); + try expect(v[93] == 39); + try expect(v[94] == 40); + try expect(v[95] == 41); + try expect(v[96] == 42); + try expect(v[97] == 43); + try expect(v[98] == 44); + try expect(v[99] == 45); + try expect(v[100] == 46); + try expect(v[101] == 47); + try expect(v[102] == 48); + try expect(v[103] == 49); + try expect(v[104] == 50); + try expect(v[105] == 51); + try expect(v[106] == 52); + try expect(v[107] == 53); + try expect(v[108] == 54); + try expect(v[109] == 55); + try expect(v[110] == 56); + try expect(v[111] == 57); + try expect(v[112] == 58); + try expect(v[113] == 59); + try expect(v[114] == 60); + try expect(v[115] == 61); + try expect(v[116] == 62); + try expect(v[117] == 63); + try expect(v[118] == 64); + try expect(v[119] == 65); + try expect(v[120] == 66); + try expect(v[121] == 67); + try expect(v[122] == 68); + try expect(v[123] == 69); + try expect(v[124] == 70); + try expect(v[125] == 71); + try expect(v[126] == 72); + try expect(v[127] == 73); + try expect(v[128] == 74); + try expect(v[129] == 75); + try expect(v[130] == 76); + try expect(v[131] == 77); + try expect(v[132] == 78); + try expect(v[133] == 79); + try expect(v[134] == 80); + try expect(v[135] == 81); + try expect(v[136] == 82); + try expect(v[137] == 83); + try expect(v[138] == 84); + try expect(v[139] == 85); + try expect(v[140] == 86); + try expect(v[141] == 87); + try expect(v[142] == 88); + try expect(v[143] == 89); + try expect(v[144] == 90); + try expect(v[145] == 91); + try expect(v[146] == 92); + try expect(v[147] == 93); + try expect(v[148] == 94); + try expect(v[149] == 95); + try expect(v[150] == 96); + try expect(v[151] == 97); + try expect(v[152] == 98); + try expect(v[153] == 99); + try expect(v[154] == 0); + try expect(v[155] == 1); + try expect(v[156] == 2); + try expect(v[157] == 3); + try expect(v[158] == 4); + try expect(v[159] == 5); + try expect(v[160] == 6); + try expect(v[161] == 7); + try expect(v[162] == 8); + try expect(v[163] == 9); + try expect(v[164] == 10); + try expect(v[165] == 11); + try expect(v[166] == 12); + try expect(v[167] == 13); + try expect(v[168] == 14); + try expect(v[169] == 15); + try expect(v[170] == 16); + try expect(v[171] == 17); + try expect(v[172] == 18); + try expect(v[173] == 19); + try expect(v[174] == 20); + try expect(v[175] == 21); + try expect(v[176] == 22); + try expect(v[177] == 23); + try expect(v[178] == 24); + try expect(v[179] == 25); + try expect(v[180] == 26); + try expect(v[181] == 27); + try expect(v[182] == 28); + try expect(v[183] == 29); + try expect(v[184] == 30); + try expect(v[185] == 31); + try expect(v[186] == 32); + try expect(v[187] == 33); + try expect(v[188] == 34); + try expect(v[189] == 35); + try expect(v[190] == 36); + try expect(v[191] == 37); + try expect(v[192] == 38); + try expect(v[193] == 39); + try expect(v[194] == 40); + try expect(v[195] == 41); + try expect(v[196] == 42); + try expect(v[197] == 43); + try expect(v[198] == 44); + try expect(v[199] == 45); + try expect(v[200] == 46); + try expect(v[201] == 47); + try expect(v[202] == 48); + try expect(v[203] == 49); + try expect(v[204] == 50); + try expect(v[205] == 51); + try expect(v[206] == 52); + try expect(v[207] == 53); + try expect(v[208] == 54); + try expect(v[209] == 55); + try expect(v[210] == 56); + try expect(v[211] == 57); + try expect(v[212] == 58); + try expect(v[213] == 59); + try expect(v[214] == 60); + try expect(v[215] == 61); + try expect(v[216] == 62); + try expect(v[217] == 63); + try expect(v[218] == 64); + try expect(v[219] == 65); + try expect(v[220] == 66); + try expect(v[221] == 67); + try expect(v[222] == 68); + try expect(v[223] == 69); + try expect(v[224] == 70); + try expect(v[225] == 71); + try expect(v[226] == 72); + try expect(v[227] == 73); + try expect(v[228] == 74); + try expect(v[229] == 75); + try expect(v[230] == 76); + try expect(v[231] == 77); + try expect(v[232] == 78); + try expect(v[233] == 79); + try expect(v[234] == 80); + try expect(v[235] == 81); + try expect(v[236] == 82); + try expect(v[237] == 83); + try expect(v[238] == 84); + try expect(v[239] == 85); + try expect(v[240] == 86); + try expect(v[241] == 87); + try expect(v[242] == 88); + try expect(v[243] == 89); + try expect(v[244] == 90); + try expect(v[245] == 91); + try expect(v[246] == 92); + try expect(v[247] == 93); + try expect(v[248] == 94); + try expect(v[249] == 95); + try expect(v[250] == 96); + try expect(v[251] == 97); + try expect(v[252] == 98); + try expect(v[253] == 99); + try expect(v[254] == 0); + try expect(v[255] == 1); + try expect(v[256] == 2); + try expect(v[257] == 3); + try expect(v[258] == 4); + try expect(v[259] == 5); + try expect(v[260] == 6); + try expect(v[261] == 7); + try expect(v[262] == 8); + try expect(v[263] == 9); + try expect(v[264] == 10); + try expect(v[265] == 11); + try expect(v[266] == 12); + try expect(v[267] == 13); + try expect(v[268] == 14); + try expect(v[269] == 15); + try expect(v[270] == 16); + try expect(v[271] == 17); + try expect(v[272] == 18); + try expect(v[273] == 19); + try expect(v[274] == 20); + try expect(v[275] == 21); + try expect(v[276] == 22); + try expect(v[277] == 23); + try expect(v[278] == 24); + try expect(v[279] == 25); + try expect(v[280] == 26); + try expect(v[281] == 27); + try expect(v[282] == 28); + try expect(v[283] == 29); + try expect(v[284] == 30); + try expect(v[285] == 31); + try expect(v[286] == 32); + try expect(v[287] == 33); + try expect(v[288] == 34); + try expect(v[289] == 35); + try expect(v[290] == 36); + try expect(v[291] == 37); + try expect(v[292] == 38); + try expect(v[293] == 39); + try expect(v[294] == 40); + try expect(v[295] == 41); + try expect(v[296] == 42); + try expect(v[297] == 43); + try expect(v[298] == 44); + try expect(v[299] == 45); + try expect(v[300] == 46); + try expect(v[301] == 47); + try expect(v[302] == 48); + try expect(v[303] == 49); + try expect(v[304] == 50); + try expect(v[305] == 51); + try expect(v[306] == 52); + try expect(v[307] == 53); + try expect(v[308] == 54); + try expect(v[309] == 55); + try expect(v[310] == 56); + try expect(v[311] == 57); + try expect(v[312] == 58); + try expect(v[313] == 59); + try expect(v[314] == 60); + try expect(v[315] == 61); + try expect(v[316] == 62); + try expect(v[317] == 63); + try expect(v[318] == 64); + try expect(v[319] == 65); + try expect(v[320] == 66); + try expect(v[321] == 67); + try expect(v[322] == 68); + try expect(v[323] == 69); + try expect(v[324] == 70); + try expect(v[325] == 71); + try expect(v[326] == 72); + try expect(v[327] == 73); + try expect(v[328] == 74); + try expect(v[329] == 75); + try expect(v[330] == 76); + try expect(v[331] == 77); + try expect(v[332] == 78); + try expect(v[333] == 79); + try expect(v[334] == 80); + try expect(v[335] == 81); + try expect(v[336] == 82); + try expect(v[337] == 83); + try expect(v[338] == 84); + try expect(v[339] == 85); + try expect(v[340] == 86); + try expect(v[341] == 87); + try expect(v[342] == 88); + try expect(v[343] == 89); + try expect(v[344] == 90); + try expect(v[345] == 91); + try expect(v[346] == 92); + try expect(v[347] == 93); + try expect(v[348] == 94); + try expect(v[349] == 95); + try expect(v[350] == 96); + try expect(v[351] == 97); + try expect(v[352] == 98); + try expect(v[353] == 99); + try expect(v[354] == 0); + try expect(v[355] == 1); + try expect(v[356] == 2); + try expect(v[357] == 3); + try expect(v[358] == 4); + try expect(v[359] == 5); + try expect(v[360] == 6); + try expect(v[361] == 7); + try expect(v[362] == 8); + try expect(v[363] == 9); + try expect(v[364] == 10); + try expect(v[365] == 11); + try expect(v[366] == 12); + try expect(v[367] == 13); + try expect(v[368] == 14); + try expect(v[369] == 15); + try expect(v[370] == 16); + try expect(v[371] == 17); + try expect(v[372] == 18); + try expect(v[373] == 19); + try expect(v[374] == 20); + try expect(v[375] == 21); + try expect(v[376] == 22); + try expect(v[377] == 23); + try expect(v[378] == 24); + try expect(v[379] == 25); + try expect(v[380] == 26); + try expect(v[381] == 27); + try expect(v[382] == 28); + try expect(v[383] == 29); + c_vector_384_u8(.{ + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + }, 384); + c_test_vector_384_u8(); +} + +export fn zig_ret_vector_512_u8() @Vector(512, u8) { + return .{ + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + }; +} +export fn zig_vector_512_u8(v: @Vector(512, u8), i: usize) void { + expect(v[0] == 26) catch @panic("test failure"); + expect(v[1] == 27) catch @panic("test failure"); + expect(v[2] == 28) catch @panic("test failure"); + expect(v[3] == 29) catch @panic("test failure"); + expect(v[4] == 30) catch @panic("test failure"); + expect(v[5] == 31) catch @panic("test failure"); + expect(v[6] == 32) catch @panic("test failure"); + expect(v[7] == 33) catch @panic("test failure"); + expect(v[8] == 34) catch @panic("test failure"); + expect(v[9] == 35) catch @panic("test failure"); + expect(v[10] == 36) catch @panic("test failure"); + expect(v[11] == 37) catch @panic("test failure"); + expect(v[12] == 38) catch @panic("test failure"); + expect(v[13] == 39) catch @panic("test failure"); + expect(v[14] == 40) catch @panic("test failure"); + expect(v[15] == 41) catch @panic("test failure"); + expect(v[16] == 42) catch @panic("test failure"); + expect(v[17] == 43) catch @panic("test failure"); + expect(v[18] == 44) catch @panic("test failure"); + expect(v[19] == 45) catch @panic("test failure"); + expect(v[20] == 46) catch @panic("test failure"); + expect(v[21] == 47) catch @panic("test failure"); + expect(v[22] == 48) catch @panic("test failure"); + expect(v[23] == 49) catch @panic("test failure"); + expect(v[24] == 50) catch @panic("test failure"); + expect(v[25] == 51) catch @panic("test failure"); + expect(v[26] == 52) catch @panic("test failure"); + expect(v[27] == 53) catch @panic("test failure"); + expect(v[28] == 54) catch @panic("test failure"); + expect(v[29] == 55) catch @panic("test failure"); + expect(v[30] == 56) catch @panic("test failure"); + expect(v[31] == 57) catch @panic("test failure"); + expect(v[32] == 58) catch @panic("test failure"); + expect(v[33] == 59) catch @panic("test failure"); + expect(v[34] == 60) catch @panic("test failure"); + expect(v[35] == 61) catch @panic("test failure"); + expect(v[36] == 62) catch @panic("test failure"); + expect(v[37] == 63) catch @panic("test failure"); + expect(v[38] == 64) catch @panic("test failure"); + expect(v[39] == 65) catch @panic("test failure"); + expect(v[40] == 66) catch @panic("test failure"); + expect(v[41] == 67) catch @panic("test failure"); + expect(v[42] == 68) catch @panic("test failure"); + expect(v[43] == 69) catch @panic("test failure"); + expect(v[44] == 70) catch @panic("test failure"); + expect(v[45] == 71) catch @panic("test failure"); + expect(v[46] == 72) catch @panic("test failure"); + expect(v[47] == 73) catch @panic("test failure"); + expect(v[48] == 74) catch @panic("test failure"); + expect(v[49] == 75) catch @panic("test failure"); + expect(v[50] == 76) catch @panic("test failure"); + expect(v[51] == 77) catch @panic("test failure"); + expect(v[52] == 78) catch @panic("test failure"); + expect(v[53] == 79) catch @panic("test failure"); + expect(v[54] == 80) catch @panic("test failure"); + expect(v[55] == 81) catch @panic("test failure"); + expect(v[56] == 82) catch @panic("test failure"); + expect(v[57] == 83) catch @panic("test failure"); + expect(v[58] == 84) catch @panic("test failure"); + expect(v[59] == 85) catch @panic("test failure"); + expect(v[60] == 86) catch @panic("test failure"); + expect(v[61] == 87) catch @panic("test failure"); + expect(v[62] == 88) catch @panic("test failure"); + expect(v[63] == 89) catch @panic("test failure"); + expect(v[64] == 90) catch @panic("test failure"); + expect(v[65] == 91) catch @panic("test failure"); + expect(v[66] == 92) catch @panic("test failure"); + expect(v[67] == 93) catch @panic("test failure"); + expect(v[68] == 94) catch @panic("test failure"); + expect(v[69] == 95) catch @panic("test failure"); + expect(v[70] == 96) catch @panic("test failure"); + expect(v[71] == 97) catch @panic("test failure"); + expect(v[72] == 98) catch @panic("test failure"); + expect(v[73] == 99) catch @panic("test failure"); + expect(v[74] == 0) catch @panic("test failure"); + expect(v[75] == 1) catch @panic("test failure"); + expect(v[76] == 2) catch @panic("test failure"); + expect(v[77] == 3) catch @panic("test failure"); + expect(v[78] == 4) catch @panic("test failure"); + expect(v[79] == 5) catch @panic("test failure"); + expect(v[80] == 6) catch @panic("test failure"); + expect(v[81] == 7) catch @panic("test failure"); + expect(v[82] == 8) catch @panic("test failure"); + expect(v[83] == 9) catch @panic("test failure"); + expect(v[84] == 10) catch @panic("test failure"); + expect(v[85] == 11) catch @panic("test failure"); + expect(v[86] == 12) catch @panic("test failure"); + expect(v[87] == 13) catch @panic("test failure"); + expect(v[88] == 14) catch @panic("test failure"); + expect(v[89] == 15) catch @panic("test failure"); + expect(v[90] == 16) catch @panic("test failure"); + expect(v[91] == 17) catch @panic("test failure"); + expect(v[92] == 18) catch @panic("test failure"); + expect(v[93] == 19) catch @panic("test failure"); + expect(v[94] == 20) catch @panic("test failure"); + expect(v[95] == 21) catch @panic("test failure"); + expect(v[96] == 22) catch @panic("test failure"); + expect(v[97] == 23) catch @panic("test failure"); + expect(v[98] == 24) catch @panic("test failure"); + expect(v[99] == 25) catch @panic("test failure"); + expect(v[100] == 26) catch @panic("test failure"); + expect(v[101] == 27) catch @panic("test failure"); + expect(v[102] == 28) catch @panic("test failure"); + expect(v[103] == 29) catch @panic("test failure"); + expect(v[104] == 30) catch @panic("test failure"); + expect(v[105] == 31) catch @panic("test failure"); + expect(v[106] == 32) catch @panic("test failure"); + expect(v[107] == 33) catch @panic("test failure"); + expect(v[108] == 34) catch @panic("test failure"); + expect(v[109] == 35) catch @panic("test failure"); + expect(v[110] == 36) catch @panic("test failure"); + expect(v[111] == 37) catch @panic("test failure"); + expect(v[112] == 38) catch @panic("test failure"); + expect(v[113] == 39) catch @panic("test failure"); + expect(v[114] == 40) catch @panic("test failure"); + expect(v[115] == 41) catch @panic("test failure"); + expect(v[116] == 42) catch @panic("test failure"); + expect(v[117] == 43) catch @panic("test failure"); + expect(v[118] == 44) catch @panic("test failure"); + expect(v[119] == 45) catch @panic("test failure"); + expect(v[120] == 46) catch @panic("test failure"); + expect(v[121] == 47) catch @panic("test failure"); + expect(v[122] == 48) catch @panic("test failure"); + expect(v[123] == 49) catch @panic("test failure"); + expect(v[124] == 50) catch @panic("test failure"); + expect(v[125] == 51) catch @panic("test failure"); + expect(v[126] == 52) catch @panic("test failure"); + expect(v[127] == 53) catch @panic("test failure"); + expect(v[128] == 54) catch @panic("test failure"); + expect(v[129] == 55) catch @panic("test failure"); + expect(v[130] == 56) catch @panic("test failure"); + expect(v[131] == 57) catch @panic("test failure"); + expect(v[132] == 58) catch @panic("test failure"); + expect(v[133] == 59) catch @panic("test failure"); + expect(v[134] == 60) catch @panic("test failure"); + expect(v[135] == 61) catch @panic("test failure"); + expect(v[136] == 62) catch @panic("test failure"); + expect(v[137] == 63) catch @panic("test failure"); + expect(v[138] == 64) catch @panic("test failure"); + expect(v[139] == 65) catch @panic("test failure"); + expect(v[140] == 66) catch @panic("test failure"); + expect(v[141] == 67) catch @panic("test failure"); + expect(v[142] == 68) catch @panic("test failure"); + expect(v[143] == 69) catch @panic("test failure"); + expect(v[144] == 70) catch @panic("test failure"); + expect(v[145] == 71) catch @panic("test failure"); + expect(v[146] == 72) catch @panic("test failure"); + expect(v[147] == 73) catch @panic("test failure"); + expect(v[148] == 74) catch @panic("test failure"); + expect(v[149] == 75) catch @panic("test failure"); + expect(v[150] == 76) catch @panic("test failure"); + expect(v[151] == 77) catch @panic("test failure"); + expect(v[152] == 78) catch @panic("test failure"); + expect(v[153] == 79) catch @panic("test failure"); + expect(v[154] == 80) catch @panic("test failure"); + expect(v[155] == 81) catch @panic("test failure"); + expect(v[156] == 82) catch @panic("test failure"); + expect(v[157] == 83) catch @panic("test failure"); + expect(v[158] == 84) catch @panic("test failure"); + expect(v[159] == 85) catch @panic("test failure"); + expect(v[160] == 86) catch @panic("test failure"); + expect(v[161] == 87) catch @panic("test failure"); + expect(v[162] == 88) catch @panic("test failure"); + expect(v[163] == 89) catch @panic("test failure"); + expect(v[164] == 90) catch @panic("test failure"); + expect(v[165] == 91) catch @panic("test failure"); + expect(v[166] == 92) catch @panic("test failure"); + expect(v[167] == 93) catch @panic("test failure"); + expect(v[168] == 94) catch @panic("test failure"); + expect(v[169] == 95) catch @panic("test failure"); + expect(v[170] == 96) catch @panic("test failure"); + expect(v[171] == 97) catch @panic("test failure"); + expect(v[172] == 98) catch @panic("test failure"); + expect(v[173] == 99) catch @panic("test failure"); + expect(v[174] == 0) catch @panic("test failure"); + expect(v[175] == 1) catch @panic("test failure"); + expect(v[176] == 2) catch @panic("test failure"); + expect(v[177] == 3) catch @panic("test failure"); + expect(v[178] == 4) catch @panic("test failure"); + expect(v[179] == 5) catch @panic("test failure"); + expect(v[180] == 6) catch @panic("test failure"); + expect(v[181] == 7) catch @panic("test failure"); + expect(v[182] == 8) catch @panic("test failure"); + expect(v[183] == 9) catch @panic("test failure"); + expect(v[184] == 10) catch @panic("test failure"); + expect(v[185] == 11) catch @panic("test failure"); + expect(v[186] == 12) catch @panic("test failure"); + expect(v[187] == 13) catch @panic("test failure"); + expect(v[188] == 14) catch @panic("test failure"); + expect(v[189] == 15) catch @panic("test failure"); + expect(v[190] == 16) catch @panic("test failure"); + expect(v[191] == 17) catch @panic("test failure"); + expect(v[192] == 18) catch @panic("test failure"); + expect(v[193] == 19) catch @panic("test failure"); + expect(v[194] == 20) catch @panic("test failure"); + expect(v[195] == 21) catch @panic("test failure"); + expect(v[196] == 22) catch @panic("test failure"); + expect(v[197] == 23) catch @panic("test failure"); + expect(v[198] == 24) catch @panic("test failure"); + expect(v[199] == 25) catch @panic("test failure"); + expect(v[200] == 26) catch @panic("test failure"); + expect(v[201] == 27) catch @panic("test failure"); + expect(v[202] == 28) catch @panic("test failure"); + expect(v[203] == 29) catch @panic("test failure"); + expect(v[204] == 30) catch @panic("test failure"); + expect(v[205] == 31) catch @panic("test failure"); + expect(v[206] == 32) catch @panic("test failure"); + expect(v[207] == 33) catch @panic("test failure"); + expect(v[208] == 34) catch @panic("test failure"); + expect(v[209] == 35) catch @panic("test failure"); + expect(v[210] == 36) catch @panic("test failure"); + expect(v[211] == 37) catch @panic("test failure"); + expect(v[212] == 38) catch @panic("test failure"); + expect(v[213] == 39) catch @panic("test failure"); + expect(v[214] == 40) catch @panic("test failure"); + expect(v[215] == 41) catch @panic("test failure"); + expect(v[216] == 42) catch @panic("test failure"); + expect(v[217] == 43) catch @panic("test failure"); + expect(v[218] == 44) catch @panic("test failure"); + expect(v[219] == 45) catch @panic("test failure"); + expect(v[220] == 46) catch @panic("test failure"); + expect(v[221] == 47) catch @panic("test failure"); + expect(v[222] == 48) catch @panic("test failure"); + expect(v[223] == 49) catch @panic("test failure"); + expect(v[224] == 50) catch @panic("test failure"); + expect(v[225] == 51) catch @panic("test failure"); + expect(v[226] == 52) catch @panic("test failure"); + expect(v[227] == 53) catch @panic("test failure"); + expect(v[228] == 54) catch @panic("test failure"); + expect(v[229] == 55) catch @panic("test failure"); + expect(v[230] == 56) catch @panic("test failure"); + expect(v[231] == 57) catch @panic("test failure"); + expect(v[232] == 58) catch @panic("test failure"); + expect(v[233] == 59) catch @panic("test failure"); + expect(v[234] == 60) catch @panic("test failure"); + expect(v[235] == 61) catch @panic("test failure"); + expect(v[236] == 62) catch @panic("test failure"); + expect(v[237] == 63) catch @panic("test failure"); + expect(v[238] == 64) catch @panic("test failure"); + expect(v[239] == 65) catch @panic("test failure"); + expect(v[240] == 66) catch @panic("test failure"); + expect(v[241] == 67) catch @panic("test failure"); + expect(v[242] == 68) catch @panic("test failure"); + expect(v[243] == 69) catch @panic("test failure"); + expect(v[244] == 70) catch @panic("test failure"); + expect(v[245] == 71) catch @panic("test failure"); + expect(v[246] == 72) catch @panic("test failure"); + expect(v[247] == 73) catch @panic("test failure"); + expect(v[248] == 74) catch @panic("test failure"); + expect(v[249] == 75) catch @panic("test failure"); + expect(v[250] == 76) catch @panic("test failure"); + expect(v[251] == 77) catch @panic("test failure"); + expect(v[252] == 78) catch @panic("test failure"); + expect(v[253] == 79) catch @panic("test failure"); + expect(v[254] == 80) catch @panic("test failure"); + expect(v[255] == 81) catch @panic("test failure"); + expect(v[256] == 82) catch @panic("test failure"); + expect(v[257] == 83) catch @panic("test failure"); + expect(v[258] == 84) catch @panic("test failure"); + expect(v[259] == 85) catch @panic("test failure"); + expect(v[260] == 86) catch @panic("test failure"); + expect(v[261] == 87) catch @panic("test failure"); + expect(v[262] == 88) catch @panic("test failure"); + expect(v[263] == 89) catch @panic("test failure"); + expect(v[264] == 90) catch @panic("test failure"); + expect(v[265] == 91) catch @panic("test failure"); + expect(v[266] == 92) catch @panic("test failure"); + expect(v[267] == 93) catch @panic("test failure"); + expect(v[268] == 94) catch @panic("test failure"); + expect(v[269] == 95) catch @panic("test failure"); + expect(v[270] == 96) catch @panic("test failure"); + expect(v[271] == 97) catch @panic("test failure"); + expect(v[272] == 98) catch @panic("test failure"); + expect(v[273] == 99) catch @panic("test failure"); + expect(v[274] == 0) catch @panic("test failure"); + expect(v[275] == 1) catch @panic("test failure"); + expect(v[276] == 2) catch @panic("test failure"); + expect(v[277] == 3) catch @panic("test failure"); + expect(v[278] == 4) catch @panic("test failure"); + expect(v[279] == 5) catch @panic("test failure"); + expect(v[280] == 6) catch @panic("test failure"); + expect(v[281] == 7) catch @panic("test failure"); + expect(v[282] == 8) catch @panic("test failure"); + expect(v[283] == 9) catch @panic("test failure"); + expect(v[284] == 10) catch @panic("test failure"); + expect(v[285] == 11) catch @panic("test failure"); + expect(v[286] == 12) catch @panic("test failure"); + expect(v[287] == 13) catch @panic("test failure"); + expect(v[288] == 14) catch @panic("test failure"); + expect(v[289] == 15) catch @panic("test failure"); + expect(v[290] == 16) catch @panic("test failure"); + expect(v[291] == 17) catch @panic("test failure"); + expect(v[292] == 18) catch @panic("test failure"); + expect(v[293] == 19) catch @panic("test failure"); + expect(v[294] == 20) catch @panic("test failure"); + expect(v[295] == 21) catch @panic("test failure"); + expect(v[296] == 22) catch @panic("test failure"); + expect(v[297] == 23) catch @panic("test failure"); + expect(v[298] == 24) catch @panic("test failure"); + expect(v[299] == 25) catch @panic("test failure"); + expect(v[300] == 26) catch @panic("test failure"); + expect(v[301] == 27) catch @panic("test failure"); + expect(v[302] == 28) catch @panic("test failure"); + expect(v[303] == 29) catch @panic("test failure"); + expect(v[304] == 30) catch @panic("test failure"); + expect(v[305] == 31) catch @panic("test failure"); + expect(v[306] == 32) catch @panic("test failure"); + expect(v[307] == 33) catch @panic("test failure"); + expect(v[308] == 34) catch @panic("test failure"); + expect(v[309] == 35) catch @panic("test failure"); + expect(v[310] == 36) catch @panic("test failure"); + expect(v[311] == 37) catch @panic("test failure"); + expect(v[312] == 38) catch @panic("test failure"); + expect(v[313] == 39) catch @panic("test failure"); + expect(v[314] == 40) catch @panic("test failure"); + expect(v[315] == 41) catch @panic("test failure"); + expect(v[316] == 42) catch @panic("test failure"); + expect(v[317] == 43) catch @panic("test failure"); + expect(v[318] == 44) catch @panic("test failure"); + expect(v[319] == 45) catch @panic("test failure"); + expect(v[320] == 46) catch @panic("test failure"); + expect(v[321] == 47) catch @panic("test failure"); + expect(v[322] == 48) catch @panic("test failure"); + expect(v[323] == 49) catch @panic("test failure"); + expect(v[324] == 50) catch @panic("test failure"); + expect(v[325] == 51) catch @panic("test failure"); + expect(v[326] == 52) catch @panic("test failure"); + expect(v[327] == 53) catch @panic("test failure"); + expect(v[328] == 54) catch @panic("test failure"); + expect(v[329] == 55) catch @panic("test failure"); + expect(v[330] == 56) catch @panic("test failure"); + expect(v[331] == 57) catch @panic("test failure"); + expect(v[332] == 58) catch @panic("test failure"); + expect(v[333] == 59) catch @panic("test failure"); + expect(v[334] == 60) catch @panic("test failure"); + expect(v[335] == 61) catch @panic("test failure"); + expect(v[336] == 62) catch @panic("test failure"); + expect(v[337] == 63) catch @panic("test failure"); + expect(v[338] == 64) catch @panic("test failure"); + expect(v[339] == 65) catch @panic("test failure"); + expect(v[340] == 66) catch @panic("test failure"); + expect(v[341] == 67) catch @panic("test failure"); + expect(v[342] == 68) catch @panic("test failure"); + expect(v[343] == 69) catch @panic("test failure"); + expect(v[344] == 70) catch @panic("test failure"); + expect(v[345] == 71) catch @panic("test failure"); + expect(v[346] == 72) catch @panic("test failure"); + expect(v[347] == 73) catch @panic("test failure"); + expect(v[348] == 74) catch @panic("test failure"); + expect(v[349] == 75) catch @panic("test failure"); + expect(v[350] == 76) catch @panic("test failure"); + expect(v[351] == 77) catch @panic("test failure"); + expect(v[352] == 78) catch @panic("test failure"); + expect(v[353] == 79) catch @panic("test failure"); + expect(v[354] == 80) catch @panic("test failure"); + expect(v[355] == 81) catch @panic("test failure"); + expect(v[356] == 82) catch @panic("test failure"); + expect(v[357] == 83) catch @panic("test failure"); + expect(v[358] == 84) catch @panic("test failure"); + expect(v[359] == 85) catch @panic("test failure"); + expect(v[360] == 86) catch @panic("test failure"); + expect(v[361] == 87) catch @panic("test failure"); + expect(v[362] == 88) catch @panic("test failure"); + expect(v[363] == 89) catch @panic("test failure"); + expect(v[364] == 90) catch @panic("test failure"); + expect(v[365] == 91) catch @panic("test failure"); + expect(v[366] == 92) catch @panic("test failure"); + expect(v[367] == 93) catch @panic("test failure"); + expect(v[368] == 94) catch @panic("test failure"); + expect(v[369] == 95) catch @panic("test failure"); + expect(v[370] == 96) catch @panic("test failure"); + expect(v[371] == 97) catch @panic("test failure"); + expect(v[372] == 98) catch @panic("test failure"); + expect(v[373] == 99) catch @panic("test failure"); + expect(v[374] == 0) catch @panic("test failure"); + expect(v[375] == 1) catch @panic("test failure"); + expect(v[376] == 2) catch @panic("test failure"); + expect(v[377] == 3) catch @panic("test failure"); + expect(v[378] == 4) catch @panic("test failure"); + expect(v[379] == 5) catch @panic("test failure"); + expect(v[380] == 6) catch @panic("test failure"); + expect(v[381] == 7) catch @panic("test failure"); + expect(v[382] == 8) catch @panic("test failure"); + expect(v[383] == 9) catch @panic("test failure"); + expect(v[384] == 10) catch @panic("test failure"); + expect(v[385] == 11) catch @panic("test failure"); + expect(v[386] == 12) catch @panic("test failure"); + expect(v[387] == 13) catch @panic("test failure"); + expect(v[388] == 14) catch @panic("test failure"); + expect(v[389] == 15) catch @panic("test failure"); + expect(v[390] == 16) catch @panic("test failure"); + expect(v[391] == 17) catch @panic("test failure"); + expect(v[392] == 18) catch @panic("test failure"); + expect(v[393] == 19) catch @panic("test failure"); + expect(v[394] == 20) catch @panic("test failure"); + expect(v[395] == 21) catch @panic("test failure"); + expect(v[396] == 22) catch @panic("test failure"); + expect(v[397] == 23) catch @panic("test failure"); + expect(v[398] == 24) catch @panic("test failure"); + expect(v[399] == 25) catch @panic("test failure"); + expect(v[400] == 26) catch @panic("test failure"); + expect(v[401] == 27) catch @panic("test failure"); + expect(v[402] == 28) catch @panic("test failure"); + expect(v[403] == 29) catch @panic("test failure"); + expect(v[404] == 30) catch @panic("test failure"); + expect(v[405] == 31) catch @panic("test failure"); + expect(v[406] == 32) catch @panic("test failure"); + expect(v[407] == 33) catch @panic("test failure"); + expect(v[408] == 34) catch @panic("test failure"); + expect(v[409] == 35) catch @panic("test failure"); + expect(v[410] == 36) catch @panic("test failure"); + expect(v[411] == 37) catch @panic("test failure"); + expect(v[412] == 38) catch @panic("test failure"); + expect(v[413] == 39) catch @panic("test failure"); + expect(v[414] == 40) catch @panic("test failure"); + expect(v[415] == 41) catch @panic("test failure"); + expect(v[416] == 42) catch @panic("test failure"); + expect(v[417] == 43) catch @panic("test failure"); + expect(v[418] == 44) catch @panic("test failure"); + expect(v[419] == 45) catch @panic("test failure"); + expect(v[420] == 46) catch @panic("test failure"); + expect(v[421] == 47) catch @panic("test failure"); + expect(v[422] == 48) catch @panic("test failure"); + expect(v[423] == 49) catch @panic("test failure"); + expect(v[424] == 50) catch @panic("test failure"); + expect(v[425] == 51) catch @panic("test failure"); + expect(v[426] == 52) catch @panic("test failure"); + expect(v[427] == 53) catch @panic("test failure"); + expect(v[428] == 54) catch @panic("test failure"); + expect(v[429] == 55) catch @panic("test failure"); + expect(v[430] == 56) catch @panic("test failure"); + expect(v[431] == 57) catch @panic("test failure"); + expect(v[432] == 58) catch @panic("test failure"); + expect(v[433] == 59) catch @panic("test failure"); + expect(v[434] == 60) catch @panic("test failure"); + expect(v[435] == 61) catch @panic("test failure"); + expect(v[436] == 62) catch @panic("test failure"); + expect(v[437] == 63) catch @panic("test failure"); + expect(v[438] == 64) catch @panic("test failure"); + expect(v[439] == 65) catch @panic("test failure"); + expect(v[440] == 66) catch @panic("test failure"); + expect(v[441] == 67) catch @panic("test failure"); + expect(v[442] == 68) catch @panic("test failure"); + expect(v[443] == 69) catch @panic("test failure"); + expect(v[444] == 70) catch @panic("test failure"); + expect(v[445] == 71) catch @panic("test failure"); + expect(v[446] == 72) catch @panic("test failure"); + expect(v[447] == 73) catch @panic("test failure"); + expect(v[448] == 74) catch @panic("test failure"); + expect(v[449] == 75) catch @panic("test failure"); + expect(v[450] == 76) catch @panic("test failure"); + expect(v[451] == 77) catch @panic("test failure"); + expect(v[452] == 78) catch @panic("test failure"); + expect(v[453] == 79) catch @panic("test failure"); + expect(v[454] == 80) catch @panic("test failure"); + expect(v[455] == 81) catch @panic("test failure"); + expect(v[456] == 82) catch @panic("test failure"); + expect(v[457] == 83) catch @panic("test failure"); + expect(v[458] == 84) catch @panic("test failure"); + expect(v[459] == 85) catch @panic("test failure"); + expect(v[460] == 86) catch @panic("test failure"); + expect(v[461] == 87) catch @panic("test failure"); + expect(v[462] == 88) catch @panic("test failure"); + expect(v[463] == 89) catch @panic("test failure"); + expect(v[464] == 90) catch @panic("test failure"); + expect(v[465] == 91) catch @panic("test failure"); + expect(v[466] == 92) catch @panic("test failure"); + expect(v[467] == 93) catch @panic("test failure"); + expect(v[468] == 94) catch @panic("test failure"); + expect(v[469] == 95) catch @panic("test failure"); + expect(v[470] == 96) catch @panic("test failure"); + expect(v[471] == 97) catch @panic("test failure"); + expect(v[472] == 98) catch @panic("test failure"); + expect(v[473] == 99) catch @panic("test failure"); + expect(v[474] == 0) catch @panic("test failure"); + expect(v[475] == 1) catch @panic("test failure"); + expect(v[476] == 2) catch @panic("test failure"); + expect(v[477] == 3) catch @panic("test failure"); + expect(v[478] == 4) catch @panic("test failure"); + expect(v[479] == 5) catch @panic("test failure"); + expect(v[480] == 6) catch @panic("test failure"); + expect(v[481] == 7) catch @panic("test failure"); + expect(v[482] == 8) catch @panic("test failure"); + expect(v[483] == 9) catch @panic("test failure"); + expect(v[484] == 10) catch @panic("test failure"); + expect(v[485] == 11) catch @panic("test failure"); + expect(v[486] == 12) catch @panic("test failure"); + expect(v[487] == 13) catch @panic("test failure"); + expect(v[488] == 14) catch @panic("test failure"); + expect(v[489] == 15) catch @panic("test failure"); + expect(v[490] == 16) catch @panic("test failure"); + expect(v[491] == 17) catch @panic("test failure"); + expect(v[492] == 18) catch @panic("test failure"); + expect(v[493] == 19) catch @panic("test failure"); + expect(v[494] == 20) catch @panic("test failure"); + expect(v[495] == 21) catch @panic("test failure"); + expect(v[496] == 22) catch @panic("test failure"); + expect(v[497] == 23) catch @panic("test failure"); + expect(v[498] == 24) catch @panic("test failure"); + expect(v[499] == 25) catch @panic("test failure"); + expect(v[500] == 26) catch @panic("test failure"); + expect(v[501] == 27) catch @panic("test failure"); + expect(v[502] == 28) catch @panic("test failure"); + expect(v[503] == 29) catch @panic("test failure"); + expect(v[504] == 30) catch @panic("test failure"); + expect(v[505] == 31) catch @panic("test failure"); + expect(v[506] == 32) catch @panic("test failure"); + expect(v[507] == 33) catch @panic("test failure"); + expect(v[508] == 34) catch @panic("test failure"); + expect(v[509] == 35) catch @panic("test failure"); + expect(v[510] == 36) catch @panic("test failure"); + expect(v[511] == 37) catch @panic("test failure"); + expect(i == 512) catch @panic("test failure"); +} + +extern fn c_ret_vector_512_u8() @Vector(512, u8); +extern fn c_vector_512_u8(@Vector(512, u8), usize) void; +extern fn c_test_vector_512_u8() void; + +test "@Vector(512, u8)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 39); + try expect(v[2] == 40); + try expect(v[3] == 41); + try expect(v[4] == 42); + try expect(v[5] == 43); + try expect(v[6] == 44); + try expect(v[7] == 45); + try expect(v[8] == 46); + try expect(v[9] == 47); + try expect(v[10] == 48); + try expect(v[11] == 49); + try expect(v[12] == 50); + try expect(v[13] == 51); + try expect(v[14] == 52); + try expect(v[15] == 53); + try expect(v[16] == 54); + try expect(v[17] == 55); + try expect(v[18] == 56); + try expect(v[19] == 57); + try expect(v[20] == 58); + try expect(v[21] == 59); + try expect(v[22] == 60); + try expect(v[23] == 61); + try expect(v[24] == 62); + try expect(v[25] == 63); + try expect(v[26] == 64); + try expect(v[27] == 65); + try expect(v[28] == 66); + try expect(v[29] == 67); + try expect(v[30] == 68); + try expect(v[31] == 69); + try expect(v[32] == 70); + try expect(v[33] == 71); + try expect(v[34] == 72); + try expect(v[35] == 73); + try expect(v[36] == 74); + try expect(v[37] == 75); + try expect(v[38] == 76); + try expect(v[39] == 77); + try expect(v[40] == 78); + try expect(v[41] == 79); + try expect(v[42] == 80); + try expect(v[43] == 81); + try expect(v[44] == 82); + try expect(v[45] == 83); + try expect(v[46] == 84); + try expect(v[47] == 85); + try expect(v[48] == 86); + try expect(v[49] == 87); + try expect(v[50] == 88); + try expect(v[51] == 89); + try expect(v[52] == 90); + try expect(v[53] == 91); + try expect(v[54] == 92); + try expect(v[55] == 93); + try expect(v[56] == 94); + try expect(v[57] == 95); + try expect(v[58] == 96); + try expect(v[59] == 97); + try expect(v[60] == 98); + try expect(v[61] == 99); + try expect(v[62] == 0); + try expect(v[63] == 1); + try expect(v[64] == 2); + try expect(v[65] == 3); + try expect(v[66] == 4); + try expect(v[67] == 5); + try expect(v[68] == 6); + try expect(v[69] == 7); + try expect(v[70] == 8); + try expect(v[71] == 9); + try expect(v[72] == 10); + try expect(v[73] == 11); + try expect(v[74] == 12); + try expect(v[75] == 13); + try expect(v[76] == 14); + try expect(v[77] == 15); + try expect(v[78] == 16); + try expect(v[79] == 17); + try expect(v[80] == 18); + try expect(v[81] == 19); + try expect(v[82] == 20); + try expect(v[83] == 21); + try expect(v[84] == 22); + try expect(v[85] == 23); + try expect(v[86] == 24); + try expect(v[87] == 25); + try expect(v[88] == 26); + try expect(v[89] == 27); + try expect(v[90] == 28); + try expect(v[91] == 29); + try expect(v[92] == 30); + try expect(v[93] == 31); + try expect(v[94] == 32); + try expect(v[95] == 33); + try expect(v[96] == 34); + try expect(v[97] == 35); + try expect(v[98] == 36); + try expect(v[99] == 37); + try expect(v[100] == 38); + try expect(v[101] == 39); + try expect(v[102] == 40); + try expect(v[103] == 41); + try expect(v[104] == 42); + try expect(v[105] == 43); + try expect(v[106] == 44); + try expect(v[107] == 45); + try expect(v[108] == 46); + try expect(v[109] == 47); + try expect(v[110] == 48); + try expect(v[111] == 49); + try expect(v[112] == 50); + try expect(v[113] == 51); + try expect(v[114] == 52); + try expect(v[115] == 53); + try expect(v[116] == 54); + try expect(v[117] == 55); + try expect(v[118] == 56); + try expect(v[119] == 57); + try expect(v[120] == 58); + try expect(v[121] == 59); + try expect(v[122] == 60); + try expect(v[123] == 61); + try expect(v[124] == 62); + try expect(v[125] == 63); + try expect(v[126] == 64); + try expect(v[127] == 65); + try expect(v[128] == 66); + try expect(v[129] == 67); + try expect(v[130] == 68); + try expect(v[131] == 69); + try expect(v[132] == 70); + try expect(v[133] == 71); + try expect(v[134] == 72); + try expect(v[135] == 73); + try expect(v[136] == 74); + try expect(v[137] == 75); + try expect(v[138] == 76); + try expect(v[139] == 77); + try expect(v[140] == 78); + try expect(v[141] == 79); + try expect(v[142] == 80); + try expect(v[143] == 81); + try expect(v[144] == 82); + try expect(v[145] == 83); + try expect(v[146] == 84); + try expect(v[147] == 85); + try expect(v[148] == 86); + try expect(v[149] == 87); + try expect(v[150] == 88); + try expect(v[151] == 89); + try expect(v[152] == 90); + try expect(v[153] == 91); + try expect(v[154] == 92); + try expect(v[155] == 93); + try expect(v[156] == 94); + try expect(v[157] == 95); + try expect(v[158] == 96); + try expect(v[159] == 97); + try expect(v[160] == 98); + try expect(v[161] == 99); + try expect(v[162] == 0); + try expect(v[163] == 1); + try expect(v[164] == 2); + try expect(v[165] == 3); + try expect(v[166] == 4); + try expect(v[167] == 5); + try expect(v[168] == 6); + try expect(v[169] == 7); + try expect(v[170] == 8); + try expect(v[171] == 9); + try expect(v[172] == 10); + try expect(v[173] == 11); + try expect(v[174] == 12); + try expect(v[175] == 13); + try expect(v[176] == 14); + try expect(v[177] == 15); + try expect(v[178] == 16); + try expect(v[179] == 17); + try expect(v[180] == 18); + try expect(v[181] == 19); + try expect(v[182] == 20); + try expect(v[183] == 21); + try expect(v[184] == 22); + try expect(v[185] == 23); + try expect(v[186] == 24); + try expect(v[187] == 25); + try expect(v[188] == 26); + try expect(v[189] == 27); + try expect(v[190] == 28); + try expect(v[191] == 29); + try expect(v[192] == 30); + try expect(v[193] == 31); + try expect(v[194] == 32); + try expect(v[195] == 33); + try expect(v[196] == 34); + try expect(v[197] == 35); + try expect(v[198] == 36); + try expect(v[199] == 37); + try expect(v[200] == 38); + try expect(v[201] == 39); + try expect(v[202] == 40); + try expect(v[203] == 41); + try expect(v[204] == 42); + try expect(v[205] == 43); + try expect(v[206] == 44); + try expect(v[207] == 45); + try expect(v[208] == 46); + try expect(v[209] == 47); + try expect(v[210] == 48); + try expect(v[211] == 49); + try expect(v[212] == 50); + try expect(v[213] == 51); + try expect(v[214] == 52); + try expect(v[215] == 53); + try expect(v[216] == 54); + try expect(v[217] == 55); + try expect(v[218] == 56); + try expect(v[219] == 57); + try expect(v[220] == 58); + try expect(v[221] == 59); + try expect(v[222] == 60); + try expect(v[223] == 61); + try expect(v[224] == 62); + try expect(v[225] == 63); + try expect(v[226] == 64); + try expect(v[227] == 65); + try expect(v[228] == 66); + try expect(v[229] == 67); + try expect(v[230] == 68); + try expect(v[231] == 69); + try expect(v[232] == 70); + try expect(v[233] == 71); + try expect(v[234] == 72); + try expect(v[235] == 73); + try expect(v[236] == 74); + try expect(v[237] == 75); + try expect(v[238] == 76); + try expect(v[239] == 77); + try expect(v[240] == 78); + try expect(v[241] == 79); + try expect(v[242] == 80); + try expect(v[243] == 81); + try expect(v[244] == 82); + try expect(v[245] == 83); + try expect(v[246] == 84); + try expect(v[247] == 85); + try expect(v[248] == 86); + try expect(v[249] == 87); + try expect(v[250] == 88); + try expect(v[251] == 89); + try expect(v[252] == 90); + try expect(v[253] == 91); + try expect(v[254] == 92); + try expect(v[255] == 93); + try expect(v[256] == 94); + try expect(v[257] == 95); + try expect(v[258] == 96); + try expect(v[259] == 97); + try expect(v[260] == 98); + try expect(v[261] == 99); + try expect(v[262] == 0); + try expect(v[263] == 1); + try expect(v[264] == 2); + try expect(v[265] == 3); + try expect(v[266] == 4); + try expect(v[267] == 5); + try expect(v[268] == 6); + try expect(v[269] == 7); + try expect(v[270] == 8); + try expect(v[271] == 9); + try expect(v[272] == 10); + try expect(v[273] == 11); + try expect(v[274] == 12); + try expect(v[275] == 13); + try expect(v[276] == 14); + try expect(v[277] == 15); + try expect(v[278] == 16); + try expect(v[279] == 17); + try expect(v[280] == 18); + try expect(v[281] == 19); + try expect(v[282] == 20); + try expect(v[283] == 21); + try expect(v[284] == 22); + try expect(v[285] == 23); + try expect(v[286] == 24); + try expect(v[287] == 25); + try expect(v[288] == 26); + try expect(v[289] == 27); + try expect(v[290] == 28); + try expect(v[291] == 29); + try expect(v[292] == 30); + try expect(v[293] == 31); + try expect(v[294] == 32); + try expect(v[295] == 33); + try expect(v[296] == 34); + try expect(v[297] == 35); + try expect(v[298] == 36); + try expect(v[299] == 37); + try expect(v[300] == 38); + try expect(v[301] == 39); + try expect(v[302] == 40); + try expect(v[303] == 41); + try expect(v[304] == 42); + try expect(v[305] == 43); + try expect(v[306] == 44); + try expect(v[307] == 45); + try expect(v[308] == 46); + try expect(v[309] == 47); + try expect(v[310] == 48); + try expect(v[311] == 49); + try expect(v[312] == 50); + try expect(v[313] == 51); + try expect(v[314] == 52); + try expect(v[315] == 53); + try expect(v[316] == 54); + try expect(v[317] == 55); + try expect(v[318] == 56); + try expect(v[319] == 57); + try expect(v[320] == 58); + try expect(v[321] == 59); + try expect(v[322] == 60); + try expect(v[323] == 61); + try expect(v[324] == 62); + try expect(v[325] == 63); + try expect(v[326] == 64); + try expect(v[327] == 65); + try expect(v[328] == 66); + try expect(v[329] == 67); + try expect(v[330] == 68); + try expect(v[331] == 69); + try expect(v[332] == 70); + try expect(v[333] == 71); + try expect(v[334] == 72); + try expect(v[335] == 73); + try expect(v[336] == 74); + try expect(v[337] == 75); + try expect(v[338] == 76); + try expect(v[339] == 77); + try expect(v[340] == 78); + try expect(v[341] == 79); + try expect(v[342] == 80); + try expect(v[343] == 81); + try expect(v[344] == 82); + try expect(v[345] == 83); + try expect(v[346] == 84); + try expect(v[347] == 85); + try expect(v[348] == 86); + try expect(v[349] == 87); + try expect(v[350] == 88); + try expect(v[351] == 89); + try expect(v[352] == 90); + try expect(v[353] == 91); + try expect(v[354] == 92); + try expect(v[355] == 93); + try expect(v[356] == 94); + try expect(v[357] == 95); + try expect(v[358] == 96); + try expect(v[359] == 97); + try expect(v[360] == 98); + try expect(v[361] == 99); + try expect(v[362] == 0); + try expect(v[363] == 1); + try expect(v[364] == 2); + try expect(v[365] == 3); + try expect(v[366] == 4); + try expect(v[367] == 5); + try expect(v[368] == 6); + try expect(v[369] == 7); + try expect(v[370] == 8); + try expect(v[371] == 9); + try expect(v[372] == 10); + try expect(v[373] == 11); + try expect(v[374] == 12); + try expect(v[375] == 13); + try expect(v[376] == 14); + try expect(v[377] == 15); + try expect(v[378] == 16); + try expect(v[379] == 17); + try expect(v[380] == 18); + try expect(v[381] == 19); + try expect(v[382] == 20); + try expect(v[383] == 21); + try expect(v[384] == 22); + try expect(v[385] == 23); + try expect(v[386] == 24); + try expect(v[387] == 25); + try expect(v[388] == 26); + try expect(v[389] == 27); + try expect(v[390] == 28); + try expect(v[391] == 29); + try expect(v[392] == 30); + try expect(v[393] == 31); + try expect(v[394] == 32); + try expect(v[395] == 33); + try expect(v[396] == 34); + try expect(v[397] == 35); + try expect(v[398] == 36); + try expect(v[399] == 37); + try expect(v[400] == 38); + try expect(v[401] == 39); + try expect(v[402] == 40); + try expect(v[403] == 41); + try expect(v[404] == 42); + try expect(v[405] == 43); + try expect(v[406] == 44); + try expect(v[407] == 45); + try expect(v[408] == 46); + try expect(v[409] == 47); + try expect(v[410] == 48); + try expect(v[411] == 49); + try expect(v[412] == 50); + try expect(v[413] == 51); + try expect(v[414] == 52); + try expect(v[415] == 53); + try expect(v[416] == 54); + try expect(v[417] == 55); + try expect(v[418] == 56); + try expect(v[419] == 57); + try expect(v[420] == 58); + try expect(v[421] == 59); + try expect(v[422] == 60); + try expect(v[423] == 61); + try expect(v[424] == 62); + try expect(v[425] == 63); + try expect(v[426] == 64); + try expect(v[427] == 65); + try expect(v[428] == 66); + try expect(v[429] == 67); + try expect(v[430] == 68); + try expect(v[431] == 69); + try expect(v[432] == 70); + try expect(v[433] == 71); + try expect(v[434] == 72); + try expect(v[435] == 73); + try expect(v[436] == 74); + try expect(v[437] == 75); + try expect(v[438] == 76); + try expect(v[439] == 77); + try expect(v[440] == 78); + try expect(v[441] == 79); + try expect(v[442] == 80); + try expect(v[443] == 81); + try expect(v[444] == 82); + try expect(v[445] == 83); + try expect(v[446] == 84); + try expect(v[447] == 85); + try expect(v[448] == 86); + try expect(v[449] == 87); + try expect(v[450] == 88); + try expect(v[451] == 89); + try expect(v[452] == 90); + try expect(v[453] == 91); + try expect(v[454] == 92); + try expect(v[455] == 93); + try expect(v[456] == 94); + try expect(v[457] == 95); + try expect(v[458] == 96); + try expect(v[459] == 97); + try expect(v[460] == 98); + try expect(v[461] == 99); + try expect(v[462] == 0); + try expect(v[463] == 1); + try expect(v[464] == 2); + try expect(v[465] == 3); + try expect(v[466] == 4); + try expect(v[467] == 5); + try expect(v[468] == 6); + try expect(v[469] == 7); + try expect(v[470] == 8); + try expect(v[471] == 9); + try expect(v[472] == 10); + try expect(v[473] == 11); + try expect(v[474] == 12); + try expect(v[475] == 13); + try expect(v[476] == 14); + try expect(v[477] == 15); + try expect(v[478] == 16); + try expect(v[479] == 17); + try expect(v[480] == 18); + try expect(v[481] == 19); + try expect(v[482] == 20); + try expect(v[483] == 21); + try expect(v[484] == 22); + try expect(v[485] == 23); + try expect(v[486] == 24); + try expect(v[487] == 25); + try expect(v[488] == 26); + try expect(v[489] == 27); + try expect(v[490] == 28); + try expect(v[491] == 29); + try expect(v[492] == 30); + try expect(v[493] == 31); + try expect(v[494] == 32); + try expect(v[495] == 33); + try expect(v[496] == 34); + try expect(v[497] == 35); + try expect(v[498] == 36); + try expect(v[499] == 37); + try expect(v[500] == 38); + try expect(v[501] == 39); + try expect(v[502] == 40); + try expect(v[503] == 41); + try expect(v[504] == 42); + try expect(v[505] == 43); + try expect(v[506] == 44); + try expect(v[507] == 45); + try expect(v[508] == 46); + try expect(v[509] == 47); + try expect(v[510] == 48); + try expect(v[511] == 49); + c_vector_512_u8(.{ + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, + 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + }, 512); + c_test_vector_512_u8(); +} + +export fn zig_ret_vector_1_u16() @Vector(1, u16) { + return .{1}; +} +export fn zig_vector_1_u16(v: @Vector(1, u16), i: usize) void { + expect(v[0] == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_vector_1_u16() @Vector(1, u16); +extern fn c_vector_1_u16(@Vector(1, u16), usize) void; +extern fn c_test_vector_1_u16() void; + +test "@Vector(1, u16)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + + const v = c_ret_vector_1_u16(); + try expect(v[0] == 3); + c_vector_1_u16(.{4}, 1); + c_test_vector_1_u16(); +} + +export fn zig_ret_vector_2_u16() @Vector(2, u16) { + return .{ 5, 6 }; +} +export fn zig_vector_2_u16(v: @Vector(2, u16), i: usize) void { + expect(v[0] == 7) catch @panic("test failure"); + expect(v[1] == 8) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} + +extern fn c_ret_vector_2_u16() @Vector(2, u16); +extern fn c_vector_2_u16(@Vector(2, u16), usize) void; +extern fn c_test_vector_2_u16() void; + +test "@Vector(2, u16)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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; + + const v = c_ret_vector_2_u16(); + try expect(v[0] == 9); + try expect(v[1] == 10); + c_vector_2_u16(.{ 11, 12 }, 2); + c_test_vector_2_u16(); +} + +export fn zig_ret_vector_3_u16() @Vector(3, u16) { + return .{ 13, 14, 15 }; +} +export fn zig_vector_3_u16(v: @Vector(3, u16), i: usize) void { + expect(v[0] == 16) catch @panic("test failure"); + expect(v[1] == 17) catch @panic("test failure"); + expect(v[2] == 18) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_vector_3_u16() @Vector(3, u16); +extern fn c_vector_3_u16(@Vector(3, u16), usize) void; +extern fn c_test_vector_3_u16() void; + +test "@Vector(3, u16)" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) 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.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); + try expect(v[1] == 20); + try expect(v[2] == 21); + c_vector_3_u16(.{ 22, 23, 24 }, 3); + c_test_vector_3_u16(); +} + +export fn zig_ret_vector_4_u16() @Vector(4, u16) { + return .{ 25, 26, 27, 28 }; +} +export fn zig_vector_4_u16(v: @Vector(4, u16), i: usize) void { + expect(v[0] == 29) catch @panic("test failure"); + expect(v[1] == 30) catch @panic("test failure"); + expect(v[2] == 31) catch @panic("test failure"); + expect(v[3] == 32) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_vector_4_u16_vector_4_u16(v0: @Vector(4, u16), v1: @Vector(4, u16), i: usize) void { + expect(v0[0] == 33) catch @panic("test failure"); + expect(v0[1] == 34) catch @panic("test failure"); + expect(v0[2] == 35) catch @panic("test failure"); + expect(v0[3] == 36) catch @panic("test failure"); + expect(v1[0] == 37) catch @panic("test failure"); + expect(v1[1] == 38) catch @panic("test failure"); + expect(v1[2] == 39) catch @panic("test failure"); + expect(v1[3] == 40) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_4_u16() @Vector(4, u16); +extern fn c_vector_4_u16(@Vector(4, u16), usize) void; +extern fn c_vector_4_u16_vector_4_u16(@Vector(4, u16), @Vector(4, u16), usize) void; +extern fn c_test_vector_4_u16() void; + +test "@Vector(4, u16)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) 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_u16(); + try expect(v[0] == 41); + try expect(v[1] == 42); + try expect(v[2] == 43); + try expect(v[3] == 44); + c_vector_4_u16(.{ 45, 46, 47, 48 }, 4); + c_vector_4_u16_vector_4_u16(.{ 49, 50, 51, 52 }, .{ 53, 54, 55, 56 }, 8); + c_test_vector_4_u16(); +} + +export fn zig_ret_vector_6_u16() @Vector(6, u16) { + return .{ 41, 42, 43, 44, 45, 46 }; +} +export fn zig_vector_6_u16(v: @Vector(6, u16), i: usize) void { + expect(v[0] == 47) catch @panic("test failure"); + expect(v[1] == 48) catch @panic("test failure"); + expect(v[2] == 49) catch @panic("test failure"); + expect(v[3] == 50) catch @panic("test failure"); + expect(v[4] == 51) catch @panic("test failure"); + expect(v[5] == 52) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} + +extern fn c_ret_vector_6_u16() @Vector(6, u16); +extern fn c_vector_6_u16(@Vector(6, u16), usize) void; +extern fn c_test_vector_6_u16() void; + +test "@Vector(6, u16)" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + + const v = c_ret_vector_6_u16(); + try expect(v[0] == 53); + try expect(v[1] == 54); + try expect(v[2] == 55); + try expect(v[3] == 56); + try expect(v[4] == 57); + try expect(v[5] == 58); + c_vector_6_u16(.{ 59, 60, 61, 62, 63, 64 }, 6); + c_test_vector_6_u16(); +} + +export fn zig_ret_vector_8_u16() @Vector(8, u16) { + return .{ 65, 66, 67, 68, 69, 70, 71, 72 }; +} +export fn zig_vector_8_u16(v: @Vector(8, u16), i: usize) void { + expect(v[0] == 73) catch @panic("test failure"); + expect(v[1] == 74) catch @panic("test failure"); + expect(v[2] == 75) catch @panic("test failure"); + expect(v[3] == 76) catch @panic("test failure"); + expect(v[4] == 77) catch @panic("test failure"); + expect(v[5] == 78) catch @panic("test failure"); + expect(v[6] == 79) catch @panic("test failure"); + expect(v[7] == 80) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_8_u16() @Vector(8, u16); +extern fn c_vector_8_u16(@Vector(8, u16), usize) void; +extern fn c_test_vector_8_u16() void; + +test "@Vector(8, u16)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + + const v = c_ret_vector_8_u16(); + try expect(v[0] == 81); + try expect(v[1] == 82); + try expect(v[2] == 83); + try expect(v[3] == 84); + try expect(v[4] == 85); + try expect(v[5] == 86); + try expect(v[6] == 87); + try expect(v[7] == 88); + c_vector_8_u16(.{ 89, 90, 91, 92, 93, 94, 95, 96 }, 8); + c_test_vector_8_u16(); +} + +export fn zig_ret_vector_12_u16() @Vector(12, u16) { + return .{ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108 }; +} +export fn zig_vector_12_u16(v: @Vector(12, u16), i: usize) void { + expect(v[0] == 109) catch @panic("test failure"); + expect(v[1] == 110) catch @panic("test failure"); + expect(v[2] == 111) catch @panic("test failure"); + expect(v[3] == 112) catch @panic("test failure"); + expect(v[4] == 113) catch @panic("test failure"); + expect(v[5] == 114) catch @panic("test failure"); + expect(v[6] == 115) catch @panic("test failure"); + expect(v[7] == 116) catch @panic("test failure"); + expect(v[8] == 117) catch @panic("test failure"); + expect(v[9] == 118) catch @panic("test failure"); + expect(v[10] == 119) catch @panic("test failure"); + expect(v[11] == 120) catch @panic("test failure"); + expect(i == 12) catch @panic("test failure"); +} + +extern fn c_ret_vector_12_u16() @Vector(12, u16); +extern fn c_vector_12_u16(@Vector(12, u16), usize) void; +extern fn c_test_vector_12_u16() void; + +test "@Vector(12, u16)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_12_u16(); + try expect(v[0] == 121); + try expect(v[1] == 122); + try expect(v[2] == 123); + try expect(v[3] == 124); + try expect(v[4] == 125); + try expect(v[5] == 126); + try expect(v[6] == 127); + try expect(v[7] == 128); + try expect(v[8] == 129); + try expect(v[9] == 130); + try expect(v[10] == 131); + try expect(v[11] == 132); + c_vector_12_u16(.{ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144 }, 12); + c_test_vector_12_u16(); +} + +export fn zig_ret_vector_16_u16() @Vector(16, u16) { + return .{ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 }; +} +export fn zig_vector_16_u16(v: @Vector(16, u16), i: usize) void { + expect(v[0] == 161) catch @panic("test failure"); + expect(v[1] == 162) catch @panic("test failure"); + expect(v[2] == 163) catch @panic("test failure"); + expect(v[3] == 164) catch @panic("test failure"); + expect(v[4] == 165) catch @panic("test failure"); + expect(v[5] == 166) catch @panic("test failure"); + expect(v[6] == 167) catch @panic("test failure"); + expect(v[7] == 168) catch @panic("test failure"); + expect(v[8] == 169) catch @panic("test failure"); + expect(v[9] == 170) catch @panic("test failure"); + expect(v[10] == 171) catch @panic("test failure"); + expect(v[11] == 172) catch @panic("test failure"); + expect(v[12] == 173) catch @panic("test failure"); + expect(v[13] == 174) catch @panic("test failure"); + expect(v[14] == 175) catch @panic("test failure"); + expect(v[15] == 176) catch @panic("test failure"); + expect(i == 16) catch @panic("test failure"); +} + +extern fn c_ret_vector_16_u16() @Vector(16, u16); +extern fn c_vector_16_u16(@Vector(16, u16), usize) void; +extern fn c_test_vector_16_u16() void; + +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); + try expect(v[1] == 178); + try expect(v[2] == 179); + try expect(v[3] == 180); + try expect(v[4] == 181); + try expect(v[5] == 182); + try expect(v[6] == 183); + try expect(v[7] == 184); + try expect(v[8] == 185); + try expect(v[9] == 186); + try expect(v[10] == 187); + try expect(v[11] == 188); + try expect(v[12] == 189); + try expect(v[13] == 190); + try expect(v[14] == 191); + try expect(v[15] == 192); + c_vector_16_u16(.{ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208 }, 16); + c_test_vector_16_u16(); +} + +export fn zig_ret_vector_24_u16() @Vector(24, u16) { + return .{ + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, + }; +} +export fn zig_vector_24_u16(v: @Vector(24, u16), i: usize) void { + expect(v[0] == 233) catch @panic("test failure"); + expect(v[1] == 234) catch @panic("test failure"); + expect(v[2] == 235) catch @panic("test failure"); + expect(v[3] == 236) catch @panic("test failure"); + expect(v[4] == 237) catch @panic("test failure"); + expect(v[5] == 238) catch @panic("test failure"); + expect(v[6] == 239) catch @panic("test failure"); + expect(v[7] == 240) catch @panic("test failure"); + expect(v[8] == 241) catch @panic("test failure"); + expect(v[9] == 242) catch @panic("test failure"); + expect(v[10] == 243) catch @panic("test failure"); + expect(v[11] == 244) catch @panic("test failure"); + expect(v[12] == 245) catch @panic("test failure"); + expect(v[13] == 246) catch @panic("test failure"); + expect(v[14] == 247) catch @panic("test failure"); + expect(v[15] == 248) catch @panic("test failure"); + expect(v[16] == 249) catch @panic("test failure"); + expect(v[17] == 250) catch @panic("test failure"); + expect(v[18] == 251) catch @panic("test failure"); + expect(v[19] == 252) catch @panic("test failure"); + expect(v[20] == 253) catch @panic("test failure"); + expect(v[21] == 254) catch @panic("test failure"); + expect(v[22] == 255) catch @panic("test failure"); + expect(v[23] == 256) catch @panic("test failure"); + expect(i == 24) catch @panic("test failure"); +} + +extern fn c_ret_vector_24_u16() @Vector(24, u16); +extern fn c_vector_24_u16(@Vector(24, u16), usize) void; +extern fn c_test_vector_24_u16() void; + +test "@Vector(24, u16)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_24_u16(); + try expect(v[0] == 257); + try expect(v[1] == 258); + try expect(v[2] == 259); + try expect(v[3] == 260); + try expect(v[4] == 261); + try expect(v[5] == 262); + try expect(v[6] == 263); + try expect(v[7] == 264); + try expect(v[8] == 265); + try expect(v[9] == 266); + try expect(v[10] == 267); + try expect(v[11] == 268); + try expect(v[12] == 269); + try expect(v[13] == 270); + try expect(v[14] == 271); + try expect(v[15] == 272); + try expect(v[16] == 273); + try expect(v[17] == 274); + try expect(v[18] == 275); + try expect(v[19] == 276); + try expect(v[20] == 277); + try expect(v[21] == 278); + try expect(v[22] == 279); + try expect(v[23] == 280); + c_vector_24_u16(.{ + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, + }, 24); + c_test_vector_24_u16(); +} + +export fn zig_ret_vector_32_u16() @Vector(32, u16) { + return .{ + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, + }; +} +export fn zig_vector_32_u16(v: @Vector(32, u16), i: usize) void { + expect(v[0] == 337) catch @panic("test failure"); + expect(v[1] == 338) catch @panic("test failure"); + expect(v[2] == 339) catch @panic("test failure"); + expect(v[3] == 340) catch @panic("test failure"); + expect(v[4] == 341) catch @panic("test failure"); + expect(v[5] == 342) catch @panic("test failure"); + expect(v[6] == 343) catch @panic("test failure"); + expect(v[7] == 344) catch @panic("test failure"); + expect(v[8] == 345) catch @panic("test failure"); + expect(v[9] == 346) catch @panic("test failure"); + expect(v[10] == 347) catch @panic("test failure"); + expect(v[11] == 348) catch @panic("test failure"); + expect(v[12] == 349) catch @panic("test failure"); + expect(v[13] == 350) catch @panic("test failure"); + expect(v[14] == 351) catch @panic("test failure"); + expect(v[15] == 352) catch @panic("test failure"); + expect(v[16] == 353) catch @panic("test failure"); + expect(v[17] == 354) catch @panic("test failure"); + expect(v[18] == 355) catch @panic("test failure"); + expect(v[19] == 356) catch @panic("test failure"); + expect(v[20] == 357) catch @panic("test failure"); + expect(v[21] == 358) catch @panic("test failure"); + expect(v[22] == 359) catch @panic("test failure"); + expect(v[23] == 360) catch @panic("test failure"); + expect(v[24] == 361) catch @panic("test failure"); + expect(v[25] == 362) catch @panic("test failure"); + expect(v[26] == 363) catch @panic("test failure"); + expect(v[27] == 364) catch @panic("test failure"); + expect(v[28] == 365) catch @panic("test failure"); + expect(v[29] == 366) catch @panic("test failure"); + expect(v[30] == 367) catch @panic("test failure"); + expect(v[31] == 368) catch @panic("test failure"); + expect(i == 32) catch @panic("test failure"); +} + +extern fn c_ret_vector_32_u16() @Vector(32, u16); +extern fn c_vector_32_u16(@Vector(32, u16), usize) void; +extern fn c_test_vector_32_u16() void; + +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); + try expect(v[1] == 370); + try expect(v[2] == 371); + try expect(v[3] == 372); + try expect(v[4] == 373); + try expect(v[5] == 374); + try expect(v[6] == 375); + try expect(v[7] == 376); + try expect(v[8] == 377); + try expect(v[9] == 378); + try expect(v[10] == 379); + try expect(v[11] == 380); + try expect(v[12] == 381); + try expect(v[13] == 382); + try expect(v[14] == 383); + try expect(v[15] == 384); + try expect(v[16] == 385); + try expect(v[17] == 386); + try expect(v[18] == 387); + try expect(v[19] == 388); + try expect(v[20] == 389); + try expect(v[21] == 390); + try expect(v[22] == 391); + try expect(v[23] == 392); + try expect(v[24] == 393); + try expect(v[25] == 394); + try expect(v[26] == 395); + try expect(v[27] == 396); + try expect(v[28] == 397); + try expect(v[29] == 398); + try expect(v[30] == 399); + try expect(v[31] == 400); + c_vector_32_u16(.{ + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, + }, 32); + c_test_vector_32_u16(); +} + +export fn zig_ret_vector_48_u16() @Vector(48, u16) { + return .{ + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, + }; +} +export fn zig_vector_48_u16(v: @Vector(48, u16), i: usize) void { + expect(v[0] == 481) catch @panic("test failure"); + expect(v[1] == 482) catch @panic("test failure"); + expect(v[2] == 483) catch @panic("test failure"); + expect(v[3] == 484) catch @panic("test failure"); + expect(v[4] == 485) catch @panic("test failure"); + expect(v[5] == 486) catch @panic("test failure"); + expect(v[6] == 487) catch @panic("test failure"); + expect(v[7] == 488) catch @panic("test failure"); + expect(v[8] == 489) catch @panic("test failure"); + expect(v[9] == 490) catch @panic("test failure"); + expect(v[10] == 491) catch @panic("test failure"); + expect(v[11] == 492) catch @panic("test failure"); + expect(v[12] == 493) catch @panic("test failure"); + expect(v[13] == 494) catch @panic("test failure"); + expect(v[14] == 495) catch @panic("test failure"); + expect(v[15] == 496) catch @panic("test failure"); + expect(v[16] == 497) catch @panic("test failure"); + expect(v[17] == 498) catch @panic("test failure"); + expect(v[18] == 499) catch @panic("test failure"); + expect(v[19] == 500) catch @panic("test failure"); + expect(v[20] == 501) catch @panic("test failure"); + expect(v[21] == 502) catch @panic("test failure"); + expect(v[22] == 503) catch @panic("test failure"); + expect(v[23] == 504) catch @panic("test failure"); + expect(v[24] == 505) catch @panic("test failure"); + expect(v[25] == 506) catch @panic("test failure"); + expect(v[26] == 507) catch @panic("test failure"); + expect(v[27] == 508) catch @panic("test failure"); + expect(v[28] == 509) catch @panic("test failure"); + expect(v[29] == 510) catch @panic("test failure"); + expect(v[30] == 511) catch @panic("test failure"); + expect(v[31] == 512) catch @panic("test failure"); + expect(v[32] == 513) catch @panic("test failure"); + expect(v[33] == 514) catch @panic("test failure"); + expect(v[34] == 515) catch @panic("test failure"); + expect(v[35] == 516) catch @panic("test failure"); + expect(v[36] == 517) catch @panic("test failure"); + expect(v[37] == 518) catch @panic("test failure"); + expect(v[38] == 519) catch @panic("test failure"); + expect(v[39] == 520) catch @panic("test failure"); + expect(v[40] == 521) catch @panic("test failure"); + expect(v[41] == 522) catch @panic("test failure"); + expect(v[42] == 523) catch @panic("test failure"); + expect(v[43] == 524) catch @panic("test failure"); + expect(v[44] == 525) catch @panic("test failure"); + expect(v[45] == 526) catch @panic("test failure"); + expect(v[46] == 527) catch @panic("test failure"); + expect(v[47] == 528) catch @panic("test failure"); + expect(i == 48) catch @panic("test failure"); +} + +extern fn c_ret_vector_48_u16() @Vector(48, u16); +extern fn c_vector_48_u16(@Vector(48, u16), usize) void; +extern fn c_test_vector_48_u16() void; + +test "@Vector(48, u16)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_48_u16(); + try expect(v[0] == 529); + try expect(v[1] == 530); + try expect(v[2] == 531); + try expect(v[3] == 532); + try expect(v[4] == 533); + try expect(v[5] == 534); + try expect(v[6] == 535); + try expect(v[7] == 536); + try expect(v[8] == 537); + try expect(v[9] == 538); + try expect(v[10] == 539); + try expect(v[11] == 540); + try expect(v[12] == 541); + try expect(v[13] == 542); + try expect(v[14] == 543); + try expect(v[15] == 544); + try expect(v[16] == 545); + try expect(v[17] == 546); + try expect(v[18] == 547); + try expect(v[19] == 548); + try expect(v[20] == 549); + try expect(v[21] == 550); + try expect(v[22] == 551); + try expect(v[23] == 552); + try expect(v[24] == 553); + try expect(v[25] == 554); + try expect(v[26] == 555); + try expect(v[27] == 556); + try expect(v[28] == 557); + try expect(v[29] == 558); + try expect(v[30] == 559); + try expect(v[31] == 560); + try expect(v[32] == 561); + try expect(v[33] == 562); + try expect(v[34] == 563); + try expect(v[35] == 564); + try expect(v[36] == 565); + try expect(v[37] == 566); + try expect(v[38] == 567); + try expect(v[39] == 568); + try expect(v[40] == 569); + try expect(v[41] == 570); + try expect(v[42] == 571); + try expect(v[43] == 572); + try expect(v[44] == 573); + try expect(v[45] == 574); + try expect(v[46] == 575); + try expect(v[47] == 576); + c_vector_48_u16(.{ + 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, + 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, + 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + }, 48); + c_test_vector_48_u16(); +} + +export fn zig_ret_vector_64_u16() @Vector(64, u16) { + return .{ + 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, + 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, + 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, + 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, + }; +} +export fn zig_vector_64_u16(v: @Vector(64, u16), i: usize) void { + expect(v[0] == 689) catch @panic("test failure"); + expect(v[1] == 690) catch @panic("test failure"); + expect(v[2] == 691) catch @panic("test failure"); + expect(v[3] == 692) catch @panic("test failure"); + expect(v[4] == 693) catch @panic("test failure"); + expect(v[5] == 694) catch @panic("test failure"); + expect(v[6] == 695) catch @panic("test failure"); + expect(v[7] == 696) catch @panic("test failure"); + expect(v[8] == 697) catch @panic("test failure"); + expect(v[9] == 698) catch @panic("test failure"); + expect(v[10] == 699) catch @panic("test failure"); + expect(v[11] == 700) catch @panic("test failure"); + expect(v[12] == 701) catch @panic("test failure"); + expect(v[13] == 702) catch @panic("test failure"); + expect(v[14] == 703) catch @panic("test failure"); + expect(v[15] == 704) catch @panic("test failure"); + expect(v[16] == 705) catch @panic("test failure"); + expect(v[17] == 706) catch @panic("test failure"); + expect(v[18] == 707) catch @panic("test failure"); + expect(v[19] == 708) catch @panic("test failure"); + expect(v[20] == 709) catch @panic("test failure"); + expect(v[21] == 710) catch @panic("test failure"); + expect(v[22] == 711) catch @panic("test failure"); + expect(v[23] == 712) catch @panic("test failure"); + expect(v[24] == 713) catch @panic("test failure"); + expect(v[25] == 714) catch @panic("test failure"); + expect(v[26] == 715) catch @panic("test failure"); + expect(v[27] == 716) catch @panic("test failure"); + expect(v[28] == 717) catch @panic("test failure"); + expect(v[29] == 718) catch @panic("test failure"); + expect(v[30] == 719) catch @panic("test failure"); + expect(v[31] == 720) catch @panic("test failure"); + expect(v[32] == 721) catch @panic("test failure"); + expect(v[33] == 722) catch @panic("test failure"); + expect(v[34] == 723) catch @panic("test failure"); + expect(v[35] == 724) catch @panic("test failure"); + expect(v[36] == 725) catch @panic("test failure"); + expect(v[37] == 726) catch @panic("test failure"); + expect(v[38] == 727) catch @panic("test failure"); + expect(v[39] == 728) catch @panic("test failure"); + expect(v[40] == 729) catch @panic("test failure"); + expect(v[41] == 730) catch @panic("test failure"); + expect(v[42] == 731) catch @panic("test failure"); + expect(v[43] == 732) catch @panic("test failure"); + expect(v[44] == 733) catch @panic("test failure"); + expect(v[45] == 734) catch @panic("test failure"); + expect(v[46] == 735) catch @panic("test failure"); + expect(v[47] == 736) catch @panic("test failure"); + expect(v[48] == 737) catch @panic("test failure"); + expect(v[49] == 738) catch @panic("test failure"); + expect(v[50] == 739) catch @panic("test failure"); + expect(v[51] == 740) catch @panic("test failure"); + expect(v[52] == 741) catch @panic("test failure"); + expect(v[53] == 742) catch @panic("test failure"); + expect(v[54] == 743) catch @panic("test failure"); + expect(v[55] == 744) catch @panic("test failure"); + expect(v[56] == 745) catch @panic("test failure"); + expect(v[57] == 746) catch @panic("test failure"); + expect(v[58] == 747) catch @panic("test failure"); + expect(v[59] == 748) catch @panic("test failure"); + expect(v[60] == 749) catch @panic("test failure"); + expect(v[61] == 750) catch @panic("test failure"); + expect(v[62] == 751) catch @panic("test failure"); + expect(v[63] == 752) catch @panic("test failure"); + expect(i == 64) catch @panic("test failure"); +} + +extern fn c_ret_vector_64_u16() @Vector(64, u16); +extern fn c_vector_64_u16(@Vector(64, u16), usize) void; +extern fn c_test_vector_64_u16() void; + +test "@Vector(64, u16)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 754); + try expect(v[2] == 755); + try expect(v[3] == 756); + try expect(v[4] == 757); + try expect(v[5] == 758); + try expect(v[6] == 759); + try expect(v[7] == 760); + try expect(v[8] == 761); + try expect(v[9] == 762); + try expect(v[10] == 763); + try expect(v[11] == 764); + try expect(v[12] == 765); + try expect(v[13] == 766); + try expect(v[14] == 767); + try expect(v[15] == 768); + try expect(v[16] == 769); + try expect(v[17] == 770); + try expect(v[18] == 771); + try expect(v[19] == 772); + try expect(v[20] == 773); + try expect(v[21] == 774); + try expect(v[22] == 775); + try expect(v[23] == 776); + try expect(v[24] == 777); + try expect(v[25] == 778); + try expect(v[26] == 779); + try expect(v[27] == 780); + try expect(v[28] == 781); + try expect(v[29] == 782); + try expect(v[30] == 783); + try expect(v[31] == 784); + try expect(v[32] == 785); + try expect(v[33] == 786); + try expect(v[34] == 787); + try expect(v[35] == 788); + try expect(v[36] == 789); + try expect(v[37] == 790); + try expect(v[38] == 791); + try expect(v[39] == 792); + try expect(v[40] == 793); + try expect(v[41] == 794); + try expect(v[42] == 795); + try expect(v[43] == 796); + try expect(v[44] == 797); + try expect(v[45] == 798); + try expect(v[46] == 799); + try expect(v[47] == 800); + try expect(v[48] == 801); + try expect(v[49] == 802); + try expect(v[50] == 803); + try expect(v[51] == 804); + try expect(v[52] == 805); + try expect(v[53] == 806); + try expect(v[54] == 807); + try expect(v[55] == 808); + try expect(v[56] == 809); + try expect(v[57] == 810); + try expect(v[58] == 811); + try expect(v[59] == 812); + try expect(v[60] == 813); + try expect(v[61] == 814); + try expect(v[62] == 815); + try expect(v[63] == 816); + c_vector_64_u16(.{ + 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, + 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, + 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, + 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, + }, 64); + c_test_vector_64_u16(); +} + +export fn zig_ret_vector_96_u16() @Vector(96, u16) { + return .{ + 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, + 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, + 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, + 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, + 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, + 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, + }; +} +export fn zig_vector_96_u16(v: @Vector(96, u16), i: usize) void { + expect(v[0] == 986) catch @panic("test failure"); + expect(v[1] == 987) catch @panic("test failure"); + expect(v[2] == 988) catch @panic("test failure"); + expect(v[3] == 989) catch @panic("test failure"); + expect(v[4] == 990) catch @panic("test failure"); + expect(v[5] == 991) catch @panic("test failure"); + expect(v[6] == 992) catch @panic("test failure"); + expect(v[7] == 993) catch @panic("test failure"); + expect(v[8] == 994) catch @panic("test failure"); + expect(v[9] == 995) catch @panic("test failure"); + expect(v[10] == 996) catch @panic("test failure"); + expect(v[11] == 997) catch @panic("test failure"); + expect(v[12] == 998) catch @panic("test failure"); + expect(v[13] == 999) catch @panic("test failure"); + expect(v[14] == 1000) catch @panic("test failure"); + expect(v[15] == 1001) catch @panic("test failure"); + expect(v[16] == 1002) catch @panic("test failure"); + expect(v[17] == 1003) catch @panic("test failure"); + expect(v[18] == 1004) catch @panic("test failure"); + expect(v[19] == 1005) catch @panic("test failure"); + expect(v[20] == 1006) catch @panic("test failure"); + expect(v[21] == 1007) catch @panic("test failure"); + expect(v[22] == 1008) catch @panic("test failure"); + expect(v[23] == 1009) catch @panic("test failure"); + expect(v[24] == 1010) catch @panic("test failure"); + expect(v[25] == 1011) catch @panic("test failure"); + expect(v[26] == 1012) catch @panic("test failure"); + expect(v[27] == 1013) catch @panic("test failure"); + expect(v[28] == 1014) catch @panic("test failure"); + expect(v[29] == 1015) catch @panic("test failure"); + expect(v[30] == 1016) catch @panic("test failure"); + expect(v[31] == 1017) catch @panic("test failure"); + expect(v[32] == 1018) catch @panic("test failure"); + expect(v[33] == 1019) catch @panic("test failure"); + expect(v[34] == 1020) catch @panic("test failure"); + expect(v[35] == 1021) catch @panic("test failure"); + expect(v[36] == 1022) catch @panic("test failure"); + expect(v[37] == 1023) catch @panic("test failure"); + expect(v[38] == 1024) catch @panic("test failure"); + expect(v[39] == 1025) catch @panic("test failure"); + expect(v[40] == 1026) catch @panic("test failure"); + expect(v[41] == 1027) catch @panic("test failure"); + expect(v[42] == 1028) catch @panic("test failure"); + expect(v[43] == 1029) catch @panic("test failure"); + expect(v[44] == 1030) catch @panic("test failure"); + expect(v[45] == 1031) catch @panic("test failure"); + expect(v[46] == 1032) catch @panic("test failure"); + expect(v[47] == 1033) catch @panic("test failure"); + expect(v[48] == 1034) catch @panic("test failure"); + expect(v[49] == 1035) catch @panic("test failure"); + expect(v[50] == 1036) catch @panic("test failure"); + expect(v[51] == 1037) catch @panic("test failure"); + expect(v[52] == 1038) catch @panic("test failure"); + expect(v[53] == 1039) catch @panic("test failure"); + expect(v[54] == 1040) catch @panic("test failure"); + expect(v[55] == 1041) catch @panic("test failure"); + expect(v[56] == 1042) catch @panic("test failure"); + expect(v[57] == 1043) catch @panic("test failure"); + expect(v[58] == 1044) catch @panic("test failure"); + expect(v[59] == 1045) catch @panic("test failure"); + expect(v[60] == 1046) catch @panic("test failure"); + expect(v[61] == 1047) catch @panic("test failure"); + expect(v[62] == 1048) catch @panic("test failure"); + expect(v[63] == 1049) catch @panic("test failure"); + expect(v[64] == 1050) catch @panic("test failure"); + expect(v[65] == 1051) catch @panic("test failure"); + expect(v[66] == 1052) catch @panic("test failure"); + expect(v[67] == 1053) catch @panic("test failure"); + expect(v[68] == 1054) catch @panic("test failure"); + expect(v[69] == 1055) catch @panic("test failure"); + expect(v[70] == 1056) catch @panic("test failure"); + expect(v[71] == 1057) catch @panic("test failure"); + expect(v[72] == 1058) catch @panic("test failure"); + expect(v[73] == 1059) catch @panic("test failure"); + expect(v[74] == 1060) catch @panic("test failure"); + expect(v[75] == 1061) catch @panic("test failure"); + expect(v[76] == 1062) catch @panic("test failure"); + expect(v[77] == 1063) catch @panic("test failure"); + expect(v[78] == 1064) catch @panic("test failure"); + expect(v[79] == 1065) catch @panic("test failure"); + expect(v[80] == 1066) catch @panic("test failure"); + expect(v[81] == 1067) catch @panic("test failure"); + expect(v[82] == 1068) catch @panic("test failure"); + expect(v[83] == 1069) catch @panic("test failure"); + expect(v[84] == 1070) catch @panic("test failure"); + expect(v[85] == 1071) catch @panic("test failure"); + expect(v[86] == 1072) catch @panic("test failure"); + expect(v[87] == 1073) catch @panic("test failure"); + expect(v[88] == 1074) catch @panic("test failure"); + expect(v[89] == 1075) catch @panic("test failure"); + expect(v[90] == 1076) catch @panic("test failure"); + expect(v[91] == 1077) catch @panic("test failure"); + expect(v[92] == 1078) catch @panic("test failure"); + expect(v[93] == 1079) catch @panic("test failure"); + expect(v[94] == 1080) catch @panic("test failure"); + expect(v[95] == 1081) catch @panic("test failure"); + expect(i == 96) catch @panic("test failure"); +} + +extern fn c_ret_vector_96_u16() @Vector(96, u16); +extern fn c_vector_96_u16(@Vector(96, u16), usize) void; +extern fn c_test_vector_96_u16() void; + +test "@Vector(96, u16)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_96_u16(); + try expect(v[0] == 1082); + try expect(v[1] == 1083); + try expect(v[2] == 1084); + try expect(v[3] == 1085); + try expect(v[4] == 1086); + try expect(v[5] == 1087); + try expect(v[6] == 1088); + try expect(v[7] == 1089); + try expect(v[8] == 1090); + try expect(v[9] == 1091); + try expect(v[10] == 1092); + try expect(v[11] == 1093); + try expect(v[12] == 1094); + try expect(v[13] == 1095); + try expect(v[14] == 1096); + try expect(v[15] == 1097); + try expect(v[16] == 1098); + try expect(v[17] == 1099); + try expect(v[18] == 1100); + try expect(v[19] == 1101); + try expect(v[20] == 1102); + try expect(v[21] == 1103); + try expect(v[22] == 1104); + try expect(v[23] == 1105); + try expect(v[24] == 1106); + try expect(v[25] == 1107); + try expect(v[26] == 1108); + try expect(v[27] == 1109); + try expect(v[28] == 1110); + try expect(v[29] == 1111); + try expect(v[30] == 1112); + try expect(v[31] == 1113); + try expect(v[32] == 1114); + try expect(v[33] == 1115); + try expect(v[34] == 1116); + try expect(v[35] == 1117); + try expect(v[36] == 1118); + try expect(v[37] == 1119); + try expect(v[38] == 1120); + try expect(v[39] == 1121); + try expect(v[40] == 1122); + try expect(v[41] == 1123); + try expect(v[42] == 1124); + try expect(v[43] == 1125); + try expect(v[44] == 1126); + try expect(v[45] == 1127); + try expect(v[46] == 1128); + try expect(v[47] == 1129); + try expect(v[48] == 1130); + try expect(v[49] == 1131); + try expect(v[50] == 1132); + try expect(v[51] == 1133); + try expect(v[52] == 1134); + try expect(v[53] == 1135); + try expect(v[54] == 1136); + try expect(v[55] == 1137); + try expect(v[56] == 1138); + try expect(v[57] == 1139); + try expect(v[58] == 1140); + try expect(v[59] == 1141); + try expect(v[60] == 1142); + try expect(v[61] == 1143); + try expect(v[62] == 1144); + try expect(v[63] == 1145); + try expect(v[64] == 1146); + try expect(v[65] == 1147); + try expect(v[66] == 1148); + try expect(v[67] == 1149); + try expect(v[68] == 1150); + try expect(v[69] == 1151); + try expect(v[70] == 1152); + try expect(v[71] == 1153); + try expect(v[72] == 1154); + try expect(v[73] == 1155); + try expect(v[74] == 1156); + try expect(v[75] == 1157); + try expect(v[76] == 1158); + try expect(v[77] == 1159); + try expect(v[78] == 1160); + try expect(v[79] == 1161); + try expect(v[80] == 1162); + try expect(v[81] == 1163); + try expect(v[82] == 1164); + try expect(v[83] == 1165); + try expect(v[84] == 1166); + try expect(v[85] == 1167); + try expect(v[86] == 1168); + try expect(v[87] == 1169); + try expect(v[88] == 1170); + try expect(v[89] == 1171); + try expect(v[90] == 1172); + try expect(v[91] == 1173); + try expect(v[92] == 1174); + try expect(v[93] == 1175); + try expect(v[94] == 1176); + try expect(v[95] == 1177); + c_vector_96_u16(.{ + 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, + 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, + 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, + 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, + 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, + 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, + }, 96); + c_test_vector_96_u16(); +} + +export fn zig_ret_vector_128_u16() @Vector(128, u16) { + return .{ + 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, + 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, + 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, + 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, + 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, + 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, + 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, + 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, + }; +} +export fn zig_vector_128_u16(v: @Vector(128, u16), i: usize) void { + expect(v[0] == 1402) catch @panic("test failure"); + expect(v[1] == 1403) catch @panic("test failure"); + expect(v[2] == 1404) catch @panic("test failure"); + expect(v[3] == 1405) catch @panic("test failure"); + expect(v[4] == 1406) catch @panic("test failure"); + expect(v[5] == 1407) catch @panic("test failure"); + expect(v[6] == 1408) catch @panic("test failure"); + expect(v[7] == 1409) catch @panic("test failure"); + expect(v[8] == 1410) catch @panic("test failure"); + expect(v[9] == 1411) catch @panic("test failure"); + expect(v[10] == 1412) catch @panic("test failure"); + expect(v[11] == 1413) catch @panic("test failure"); + expect(v[12] == 1414) catch @panic("test failure"); + expect(v[13] == 1415) catch @panic("test failure"); + expect(v[14] == 1416) catch @panic("test failure"); + expect(v[15] == 1417) catch @panic("test failure"); + expect(v[16] == 1418) catch @panic("test failure"); + expect(v[17] == 1419) catch @panic("test failure"); + expect(v[18] == 1420) catch @panic("test failure"); + expect(v[19] == 1421) catch @panic("test failure"); + expect(v[20] == 1422) catch @panic("test failure"); + expect(v[21] == 1423) catch @panic("test failure"); + expect(v[22] == 1424) catch @panic("test failure"); + expect(v[23] == 1425) catch @panic("test failure"); + expect(v[24] == 1426) catch @panic("test failure"); + expect(v[25] == 1427) catch @panic("test failure"); + expect(v[26] == 1428) catch @panic("test failure"); + expect(v[27] == 1429) catch @panic("test failure"); + expect(v[28] == 1430) catch @panic("test failure"); + expect(v[29] == 1431) catch @panic("test failure"); + expect(v[30] == 1432) catch @panic("test failure"); + expect(v[31] == 1433) catch @panic("test failure"); + expect(v[32] == 1434) catch @panic("test failure"); + expect(v[33] == 1435) catch @panic("test failure"); + expect(v[34] == 1436) catch @panic("test failure"); + expect(v[35] == 1437) catch @panic("test failure"); + expect(v[36] == 1438) catch @panic("test failure"); + expect(v[37] == 1439) catch @panic("test failure"); + expect(v[38] == 1440) catch @panic("test failure"); + expect(v[39] == 1441) catch @panic("test failure"); + expect(v[40] == 1442) catch @panic("test failure"); + expect(v[41] == 1443) catch @panic("test failure"); + expect(v[42] == 1444) catch @panic("test failure"); + expect(v[43] == 1445) catch @panic("test failure"); + expect(v[44] == 1446) catch @panic("test failure"); + expect(v[45] == 1447) catch @panic("test failure"); + expect(v[46] == 1448) catch @panic("test failure"); + expect(v[47] == 1449) catch @panic("test failure"); + expect(v[48] == 1450) catch @panic("test failure"); + expect(v[49] == 1451) catch @panic("test failure"); + expect(v[50] == 1452) catch @panic("test failure"); + expect(v[51] == 1453) catch @panic("test failure"); + expect(v[52] == 1454) catch @panic("test failure"); + expect(v[53] == 1455) catch @panic("test failure"); + expect(v[54] == 1456) catch @panic("test failure"); + expect(v[55] == 1457) catch @panic("test failure"); + expect(v[56] == 1458) catch @panic("test failure"); + expect(v[57] == 1459) catch @panic("test failure"); + expect(v[58] == 1460) catch @panic("test failure"); + expect(v[59] == 1461) catch @panic("test failure"); + expect(v[60] == 1462) catch @panic("test failure"); + expect(v[61] == 1463) catch @panic("test failure"); + expect(v[62] == 1464) catch @panic("test failure"); + expect(v[63] == 1465) catch @panic("test failure"); + expect(v[64] == 1466) catch @panic("test failure"); + expect(v[65] == 1467) catch @panic("test failure"); + expect(v[66] == 1468) catch @panic("test failure"); + expect(v[67] == 1469) catch @panic("test failure"); + expect(v[68] == 1470) catch @panic("test failure"); + expect(v[69] == 1471) catch @panic("test failure"); + expect(v[70] == 1472) catch @panic("test failure"); + expect(v[71] == 1473) catch @panic("test failure"); + expect(v[72] == 1474) catch @panic("test failure"); + expect(v[73] == 1475) catch @panic("test failure"); + expect(v[74] == 1476) catch @panic("test failure"); + expect(v[75] == 1477) catch @panic("test failure"); + expect(v[76] == 1478) catch @panic("test failure"); + expect(v[77] == 1479) catch @panic("test failure"); + expect(v[78] == 1480) catch @panic("test failure"); + expect(v[79] == 1481) catch @panic("test failure"); + expect(v[80] == 1482) catch @panic("test failure"); + expect(v[81] == 1483) catch @panic("test failure"); + expect(v[82] == 1484) catch @panic("test failure"); + expect(v[83] == 1485) catch @panic("test failure"); + expect(v[84] == 1486) catch @panic("test failure"); + expect(v[85] == 1487) catch @panic("test failure"); + expect(v[86] == 1488) catch @panic("test failure"); + expect(v[87] == 1489) catch @panic("test failure"); + expect(v[88] == 1490) catch @panic("test failure"); + expect(v[89] == 1491) catch @panic("test failure"); + expect(v[90] == 1492) catch @panic("test failure"); + expect(v[91] == 1493) catch @panic("test failure"); + expect(v[92] == 1494) catch @panic("test failure"); + expect(v[93] == 1495) catch @panic("test failure"); + expect(v[94] == 1496) catch @panic("test failure"); + expect(v[95] == 1497) catch @panic("test failure"); + expect(v[96] == 1498) catch @panic("test failure"); + expect(v[97] == 1499) catch @panic("test failure"); + expect(v[98] == 1500) catch @panic("test failure"); + expect(v[99] == 1501) catch @panic("test failure"); + expect(v[100] == 1502) catch @panic("test failure"); + expect(v[101] == 1503) catch @panic("test failure"); + expect(v[102] == 1504) catch @panic("test failure"); + expect(v[103] == 1505) catch @panic("test failure"); + expect(v[104] == 1506) catch @panic("test failure"); + expect(v[105] == 1507) catch @panic("test failure"); + expect(v[106] == 1508) catch @panic("test failure"); + expect(v[107] == 1509) catch @panic("test failure"); + expect(v[108] == 1510) catch @panic("test failure"); + expect(v[109] == 1511) catch @panic("test failure"); + expect(v[110] == 1512) catch @panic("test failure"); + expect(v[111] == 1513) catch @panic("test failure"); + expect(v[112] == 1514) catch @panic("test failure"); + expect(v[113] == 1515) catch @panic("test failure"); + expect(v[114] == 1516) catch @panic("test failure"); + expect(v[115] == 1517) catch @panic("test failure"); + expect(v[116] == 1518) catch @panic("test failure"); + expect(v[117] == 1519) catch @panic("test failure"); + expect(v[118] == 1520) catch @panic("test failure"); + expect(v[119] == 1521) catch @panic("test failure"); + expect(v[120] == 1522) catch @panic("test failure"); + expect(v[121] == 1523) catch @panic("test failure"); + expect(v[122] == 1524) catch @panic("test failure"); + expect(v[123] == 1525) catch @panic("test failure"); + expect(v[124] == 1526) catch @panic("test failure"); + expect(v[125] == 1527) catch @panic("test failure"); + expect(v[126] == 1528) catch @panic("test failure"); + expect(v[127] == 1529) catch @panic("test failure"); + expect(i == 128) catch @panic("test failure"); +} + +extern fn c_ret_vector_128_u16() @Vector(128, u16); +extern fn c_vector_128_u16(@Vector(128, u16), usize) void; +extern fn c_test_vector_128_u16() void; + +test "@Vector(128, u16)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 1531); + try expect(v[2] == 1532); + try expect(v[3] == 1533); + try expect(v[4] == 1534); + try expect(v[5] == 1535); + try expect(v[6] == 1536); + try expect(v[7] == 1537); + try expect(v[8] == 1538); + try expect(v[9] == 1539); + try expect(v[10] == 1540); + try expect(v[11] == 1541); + try expect(v[12] == 1542); + try expect(v[13] == 1543); + try expect(v[14] == 1544); + try expect(v[15] == 1545); + try expect(v[16] == 1546); + try expect(v[17] == 1547); + try expect(v[18] == 1548); + try expect(v[19] == 1549); + try expect(v[20] == 1550); + try expect(v[21] == 1551); + try expect(v[22] == 1552); + try expect(v[23] == 1553); + try expect(v[24] == 1554); + try expect(v[25] == 1555); + try expect(v[26] == 1556); + try expect(v[27] == 1557); + try expect(v[28] == 1558); + try expect(v[29] == 1559); + try expect(v[30] == 1560); + try expect(v[31] == 1561); + try expect(v[32] == 1562); + try expect(v[33] == 1563); + try expect(v[34] == 1564); + try expect(v[35] == 1565); + try expect(v[36] == 1566); + try expect(v[37] == 1567); + try expect(v[38] == 1568); + try expect(v[39] == 1569); + try expect(v[40] == 1570); + try expect(v[41] == 1571); + try expect(v[42] == 1572); + try expect(v[43] == 1573); + try expect(v[44] == 1574); + try expect(v[45] == 1575); + try expect(v[46] == 1576); + try expect(v[47] == 1577); + try expect(v[48] == 1578); + try expect(v[49] == 1579); + try expect(v[50] == 1580); + try expect(v[51] == 1581); + try expect(v[52] == 1582); + try expect(v[53] == 1583); + try expect(v[54] == 1584); + try expect(v[55] == 1585); + try expect(v[56] == 1586); + try expect(v[57] == 1587); + try expect(v[58] == 1588); + try expect(v[59] == 1589); + try expect(v[60] == 1590); + try expect(v[61] == 1591); + try expect(v[62] == 1592); + try expect(v[63] == 1593); + try expect(v[64] == 1594); + try expect(v[65] == 1595); + try expect(v[66] == 1596); + try expect(v[67] == 1597); + try expect(v[68] == 1598); + try expect(v[69] == 1599); + try expect(v[70] == 1600); + try expect(v[71] == 1601); + try expect(v[72] == 1602); + try expect(v[73] == 1603); + try expect(v[74] == 1604); + try expect(v[75] == 1605); + try expect(v[76] == 1606); + try expect(v[77] == 1607); + try expect(v[78] == 1608); + try expect(v[79] == 1609); + try expect(v[80] == 1610); + try expect(v[81] == 1611); + try expect(v[82] == 1612); + try expect(v[83] == 1613); + try expect(v[84] == 1614); + try expect(v[85] == 1615); + try expect(v[86] == 1616); + try expect(v[87] == 1617); + try expect(v[88] == 1618); + try expect(v[89] == 1619); + try expect(v[90] == 1620); + try expect(v[91] == 1621); + try expect(v[92] == 1622); + try expect(v[93] == 1623); + try expect(v[94] == 1624); + try expect(v[95] == 1625); + try expect(v[96] == 1626); + try expect(v[97] == 1627); + try expect(v[98] == 1628); + try expect(v[99] == 1629); + try expect(v[100] == 1630); + try expect(v[101] == 1631); + try expect(v[102] == 1632); + try expect(v[103] == 1633); + try expect(v[104] == 1634); + try expect(v[105] == 1635); + try expect(v[106] == 1636); + try expect(v[107] == 1637); + try expect(v[108] == 1638); + try expect(v[109] == 1639); + try expect(v[110] == 1640); + try expect(v[111] == 1641); + try expect(v[112] == 1642); + try expect(v[113] == 1643); + try expect(v[114] == 1644); + try expect(v[115] == 1645); + try expect(v[116] == 1646); + try expect(v[117] == 1647); + try expect(v[118] == 1648); + try expect(v[119] == 1649); + try expect(v[120] == 1650); + try expect(v[121] == 1651); + try expect(v[122] == 1652); + try expect(v[123] == 1653); + try expect(v[124] == 1654); + try expect(v[125] == 1655); + try expect(v[126] == 1656); + try expect(v[127] == 1657); + c_vector_128_u16(.{ + 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, + 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, + 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1705, + 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, + 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, + 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 1750, 1751, 1752, 1753, + 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, + 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, + }, 128); + c_test_vector_128_u16(); +} + +export fn zig_ret_vector_192_u16() @Vector(192, u16) { + return .{ + 1786, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800, 1801, + 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1816, 1817, + 1818, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833, + 1834, 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1849, + 1850, 1851, 1852, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1860, 1861, 1862, 1863, 1864, 1865, + 1866, 1867, 1868, 1869, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1877, 1878, 1879, 1880, 1881, + 1882, 1883, 1884, 1885, 1886, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, + 1898, 1899, 1900, 1901, 1902, 1903, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, + 1914, 1915, 1916, 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929, + 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1937, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, + 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, + 1962, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, + }; +} +export fn zig_vector_192_u16(v: @Vector(192, u16), i: usize) void { + expect(v[0] == 1978) catch @panic("test failure"); + expect(v[1] == 1979) catch @panic("test failure"); + expect(v[2] == 1980) catch @panic("test failure"); + expect(v[3] == 1981) catch @panic("test failure"); + expect(v[4] == 1982) catch @panic("test failure"); + expect(v[5] == 1983) catch @panic("test failure"); + expect(v[6] == 1984) catch @panic("test failure"); + expect(v[7] == 1985) catch @panic("test failure"); + expect(v[8] == 1986) catch @panic("test failure"); + expect(v[9] == 1987) catch @panic("test failure"); + expect(v[10] == 1988) catch @panic("test failure"); + expect(v[11] == 1989) catch @panic("test failure"); + expect(v[12] == 1990) catch @panic("test failure"); + expect(v[13] == 1991) catch @panic("test failure"); + expect(v[14] == 1992) catch @panic("test failure"); + expect(v[15] == 1993) catch @panic("test failure"); + expect(v[16] == 1994) catch @panic("test failure"); + expect(v[17] == 1995) catch @panic("test failure"); + expect(v[18] == 1996) catch @panic("test failure"); + expect(v[19] == 1997) catch @panic("test failure"); + expect(v[20] == 1998) catch @panic("test failure"); + expect(v[21] == 1999) catch @panic("test failure"); + expect(v[22] == 2000) catch @panic("test failure"); + expect(v[23] == 2001) catch @panic("test failure"); + expect(v[24] == 2002) catch @panic("test failure"); + expect(v[25] == 2003) catch @panic("test failure"); + expect(v[26] == 2004) catch @panic("test failure"); + expect(v[27] == 2005) catch @panic("test failure"); + expect(v[28] == 2006) catch @panic("test failure"); + expect(v[29] == 2007) catch @panic("test failure"); + expect(v[30] == 2008) catch @panic("test failure"); + expect(v[31] == 2009) catch @panic("test failure"); + expect(v[32] == 2010) catch @panic("test failure"); + expect(v[33] == 2011) catch @panic("test failure"); + expect(v[34] == 2012) catch @panic("test failure"); + expect(v[35] == 2013) catch @panic("test failure"); + expect(v[36] == 2014) catch @panic("test failure"); + expect(v[37] == 2015) catch @panic("test failure"); + expect(v[38] == 2016) catch @panic("test failure"); + expect(v[39] == 2017) catch @panic("test failure"); + expect(v[40] == 2018) catch @panic("test failure"); + expect(v[41] == 2019) catch @panic("test failure"); + expect(v[42] == 2020) catch @panic("test failure"); + expect(v[43] == 2021) catch @panic("test failure"); + expect(v[44] == 2022) catch @panic("test failure"); + expect(v[45] == 2023) catch @panic("test failure"); + expect(v[46] == 2024) catch @panic("test failure"); + expect(v[47] == 2025) catch @panic("test failure"); + expect(v[48] == 2026) catch @panic("test failure"); + expect(v[49] == 2027) catch @panic("test failure"); + expect(v[50] == 2028) catch @panic("test failure"); + expect(v[51] == 2029) catch @panic("test failure"); + expect(v[52] == 2030) catch @panic("test failure"); + expect(v[53] == 2031) catch @panic("test failure"); + expect(v[54] == 2032) catch @panic("test failure"); + expect(v[55] == 2033) catch @panic("test failure"); + expect(v[56] == 2034) catch @panic("test failure"); + expect(v[57] == 2035) catch @panic("test failure"); + expect(v[58] == 2036) catch @panic("test failure"); + expect(v[59] == 2037) catch @panic("test failure"); + expect(v[60] == 2038) catch @panic("test failure"); + expect(v[61] == 2039) catch @panic("test failure"); + expect(v[62] == 2040) catch @panic("test failure"); + expect(v[63] == 2041) catch @panic("test failure"); + expect(v[64] == 2042) catch @panic("test failure"); + expect(v[65] == 2043) catch @panic("test failure"); + expect(v[66] == 2044) catch @panic("test failure"); + expect(v[67] == 2045) catch @panic("test failure"); + expect(v[68] == 2046) catch @panic("test failure"); + expect(v[69] == 2047) catch @panic("test failure"); + expect(v[70] == 2048) catch @panic("test failure"); + expect(v[71] == 2049) catch @panic("test failure"); + expect(v[72] == 2050) catch @panic("test failure"); + expect(v[73] == 2051) catch @panic("test failure"); + expect(v[74] == 2052) catch @panic("test failure"); + expect(v[75] == 2053) catch @panic("test failure"); + expect(v[76] == 2054) catch @panic("test failure"); + expect(v[77] == 2055) catch @panic("test failure"); + expect(v[78] == 2056) catch @panic("test failure"); + expect(v[79] == 2057) catch @panic("test failure"); + expect(v[80] == 2058) catch @panic("test failure"); + expect(v[81] == 2059) catch @panic("test failure"); + expect(v[82] == 2060) catch @panic("test failure"); + expect(v[83] == 2061) catch @panic("test failure"); + expect(v[84] == 2062) catch @panic("test failure"); + expect(v[85] == 2063) catch @panic("test failure"); + expect(v[86] == 2064) catch @panic("test failure"); + expect(v[87] == 2065) catch @panic("test failure"); + expect(v[88] == 2066) catch @panic("test failure"); + expect(v[89] == 2067) catch @panic("test failure"); + expect(v[90] == 2068) catch @panic("test failure"); + expect(v[91] == 2069) catch @panic("test failure"); + expect(v[92] == 2070) catch @panic("test failure"); + expect(v[93] == 2071) catch @panic("test failure"); + expect(v[94] == 2072) catch @panic("test failure"); + expect(v[95] == 2073) catch @panic("test failure"); + expect(v[96] == 2074) catch @panic("test failure"); + expect(v[97] == 2075) catch @panic("test failure"); + expect(v[98] == 2076) catch @panic("test failure"); + expect(v[99] == 2077) catch @panic("test failure"); + expect(v[100] == 2078) catch @panic("test failure"); + expect(v[101] == 2079) catch @panic("test failure"); + expect(v[102] == 2080) catch @panic("test failure"); + expect(v[103] == 2081) catch @panic("test failure"); + expect(v[104] == 2082) catch @panic("test failure"); + expect(v[105] == 2083) catch @panic("test failure"); + expect(v[106] == 2084) catch @panic("test failure"); + expect(v[107] == 2085) catch @panic("test failure"); + expect(v[108] == 2086) catch @panic("test failure"); + expect(v[109] == 2087) catch @panic("test failure"); + expect(v[110] == 2088) catch @panic("test failure"); + expect(v[111] == 2089) catch @panic("test failure"); + expect(v[112] == 2090) catch @panic("test failure"); + expect(v[113] == 2091) catch @panic("test failure"); + expect(v[114] == 2092) catch @panic("test failure"); + expect(v[115] == 2093) catch @panic("test failure"); + expect(v[116] == 2094) catch @panic("test failure"); + expect(v[117] == 2095) catch @panic("test failure"); + expect(v[118] == 2096) catch @panic("test failure"); + expect(v[119] == 2097) catch @panic("test failure"); + expect(v[120] == 2098) catch @panic("test failure"); + expect(v[121] == 2099) catch @panic("test failure"); + expect(v[122] == 2100) catch @panic("test failure"); + expect(v[123] == 2101) catch @panic("test failure"); + expect(v[124] == 2102) catch @panic("test failure"); + expect(v[125] == 2103) catch @panic("test failure"); + expect(v[126] == 2104) catch @panic("test failure"); + expect(v[127] == 2105) catch @panic("test failure"); + expect(v[128] == 2106) catch @panic("test failure"); + expect(v[129] == 2107) catch @panic("test failure"); + expect(v[130] == 2108) catch @panic("test failure"); + expect(v[131] == 2109) catch @panic("test failure"); + expect(v[132] == 2110) catch @panic("test failure"); + expect(v[133] == 2111) catch @panic("test failure"); + expect(v[134] == 2112) catch @panic("test failure"); + expect(v[135] == 2113) catch @panic("test failure"); + expect(v[136] == 2114) catch @panic("test failure"); + expect(v[137] == 2115) catch @panic("test failure"); + expect(v[138] == 2116) catch @panic("test failure"); + expect(v[139] == 2117) catch @panic("test failure"); + expect(v[140] == 2118) catch @panic("test failure"); + expect(v[141] == 2119) catch @panic("test failure"); + expect(v[142] == 2120) catch @panic("test failure"); + expect(v[143] == 2121) catch @panic("test failure"); + expect(v[144] == 2122) catch @panic("test failure"); + expect(v[145] == 2123) catch @panic("test failure"); + expect(v[146] == 2124) catch @panic("test failure"); + expect(v[147] == 2125) catch @panic("test failure"); + expect(v[148] == 2126) catch @panic("test failure"); + expect(v[149] == 2127) catch @panic("test failure"); + expect(v[150] == 2128) catch @panic("test failure"); + expect(v[151] == 2129) catch @panic("test failure"); + expect(v[152] == 2130) catch @panic("test failure"); + expect(v[153] == 2131) catch @panic("test failure"); + expect(v[154] == 2132) catch @panic("test failure"); + expect(v[155] == 2133) catch @panic("test failure"); + expect(v[156] == 2134) catch @panic("test failure"); + expect(v[157] == 2135) catch @panic("test failure"); + expect(v[158] == 2136) catch @panic("test failure"); + expect(v[159] == 2137) catch @panic("test failure"); + expect(v[160] == 2138) catch @panic("test failure"); + expect(v[161] == 2139) catch @panic("test failure"); + expect(v[162] == 2140) catch @panic("test failure"); + expect(v[163] == 2141) catch @panic("test failure"); + expect(v[164] == 2142) catch @panic("test failure"); + expect(v[165] == 2143) catch @panic("test failure"); + expect(v[166] == 2144) catch @panic("test failure"); + expect(v[167] == 2145) catch @panic("test failure"); + expect(v[168] == 2146) catch @panic("test failure"); + expect(v[169] == 2147) catch @panic("test failure"); + expect(v[170] == 2148) catch @panic("test failure"); + expect(v[171] == 2149) catch @panic("test failure"); + expect(v[172] == 2150) catch @panic("test failure"); + expect(v[173] == 2151) catch @panic("test failure"); + expect(v[174] == 2152) catch @panic("test failure"); + expect(v[175] == 2153) catch @panic("test failure"); + expect(v[176] == 2154) catch @panic("test failure"); + expect(v[177] == 2155) catch @panic("test failure"); + expect(v[178] == 2156) catch @panic("test failure"); + expect(v[179] == 2157) catch @panic("test failure"); + expect(v[180] == 2158) catch @panic("test failure"); + expect(v[181] == 2159) catch @panic("test failure"); + expect(v[182] == 2160) catch @panic("test failure"); + expect(v[183] == 2161) catch @panic("test failure"); + expect(v[184] == 2162) catch @panic("test failure"); + expect(v[185] == 2163) catch @panic("test failure"); + expect(v[186] == 2164) catch @panic("test failure"); + expect(v[187] == 2165) catch @panic("test failure"); + expect(v[188] == 2166) catch @panic("test failure"); + expect(v[189] == 2167) catch @panic("test failure"); + expect(v[190] == 2168) catch @panic("test failure"); + expect(v[191] == 2169) catch @panic("test failure"); + expect(i == 192) catch @panic("test failure"); +} + +extern fn c_ret_vector_192_u16() @Vector(192, u16); +extern fn c_vector_192_u16(@Vector(192, u16), usize) void; +extern fn c_test_vector_192_u16() void; + +test "@Vector(192, u16)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_192_u16(); + try expect(v[0] == 2170); + try expect(v[1] == 2171); + try expect(v[2] == 2172); + try expect(v[3] == 2173); + try expect(v[4] == 2174); + try expect(v[5] == 2175); + try expect(v[6] == 2176); + try expect(v[7] == 2177); + try expect(v[8] == 2178); + try expect(v[9] == 2179); + try expect(v[10] == 2180); + try expect(v[11] == 2181); + try expect(v[12] == 2182); + try expect(v[13] == 2183); + try expect(v[14] == 2184); + try expect(v[15] == 2185); + try expect(v[16] == 2186); + try expect(v[17] == 2187); + try expect(v[18] == 2188); + try expect(v[19] == 2189); + try expect(v[20] == 2190); + try expect(v[21] == 2191); + try expect(v[22] == 2192); + try expect(v[23] == 2193); + try expect(v[24] == 2194); + try expect(v[25] == 2195); + try expect(v[26] == 2196); + try expect(v[27] == 2197); + try expect(v[28] == 2198); + try expect(v[29] == 2199); + try expect(v[30] == 2200); + try expect(v[31] == 2201); + try expect(v[32] == 2202); + try expect(v[33] == 2203); + try expect(v[34] == 2204); + try expect(v[35] == 2205); + try expect(v[36] == 2206); + try expect(v[37] == 2207); + try expect(v[38] == 2208); + try expect(v[39] == 2209); + try expect(v[40] == 2210); + try expect(v[41] == 2211); + try expect(v[42] == 2212); + try expect(v[43] == 2213); + try expect(v[44] == 2214); + try expect(v[45] == 2215); + try expect(v[46] == 2216); + try expect(v[47] == 2217); + try expect(v[48] == 2218); + try expect(v[49] == 2219); + try expect(v[50] == 2220); + try expect(v[51] == 2221); + try expect(v[52] == 2222); + try expect(v[53] == 2223); + try expect(v[54] == 2224); + try expect(v[55] == 2225); + try expect(v[56] == 2226); + try expect(v[57] == 2227); + try expect(v[58] == 2228); + try expect(v[59] == 2229); + try expect(v[60] == 2230); + try expect(v[61] == 2231); + try expect(v[62] == 2232); + try expect(v[63] == 2233); + try expect(v[64] == 2234); + try expect(v[65] == 2235); + try expect(v[66] == 2236); + try expect(v[67] == 2237); + try expect(v[68] == 2238); + try expect(v[69] == 2239); + try expect(v[70] == 2240); + try expect(v[71] == 2241); + try expect(v[72] == 2242); + try expect(v[73] == 2243); + try expect(v[74] == 2244); + try expect(v[75] == 2245); + try expect(v[76] == 2246); + try expect(v[77] == 2247); + try expect(v[78] == 2248); + try expect(v[79] == 2249); + try expect(v[80] == 2250); + try expect(v[81] == 2251); + try expect(v[82] == 2252); + try expect(v[83] == 2253); + try expect(v[84] == 2254); + try expect(v[85] == 2255); + try expect(v[86] == 2256); + try expect(v[87] == 2257); + try expect(v[88] == 2258); + try expect(v[89] == 2259); + try expect(v[90] == 2260); + try expect(v[91] == 2261); + try expect(v[92] == 2262); + try expect(v[93] == 2263); + try expect(v[94] == 2264); + try expect(v[95] == 2265); + try expect(v[96] == 2266); + try expect(v[97] == 2267); + try expect(v[98] == 2268); + try expect(v[99] == 2269); + try expect(v[100] == 2270); + try expect(v[101] == 2271); + try expect(v[102] == 2272); + try expect(v[103] == 2273); + try expect(v[104] == 2274); + try expect(v[105] == 2275); + try expect(v[106] == 2276); + try expect(v[107] == 2277); + try expect(v[108] == 2278); + try expect(v[109] == 2279); + try expect(v[110] == 2280); + try expect(v[111] == 2281); + try expect(v[112] == 2282); + try expect(v[113] == 2283); + try expect(v[114] == 2284); + try expect(v[115] == 2285); + try expect(v[116] == 2286); + try expect(v[117] == 2287); + try expect(v[118] == 2288); + try expect(v[119] == 2289); + try expect(v[120] == 2290); + try expect(v[121] == 2291); + try expect(v[122] == 2292); + try expect(v[123] == 2293); + try expect(v[124] == 2294); + try expect(v[125] == 2295); + try expect(v[126] == 2296); + try expect(v[127] == 2297); + try expect(v[128] == 2298); + try expect(v[129] == 2299); + try expect(v[130] == 2300); + try expect(v[131] == 2301); + try expect(v[132] == 2302); + try expect(v[133] == 2303); + try expect(v[134] == 2304); + try expect(v[135] == 2305); + try expect(v[136] == 2306); + try expect(v[137] == 2307); + try expect(v[138] == 2308); + try expect(v[139] == 2309); + try expect(v[140] == 2310); + try expect(v[141] == 2311); + try expect(v[142] == 2312); + try expect(v[143] == 2313); + try expect(v[144] == 2314); + try expect(v[145] == 2315); + try expect(v[146] == 2316); + try expect(v[147] == 2317); + try expect(v[148] == 2318); + try expect(v[149] == 2319); + try expect(v[150] == 2320); + try expect(v[151] == 2321); + try expect(v[152] == 2322); + try expect(v[153] == 2323); + try expect(v[154] == 2324); + try expect(v[155] == 2325); + try expect(v[156] == 2326); + try expect(v[157] == 2327); + try expect(v[158] == 2328); + try expect(v[159] == 2329); + try expect(v[160] == 2330); + try expect(v[161] == 2331); + try expect(v[162] == 2332); + try expect(v[163] == 2333); + try expect(v[164] == 2334); + try expect(v[165] == 2335); + try expect(v[166] == 2336); + try expect(v[167] == 2337); + try expect(v[168] == 2338); + try expect(v[169] == 2339); + try expect(v[170] == 2340); + try expect(v[171] == 2341); + try expect(v[172] == 2342); + try expect(v[173] == 2343); + try expect(v[174] == 2344); + try expect(v[175] == 2345); + try expect(v[176] == 2346); + try expect(v[177] == 2347); + try expect(v[178] == 2348); + try expect(v[179] == 2349); + try expect(v[180] == 2350); + try expect(v[181] == 2351); + try expect(v[182] == 2352); + try expect(v[183] == 2353); + try expect(v[184] == 2354); + try expect(v[185] == 2355); + try expect(v[186] == 2356); + try expect(v[187] == 2357); + try expect(v[188] == 2358); + try expect(v[189] == 2359); + try expect(v[190] == 2360); + try expect(v[191] == 2361); + c_vector_192_u16(.{ + 2362, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, + 2378, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, + 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, + 2410, 2411, 2412, 2413, 2414, 2415, 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2423, 2424, 2425, + 2426, 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, 2439, 2440, 2441, + 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2454, 2455, 2456, 2457, + 2458, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, 2472, 2473, + 2474, 2475, 2476, 2477, 2478, 2479, 2480, 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, + 2490, 2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499, 2500, 2501, 2502, 2503, 2504, 2505, + 2506, 2507, 2508, 2509, 2510, 2511, 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, + 2522, 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530, 2531, 2532, 2533, 2534, 2535, 2536, 2537, + 2538, 2539, 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, 2553, + }, 192); + c_test_vector_192_u16(); +} + +export fn zig_ret_vector_256_u16() @Vector(256, u16) { + return .{ + 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, + 2570, 2571, 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, 2583, 2584, 2585, + 2586, 2587, 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2600, 2601, + 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616, 2617, + 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, + 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649, + 2650, 2651, 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, + 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, 2676, 2677, 2678, 2679, 2680, 2681, + 2682, 2683, 2684, 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, 2695, 2696, 2697, + 2698, 2699, 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, 2708, 2709, 2710, 2711, 2712, 2713, + 2714, 2715, 2716, 2717, 2718, 2719, 2720, 2721, 2722, 2723, 2724, 2725, 2726, 2727, 2728, 2729, + 2730, 2731, 2732, 2733, 2734, 2735, 2736, 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, + 2746, 2747, 2748, 2749, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, 2761, + 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2774, 2775, 2776, 2777, + 2778, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, 2789, 2790, 2791, 2792, 2793, + 2794, 2795, 2796, 2797, 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, 2809, + }; +} +export fn zig_vector_256_u16(v: @Vector(256, u16), i: usize) void { + expect(v[0] == 2810) catch @panic("test failure"); + expect(v[1] == 2811) catch @panic("test failure"); + expect(v[2] == 2812) catch @panic("test failure"); + expect(v[3] == 2813) catch @panic("test failure"); + expect(v[4] == 2814) catch @panic("test failure"); + expect(v[5] == 2815) catch @panic("test failure"); + expect(v[6] == 2816) catch @panic("test failure"); + expect(v[7] == 2817) catch @panic("test failure"); + expect(v[8] == 2818) catch @panic("test failure"); + expect(v[9] == 2819) catch @panic("test failure"); + expect(v[10] == 2820) catch @panic("test failure"); + expect(v[11] == 2821) catch @panic("test failure"); + expect(v[12] == 2822) catch @panic("test failure"); + expect(v[13] == 2823) catch @panic("test failure"); + expect(v[14] == 2824) catch @panic("test failure"); + expect(v[15] == 2825) catch @panic("test failure"); + expect(v[16] == 2826) catch @panic("test failure"); + expect(v[17] == 2827) catch @panic("test failure"); + expect(v[18] == 2828) catch @panic("test failure"); + expect(v[19] == 2829) catch @panic("test failure"); + expect(v[20] == 2830) catch @panic("test failure"); + expect(v[21] == 2831) catch @panic("test failure"); + expect(v[22] == 2832) catch @panic("test failure"); + expect(v[23] == 2833) catch @panic("test failure"); + expect(v[24] == 2834) catch @panic("test failure"); + expect(v[25] == 2835) catch @panic("test failure"); + expect(v[26] == 2836) catch @panic("test failure"); + expect(v[27] == 2837) catch @panic("test failure"); + expect(v[28] == 2838) catch @panic("test failure"); + expect(v[29] == 2839) catch @panic("test failure"); + expect(v[30] == 2840) catch @panic("test failure"); + expect(v[31] == 2841) catch @panic("test failure"); + expect(v[32] == 2842) catch @panic("test failure"); + expect(v[33] == 2843) catch @panic("test failure"); + expect(v[34] == 2844) catch @panic("test failure"); + expect(v[35] == 2845) catch @panic("test failure"); + expect(v[36] == 2846) catch @panic("test failure"); + expect(v[37] == 2847) catch @panic("test failure"); + expect(v[38] == 2848) catch @panic("test failure"); + expect(v[39] == 2849) catch @panic("test failure"); + expect(v[40] == 2850) catch @panic("test failure"); + expect(v[41] == 2851) catch @panic("test failure"); + expect(v[42] == 2852) catch @panic("test failure"); + expect(v[43] == 2853) catch @panic("test failure"); + expect(v[44] == 2854) catch @panic("test failure"); + expect(v[45] == 2855) catch @panic("test failure"); + expect(v[46] == 2856) catch @panic("test failure"); + expect(v[47] == 2857) catch @panic("test failure"); + expect(v[48] == 2858) catch @panic("test failure"); + expect(v[49] == 2859) catch @panic("test failure"); + expect(v[50] == 2860) catch @panic("test failure"); + expect(v[51] == 2861) catch @panic("test failure"); + expect(v[52] == 2862) catch @panic("test failure"); + expect(v[53] == 2863) catch @panic("test failure"); + expect(v[54] == 2864) catch @panic("test failure"); + expect(v[55] == 2865) catch @panic("test failure"); + expect(v[56] == 2866) catch @panic("test failure"); + expect(v[57] == 2867) catch @panic("test failure"); + expect(v[58] == 2868) catch @panic("test failure"); + expect(v[59] == 2869) catch @panic("test failure"); + expect(v[60] == 2870) catch @panic("test failure"); + expect(v[61] == 2871) catch @panic("test failure"); + expect(v[62] == 2872) catch @panic("test failure"); + expect(v[63] == 2873) catch @panic("test failure"); + expect(v[64] == 2874) catch @panic("test failure"); + expect(v[65] == 2875) catch @panic("test failure"); + expect(v[66] == 2876) catch @panic("test failure"); + expect(v[67] == 2877) catch @panic("test failure"); + expect(v[68] == 2878) catch @panic("test failure"); + expect(v[69] == 2879) catch @panic("test failure"); + expect(v[70] == 2880) catch @panic("test failure"); + expect(v[71] == 2881) catch @panic("test failure"); + expect(v[72] == 2882) catch @panic("test failure"); + expect(v[73] == 2883) catch @panic("test failure"); + expect(v[74] == 2884) catch @panic("test failure"); + expect(v[75] == 2885) catch @panic("test failure"); + expect(v[76] == 2886) catch @panic("test failure"); + expect(v[77] == 2887) catch @panic("test failure"); + expect(v[78] == 2888) catch @panic("test failure"); + expect(v[79] == 2889) catch @panic("test failure"); + expect(v[80] == 2890) catch @panic("test failure"); + expect(v[81] == 2891) catch @panic("test failure"); + expect(v[82] == 2892) catch @panic("test failure"); + expect(v[83] == 2893) catch @panic("test failure"); + expect(v[84] == 2894) catch @panic("test failure"); + expect(v[85] == 2895) catch @panic("test failure"); + expect(v[86] == 2896) catch @panic("test failure"); + expect(v[87] == 2897) catch @panic("test failure"); + expect(v[88] == 2898) catch @panic("test failure"); + expect(v[89] == 2899) catch @panic("test failure"); + expect(v[90] == 2900) catch @panic("test failure"); + expect(v[91] == 2901) catch @panic("test failure"); + expect(v[92] == 2902) catch @panic("test failure"); + expect(v[93] == 2903) catch @panic("test failure"); + expect(v[94] == 2904) catch @panic("test failure"); + expect(v[95] == 2905) catch @panic("test failure"); + expect(v[96] == 2906) catch @panic("test failure"); + expect(v[97] == 2907) catch @panic("test failure"); + expect(v[98] == 2908) catch @panic("test failure"); + expect(v[99] == 2909) catch @panic("test failure"); + expect(v[100] == 2910) catch @panic("test failure"); + expect(v[101] == 2911) catch @panic("test failure"); + expect(v[102] == 2912) catch @panic("test failure"); + expect(v[103] == 2913) catch @panic("test failure"); + expect(v[104] == 2914) catch @panic("test failure"); + expect(v[105] == 2915) catch @panic("test failure"); + expect(v[106] == 2916) catch @panic("test failure"); + expect(v[107] == 2917) catch @panic("test failure"); + expect(v[108] == 2918) catch @panic("test failure"); + expect(v[109] == 2919) catch @panic("test failure"); + expect(v[110] == 2920) catch @panic("test failure"); + expect(v[111] == 2921) catch @panic("test failure"); + expect(v[112] == 2922) catch @panic("test failure"); + expect(v[113] == 2923) catch @panic("test failure"); + expect(v[114] == 2924) catch @panic("test failure"); + expect(v[115] == 2925) catch @panic("test failure"); + expect(v[116] == 2926) catch @panic("test failure"); + expect(v[117] == 2927) catch @panic("test failure"); + expect(v[118] == 2928) catch @panic("test failure"); + expect(v[119] == 2929) catch @panic("test failure"); + expect(v[120] == 2930) catch @panic("test failure"); + expect(v[121] == 2931) catch @panic("test failure"); + expect(v[122] == 2932) catch @panic("test failure"); + expect(v[123] == 2933) catch @panic("test failure"); + expect(v[124] == 2934) catch @panic("test failure"); + expect(v[125] == 2935) catch @panic("test failure"); + expect(v[126] == 2936) catch @panic("test failure"); + expect(v[127] == 2937) catch @panic("test failure"); + expect(v[128] == 2938) catch @panic("test failure"); + expect(v[129] == 2939) catch @panic("test failure"); + expect(v[130] == 2940) catch @panic("test failure"); + expect(v[131] == 2941) catch @panic("test failure"); + expect(v[132] == 2942) catch @panic("test failure"); + expect(v[133] == 2943) catch @panic("test failure"); + expect(v[134] == 2944) catch @panic("test failure"); + expect(v[135] == 2945) catch @panic("test failure"); + expect(v[136] == 2946) catch @panic("test failure"); + expect(v[137] == 2947) catch @panic("test failure"); + expect(v[138] == 2948) catch @panic("test failure"); + expect(v[139] == 2949) catch @panic("test failure"); + expect(v[140] == 2950) catch @panic("test failure"); + expect(v[141] == 2951) catch @panic("test failure"); + expect(v[142] == 2952) catch @panic("test failure"); + expect(v[143] == 2953) catch @panic("test failure"); + expect(v[144] == 2954) catch @panic("test failure"); + expect(v[145] == 2955) catch @panic("test failure"); + expect(v[146] == 2956) catch @panic("test failure"); + expect(v[147] == 2957) catch @panic("test failure"); + expect(v[148] == 2958) catch @panic("test failure"); + expect(v[149] == 2959) catch @panic("test failure"); + expect(v[150] == 2960) catch @panic("test failure"); + expect(v[151] == 2961) catch @panic("test failure"); + expect(v[152] == 2962) catch @panic("test failure"); + expect(v[153] == 2963) catch @panic("test failure"); + expect(v[154] == 2964) catch @panic("test failure"); + expect(v[155] == 2965) catch @panic("test failure"); + expect(v[156] == 2966) catch @panic("test failure"); + expect(v[157] == 2967) catch @panic("test failure"); + expect(v[158] == 2968) catch @panic("test failure"); + expect(v[159] == 2969) catch @panic("test failure"); + expect(v[160] == 2970) catch @panic("test failure"); + expect(v[161] == 2971) catch @panic("test failure"); + expect(v[162] == 2972) catch @panic("test failure"); + expect(v[163] == 2973) catch @panic("test failure"); + expect(v[164] == 2974) catch @panic("test failure"); + expect(v[165] == 2975) catch @panic("test failure"); + expect(v[166] == 2976) catch @panic("test failure"); + expect(v[167] == 2977) catch @panic("test failure"); + expect(v[168] == 2978) catch @panic("test failure"); + expect(v[169] == 2979) catch @panic("test failure"); + expect(v[170] == 2980) catch @panic("test failure"); + expect(v[171] == 2981) catch @panic("test failure"); + expect(v[172] == 2982) catch @panic("test failure"); + expect(v[173] == 2983) catch @panic("test failure"); + expect(v[174] == 2984) catch @panic("test failure"); + expect(v[175] == 2985) catch @panic("test failure"); + expect(v[176] == 2986) catch @panic("test failure"); + expect(v[177] == 2987) catch @panic("test failure"); + expect(v[178] == 2988) catch @panic("test failure"); + expect(v[179] == 2989) catch @panic("test failure"); + expect(v[180] == 2990) catch @panic("test failure"); + expect(v[181] == 2991) catch @panic("test failure"); + expect(v[182] == 2992) catch @panic("test failure"); + expect(v[183] == 2993) catch @panic("test failure"); + expect(v[184] == 2994) catch @panic("test failure"); + expect(v[185] == 2995) catch @panic("test failure"); + expect(v[186] == 2996) catch @panic("test failure"); + expect(v[187] == 2997) catch @panic("test failure"); + expect(v[188] == 2998) catch @panic("test failure"); + expect(v[189] == 2999) catch @panic("test failure"); + expect(v[190] == 3000) catch @panic("test failure"); + expect(v[191] == 3001) catch @panic("test failure"); + expect(v[192] == 3002) catch @panic("test failure"); + expect(v[193] == 3003) catch @panic("test failure"); + expect(v[194] == 3004) catch @panic("test failure"); + expect(v[195] == 3005) catch @panic("test failure"); + expect(v[196] == 3006) catch @panic("test failure"); + expect(v[197] == 3007) catch @panic("test failure"); + expect(v[198] == 3008) catch @panic("test failure"); + expect(v[199] == 3009) catch @panic("test failure"); + expect(v[200] == 3010) catch @panic("test failure"); + expect(v[201] == 3011) catch @panic("test failure"); + expect(v[202] == 3012) catch @panic("test failure"); + expect(v[203] == 3013) catch @panic("test failure"); + expect(v[204] == 3014) catch @panic("test failure"); + expect(v[205] == 3015) catch @panic("test failure"); + expect(v[206] == 3016) catch @panic("test failure"); + expect(v[207] == 3017) catch @panic("test failure"); + expect(v[208] == 3018) catch @panic("test failure"); + expect(v[209] == 3019) catch @panic("test failure"); + expect(v[210] == 3020) catch @panic("test failure"); + expect(v[211] == 3021) catch @panic("test failure"); + expect(v[212] == 3022) catch @panic("test failure"); + expect(v[213] == 3023) catch @panic("test failure"); + expect(v[214] == 3024) catch @panic("test failure"); + expect(v[215] == 3025) catch @panic("test failure"); + expect(v[216] == 3026) catch @panic("test failure"); + expect(v[217] == 3027) catch @panic("test failure"); + expect(v[218] == 3028) catch @panic("test failure"); + expect(v[219] == 3029) catch @panic("test failure"); + expect(v[220] == 3030) catch @panic("test failure"); + expect(v[221] == 3031) catch @panic("test failure"); + expect(v[222] == 3032) catch @panic("test failure"); + expect(v[223] == 3033) catch @panic("test failure"); + expect(v[224] == 3034) catch @panic("test failure"); + expect(v[225] == 3035) catch @panic("test failure"); + expect(v[226] == 3036) catch @panic("test failure"); + expect(v[227] == 3037) catch @panic("test failure"); + expect(v[228] == 3038) catch @panic("test failure"); + expect(v[229] == 3039) catch @panic("test failure"); + expect(v[230] == 3040) catch @panic("test failure"); + expect(v[231] == 3041) catch @panic("test failure"); + expect(v[232] == 3042) catch @panic("test failure"); + expect(v[233] == 3043) catch @panic("test failure"); + expect(v[234] == 3044) catch @panic("test failure"); + expect(v[235] == 3045) catch @panic("test failure"); + expect(v[236] == 3046) catch @panic("test failure"); + expect(v[237] == 3047) catch @panic("test failure"); + expect(v[238] == 3048) catch @panic("test failure"); + expect(v[239] == 3049) catch @panic("test failure"); + expect(v[240] == 3050) catch @panic("test failure"); + expect(v[241] == 3051) catch @panic("test failure"); + expect(v[242] == 3052) catch @panic("test failure"); + expect(v[243] == 3053) catch @panic("test failure"); + expect(v[244] == 3054) catch @panic("test failure"); + expect(v[245] == 3055) catch @panic("test failure"); + expect(v[246] == 3056) catch @panic("test failure"); + expect(v[247] == 3057) catch @panic("test failure"); + expect(v[248] == 3058) catch @panic("test failure"); + expect(v[249] == 3059) catch @panic("test failure"); + expect(v[250] == 3060) catch @panic("test failure"); + expect(v[251] == 3061) catch @panic("test failure"); + expect(v[252] == 3062) catch @panic("test failure"); + expect(v[253] == 3063) catch @panic("test failure"); + expect(v[254] == 3064) catch @panic("test failure"); + expect(v[255] == 3065) catch @panic("test failure"); + expect(i == 256) catch @panic("test failure"); +} + +extern fn c_ret_vector_256_u16() @Vector(256, u16); +extern fn c_vector_256_u16(@Vector(256, u16), usize) void; +extern fn c_test_vector_256_u16() void; + +test "@Vector(256, u16)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 3067); + try expect(v[2] == 3068); + try expect(v[3] == 3069); + try expect(v[4] == 3070); + try expect(v[5] == 3071); + try expect(v[6] == 3072); + try expect(v[7] == 3073); + try expect(v[8] == 3074); + try expect(v[9] == 3075); + try expect(v[10] == 3076); + try expect(v[11] == 3077); + try expect(v[12] == 3078); + try expect(v[13] == 3079); + try expect(v[14] == 3080); + try expect(v[15] == 3081); + try expect(v[16] == 3082); + try expect(v[17] == 3083); + try expect(v[18] == 3084); + try expect(v[19] == 3085); + try expect(v[20] == 3086); + try expect(v[21] == 3087); + try expect(v[22] == 3088); + try expect(v[23] == 3089); + try expect(v[24] == 3090); + try expect(v[25] == 3091); + try expect(v[26] == 3092); + try expect(v[27] == 3093); + try expect(v[28] == 3094); + try expect(v[29] == 3095); + try expect(v[30] == 3096); + try expect(v[31] == 3097); + try expect(v[32] == 3098); + try expect(v[33] == 3099); + try expect(v[34] == 3100); + try expect(v[35] == 3101); + try expect(v[36] == 3102); + try expect(v[37] == 3103); + try expect(v[38] == 3104); + try expect(v[39] == 3105); + try expect(v[40] == 3106); + try expect(v[41] == 3107); + try expect(v[42] == 3108); + try expect(v[43] == 3109); + try expect(v[44] == 3110); + try expect(v[45] == 3111); + try expect(v[46] == 3112); + try expect(v[47] == 3113); + try expect(v[48] == 3114); + try expect(v[49] == 3115); + try expect(v[50] == 3116); + try expect(v[51] == 3117); + try expect(v[52] == 3118); + try expect(v[53] == 3119); + try expect(v[54] == 3120); + try expect(v[55] == 3121); + try expect(v[56] == 3122); + try expect(v[57] == 3123); + try expect(v[58] == 3124); + try expect(v[59] == 3125); + try expect(v[60] == 3126); + try expect(v[61] == 3127); + try expect(v[62] == 3128); + try expect(v[63] == 3129); + try expect(v[64] == 3130); + try expect(v[65] == 3131); + try expect(v[66] == 3132); + try expect(v[67] == 3133); + try expect(v[68] == 3134); + try expect(v[69] == 3135); + try expect(v[70] == 3136); + try expect(v[71] == 3137); + try expect(v[72] == 3138); + try expect(v[73] == 3139); + try expect(v[74] == 3140); + try expect(v[75] == 3141); + try expect(v[76] == 3142); + try expect(v[77] == 3143); + try expect(v[78] == 3144); + try expect(v[79] == 3145); + try expect(v[80] == 3146); + try expect(v[81] == 3147); + try expect(v[82] == 3148); + try expect(v[83] == 3149); + try expect(v[84] == 3150); + try expect(v[85] == 3151); + try expect(v[86] == 3152); + try expect(v[87] == 3153); + try expect(v[88] == 3154); + try expect(v[89] == 3155); + try expect(v[90] == 3156); + try expect(v[91] == 3157); + try expect(v[92] == 3158); + try expect(v[93] == 3159); + try expect(v[94] == 3160); + try expect(v[95] == 3161); + try expect(v[96] == 3162); + try expect(v[97] == 3163); + try expect(v[98] == 3164); + try expect(v[99] == 3165); + try expect(v[100] == 3166); + try expect(v[101] == 3167); + try expect(v[102] == 3168); + try expect(v[103] == 3169); + try expect(v[104] == 3170); + try expect(v[105] == 3171); + try expect(v[106] == 3172); + try expect(v[107] == 3173); + try expect(v[108] == 3174); + try expect(v[109] == 3175); + try expect(v[110] == 3176); + try expect(v[111] == 3177); + try expect(v[112] == 3178); + try expect(v[113] == 3179); + try expect(v[114] == 3180); + try expect(v[115] == 3181); + try expect(v[116] == 3182); + try expect(v[117] == 3183); + try expect(v[118] == 3184); + try expect(v[119] == 3185); + try expect(v[120] == 3186); + try expect(v[121] == 3187); + try expect(v[122] == 3188); + try expect(v[123] == 3189); + try expect(v[124] == 3190); + try expect(v[125] == 3191); + try expect(v[126] == 3192); + try expect(v[127] == 3193); + try expect(v[128] == 3194); + try expect(v[129] == 3195); + try expect(v[130] == 3196); + try expect(v[131] == 3197); + try expect(v[132] == 3198); + try expect(v[133] == 3199); + try expect(v[134] == 3200); + try expect(v[135] == 3201); + try expect(v[136] == 3202); + try expect(v[137] == 3203); + try expect(v[138] == 3204); + try expect(v[139] == 3205); + try expect(v[140] == 3206); + try expect(v[141] == 3207); + try expect(v[142] == 3208); + try expect(v[143] == 3209); + try expect(v[144] == 3210); + try expect(v[145] == 3211); + try expect(v[146] == 3212); + try expect(v[147] == 3213); + try expect(v[148] == 3214); + try expect(v[149] == 3215); + try expect(v[150] == 3216); + try expect(v[151] == 3217); + try expect(v[152] == 3218); + try expect(v[153] == 3219); + try expect(v[154] == 3220); + try expect(v[155] == 3221); + try expect(v[156] == 3222); + try expect(v[157] == 3223); + try expect(v[158] == 3224); + try expect(v[159] == 3225); + try expect(v[160] == 3226); + try expect(v[161] == 3227); + try expect(v[162] == 3228); + try expect(v[163] == 3229); + try expect(v[164] == 3230); + try expect(v[165] == 3231); + try expect(v[166] == 3232); + try expect(v[167] == 3233); + try expect(v[168] == 3234); + try expect(v[169] == 3235); + try expect(v[170] == 3236); + try expect(v[171] == 3237); + try expect(v[172] == 3238); + try expect(v[173] == 3239); + try expect(v[174] == 3240); + try expect(v[175] == 3241); + try expect(v[176] == 3242); + try expect(v[177] == 3243); + try expect(v[178] == 3244); + try expect(v[179] == 3245); + try expect(v[180] == 3246); + try expect(v[181] == 3247); + try expect(v[182] == 3248); + try expect(v[183] == 3249); + try expect(v[184] == 3250); + try expect(v[185] == 3251); + try expect(v[186] == 3252); + try expect(v[187] == 3253); + try expect(v[188] == 3254); + try expect(v[189] == 3255); + try expect(v[190] == 3256); + try expect(v[191] == 3257); + try expect(v[192] == 3258); + try expect(v[193] == 3259); + try expect(v[194] == 3260); + try expect(v[195] == 3261); + try expect(v[196] == 3262); + try expect(v[197] == 3263); + try expect(v[198] == 3264); + try expect(v[199] == 3265); + try expect(v[200] == 3266); + try expect(v[201] == 3267); + try expect(v[202] == 3268); + try expect(v[203] == 3269); + try expect(v[204] == 3270); + try expect(v[205] == 3271); + try expect(v[206] == 3272); + try expect(v[207] == 3273); + try expect(v[208] == 3274); + try expect(v[209] == 3275); + try expect(v[210] == 3276); + try expect(v[211] == 3277); + try expect(v[212] == 3278); + try expect(v[213] == 3279); + try expect(v[214] == 3280); + try expect(v[215] == 3281); + try expect(v[216] == 3282); + try expect(v[217] == 3283); + try expect(v[218] == 3284); + try expect(v[219] == 3285); + try expect(v[220] == 3286); + try expect(v[221] == 3287); + try expect(v[222] == 3288); + try expect(v[223] == 3289); + try expect(v[224] == 3290); + try expect(v[225] == 3291); + try expect(v[226] == 3292); + try expect(v[227] == 3293); + try expect(v[228] == 3294); + try expect(v[229] == 3295); + try expect(v[230] == 3296); + try expect(v[231] == 3297); + try expect(v[232] == 3298); + try expect(v[233] == 3299); + try expect(v[234] == 3300); + try expect(v[235] == 3301); + try expect(v[236] == 3302); + try expect(v[237] == 3303); + try expect(v[238] == 3304); + try expect(v[239] == 3305); + try expect(v[240] == 3306); + try expect(v[241] == 3307); + try expect(v[242] == 3308); + try expect(v[243] == 3309); + try expect(v[244] == 3310); + try expect(v[245] == 3311); + try expect(v[246] == 3312); + try expect(v[247] == 3313); + try expect(v[248] == 3314); + try expect(v[249] == 3315); + try expect(v[250] == 3316); + try expect(v[251] == 3317); + try expect(v[252] == 3318); + try expect(v[253] == 3319); + try expect(v[254] == 3320); + try expect(v[255] == 3321); + c_vector_256_u16(.{ + 3322, 3323, 3324, 3325, 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, 3334, 3335, 3336, 3337, + 3338, 3339, 3340, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3352, 3353, + 3354, 3355, 3356, 3357, 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3368, 3369, + 3370, 3371, 3372, 3373, 3374, 3375, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3384, 3385, + 3386, 3387, 3388, 3389, 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, 3398, 3399, 3400, 3401, + 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 3416, 3417, + 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, 3430, 3431, 3432, 3433, + 3434, 3435, 3436, 3437, 3438, 3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448, 3449, + 3450, 3451, 3452, 3453, 3454, 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, + 3466, 3467, 3468, 3469, 3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, 3479, 3480, 3481, + 3482, 3483, 3484, 3485, 3486, 3487, 3488, 3489, 3490, 3491, 3492, 3493, 3494, 3495, 3496, 3497, + 3498, 3499, 3500, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, 3511, 3512, 3513, + 3514, 3515, 3516, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 3524, 3525, 3526, 3527, 3528, 3529, + 3530, 3531, 3532, 3533, 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3544, 3545, + 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, 3558, 3559, 3560, 3561, + 3562, 3563, 3564, 3565, 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, 3574, 3575, 3576, 3577, + }, 256); + c_test_vector_256_u16(); +} + +export fn zig_ret_vector_1_u32() @Vector(1, u32) { + return .{1}; +} +export fn zig_vector_1_u32(v: @Vector(1, u32), i: usize) void { + expect(v[0] == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_vector_1_u32() @Vector(1, u32); +extern fn c_vector_1_u32(@Vector(1, u32), usize) void; +extern fn c_test_vector_1_u32() void; + +test "@Vector(1, u32)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + + const v = c_ret_vector_1_u32(); + try expect(v[0] == 3); + c_vector_1_u32(.{4}, 1); + c_test_vector_1_u32(); +} + +export fn zig_ret_vector_2_u32() @Vector(2, u32) { + return .{ 5, 6 }; +} +export fn zig_vector_2_u32(v: @Vector(2, u32), i: usize) void { + expect(v[0] == 7) catch @panic("test failure"); + expect(v[1] == 8) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} + +extern fn c_ret_vector_2_u32() @Vector(2, u32); +extern fn c_vector_2_u32(@Vector(2, u32), usize) void; +extern fn c_test_vector_2_u32() void; + +test "@Vector(2, u32)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86) 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_u32(); + try expect(v[0] == 9); + try expect(v[1] == 10); + c_vector_2_u32(.{ 11, 12 }, 2); + c_test_vector_2_u32(); +} + +export fn zig_ret_vector_3_u32() @Vector(3, u32) { + return .{ 13, 14, 15 }; +} +export fn zig_vector_3_u32(v: @Vector(3, u32), i: usize) void { + expect(v[0] == 16) catch @panic("test failure"); + expect(v[1] == 17) catch @panic("test failure"); + expect(v[2] == 18) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_vector_3_u32() @Vector(3, u32); +extern fn c_vector_3_u32(@Vector(3, u32), usize) void; +extern fn c_test_vector_3_u32() void; + +test "@Vector(3, u32)" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + + const v = c_ret_vector_3_u32(); + try expect(v[0] == 19); + try expect(v[1] == 20); + try expect(v[2] == 21); + c_vector_3_u32(.{ 22, 23, 24 }, 3); + c_test_vector_3_u32(); +} + +export fn zig_ret_vector_4_u32() @Vector(4, u32) { + return .{ 25, 26, 27, 28 }; +} +export fn zig_vector_4_u32(v: @Vector(4, u32), i: usize) void { + expect(v[0] == 29) catch @panic("test failure"); + expect(v[1] == 30) catch @panic("test failure"); + expect(v[2] == 31) catch @panic("test failure"); + expect(v[3] == 32) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_vector_4_u32_vector_4_u32(v0: @Vector(4, u32), v1: @Vector(4, u32), i: usize) void { + expect(v0[0] == 33) catch @panic("test failure"); + expect(v0[1] == 34) catch @panic("test failure"); + expect(v0[2] == 35) catch @panic("test failure"); + expect(v0[3] == 36) catch @panic("test failure"); + expect(v1[0] == 37) catch @panic("test failure"); + expect(v1[1] == 38) catch @panic("test failure"); + expect(v1[2] == 39) catch @panic("test failure"); + expect(v1[3] == 40) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_4_u32() @Vector(4, u32); +extern fn c_vector_4_u32(@Vector(4, u32), usize) void; +extern fn c_vector_4_u32_vector_4_u32(@Vector(4, u32), @Vector(4, u32), usize) void; +extern fn c_test_vector_4_u32() void; + +test "@Vector(4, u32)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + + const v = c_ret_vector_4_u32(); + try expect(v[0] == 41); + try expect(v[1] == 42); + try expect(v[2] == 43); + try expect(v[3] == 44); + c_vector_4_u32(.{ 45, 46, 47, 48 }, 4); + c_vector_4_u32_vector_4_u32(.{ 49, 50, 51, 52 }, .{ 53, 54, 55, 56 }, 8); + c_test_vector_4_u32(); +} + +export fn zig_ret_vector_6_u32() @Vector(6, u32) { + return .{ 41, 42, 43, 44, 45, 46 }; +} +export fn zig_vector_6_u32(v: @Vector(6, u32), i: usize) void { + expect(v[0] == 47) catch @panic("test failure"); + expect(v[1] == 48) catch @panic("test failure"); + expect(v[2] == 49) catch @panic("test failure"); + expect(v[3] == 50) catch @panic("test failure"); + expect(v[4] == 51) catch @panic("test failure"); + expect(v[5] == 52) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} + +extern fn c_ret_vector_6_u32() @Vector(6, u32); +extern fn c_vector_6_u32(@Vector(6, u32), usize) void; +extern fn c_test_vector_6_u32() void; + +test "@Vector(6, u32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_6_u32(); + try expect(v[0] == 53); + try expect(v[1] == 54); + try expect(v[2] == 55); + try expect(v[3] == 56); + try expect(v[4] == 57); + try expect(v[5] == 58); + c_vector_6_u32(.{ 59, 60, 61, 62, 63, 64 }, 6); + c_test_vector_6_u32(); +} + +export fn zig_ret_vector_8_u32() @Vector(8, u32) { + return .{ 65, 66, 67, 68, 69, 70, 71, 72 }; +} +export fn zig_vector_8_u32(v: @Vector(8, u32), i: usize) void { + expect(v[0] == 73) catch @panic("test failure"); + expect(v[1] == 74) catch @panic("test failure"); + expect(v[2] == 75) catch @panic("test failure"); + expect(v[3] == 76) catch @panic("test failure"); + expect(v[4] == 77) catch @panic("test failure"); + expect(v[5] == 78) catch @panic("test failure"); + expect(v[6] == 79) catch @panic("test failure"); + expect(v[7] == 80) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_8_u32() @Vector(8, u32); +extern fn c_vector_8_u32(@Vector(8, u32), usize) void; +extern fn c_test_vector_8_u32() void; + +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); + try expect(v[1] == 82); + try expect(v[2] == 83); + try expect(v[3] == 84); + try expect(v[4] == 85); + try expect(v[5] == 86); + try expect(v[6] == 87); + try expect(v[7] == 88); + c_vector_8_u32(.{ 89, 90, 91, 92, 93, 94, 95, 96 }, 8); + c_test_vector_8_u32(); +} + +export fn zig_ret_vector_12_u32() @Vector(12, u32) { + return .{ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108 }; +} +export fn zig_vector_12_u32(v: @Vector(12, u32), i: usize) void { + expect(v[0] == 109) catch @panic("test failure"); + expect(v[1] == 110) catch @panic("test failure"); + expect(v[2] == 111) catch @panic("test failure"); + expect(v[3] == 112) catch @panic("test failure"); + expect(v[4] == 113) catch @panic("test failure"); + expect(v[5] == 114) catch @panic("test failure"); + expect(v[6] == 115) catch @panic("test failure"); + expect(v[7] == 116) catch @panic("test failure"); + expect(v[8] == 117) catch @panic("test failure"); + expect(v[9] == 118) catch @panic("test failure"); + expect(v[10] == 119) catch @panic("test failure"); + expect(v[11] == 120) catch @panic("test failure"); + expect(i == 12) catch @panic("test failure"); +} + +extern fn c_ret_vector_12_u32() @Vector(12, u32); +extern fn c_vector_12_u32(@Vector(12, u32), usize) void; +extern fn c_test_vector_12_u32() void; + +test "@Vector(12, u32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_12_u32(); + try expect(v[0] == 121); + try expect(v[1] == 122); + try expect(v[2] == 123); + try expect(v[3] == 124); + try expect(v[4] == 125); + try expect(v[5] == 126); + try expect(v[6] == 127); + try expect(v[7] == 128); + try expect(v[8] == 129); + try expect(v[9] == 130); + try expect(v[10] == 131); + try expect(v[11] == 132); + c_vector_12_u32(.{ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144 }, 12); + c_test_vector_12_u32(); +} + +export fn zig_ret_vector_16_u32() @Vector(16, u32) { + return .{ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 }; +} +export fn zig_vector_16_u32(v: @Vector(16, u32), i: usize) void { + expect(v[0] == 161) catch @panic("test failure"); + expect(v[1] == 162) catch @panic("test failure"); + expect(v[2] == 163) catch @panic("test failure"); + expect(v[3] == 164) catch @panic("test failure"); + expect(v[4] == 165) catch @panic("test failure"); + expect(v[5] == 166) catch @panic("test failure"); + expect(v[6] == 167) catch @panic("test failure"); + expect(v[7] == 168) catch @panic("test failure"); + expect(v[8] == 169) catch @panic("test failure"); + expect(v[9] == 170) catch @panic("test failure"); + expect(v[10] == 171) catch @panic("test failure"); + expect(v[11] == 172) catch @panic("test failure"); + expect(v[12] == 173) catch @panic("test failure"); + expect(v[13] == 174) catch @panic("test failure"); + expect(v[14] == 175) catch @panic("test failure"); + expect(v[15] == 176) catch @panic("test failure"); + expect(i == 16) catch @panic("test failure"); +} + +extern fn c_ret_vector_16_u32() @Vector(16, u32); +extern fn c_vector_16_u32(@Vector(16, u32), usize) void; +extern fn c_test_vector_16_u32() void; + +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); + try expect(v[1] == 178); + try expect(v[2] == 179); + try expect(v[3] == 180); + try expect(v[4] == 181); + try expect(v[5] == 182); + try expect(v[6] == 183); + try expect(v[7] == 184); + try expect(v[8] == 185); + try expect(v[9] == 186); + try expect(v[10] == 187); + try expect(v[11] == 188); + try expect(v[12] == 189); + try expect(v[13] == 190); + try expect(v[14] == 191); + try expect(v[15] == 192); + c_vector_16_u32(.{ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208 }, 16); + c_test_vector_16_u32(); +} + +export fn zig_ret_vector_24_u32() @Vector(24, u32) { + return .{ + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, + }; +} +export fn zig_vector_24_u32(v: @Vector(24, u32), i: usize) void { + expect(v[0] == 233) catch @panic("test failure"); + expect(v[1] == 234) catch @panic("test failure"); + expect(v[2] == 235) catch @panic("test failure"); + expect(v[3] == 236) catch @panic("test failure"); + expect(v[4] == 237) catch @panic("test failure"); + expect(v[5] == 238) catch @panic("test failure"); + expect(v[6] == 239) catch @panic("test failure"); + expect(v[7] == 240) catch @panic("test failure"); + expect(v[8] == 241) catch @panic("test failure"); + expect(v[9] == 242) catch @panic("test failure"); + expect(v[10] == 243) catch @panic("test failure"); + expect(v[11] == 244) catch @panic("test failure"); + expect(v[12] == 245) catch @panic("test failure"); + expect(v[13] == 246) catch @panic("test failure"); + expect(v[14] == 247) catch @panic("test failure"); + expect(v[15] == 248) catch @panic("test failure"); + expect(v[16] == 249) catch @panic("test failure"); + expect(v[17] == 250) catch @panic("test failure"); + expect(v[18] == 251) catch @panic("test failure"); + expect(v[19] == 252) catch @panic("test failure"); + expect(v[20] == 253) catch @panic("test failure"); + expect(v[21] == 254) catch @panic("test failure"); + expect(v[22] == 255) catch @panic("test failure"); + expect(v[23] == 256) catch @panic("test failure"); + expect(i == 24) catch @panic("test failure"); +} + +extern fn c_ret_vector_24_u32() @Vector(24, u32); +extern fn c_vector_24_u32(@Vector(24, u32), usize) void; +extern fn c_test_vector_24_u32() void; + +test "@Vector(24, u32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_24_u32(); + try expect(v[0] == 257); + try expect(v[1] == 258); + try expect(v[2] == 259); + try expect(v[3] == 260); + try expect(v[4] == 261); + try expect(v[5] == 262); + try expect(v[6] == 263); + try expect(v[7] == 264); + try expect(v[8] == 265); + try expect(v[9] == 266); + try expect(v[10] == 267); + try expect(v[11] == 268); + try expect(v[12] == 269); + try expect(v[13] == 270); + try expect(v[14] == 271); + try expect(v[15] == 272); + try expect(v[16] == 273); + try expect(v[17] == 274); + try expect(v[18] == 275); + try expect(v[19] == 276); + try expect(v[20] == 277); + try expect(v[21] == 278); + try expect(v[22] == 279); + try expect(v[23] == 280); + c_vector_24_u32(.{ + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, + }, 24); + c_test_vector_24_u32(); +} + +export fn zig_ret_vector_32_u32() @Vector(32, u32) { + return .{ + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, + }; +} +export fn zig_vector_32_u32(v: @Vector(32, u32), i: usize) void { + expect(v[0] == 337) catch @panic("test failure"); + expect(v[1] == 338) catch @panic("test failure"); + expect(v[2] == 339) catch @panic("test failure"); + expect(v[3] == 340) catch @panic("test failure"); + expect(v[4] == 341) catch @panic("test failure"); + expect(v[5] == 342) catch @panic("test failure"); + expect(v[6] == 343) catch @panic("test failure"); + expect(v[7] == 344) catch @panic("test failure"); + expect(v[8] == 345) catch @panic("test failure"); + expect(v[9] == 346) catch @panic("test failure"); + expect(v[10] == 347) catch @panic("test failure"); + expect(v[11] == 348) catch @panic("test failure"); + expect(v[12] == 349) catch @panic("test failure"); + expect(v[13] == 350) catch @panic("test failure"); + expect(v[14] == 351) catch @panic("test failure"); + expect(v[15] == 352) catch @panic("test failure"); + expect(v[16] == 353) catch @panic("test failure"); + expect(v[17] == 354) catch @panic("test failure"); + expect(v[18] == 355) catch @panic("test failure"); + expect(v[19] == 356) catch @panic("test failure"); + expect(v[20] == 357) catch @panic("test failure"); + expect(v[21] == 358) catch @panic("test failure"); + expect(v[22] == 359) catch @panic("test failure"); + expect(v[23] == 360) catch @panic("test failure"); + expect(v[24] == 361) catch @panic("test failure"); + expect(v[25] == 362) catch @panic("test failure"); + expect(v[26] == 363) catch @panic("test failure"); + expect(v[27] == 364) catch @panic("test failure"); + expect(v[28] == 365) catch @panic("test failure"); + expect(v[29] == 366) catch @panic("test failure"); + expect(v[30] == 367) catch @panic("test failure"); + expect(v[31] == 368) catch @panic("test failure"); + expect(i == 32) catch @panic("test failure"); +} + +extern fn c_ret_vector_32_u32() @Vector(32, u32); +extern fn c_vector_32_u32(@Vector(32, u32), usize) void; +extern fn c_test_vector_32_u32() void; + +test "@Vector(32, u32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 370); + try expect(v[2] == 371); + try expect(v[3] == 372); + try expect(v[4] == 373); + try expect(v[5] == 374); + try expect(v[6] == 375); + try expect(v[7] == 376); + try expect(v[8] == 377); + try expect(v[9] == 378); + try expect(v[10] == 379); + try expect(v[11] == 380); + try expect(v[12] == 381); + try expect(v[13] == 382); + try expect(v[14] == 383); + try expect(v[15] == 384); + try expect(v[16] == 385); + try expect(v[17] == 386); + try expect(v[18] == 387); + try expect(v[19] == 388); + try expect(v[20] == 389); + try expect(v[21] == 390); + try expect(v[22] == 391); + try expect(v[23] == 392); + try expect(v[24] == 393); + try expect(v[25] == 394); + try expect(v[26] == 395); + try expect(v[27] == 396); + try expect(v[28] == 397); + try expect(v[29] == 398); + try expect(v[30] == 399); + try expect(v[31] == 400); + c_vector_32_u32(.{ + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, + }, 32); + c_test_vector_32_u32(); +} + +export fn zig_ret_vector_48_u32() @Vector(48, u32) { + return .{ + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, + }; +} +export fn zig_vector_48_u32(v: @Vector(48, u32), i: usize) void { + expect(v[0] == 481) catch @panic("test failure"); + expect(v[1] == 482) catch @panic("test failure"); + expect(v[2] == 483) catch @panic("test failure"); + expect(v[3] == 484) catch @panic("test failure"); + expect(v[4] == 485) catch @panic("test failure"); + expect(v[5] == 486) catch @panic("test failure"); + expect(v[6] == 487) catch @panic("test failure"); + expect(v[7] == 488) catch @panic("test failure"); + expect(v[8] == 489) catch @panic("test failure"); + expect(v[9] == 490) catch @panic("test failure"); + expect(v[10] == 491) catch @panic("test failure"); + expect(v[11] == 492) catch @panic("test failure"); + expect(v[12] == 493) catch @panic("test failure"); + expect(v[13] == 494) catch @panic("test failure"); + expect(v[14] == 495) catch @panic("test failure"); + expect(v[15] == 496) catch @panic("test failure"); + expect(v[16] == 497) catch @panic("test failure"); + expect(v[17] == 498) catch @panic("test failure"); + expect(v[18] == 499) catch @panic("test failure"); + expect(v[19] == 500) catch @panic("test failure"); + expect(v[20] == 501) catch @panic("test failure"); + expect(v[21] == 502) catch @panic("test failure"); + expect(v[22] == 503) catch @panic("test failure"); + expect(v[23] == 504) catch @panic("test failure"); + expect(v[24] == 505) catch @panic("test failure"); + expect(v[25] == 506) catch @panic("test failure"); + expect(v[26] == 507) catch @panic("test failure"); + expect(v[27] == 508) catch @panic("test failure"); + expect(v[28] == 509) catch @panic("test failure"); + expect(v[29] == 510) catch @panic("test failure"); + expect(v[30] == 511) catch @panic("test failure"); + expect(v[31] == 512) catch @panic("test failure"); + expect(v[32] == 513) catch @panic("test failure"); + expect(v[33] == 514) catch @panic("test failure"); + expect(v[34] == 515) catch @panic("test failure"); + expect(v[35] == 516) catch @panic("test failure"); + expect(v[36] == 517) catch @panic("test failure"); + expect(v[37] == 518) catch @panic("test failure"); + expect(v[38] == 519) catch @panic("test failure"); + expect(v[39] == 520) catch @panic("test failure"); + expect(v[40] == 521) catch @panic("test failure"); + expect(v[41] == 522) catch @panic("test failure"); + expect(v[42] == 523) catch @panic("test failure"); + expect(v[43] == 524) catch @panic("test failure"); + expect(v[44] == 525) catch @panic("test failure"); + expect(v[45] == 526) catch @panic("test failure"); + expect(v[46] == 527) catch @panic("test failure"); + expect(v[47] == 528) catch @panic("test failure"); + expect(i == 48) catch @panic("test failure"); +} + +extern fn c_ret_vector_48_u32() @Vector(48, u32); +extern fn c_vector_48_u32(@Vector(48, u32), usize) void; +extern fn c_test_vector_48_u32() void; + +test "@Vector(48, u32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_48_u32(); + try expect(v[0] == 529); + try expect(v[1] == 530); + try expect(v[2] == 531); + try expect(v[3] == 532); + try expect(v[4] == 533); + try expect(v[5] == 534); + try expect(v[6] == 535); + try expect(v[7] == 536); + try expect(v[8] == 537); + try expect(v[9] == 538); + try expect(v[10] == 539); + try expect(v[11] == 540); + try expect(v[12] == 541); + try expect(v[13] == 542); + try expect(v[14] == 543); + try expect(v[15] == 544); + try expect(v[16] == 545); + try expect(v[17] == 546); + try expect(v[18] == 547); + try expect(v[19] == 548); + try expect(v[20] == 549); + try expect(v[21] == 550); + try expect(v[22] == 551); + try expect(v[23] == 552); + try expect(v[24] == 553); + try expect(v[25] == 554); + try expect(v[26] == 555); + try expect(v[27] == 556); + try expect(v[28] == 557); + try expect(v[29] == 558); + try expect(v[30] == 559); + try expect(v[31] == 560); + try expect(v[32] == 561); + try expect(v[33] == 562); + try expect(v[34] == 563); + try expect(v[35] == 564); + try expect(v[36] == 565); + try expect(v[37] == 566); + try expect(v[38] == 567); + try expect(v[39] == 568); + try expect(v[40] == 569); + try expect(v[41] == 570); + try expect(v[42] == 571); + try expect(v[43] == 572); + try expect(v[44] == 573); + try expect(v[45] == 574); + try expect(v[46] == 575); + try expect(v[47] == 576); + c_vector_48_u32(.{ + 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, + 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, + 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + }, 48); + c_test_vector_48_u32(); +} + +export fn zig_ret_vector_64_u32() @Vector(64, u32) { + return .{ + 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, + 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, + 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, + 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, + }; +} +export fn zig_vector_64_u32(v: @Vector(64, u32), i: usize) void { + expect(v[0] == 689) catch @panic("test failure"); + expect(v[1] == 690) catch @panic("test failure"); + expect(v[2] == 691) catch @panic("test failure"); + expect(v[3] == 692) catch @panic("test failure"); + expect(v[4] == 693) catch @panic("test failure"); + expect(v[5] == 694) catch @panic("test failure"); + expect(v[6] == 695) catch @panic("test failure"); + expect(v[7] == 696) catch @panic("test failure"); + expect(v[8] == 697) catch @panic("test failure"); + expect(v[9] == 698) catch @panic("test failure"); + expect(v[10] == 699) catch @panic("test failure"); + expect(v[11] == 700) catch @panic("test failure"); + expect(v[12] == 701) catch @panic("test failure"); + expect(v[13] == 702) catch @panic("test failure"); + expect(v[14] == 703) catch @panic("test failure"); + expect(v[15] == 704) catch @panic("test failure"); + expect(v[16] == 705) catch @panic("test failure"); + expect(v[17] == 706) catch @panic("test failure"); + expect(v[18] == 707) catch @panic("test failure"); + expect(v[19] == 708) catch @panic("test failure"); + expect(v[20] == 709) catch @panic("test failure"); + expect(v[21] == 710) catch @panic("test failure"); + expect(v[22] == 711) catch @panic("test failure"); + expect(v[23] == 712) catch @panic("test failure"); + expect(v[24] == 713) catch @panic("test failure"); + expect(v[25] == 714) catch @panic("test failure"); + expect(v[26] == 715) catch @panic("test failure"); + expect(v[27] == 716) catch @panic("test failure"); + expect(v[28] == 717) catch @panic("test failure"); + expect(v[29] == 718) catch @panic("test failure"); + expect(v[30] == 719) catch @panic("test failure"); + expect(v[31] == 720) catch @panic("test failure"); + expect(v[32] == 721) catch @panic("test failure"); + expect(v[33] == 722) catch @panic("test failure"); + expect(v[34] == 723) catch @panic("test failure"); + expect(v[35] == 724) catch @panic("test failure"); + expect(v[36] == 725) catch @panic("test failure"); + expect(v[37] == 726) catch @panic("test failure"); + expect(v[38] == 727) catch @panic("test failure"); + expect(v[39] == 728) catch @panic("test failure"); + expect(v[40] == 729) catch @panic("test failure"); + expect(v[41] == 730) catch @panic("test failure"); + expect(v[42] == 731) catch @panic("test failure"); + expect(v[43] == 732) catch @panic("test failure"); + expect(v[44] == 733) catch @panic("test failure"); + expect(v[45] == 734) catch @panic("test failure"); + expect(v[46] == 735) catch @panic("test failure"); + expect(v[47] == 736) catch @panic("test failure"); + expect(v[48] == 737) catch @panic("test failure"); + expect(v[49] == 738) catch @panic("test failure"); + expect(v[50] == 739) catch @panic("test failure"); + expect(v[51] == 740) catch @panic("test failure"); + expect(v[52] == 741) catch @panic("test failure"); + expect(v[53] == 742) catch @panic("test failure"); + expect(v[54] == 743) catch @panic("test failure"); + expect(v[55] == 744) catch @panic("test failure"); + expect(v[56] == 745) catch @panic("test failure"); + expect(v[57] == 746) catch @panic("test failure"); + expect(v[58] == 747) catch @panic("test failure"); + expect(v[59] == 748) catch @panic("test failure"); + expect(v[60] == 749) catch @panic("test failure"); + expect(v[61] == 750) catch @panic("test failure"); + expect(v[62] == 751) catch @panic("test failure"); + expect(v[63] == 752) catch @panic("test failure"); + expect(i == 64) catch @panic("test failure"); +} + +extern fn c_ret_vector_64_u32() @Vector(64, u32); +extern fn c_vector_64_u32(@Vector(64, u32), usize) void; +extern fn c_test_vector_64_u32() void; + +test "@Vector(64, u32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 754); + try expect(v[2] == 755); + try expect(v[3] == 756); + try expect(v[4] == 757); + try expect(v[5] == 758); + try expect(v[6] == 759); + try expect(v[7] == 760); + try expect(v[8] == 761); + try expect(v[9] == 762); + try expect(v[10] == 763); + try expect(v[11] == 764); + try expect(v[12] == 765); + try expect(v[13] == 766); + try expect(v[14] == 767); + try expect(v[15] == 768); + try expect(v[16] == 769); + try expect(v[17] == 770); + try expect(v[18] == 771); + try expect(v[19] == 772); + try expect(v[20] == 773); + try expect(v[21] == 774); + try expect(v[22] == 775); + try expect(v[23] == 776); + try expect(v[24] == 777); + try expect(v[25] == 778); + try expect(v[26] == 779); + try expect(v[27] == 780); + try expect(v[28] == 781); + try expect(v[29] == 782); + try expect(v[30] == 783); + try expect(v[31] == 784); + try expect(v[32] == 785); + try expect(v[33] == 786); + try expect(v[34] == 787); + try expect(v[35] == 788); + try expect(v[36] == 789); + try expect(v[37] == 790); + try expect(v[38] == 791); + try expect(v[39] == 792); + try expect(v[40] == 793); + try expect(v[41] == 794); + try expect(v[42] == 795); + try expect(v[43] == 796); + try expect(v[44] == 797); + try expect(v[45] == 798); + try expect(v[46] == 799); + try expect(v[47] == 800); + try expect(v[48] == 801); + try expect(v[49] == 802); + try expect(v[50] == 803); + try expect(v[51] == 804); + try expect(v[52] == 805); + try expect(v[53] == 806); + try expect(v[54] == 807); + try expect(v[55] == 808); + try expect(v[56] == 809); + try expect(v[57] == 810); + try expect(v[58] == 811); + try expect(v[59] == 812); + try expect(v[60] == 813); + try expect(v[61] == 814); + try expect(v[62] == 815); + try expect(v[63] == 816); + c_vector_64_u32(.{ + 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, + 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, + 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, + 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, + }, 64); + c_test_vector_64_u32(); +} + +export fn zig_ret_vector_96_u32() @Vector(96, u32) { + return .{ + 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, + 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, + 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, + 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, + 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, + 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, + }; +} +export fn zig_vector_96_u32(v: @Vector(96, u32), i: usize) void { + expect(v[0] == 986) catch @panic("test failure"); + expect(v[1] == 987) catch @panic("test failure"); + expect(v[2] == 988) catch @panic("test failure"); + expect(v[3] == 989) catch @panic("test failure"); + expect(v[4] == 990) catch @panic("test failure"); + expect(v[5] == 991) catch @panic("test failure"); + expect(v[6] == 992) catch @panic("test failure"); + expect(v[7] == 993) catch @panic("test failure"); + expect(v[8] == 994) catch @panic("test failure"); + expect(v[9] == 995) catch @panic("test failure"); + expect(v[10] == 996) catch @panic("test failure"); + expect(v[11] == 997) catch @panic("test failure"); + expect(v[12] == 998) catch @panic("test failure"); + expect(v[13] == 999) catch @panic("test failure"); + expect(v[14] == 1000) catch @panic("test failure"); + expect(v[15] == 1001) catch @panic("test failure"); + expect(v[16] == 1002) catch @panic("test failure"); + expect(v[17] == 1003) catch @panic("test failure"); + expect(v[18] == 1004) catch @panic("test failure"); + expect(v[19] == 1005) catch @panic("test failure"); + expect(v[20] == 1006) catch @panic("test failure"); + expect(v[21] == 1007) catch @panic("test failure"); + expect(v[22] == 1008) catch @panic("test failure"); + expect(v[23] == 1009) catch @panic("test failure"); + expect(v[24] == 1010) catch @panic("test failure"); + expect(v[25] == 1011) catch @panic("test failure"); + expect(v[26] == 1012) catch @panic("test failure"); + expect(v[27] == 1013) catch @panic("test failure"); + expect(v[28] == 1014) catch @panic("test failure"); + expect(v[29] == 1015) catch @panic("test failure"); + expect(v[30] == 1016) catch @panic("test failure"); + expect(v[31] == 1017) catch @panic("test failure"); + expect(v[32] == 1018) catch @panic("test failure"); + expect(v[33] == 1019) catch @panic("test failure"); + expect(v[34] == 1020) catch @panic("test failure"); + expect(v[35] == 1021) catch @panic("test failure"); + expect(v[36] == 1022) catch @panic("test failure"); + expect(v[37] == 1023) catch @panic("test failure"); + expect(v[38] == 1024) catch @panic("test failure"); + expect(v[39] == 1025) catch @panic("test failure"); + expect(v[40] == 1026) catch @panic("test failure"); + expect(v[41] == 1027) catch @panic("test failure"); + expect(v[42] == 1028) catch @panic("test failure"); + expect(v[43] == 1029) catch @panic("test failure"); + expect(v[44] == 1030) catch @panic("test failure"); + expect(v[45] == 1031) catch @panic("test failure"); + expect(v[46] == 1032) catch @panic("test failure"); + expect(v[47] == 1033) catch @panic("test failure"); + expect(v[48] == 1034) catch @panic("test failure"); + expect(v[49] == 1035) catch @panic("test failure"); + expect(v[50] == 1036) catch @panic("test failure"); + expect(v[51] == 1037) catch @panic("test failure"); + expect(v[52] == 1038) catch @panic("test failure"); + expect(v[53] == 1039) catch @panic("test failure"); + expect(v[54] == 1040) catch @panic("test failure"); + expect(v[55] == 1041) catch @panic("test failure"); + expect(v[56] == 1042) catch @panic("test failure"); + expect(v[57] == 1043) catch @panic("test failure"); + expect(v[58] == 1044) catch @panic("test failure"); + expect(v[59] == 1045) catch @panic("test failure"); + expect(v[60] == 1046) catch @panic("test failure"); + expect(v[61] == 1047) catch @panic("test failure"); + expect(v[62] == 1048) catch @panic("test failure"); + expect(v[63] == 1049) catch @panic("test failure"); + expect(v[64] == 1050) catch @panic("test failure"); + expect(v[65] == 1051) catch @panic("test failure"); + expect(v[66] == 1052) catch @panic("test failure"); + expect(v[67] == 1053) catch @panic("test failure"); + expect(v[68] == 1054) catch @panic("test failure"); + expect(v[69] == 1055) catch @panic("test failure"); + expect(v[70] == 1056) catch @panic("test failure"); + expect(v[71] == 1057) catch @panic("test failure"); + expect(v[72] == 1058) catch @panic("test failure"); + expect(v[73] == 1059) catch @panic("test failure"); + expect(v[74] == 1060) catch @panic("test failure"); + expect(v[75] == 1061) catch @panic("test failure"); + expect(v[76] == 1062) catch @panic("test failure"); + expect(v[77] == 1063) catch @panic("test failure"); + expect(v[78] == 1064) catch @panic("test failure"); + expect(v[79] == 1065) catch @panic("test failure"); + expect(v[80] == 1066) catch @panic("test failure"); + expect(v[81] == 1067) catch @panic("test failure"); + expect(v[82] == 1068) catch @panic("test failure"); + expect(v[83] == 1069) catch @panic("test failure"); + expect(v[84] == 1070) catch @panic("test failure"); + expect(v[85] == 1071) catch @panic("test failure"); + expect(v[86] == 1072) catch @panic("test failure"); + expect(v[87] == 1073) catch @panic("test failure"); + expect(v[88] == 1074) catch @panic("test failure"); + expect(v[89] == 1075) catch @panic("test failure"); + expect(v[90] == 1076) catch @panic("test failure"); + expect(v[91] == 1077) catch @panic("test failure"); + expect(v[92] == 1078) catch @panic("test failure"); + expect(v[93] == 1079) catch @panic("test failure"); + expect(v[94] == 1080) catch @panic("test failure"); + expect(v[95] == 1081) catch @panic("test failure"); + expect(i == 96) catch @panic("test failure"); +} + +extern fn c_ret_vector_96_u32() @Vector(96, u32); +extern fn c_vector_96_u32(@Vector(96, u32), usize) void; +extern fn c_test_vector_96_u32() void; + +test "@Vector(96, u32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_96_u32(); + try expect(v[0] == 1082); + try expect(v[1] == 1083); + try expect(v[2] == 1084); + try expect(v[3] == 1085); + try expect(v[4] == 1086); + try expect(v[5] == 1087); + try expect(v[6] == 1088); + try expect(v[7] == 1089); + try expect(v[8] == 1090); + try expect(v[9] == 1091); + try expect(v[10] == 1092); + try expect(v[11] == 1093); + try expect(v[12] == 1094); + try expect(v[13] == 1095); + try expect(v[14] == 1096); + try expect(v[15] == 1097); + try expect(v[16] == 1098); + try expect(v[17] == 1099); + try expect(v[18] == 1100); + try expect(v[19] == 1101); + try expect(v[20] == 1102); + try expect(v[21] == 1103); + try expect(v[22] == 1104); + try expect(v[23] == 1105); + try expect(v[24] == 1106); + try expect(v[25] == 1107); + try expect(v[26] == 1108); + try expect(v[27] == 1109); + try expect(v[28] == 1110); + try expect(v[29] == 1111); + try expect(v[30] == 1112); + try expect(v[31] == 1113); + try expect(v[32] == 1114); + try expect(v[33] == 1115); + try expect(v[34] == 1116); + try expect(v[35] == 1117); + try expect(v[36] == 1118); + try expect(v[37] == 1119); + try expect(v[38] == 1120); + try expect(v[39] == 1121); + try expect(v[40] == 1122); + try expect(v[41] == 1123); + try expect(v[42] == 1124); + try expect(v[43] == 1125); + try expect(v[44] == 1126); + try expect(v[45] == 1127); + try expect(v[46] == 1128); + try expect(v[47] == 1129); + try expect(v[48] == 1130); + try expect(v[49] == 1131); + try expect(v[50] == 1132); + try expect(v[51] == 1133); + try expect(v[52] == 1134); + try expect(v[53] == 1135); + try expect(v[54] == 1136); + try expect(v[55] == 1137); + try expect(v[56] == 1138); + try expect(v[57] == 1139); + try expect(v[58] == 1140); + try expect(v[59] == 1141); + try expect(v[60] == 1142); + try expect(v[61] == 1143); + try expect(v[62] == 1144); + try expect(v[63] == 1145); + try expect(v[64] == 1146); + try expect(v[65] == 1147); + try expect(v[66] == 1148); + try expect(v[67] == 1149); + try expect(v[68] == 1150); + try expect(v[69] == 1151); + try expect(v[70] == 1152); + try expect(v[71] == 1153); + try expect(v[72] == 1154); + try expect(v[73] == 1155); + try expect(v[74] == 1156); + try expect(v[75] == 1157); + try expect(v[76] == 1158); + try expect(v[77] == 1159); + try expect(v[78] == 1160); + try expect(v[79] == 1161); + try expect(v[80] == 1162); + try expect(v[81] == 1163); + try expect(v[82] == 1164); + try expect(v[83] == 1165); + try expect(v[84] == 1166); + try expect(v[85] == 1167); + try expect(v[86] == 1168); + try expect(v[87] == 1169); + try expect(v[88] == 1170); + try expect(v[89] == 1171); + try expect(v[90] == 1172); + try expect(v[91] == 1173); + try expect(v[92] == 1174); + try expect(v[93] == 1175); + try expect(v[94] == 1176); + try expect(v[95] == 1177); + c_vector_96_u32(.{ + 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, + 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, + 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, + 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, + 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, + 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, + }, 96); + c_test_vector_96_u32(); +} + +export fn zig_ret_vector_128_u32() @Vector(128, u32) { + return .{ + 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, + 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, + 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, + 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, + 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, + 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, + 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, + 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, + }; +} +export fn zig_vector_128_u32(v: @Vector(128, u32), i: usize) void { + expect(v[0] == 1402) catch @panic("test failure"); + expect(v[1] == 1403) catch @panic("test failure"); + expect(v[2] == 1404) catch @panic("test failure"); + expect(v[3] == 1405) catch @panic("test failure"); + expect(v[4] == 1406) catch @panic("test failure"); + expect(v[5] == 1407) catch @panic("test failure"); + expect(v[6] == 1408) catch @panic("test failure"); + expect(v[7] == 1409) catch @panic("test failure"); + expect(v[8] == 1410) catch @panic("test failure"); + expect(v[9] == 1411) catch @panic("test failure"); + expect(v[10] == 1412) catch @panic("test failure"); + expect(v[11] == 1413) catch @panic("test failure"); + expect(v[12] == 1414) catch @panic("test failure"); + expect(v[13] == 1415) catch @panic("test failure"); + expect(v[14] == 1416) catch @panic("test failure"); + expect(v[15] == 1417) catch @panic("test failure"); + expect(v[16] == 1418) catch @panic("test failure"); + expect(v[17] == 1419) catch @panic("test failure"); + expect(v[18] == 1420) catch @panic("test failure"); + expect(v[19] == 1421) catch @panic("test failure"); + expect(v[20] == 1422) catch @panic("test failure"); + expect(v[21] == 1423) catch @panic("test failure"); + expect(v[22] == 1424) catch @panic("test failure"); + expect(v[23] == 1425) catch @panic("test failure"); + expect(v[24] == 1426) catch @panic("test failure"); + expect(v[25] == 1427) catch @panic("test failure"); + expect(v[26] == 1428) catch @panic("test failure"); + expect(v[27] == 1429) catch @panic("test failure"); + expect(v[28] == 1430) catch @panic("test failure"); + expect(v[29] == 1431) catch @panic("test failure"); + expect(v[30] == 1432) catch @panic("test failure"); + expect(v[31] == 1433) catch @panic("test failure"); + expect(v[32] == 1434) catch @panic("test failure"); + expect(v[33] == 1435) catch @panic("test failure"); + expect(v[34] == 1436) catch @panic("test failure"); + expect(v[35] == 1437) catch @panic("test failure"); + expect(v[36] == 1438) catch @panic("test failure"); + expect(v[37] == 1439) catch @panic("test failure"); + expect(v[38] == 1440) catch @panic("test failure"); + expect(v[39] == 1441) catch @panic("test failure"); + expect(v[40] == 1442) catch @panic("test failure"); + expect(v[41] == 1443) catch @panic("test failure"); + expect(v[42] == 1444) catch @panic("test failure"); + expect(v[43] == 1445) catch @panic("test failure"); + expect(v[44] == 1446) catch @panic("test failure"); + expect(v[45] == 1447) catch @panic("test failure"); + expect(v[46] == 1448) catch @panic("test failure"); + expect(v[47] == 1449) catch @panic("test failure"); + expect(v[48] == 1450) catch @panic("test failure"); + expect(v[49] == 1451) catch @panic("test failure"); + expect(v[50] == 1452) catch @panic("test failure"); + expect(v[51] == 1453) catch @panic("test failure"); + expect(v[52] == 1454) catch @panic("test failure"); + expect(v[53] == 1455) catch @panic("test failure"); + expect(v[54] == 1456) catch @panic("test failure"); + expect(v[55] == 1457) catch @panic("test failure"); + expect(v[56] == 1458) catch @panic("test failure"); + expect(v[57] == 1459) catch @panic("test failure"); + expect(v[58] == 1460) catch @panic("test failure"); + expect(v[59] == 1461) catch @panic("test failure"); + expect(v[60] == 1462) catch @panic("test failure"); + expect(v[61] == 1463) catch @panic("test failure"); + expect(v[62] == 1464) catch @panic("test failure"); + expect(v[63] == 1465) catch @panic("test failure"); + expect(v[64] == 1466) catch @panic("test failure"); + expect(v[65] == 1467) catch @panic("test failure"); + expect(v[66] == 1468) catch @panic("test failure"); + expect(v[67] == 1469) catch @panic("test failure"); + expect(v[68] == 1470) catch @panic("test failure"); + expect(v[69] == 1471) catch @panic("test failure"); + expect(v[70] == 1472) catch @panic("test failure"); + expect(v[71] == 1473) catch @panic("test failure"); + expect(v[72] == 1474) catch @panic("test failure"); + expect(v[73] == 1475) catch @panic("test failure"); + expect(v[74] == 1476) catch @panic("test failure"); + expect(v[75] == 1477) catch @panic("test failure"); + expect(v[76] == 1478) catch @panic("test failure"); + expect(v[77] == 1479) catch @panic("test failure"); + expect(v[78] == 1480) catch @panic("test failure"); + expect(v[79] == 1481) catch @panic("test failure"); + expect(v[80] == 1482) catch @panic("test failure"); + expect(v[81] == 1483) catch @panic("test failure"); + expect(v[82] == 1484) catch @panic("test failure"); + expect(v[83] == 1485) catch @panic("test failure"); + expect(v[84] == 1486) catch @panic("test failure"); + expect(v[85] == 1487) catch @panic("test failure"); + expect(v[86] == 1488) catch @panic("test failure"); + expect(v[87] == 1489) catch @panic("test failure"); + expect(v[88] == 1490) catch @panic("test failure"); + expect(v[89] == 1491) catch @panic("test failure"); + expect(v[90] == 1492) catch @panic("test failure"); + expect(v[91] == 1493) catch @panic("test failure"); + expect(v[92] == 1494) catch @panic("test failure"); + expect(v[93] == 1495) catch @panic("test failure"); + expect(v[94] == 1496) catch @panic("test failure"); + expect(v[95] == 1497) catch @panic("test failure"); + expect(v[96] == 1498) catch @panic("test failure"); + expect(v[97] == 1499) catch @panic("test failure"); + expect(v[98] == 1500) catch @panic("test failure"); + expect(v[99] == 1501) catch @panic("test failure"); + expect(v[100] == 1502) catch @panic("test failure"); + expect(v[101] == 1503) catch @panic("test failure"); + expect(v[102] == 1504) catch @panic("test failure"); + expect(v[103] == 1505) catch @panic("test failure"); + expect(v[104] == 1506) catch @panic("test failure"); + expect(v[105] == 1507) catch @panic("test failure"); + expect(v[106] == 1508) catch @panic("test failure"); + expect(v[107] == 1509) catch @panic("test failure"); + expect(v[108] == 1510) catch @panic("test failure"); + expect(v[109] == 1511) catch @panic("test failure"); + expect(v[110] == 1512) catch @panic("test failure"); + expect(v[111] == 1513) catch @panic("test failure"); + expect(v[112] == 1514) catch @panic("test failure"); + expect(v[113] == 1515) catch @panic("test failure"); + expect(v[114] == 1516) catch @panic("test failure"); + expect(v[115] == 1517) catch @panic("test failure"); + expect(v[116] == 1518) catch @panic("test failure"); + expect(v[117] == 1519) catch @panic("test failure"); + expect(v[118] == 1520) catch @panic("test failure"); + expect(v[119] == 1521) catch @panic("test failure"); + expect(v[120] == 1522) catch @panic("test failure"); + expect(v[121] == 1523) catch @panic("test failure"); + expect(v[122] == 1524) catch @panic("test failure"); + expect(v[123] == 1525) catch @panic("test failure"); + expect(v[124] == 1526) catch @panic("test failure"); + expect(v[125] == 1527) catch @panic("test failure"); + expect(v[126] == 1528) catch @panic("test failure"); + expect(v[127] == 1529) catch @panic("test failure"); + expect(i == 128) catch @panic("test failure"); +} + +extern fn c_ret_vector_128_u32() @Vector(128, u32); +extern fn c_vector_128_u32(@Vector(128, u32), usize) void; +extern fn c_test_vector_128_u32() void; + +test "@Vector(128, u32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 1531); + try expect(v[2] == 1532); + try expect(v[3] == 1533); + try expect(v[4] == 1534); + try expect(v[5] == 1535); + try expect(v[6] == 1536); + try expect(v[7] == 1537); + try expect(v[8] == 1538); + try expect(v[9] == 1539); + try expect(v[10] == 1540); + try expect(v[11] == 1541); + try expect(v[12] == 1542); + try expect(v[13] == 1543); + try expect(v[14] == 1544); + try expect(v[15] == 1545); + try expect(v[16] == 1546); + try expect(v[17] == 1547); + try expect(v[18] == 1548); + try expect(v[19] == 1549); + try expect(v[20] == 1550); + try expect(v[21] == 1551); + try expect(v[22] == 1552); + try expect(v[23] == 1553); + try expect(v[24] == 1554); + try expect(v[25] == 1555); + try expect(v[26] == 1556); + try expect(v[27] == 1557); + try expect(v[28] == 1558); + try expect(v[29] == 1559); + try expect(v[30] == 1560); + try expect(v[31] == 1561); + try expect(v[32] == 1562); + try expect(v[33] == 1563); + try expect(v[34] == 1564); + try expect(v[35] == 1565); + try expect(v[36] == 1566); + try expect(v[37] == 1567); + try expect(v[38] == 1568); + try expect(v[39] == 1569); + try expect(v[40] == 1570); + try expect(v[41] == 1571); + try expect(v[42] == 1572); + try expect(v[43] == 1573); + try expect(v[44] == 1574); + try expect(v[45] == 1575); + try expect(v[46] == 1576); + try expect(v[47] == 1577); + try expect(v[48] == 1578); + try expect(v[49] == 1579); + try expect(v[50] == 1580); + try expect(v[51] == 1581); + try expect(v[52] == 1582); + try expect(v[53] == 1583); + try expect(v[54] == 1584); + try expect(v[55] == 1585); + try expect(v[56] == 1586); + try expect(v[57] == 1587); + try expect(v[58] == 1588); + try expect(v[59] == 1589); + try expect(v[60] == 1590); + try expect(v[61] == 1591); + try expect(v[62] == 1592); + try expect(v[63] == 1593); + try expect(v[64] == 1594); + try expect(v[65] == 1595); + try expect(v[66] == 1596); + try expect(v[67] == 1597); + try expect(v[68] == 1598); + try expect(v[69] == 1599); + try expect(v[70] == 1600); + try expect(v[71] == 1601); + try expect(v[72] == 1602); + try expect(v[73] == 1603); + try expect(v[74] == 1604); + try expect(v[75] == 1605); + try expect(v[76] == 1606); + try expect(v[77] == 1607); + try expect(v[78] == 1608); + try expect(v[79] == 1609); + try expect(v[80] == 1610); + try expect(v[81] == 1611); + try expect(v[82] == 1612); + try expect(v[83] == 1613); + try expect(v[84] == 1614); + try expect(v[85] == 1615); + try expect(v[86] == 1616); + try expect(v[87] == 1617); + try expect(v[88] == 1618); + try expect(v[89] == 1619); + try expect(v[90] == 1620); + try expect(v[91] == 1621); + try expect(v[92] == 1622); + try expect(v[93] == 1623); + try expect(v[94] == 1624); + try expect(v[95] == 1625); + try expect(v[96] == 1626); + try expect(v[97] == 1627); + try expect(v[98] == 1628); + try expect(v[99] == 1629); + try expect(v[100] == 1630); + try expect(v[101] == 1631); + try expect(v[102] == 1632); + try expect(v[103] == 1633); + try expect(v[104] == 1634); + try expect(v[105] == 1635); + try expect(v[106] == 1636); + try expect(v[107] == 1637); + try expect(v[108] == 1638); + try expect(v[109] == 1639); + try expect(v[110] == 1640); + try expect(v[111] == 1641); + try expect(v[112] == 1642); + try expect(v[113] == 1643); + try expect(v[114] == 1644); + try expect(v[115] == 1645); + try expect(v[116] == 1646); + try expect(v[117] == 1647); + try expect(v[118] == 1648); + try expect(v[119] == 1649); + try expect(v[120] == 1650); + try expect(v[121] == 1651); + try expect(v[122] == 1652); + try expect(v[123] == 1653); + try expect(v[124] == 1654); + try expect(v[125] == 1655); + try expect(v[126] == 1656); + try expect(v[127] == 1657); + c_vector_128_u32(.{ + 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, + 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, + 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1705, + 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, + 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, + 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 1750, 1751, 1752, 1753, + 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, + 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, + }, 128); + c_test_vector_128_u32(); +} + +export fn zig_ret_vector_1_u64() @Vector(1, u64) { + return .{1}; +} +export fn zig_vector_1_u64(v: @Vector(1, u64), i: usize) void { + expect(v[0] == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_vector_1_u64() @Vector(1, u64); +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); + c_test_vector_1_u64(); +} + +export fn zig_ret_vector_2_u64() @Vector(2, u64) { + return .{ 5, 6 }; +} +export fn zig_vector_2_u64(v: @Vector(2, u64), i: usize) void { + expect(v[0] == 7) catch @panic("test failure"); + expect(v[1] == 8) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} + +extern fn c_ret_vector_2_u64() @Vector(2, u64); +extern fn c_vector_2_u64(@Vector(2, u64), usize) void; +extern fn c_test_vector_2_u64() void; + +test "@Vector(2, u64)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + + const v = c_ret_vector_2_u64(); + try expect(v[0] == 9); + try expect(v[1] == 10); + c_vector_2_u64(.{ 11, 12 }, 2); + c_test_vector_2_u64(); +} + +export fn zig_ret_vector_3_u64() @Vector(3, u64) { + return .{ 13, 14, 15 }; +} +export fn zig_vector_3_u64(v: @Vector(3, u64), i: usize) void { + expect(v[0] == 16) catch @panic("test failure"); + expect(v[1] == 17) catch @panic("test failure"); + expect(v[2] == 18) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_vector_3_u64() @Vector(3, u64); +extern fn c_vector_3_u64(@Vector(3, u64), usize) void; +extern fn c_test_vector_3_u64() void; + +test "@Vector(3, u64)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_3_u64(); + try expect(v[0] == 19); + try expect(v[1] == 20); + try expect(v[2] == 21); + c_vector_3_u64(.{ 22, 23, 24 }, 3); + c_test_vector_3_u64(); +} + +export fn zig_ret_vector_4_u64() @Vector(4, u64) { + return .{ 25, 26, 27, 28 }; +} +export fn zig_vector_4_u64(v: @Vector(4, u64), i: usize) void { + expect(v[0] == 29) catch @panic("test failure"); + expect(v[1] == 30) catch @panic("test failure"); + expect(v[2] == 31) catch @panic("test failure"); + expect(v[3] == 32) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} + +extern fn c_ret_vector_4_u64() @Vector(4, u64); +extern fn c_vector_4_u64(@Vector(4, u64), usize) void; +extern fn c_test_vector_4_u64() void; + +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); + try expect(v[1] == 34); + try expect(v[2] == 35); + try expect(v[3] == 36); + c_vector_4_u64(.{ 37, 38, 39, 40 }, 4); + c_test_vector_4_u64(); +} + +export fn zig_ret_vector_6_u64() @Vector(6, u64) { + return .{ 41, 42, 43, 44, 45, 46 }; +} +export fn zig_vector_6_u64(v: @Vector(6, u64), i: usize) void { + expect(v[0] == 47) catch @panic("test failure"); + expect(v[1] == 48) catch @panic("test failure"); + expect(v[2] == 49) catch @panic("test failure"); + expect(v[3] == 50) catch @panic("test failure"); + expect(v[4] == 51) catch @panic("test failure"); + expect(v[5] == 52) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} + +extern fn c_ret_vector_6_u64() @Vector(6, u64); +extern fn c_vector_6_u64(@Vector(6, u64), usize) void; +extern fn c_test_vector_6_u64() void; + +test "@Vector(6, u64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + + const v = c_ret_vector_6_u64(); + try expect(v[0] == 53); + try expect(v[1] == 54); + try expect(v[2] == 55); + try expect(v[3] == 56); + try expect(v[4] == 57); + try expect(v[5] == 58); + c_vector_6_u64(.{ 59, 60, 61, 62, 63, 64 }, 6); + c_test_vector_6_u64(); +} + +export fn zig_ret_vector_8_u64() @Vector(8, u64) { + return .{ 65, 66, 67, 68, 69, 70, 71, 72 }; +} +export fn zig_vector_8_u64(v: @Vector(8, u64), i: usize) void { + expect(v[0] == 73) catch @panic("test failure"); + expect(v[1] == 74) catch @panic("test failure"); + expect(v[2] == 75) catch @panic("test failure"); + expect(v[3] == 76) catch @panic("test failure"); + expect(v[4] == 77) catch @panic("test failure"); + expect(v[5] == 78) catch @panic("test failure"); + expect(v[6] == 79) catch @panic("test failure"); + expect(v[7] == 80) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_8_u64() @Vector(8, u64); +extern fn c_vector_8_u64(@Vector(8, u64), usize) void; +extern fn c_test_vector_8_u64() void; + +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); + try expect(v[1] == 82); + try expect(v[2] == 83); + try expect(v[3] == 84); + try expect(v[4] == 85); + try expect(v[5] == 86); + try expect(v[6] == 87); + try expect(v[7] == 88); + c_vector_8_u64(.{ 89, 90, 91, 92, 93, 94, 95, 96 }, 8); + c_test_vector_8_u64(); +} + +export fn zig_ret_vector_12_u64() @Vector(12, u64) { + return .{ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108 }; +} +export fn zig_vector_12_u64(v: @Vector(12, u64), i: usize) void { + expect(v[0] == 109) catch @panic("test failure"); + expect(v[1] == 110) catch @panic("test failure"); + expect(v[2] == 111) catch @panic("test failure"); + expect(v[3] == 112) catch @panic("test failure"); + expect(v[4] == 113) catch @panic("test failure"); + expect(v[5] == 114) catch @panic("test failure"); + expect(v[6] == 115) catch @panic("test failure"); + expect(v[7] == 116) catch @panic("test failure"); + expect(v[8] == 117) catch @panic("test failure"); + expect(v[9] == 118) catch @panic("test failure"); + expect(v[10] == 119) catch @panic("test failure"); + expect(v[11] == 120) catch @panic("test failure"); + expect(i == 12) catch @panic("test failure"); +} + +extern fn c_ret_vector_12_u64() @Vector(12, u64); +extern fn c_vector_12_u64(@Vector(12, u64), usize) void; +extern fn c_test_vector_12_u64() void; + +test "@Vector(12, u64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + + const v = c_ret_vector_12_u64(); + try expect(v[0] == 121); + try expect(v[1] == 122); + try expect(v[2] == 123); + try expect(v[3] == 124); + try expect(v[4] == 125); + try expect(v[5] == 126); + try expect(v[6] == 127); + try expect(v[7] == 128); + try expect(v[8] == 129); + try expect(v[9] == 130); + try expect(v[10] == 131); + try expect(v[11] == 132); + c_vector_12_u64(.{ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144 }, 12); + c_test_vector_12_u64(); +} + +export fn zig_ret_vector_16_u64() @Vector(16, u64) { + return .{ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 }; +} +export fn zig_vector_16_u64(v: @Vector(16, u64), i: usize) void { + expect(v[0] == 161) catch @panic("test failure"); + expect(v[1] == 162) catch @panic("test failure"); + expect(v[2] == 163) catch @panic("test failure"); + expect(v[3] == 164) catch @panic("test failure"); + expect(v[4] == 165) catch @panic("test failure"); + expect(v[5] == 166) catch @panic("test failure"); + expect(v[6] == 167) catch @panic("test failure"); + expect(v[7] == 168) catch @panic("test failure"); + expect(v[8] == 169) catch @panic("test failure"); + expect(v[9] == 170) catch @panic("test failure"); + expect(v[10] == 171) catch @panic("test failure"); + expect(v[11] == 172) catch @panic("test failure"); + expect(v[12] == 173) catch @panic("test failure"); + expect(v[13] == 174) catch @panic("test failure"); + expect(v[14] == 175) catch @panic("test failure"); + expect(v[15] == 176) catch @panic("test failure"); + expect(i == 16) catch @panic("test failure"); +} + +extern fn c_ret_vector_16_u64() @Vector(16, u64); +extern fn c_vector_16_u64(@Vector(16, u64), usize) void; +extern fn c_test_vector_16_u64() void; + +test "@Vector(16, u64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 178); + try expect(v[2] == 179); + try expect(v[3] == 180); + try expect(v[4] == 181); + try expect(v[5] == 182); + try expect(v[6] == 183); + try expect(v[7] == 184); + try expect(v[8] == 185); + try expect(v[9] == 186); + try expect(v[10] == 187); + try expect(v[11] == 188); + try expect(v[12] == 189); + try expect(v[13] == 190); + try expect(v[14] == 191); + try expect(v[15] == 192); + c_vector_16_u64(.{ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208 }, 16); + c_test_vector_16_u64(); +} + +export fn zig_ret_vector_24_u64() @Vector(24, u64) { + return .{ + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, + }; +} +export fn zig_vector_24_u64(v: @Vector(24, u64), i: usize) void { + expect(v[0] == 233) catch @panic("test failure"); + expect(v[1] == 234) catch @panic("test failure"); + expect(v[2] == 235) catch @panic("test failure"); + expect(v[3] == 236) catch @panic("test failure"); + expect(v[4] == 237) catch @panic("test failure"); + expect(v[5] == 238) catch @panic("test failure"); + expect(v[6] == 239) catch @panic("test failure"); + expect(v[7] == 240) catch @panic("test failure"); + expect(v[8] == 241) catch @panic("test failure"); + expect(v[9] == 242) catch @panic("test failure"); + expect(v[10] == 243) catch @panic("test failure"); + expect(v[11] == 244) catch @panic("test failure"); + expect(v[12] == 245) catch @panic("test failure"); + expect(v[13] == 246) catch @panic("test failure"); + expect(v[14] == 247) catch @panic("test failure"); + expect(v[15] == 248) catch @panic("test failure"); + expect(v[16] == 249) catch @panic("test failure"); + expect(v[17] == 250) catch @panic("test failure"); + expect(v[18] == 251) catch @panic("test failure"); + expect(v[19] == 252) catch @panic("test failure"); + expect(v[20] == 253) catch @panic("test failure"); + expect(v[21] == 254) catch @panic("test failure"); + expect(v[22] == 255) catch @panic("test failure"); + expect(v[23] == 256) catch @panic("test failure"); + expect(i == 24) catch @panic("test failure"); +} + +extern fn c_ret_vector_24_u64() @Vector(24, u64); +extern fn c_vector_24_u64(@Vector(24, u64), usize) void; +extern fn c_test_vector_24_u64() void; + +test "@Vector(24, u64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + + const v = c_ret_vector_24_u64(); + try expect(v[0] == 257); + try expect(v[1] == 258); + try expect(v[2] == 259); + try expect(v[3] == 260); + try expect(v[4] == 261); + try expect(v[5] == 262); + try expect(v[6] == 263); + try expect(v[7] == 264); + try expect(v[8] == 265); + try expect(v[9] == 266); + try expect(v[10] == 267); + try expect(v[11] == 268); + try expect(v[12] == 269); + try expect(v[13] == 270); + try expect(v[14] == 271); + try expect(v[15] == 272); + try expect(v[16] == 273); + try expect(v[17] == 274); + try expect(v[18] == 275); + try expect(v[19] == 276); + try expect(v[20] == 277); + try expect(v[21] == 278); + try expect(v[22] == 279); + try expect(v[23] == 280); + c_vector_24_u64(.{ + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, + }, 24); + c_test_vector_24_u64(); +} + +export fn zig_ret_vector_32_u64() @Vector(32, u64) { + return .{ + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, + }; +} +export fn zig_vector_32_u64(v: @Vector(32, u64), i: usize) void { + expect(v[0] == 337) catch @panic("test failure"); + expect(v[1] == 338) catch @panic("test failure"); + expect(v[2] == 339) catch @panic("test failure"); + expect(v[3] == 340) catch @panic("test failure"); + expect(v[4] == 341) catch @panic("test failure"); + expect(v[5] == 342) catch @panic("test failure"); + expect(v[6] == 343) catch @panic("test failure"); + expect(v[7] == 344) catch @panic("test failure"); + expect(v[8] == 345) catch @panic("test failure"); + expect(v[9] == 346) catch @panic("test failure"); + expect(v[10] == 347) catch @panic("test failure"); + expect(v[11] == 348) catch @panic("test failure"); + expect(v[12] == 349) catch @panic("test failure"); + expect(v[13] == 350) catch @panic("test failure"); + expect(v[14] == 351) catch @panic("test failure"); + expect(v[15] == 352) catch @panic("test failure"); + expect(v[16] == 353) catch @panic("test failure"); + expect(v[17] == 354) catch @panic("test failure"); + expect(v[18] == 355) catch @panic("test failure"); + expect(v[19] == 356) catch @panic("test failure"); + expect(v[20] == 357) catch @panic("test failure"); + expect(v[21] == 358) catch @panic("test failure"); + expect(v[22] == 359) catch @panic("test failure"); + expect(v[23] == 360) catch @panic("test failure"); + expect(v[24] == 361) catch @panic("test failure"); + expect(v[25] == 362) catch @panic("test failure"); + expect(v[26] == 363) catch @panic("test failure"); + expect(v[27] == 364) catch @panic("test failure"); + expect(v[28] == 365) catch @panic("test failure"); + expect(v[29] == 366) catch @panic("test failure"); + expect(v[30] == 367) catch @panic("test failure"); + expect(v[31] == 368) catch @panic("test failure"); + expect(i == 32) catch @panic("test failure"); +} + +extern fn c_ret_vector_32_u64() @Vector(32, u64); +extern fn c_vector_32_u64(@Vector(32, u64), usize) void; +extern fn c_test_vector_32_u64() void; + +test "@Vector(32, u64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 370); + try expect(v[2] == 371); + try expect(v[3] == 372); + try expect(v[4] == 373); + try expect(v[5] == 374); + try expect(v[6] == 375); + try expect(v[7] == 376); + try expect(v[8] == 377); + try expect(v[9] == 378); + try expect(v[10] == 379); + try expect(v[11] == 380); + try expect(v[12] == 381); + try expect(v[13] == 382); + try expect(v[14] == 383); + try expect(v[15] == 384); + try expect(v[16] == 385); + try expect(v[17] == 386); + try expect(v[18] == 387); + try expect(v[19] == 388); + try expect(v[20] == 389); + try expect(v[21] == 390); + try expect(v[22] == 391); + try expect(v[23] == 392); + try expect(v[24] == 393); + try expect(v[25] == 394); + try expect(v[26] == 395); + try expect(v[27] == 396); + try expect(v[28] == 397); + try expect(v[29] == 398); + try expect(v[30] == 399); + try expect(v[31] == 400); + c_vector_32_u64(.{ + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, + }, 32); + c_test_vector_32_u64(); +} + +export fn zig_ret_vector_48_u64() @Vector(48, u64) { + return .{ + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, + }; +} +export fn zig_vector_48_u64(v: @Vector(48, u64), i: usize) void { + expect(v[0] == 481) catch @panic("test failure"); + expect(v[1] == 482) catch @panic("test failure"); + expect(v[2] == 483) catch @panic("test failure"); + expect(v[3] == 484) catch @panic("test failure"); + expect(v[4] == 485) catch @panic("test failure"); + expect(v[5] == 486) catch @panic("test failure"); + expect(v[6] == 487) catch @panic("test failure"); + expect(v[7] == 488) catch @panic("test failure"); + expect(v[8] == 489) catch @panic("test failure"); + expect(v[9] == 490) catch @panic("test failure"); + expect(v[10] == 491) catch @panic("test failure"); + expect(v[11] == 492) catch @panic("test failure"); + expect(v[12] == 493) catch @panic("test failure"); + expect(v[13] == 494) catch @panic("test failure"); + expect(v[14] == 495) catch @panic("test failure"); + expect(v[15] == 496) catch @panic("test failure"); + expect(v[16] == 497) catch @panic("test failure"); + expect(v[17] == 498) catch @panic("test failure"); + expect(v[18] == 499) catch @panic("test failure"); + expect(v[19] == 500) catch @panic("test failure"); + expect(v[20] == 501) catch @panic("test failure"); + expect(v[21] == 502) catch @panic("test failure"); + expect(v[22] == 503) catch @panic("test failure"); + expect(v[23] == 504) catch @panic("test failure"); + expect(v[24] == 505) catch @panic("test failure"); + expect(v[25] == 506) catch @panic("test failure"); + expect(v[26] == 507) catch @panic("test failure"); + expect(v[27] == 508) catch @panic("test failure"); + expect(v[28] == 509) catch @panic("test failure"); + expect(v[29] == 510) catch @panic("test failure"); + expect(v[30] == 511) catch @panic("test failure"); + expect(v[31] == 512) catch @panic("test failure"); + expect(v[32] == 513) catch @panic("test failure"); + expect(v[33] == 514) catch @panic("test failure"); + expect(v[34] == 515) catch @panic("test failure"); + expect(v[35] == 516) catch @panic("test failure"); + expect(v[36] == 517) catch @panic("test failure"); + expect(v[37] == 518) catch @panic("test failure"); + expect(v[38] == 519) catch @panic("test failure"); + expect(v[39] == 520) catch @panic("test failure"); + expect(v[40] == 521) catch @panic("test failure"); + expect(v[41] == 522) catch @panic("test failure"); + expect(v[42] == 523) catch @panic("test failure"); + expect(v[43] == 524) catch @panic("test failure"); + expect(v[44] == 525) catch @panic("test failure"); + expect(v[45] == 526) catch @panic("test failure"); + expect(v[46] == 527) catch @panic("test failure"); + expect(v[47] == 528) catch @panic("test failure"); + expect(i == 48) catch @panic("test failure"); +} + +extern fn c_ret_vector_48_u64() @Vector(48, u64); +extern fn c_vector_48_u64(@Vector(48, u64), usize) void; +extern fn c_test_vector_48_u64() void; + +test "@Vector(48, u64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + + const v = c_ret_vector_48_u64(); + try expect(v[0] == 529); + try expect(v[1] == 530); + try expect(v[2] == 531); + try expect(v[3] == 532); + try expect(v[4] == 533); + try expect(v[5] == 534); + try expect(v[6] == 535); + try expect(v[7] == 536); + try expect(v[8] == 537); + try expect(v[9] == 538); + try expect(v[10] == 539); + try expect(v[11] == 540); + try expect(v[12] == 541); + try expect(v[13] == 542); + try expect(v[14] == 543); + try expect(v[15] == 544); + try expect(v[16] == 545); + try expect(v[17] == 546); + try expect(v[18] == 547); + try expect(v[19] == 548); + try expect(v[20] == 549); + try expect(v[21] == 550); + try expect(v[22] == 551); + try expect(v[23] == 552); + try expect(v[24] == 553); + try expect(v[25] == 554); + try expect(v[26] == 555); + try expect(v[27] == 556); + try expect(v[28] == 557); + try expect(v[29] == 558); + try expect(v[30] == 559); + try expect(v[31] == 560); + try expect(v[32] == 561); + try expect(v[33] == 562); + try expect(v[34] == 563); + try expect(v[35] == 564); + try expect(v[36] == 565); + try expect(v[37] == 566); + try expect(v[38] == 567); + try expect(v[39] == 568); + try expect(v[40] == 569); + try expect(v[41] == 570); + try expect(v[42] == 571); + try expect(v[43] == 572); + try expect(v[44] == 573); + try expect(v[45] == 574); + try expect(v[46] == 575); + try expect(v[47] == 576); + c_vector_48_u64(.{ + 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, + 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, + 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + }, 48); + c_test_vector_48_u64(); +} + +export fn zig_ret_vector_64_u64() @Vector(64, u64) { + return .{ + 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, + 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, + 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, + 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, + }; +} +export fn zig_vector_64_u64(v: @Vector(64, u64), i: usize) void { + expect(v[0] == 689) catch @panic("test failure"); + expect(v[1] == 690) catch @panic("test failure"); + expect(v[2] == 691) catch @panic("test failure"); + expect(v[3] == 692) catch @panic("test failure"); + expect(v[4] == 693) catch @panic("test failure"); + expect(v[5] == 694) catch @panic("test failure"); + expect(v[6] == 695) catch @panic("test failure"); + expect(v[7] == 696) catch @panic("test failure"); + expect(v[8] == 697) catch @panic("test failure"); + expect(v[9] == 698) catch @panic("test failure"); + expect(v[10] == 699) catch @panic("test failure"); + expect(v[11] == 700) catch @panic("test failure"); + expect(v[12] == 701) catch @panic("test failure"); + expect(v[13] == 702) catch @panic("test failure"); + expect(v[14] == 703) catch @panic("test failure"); + expect(v[15] == 704) catch @panic("test failure"); + expect(v[16] == 705) catch @panic("test failure"); + expect(v[17] == 706) catch @panic("test failure"); + expect(v[18] == 707) catch @panic("test failure"); + expect(v[19] == 708) catch @panic("test failure"); + expect(v[20] == 709) catch @panic("test failure"); + expect(v[21] == 710) catch @panic("test failure"); + expect(v[22] == 711) catch @panic("test failure"); + expect(v[23] == 712) catch @panic("test failure"); + expect(v[24] == 713) catch @panic("test failure"); + expect(v[25] == 714) catch @panic("test failure"); + expect(v[26] == 715) catch @panic("test failure"); + expect(v[27] == 716) catch @panic("test failure"); + expect(v[28] == 717) catch @panic("test failure"); + expect(v[29] == 718) catch @panic("test failure"); + expect(v[30] == 719) catch @panic("test failure"); + expect(v[31] == 720) catch @panic("test failure"); + expect(v[32] == 721) catch @panic("test failure"); + expect(v[33] == 722) catch @panic("test failure"); + expect(v[34] == 723) catch @panic("test failure"); + expect(v[35] == 724) catch @panic("test failure"); + expect(v[36] == 725) catch @panic("test failure"); + expect(v[37] == 726) catch @panic("test failure"); + expect(v[38] == 727) catch @panic("test failure"); + expect(v[39] == 728) catch @panic("test failure"); + expect(v[40] == 729) catch @panic("test failure"); + expect(v[41] == 730) catch @panic("test failure"); + expect(v[42] == 731) catch @panic("test failure"); + expect(v[43] == 732) catch @panic("test failure"); + expect(v[44] == 733) catch @panic("test failure"); + expect(v[45] == 734) catch @panic("test failure"); + expect(v[46] == 735) catch @panic("test failure"); + expect(v[47] == 736) catch @panic("test failure"); + expect(v[48] == 737) catch @panic("test failure"); + expect(v[49] == 738) catch @panic("test failure"); + expect(v[50] == 739) catch @panic("test failure"); + expect(v[51] == 740) catch @panic("test failure"); + expect(v[52] == 741) catch @panic("test failure"); + expect(v[53] == 742) catch @panic("test failure"); + expect(v[54] == 743) catch @panic("test failure"); + expect(v[55] == 744) catch @panic("test failure"); + expect(v[56] == 745) catch @panic("test failure"); + expect(v[57] == 746) catch @panic("test failure"); + expect(v[58] == 747) catch @panic("test failure"); + expect(v[59] == 748) catch @panic("test failure"); + expect(v[60] == 749) catch @panic("test failure"); + expect(v[61] == 750) catch @panic("test failure"); + expect(v[62] == 751) catch @panic("test failure"); + expect(v[63] == 752) catch @panic("test failure"); + expect(i == 64) catch @panic("test failure"); +} + +extern fn c_ret_vector_64_u64() @Vector(64, u64); +extern fn c_vector_64_u64(@Vector(64, u64), usize) void; +extern fn c_test_vector_64_u64() void; + +test "@Vector(64, u64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 754); + try expect(v[2] == 755); + try expect(v[3] == 756); + try expect(v[4] == 757); + try expect(v[5] == 758); + try expect(v[6] == 759); + try expect(v[7] == 760); + try expect(v[8] == 761); + try expect(v[9] == 762); + try expect(v[10] == 763); + try expect(v[11] == 764); + try expect(v[12] == 765); + try expect(v[13] == 766); + try expect(v[14] == 767); + try expect(v[15] == 768); + try expect(v[16] == 769); + try expect(v[17] == 770); + try expect(v[18] == 771); + try expect(v[19] == 772); + try expect(v[20] == 773); + try expect(v[21] == 774); + try expect(v[22] == 775); + try expect(v[23] == 776); + try expect(v[24] == 777); + try expect(v[25] == 778); + try expect(v[26] == 779); + try expect(v[27] == 780); + try expect(v[28] == 781); + try expect(v[29] == 782); + try expect(v[30] == 783); + try expect(v[31] == 784); + try expect(v[32] == 785); + try expect(v[33] == 786); + try expect(v[34] == 787); + try expect(v[35] == 788); + try expect(v[36] == 789); + try expect(v[37] == 790); + try expect(v[38] == 791); + try expect(v[39] == 792); + try expect(v[40] == 793); + try expect(v[41] == 794); + try expect(v[42] == 795); + try expect(v[43] == 796); + try expect(v[44] == 797); + try expect(v[45] == 798); + try expect(v[46] == 799); + try expect(v[47] == 800); + try expect(v[48] == 801); + try expect(v[49] == 802); + try expect(v[50] == 803); + try expect(v[51] == 804); + try expect(v[52] == 805); + try expect(v[53] == 806); + try expect(v[54] == 807); + try expect(v[55] == 808); + try expect(v[56] == 809); + try expect(v[57] == 810); + try expect(v[58] == 811); + try expect(v[59] == 812); + try expect(v[60] == 813); + try expect(v[61] == 814); + try expect(v[62] == 815); + try expect(v[63] == 816); + c_vector_64_u64(.{ + 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, + 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, + 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, + 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, + }, 64); + c_test_vector_64_u64(); +} + +export fn zig_ret_vector_1_f32() @Vector(1, f32) { + return .{1}; +} +export fn zig_vector_1_f32(v: @Vector(1, f32), i: usize) void { + expect(v[0] == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_vector_1_f32() @Vector(1, f32); +extern fn c_vector_1_f32(@Vector(1, f32), usize) void; +extern fn c_test_vector_1_f32() void; + +test "@Vector(1, f32)" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + c_vector_1_f32(.{4}, 1); + c_test_vector_1_f32(); +} + +export fn zig_ret_vector_2_f32() @Vector(2, f32) { + return .{ 5, 6 }; +} +export fn zig_vector_2_f32(v: @Vector(2, f32), i: usize) void { + expect(v[0] == 7) catch @panic("test failure"); + expect(v[1] == 8) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} + +extern fn c_ret_vector_2_f32() @Vector(2, f32); +extern fn c_vector_2_f32(@Vector(2, f32), usize) void; +extern fn c_test_vector_2_f32() void; + +test "@Vector(2, f32)" { + if (builtin.cpu.arch == .loongarch64) 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_2_f32(); + try expect(v[0] == 9); + try expect(v[1] == 10); + c_vector_2_f32(.{ 11, 12 }, 2); + c_test_vector_2_f32(); +} + +export fn zig_ret_vector_3_f32() @Vector(3, f32) { + return .{ 13, 14, 15 }; +} +export fn zig_vector_3_f32(v: @Vector(3, f32), i: usize) void { + expect(v[0] == 16) catch @panic("test failure"); + expect(v[1] == 17) catch @panic("test failure"); + expect(v[2] == 18) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_vector_3_f32() @Vector(3, f32); +extern fn c_vector_3_f32(@Vector(3, f32), usize) void; +extern fn c_test_vector_3_f32() void; + +test "@Vector(3, f32)" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + + const v = c_ret_vector_3_f32(); + try expect(v[0] == 19); + try expect(v[1] == 20); + try expect(v[2] == 21); + c_vector_3_f32(.{ 22, 23, 24 }, 32); + c_test_vector_3_f32(); +} + +export fn zig_ret_vector_4_f32() @Vector(4, f32) { + return .{ 25, 26, 27, 28 }; +} +export fn zig_vector_4_f32(v: @Vector(4, f32), i: usize) void { + expect(v[0] == 29) catch @panic("test failure"); + expect(v[1] == 30) catch @panic("test failure"); + expect(v[2] == 31) catch @panic("test failure"); + expect(v[3] == 32) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_vector_4_f32_vector_4_f32(v0: @Vector(4, f32), v1: @Vector(4, f32), i: usize) void { + expect(v0[0] == 33) catch @panic("test failure"); + expect(v0[1] == 34) catch @panic("test failure"); + expect(v0[2] == 35) catch @panic("test failure"); + expect(v0[3] == 36) catch @panic("test failure"); + expect(v1[0] == 37) catch @panic("test failure"); + expect(v1[1] == 38) catch @panic("test failure"); + expect(v1[2] == 39) catch @panic("test failure"); + expect(v1[3] == 40) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} +extern fn c_ret_vector_4_f32() @Vector(4, f32); + +extern fn c_vector_4_f32(@Vector(4, f32), usize) void; +extern fn c_vector_4_f32_vector_4_f32(@Vector(4, f32), @Vector(4, f32), usize) void; +extern fn c_test_vector_4_f32() void; + +test "@Vector(4, f32)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + + const v = c_ret_vector_4_f32(); + try expect(v[0] == 41); + try expect(v[1] == 42); + try expect(v[2] == 43); + try expect(v[3] == 44); + c_vector_4_f32(.{ 45, 46, 47, 48 }, 4); + c_vector_4_f32_vector_4_f32(.{ 49, 50, 51, 52 }, .{ 53, 54, 55, 56 }, 8); + c_test_vector_4_f32(); +} + +export fn zig_ret_vector_6_f32() @Vector(6, f32) { + return .{ 41, 42, 43, 44, 45, 46 }; +} +export fn zig_vector_6_f32(v: @Vector(6, f32), i: usize) void { + expect(v[0] == 47) catch @panic("test failure"); + expect(v[1] == 48) catch @panic("test failure"); + expect(v[2] == 49) catch @panic("test failure"); + expect(v[3] == 50) catch @panic("test failure"); + expect(v[4] == 51) catch @panic("test failure"); + expect(v[5] == 52) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} + +extern fn c_ret_vector_6_f32() @Vector(6, f32); +extern fn c_vector_6_f32(@Vector(6, f32), usize) void; +extern fn c_test_vector_6_f32() void; + +test "@Vector(6, f32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_6_f32(); + try expect(v[0] == 53); + try expect(v[1] == 54); + try expect(v[2] == 55); + try expect(v[3] == 56); + try expect(v[4] == 57); + try expect(v[5] == 58); + c_vector_6_f32(.{ 59, 60, 61, 62, 63, 64 }, 6); + c_test_vector_6_f32(); +} + +export fn zig_ret_vector_8_f32() @Vector(8, f32) { + return .{ 65, 66, 67, 68, 69, 70, 71, 72 }; +} +export fn zig_vector_8_f32(v: @Vector(8, f32), i: usize) void { + expect(v[0] == 73) catch @panic("test failure"); + expect(v[1] == 74) catch @panic("test failure"); + expect(v[2] == 75) catch @panic("test failure"); + expect(v[3] == 76) catch @panic("test failure"); + expect(v[4] == 77) catch @panic("test failure"); + expect(v[5] == 78) catch @panic("test failure"); + expect(v[6] == 79) catch @panic("test failure"); + expect(v[7] == 80) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_8_f32() @Vector(8, f32); +extern fn c_vector_8_f32(@Vector(8, f32), usize) void; +extern fn c_test_vector_8_f32() void; + +test "@Vector(8, f32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 82); + try expect(v[2] == 83); + try expect(v[3] == 84); + try expect(v[4] == 85); + try expect(v[5] == 86); + try expect(v[6] == 87); + try expect(v[7] == 88); + c_vector_8_f32(.{ 89, 90, 91, 92, 93, 94, 95, 96 }, 8); + c_test_vector_8_f32(); +} + +export fn zig_ret_vector_12_f32() @Vector(12, f32) { + return .{ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108 }; +} +export fn zig_vector_12_f32(v: @Vector(12, f32), i: usize) void { + expect(v[0] == 109) catch @panic("test failure"); + expect(v[1] == 110) catch @panic("test failure"); + expect(v[2] == 111) catch @panic("test failure"); + expect(v[3] == 112) catch @panic("test failure"); + expect(v[4] == 113) catch @panic("test failure"); + expect(v[5] == 114) catch @panic("test failure"); + expect(v[6] == 115) catch @panic("test failure"); + expect(v[7] == 116) catch @panic("test failure"); + expect(v[8] == 117) catch @panic("test failure"); + expect(v[9] == 118) catch @panic("test failure"); + expect(v[10] == 119) catch @panic("test failure"); + expect(v[11] == 120) catch @panic("test failure"); + expect(i == 12) catch @panic("test failure"); +} + +extern fn c_ret_vector_12_f32() @Vector(12, f32); +extern fn c_vector_12_f32(@Vector(12, f32), usize) void; +extern fn c_test_vector_12_f32() void; + +test "@Vector(12, f32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_12_f32(); + try expect(v[0] == 121); + try expect(v[1] == 122); + try expect(v[2] == 123); + try expect(v[3] == 124); + try expect(v[4] == 125); + try expect(v[5] == 126); + try expect(v[6] == 127); + try expect(v[7] == 128); + try expect(v[8] == 129); + try expect(v[9] == 130); + try expect(v[10] == 131); + try expect(v[11] == 132); + c_vector_12_f32(.{ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144 }, 12); + c_test_vector_12_f32(); +} + +export fn zig_ret_vector_16_f32() @Vector(16, f32) { + return .{ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 }; +} +export fn zig_vector_16_f32(v: @Vector(16, f32), i: usize) void { + expect(v[0] == 161) catch @panic("test failure"); + expect(v[1] == 162) catch @panic("test failure"); + expect(v[2] == 163) catch @panic("test failure"); + expect(v[3] == 164) catch @panic("test failure"); + expect(v[4] == 165) catch @panic("test failure"); + expect(v[5] == 166) catch @panic("test failure"); + expect(v[6] == 167) catch @panic("test failure"); + expect(v[7] == 168) catch @panic("test failure"); + expect(v[8] == 169) catch @panic("test failure"); + expect(v[9] == 170) catch @panic("test failure"); + expect(v[10] == 171) catch @panic("test failure"); + expect(v[11] == 172) catch @panic("test failure"); + expect(v[12] == 173) catch @panic("test failure"); + expect(v[13] == 174) catch @panic("test failure"); + expect(v[14] == 175) catch @panic("test failure"); + expect(v[15] == 176) catch @panic("test failure"); + expect(i == 16) catch @panic("test failure"); +} + +extern fn c_ret_vector_16_f32() @Vector(16, f32); +extern fn c_vector_16_f32(@Vector(16, f32), usize) void; +extern fn c_test_vector_16_f32() void; + +test "@Vector(16, f32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 178); + try expect(v[2] == 179); + try expect(v[3] == 180); + try expect(v[4] == 181); + try expect(v[5] == 182); + try expect(v[6] == 183); + try expect(v[7] == 184); + try expect(v[8] == 185); + try expect(v[9] == 186); + try expect(v[10] == 187); + try expect(v[11] == 188); + try expect(v[12] == 189); + try expect(v[13] == 190); + try expect(v[14] == 191); + try expect(v[15] == 192); + c_vector_16_f32(.{ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208 }, 16); + c_test_vector_16_f32(); +} + +export fn zig_ret_vector_24_f32() @Vector(24, f32) { + return .{ + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, + }; +} +export fn zig_vector_24_f32(v: @Vector(24, f32), i: usize) void { + expect(v[0] == 233) catch @panic("test failure"); + expect(v[1] == 234) catch @panic("test failure"); + expect(v[2] == 235) catch @panic("test failure"); + expect(v[3] == 236) catch @panic("test failure"); + expect(v[4] == 237) catch @panic("test failure"); + expect(v[5] == 238) catch @panic("test failure"); + expect(v[6] == 239) catch @panic("test failure"); + expect(v[7] == 240) catch @panic("test failure"); + expect(v[8] == 241) catch @panic("test failure"); + expect(v[9] == 242) catch @panic("test failure"); + expect(v[10] == 243) catch @panic("test failure"); + expect(v[11] == 244) catch @panic("test failure"); + expect(v[12] == 245) catch @panic("test failure"); + expect(v[13] == 246) catch @panic("test failure"); + expect(v[14] == 247) catch @panic("test failure"); + expect(v[15] == 248) catch @panic("test failure"); + expect(v[16] == 249) catch @panic("test failure"); + expect(v[17] == 250) catch @panic("test failure"); + expect(v[18] == 251) catch @panic("test failure"); + expect(v[19] == 252) catch @panic("test failure"); + expect(v[20] == 253) catch @panic("test failure"); + expect(v[21] == 254) catch @panic("test failure"); + expect(v[22] == 255) catch @panic("test failure"); + expect(v[23] == 256) catch @panic("test failure"); + expect(i == 24) catch @panic("test failure"); +} + +extern fn c_ret_vector_24_f32() @Vector(24, f32); +extern fn c_vector_24_f32(@Vector(24, f32), usize) void; +extern fn c_test_vector_24_f32() void; + +test "@Vector(24, f32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_24_f32(); + try expect(v[0] == 257); + try expect(v[1] == 258); + try expect(v[2] == 259); + try expect(v[3] == 260); + try expect(v[4] == 261); + try expect(v[5] == 262); + try expect(v[6] == 263); + try expect(v[7] == 264); + try expect(v[8] == 265); + try expect(v[9] == 266); + try expect(v[10] == 267); + try expect(v[11] == 268); + try expect(v[12] == 269); + try expect(v[13] == 270); + try expect(v[14] == 271); + try expect(v[15] == 272); + try expect(v[16] == 273); + try expect(v[17] == 274); + try expect(v[18] == 275); + try expect(v[19] == 276); + try expect(v[20] == 277); + try expect(v[21] == 278); + try expect(v[22] == 279); + try expect(v[23] == 280); + c_vector_24_f32(.{ + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, + }, 24); + c_test_vector_24_f32(); +} + +export fn zig_ret_vector_32_f32() @Vector(32, f32) { + return .{ + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, + }; +} +export fn zig_vector_32_f32(v: @Vector(32, f32), i: usize) void { + expect(v[0] == 337) catch @panic("test failure"); + expect(v[1] == 338) catch @panic("test failure"); + expect(v[2] == 339) catch @panic("test failure"); + expect(v[3] == 340) catch @panic("test failure"); + expect(v[4] == 341) catch @panic("test failure"); + expect(v[5] == 342) catch @panic("test failure"); + expect(v[6] == 343) catch @panic("test failure"); + expect(v[7] == 344) catch @panic("test failure"); + expect(v[8] == 345) catch @panic("test failure"); + expect(v[9] == 346) catch @panic("test failure"); + expect(v[10] == 347) catch @panic("test failure"); + expect(v[11] == 348) catch @panic("test failure"); + expect(v[12] == 349) catch @panic("test failure"); + expect(v[13] == 350) catch @panic("test failure"); + expect(v[14] == 351) catch @panic("test failure"); + expect(v[15] == 352) catch @panic("test failure"); + expect(v[16] == 353) catch @panic("test failure"); + expect(v[17] == 354) catch @panic("test failure"); + expect(v[18] == 355) catch @panic("test failure"); + expect(v[19] == 356) catch @panic("test failure"); + expect(v[20] == 357) catch @panic("test failure"); + expect(v[21] == 358) catch @panic("test failure"); + expect(v[22] == 359) catch @panic("test failure"); + expect(v[23] == 360) catch @panic("test failure"); + expect(v[24] == 361) catch @panic("test failure"); + expect(v[25] == 362) catch @panic("test failure"); + expect(v[26] == 363) catch @panic("test failure"); + expect(v[27] == 364) catch @panic("test failure"); + expect(v[28] == 365) catch @panic("test failure"); + expect(v[29] == 366) catch @panic("test failure"); + expect(v[30] == 367) catch @panic("test failure"); + expect(v[31] == 368) catch @panic("test failure"); + expect(i == 32) catch @panic("test failure"); +} + +extern fn c_ret_vector_32_f32() @Vector(32, f32); +extern fn c_vector_32_f32(@Vector(32, f32), usize) void; +extern fn c_test_vector_32_f32() void; + +test "@Vector(32, f32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 370); + try expect(v[2] == 371); + try expect(v[3] == 372); + try expect(v[4] == 373); + try expect(v[5] == 374); + try expect(v[6] == 375); + try expect(v[7] == 376); + try expect(v[8] == 377); + try expect(v[9] == 378); + try expect(v[10] == 379); + try expect(v[11] == 380); + try expect(v[12] == 381); + try expect(v[13] == 382); + try expect(v[14] == 383); + try expect(v[15] == 384); + try expect(v[16] == 385); + try expect(v[17] == 386); + try expect(v[18] == 387); + try expect(v[19] == 388); + try expect(v[20] == 389); + try expect(v[21] == 390); + try expect(v[22] == 391); + try expect(v[23] == 392); + try expect(v[24] == 393); + try expect(v[25] == 394); + try expect(v[26] == 395); + try expect(v[27] == 396); + try expect(v[28] == 397); + try expect(v[29] == 398); + try expect(v[30] == 399); + try expect(v[31] == 400); + c_vector_32_f32(.{ + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, + }, 32); + c_test_vector_32_f32(); +} + +export fn zig_ret_vector_48_f32() @Vector(48, f32) { + return .{ + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, + }; +} +export fn zig_vector_48_f32(v: @Vector(48, f32), i: usize) void { + expect(v[0] == 481) catch @panic("test failure"); + expect(v[1] == 482) catch @panic("test failure"); + expect(v[2] == 483) catch @panic("test failure"); + expect(v[3] == 484) catch @panic("test failure"); + expect(v[4] == 485) catch @panic("test failure"); + expect(v[5] == 486) catch @panic("test failure"); + expect(v[6] == 487) catch @panic("test failure"); + expect(v[7] == 488) catch @panic("test failure"); + expect(v[8] == 489) catch @panic("test failure"); + expect(v[9] == 490) catch @panic("test failure"); + expect(v[10] == 491) catch @panic("test failure"); + expect(v[11] == 492) catch @panic("test failure"); + expect(v[12] == 493) catch @panic("test failure"); + expect(v[13] == 494) catch @panic("test failure"); + expect(v[14] == 495) catch @panic("test failure"); + expect(v[15] == 496) catch @panic("test failure"); + expect(v[16] == 497) catch @panic("test failure"); + expect(v[17] == 498) catch @panic("test failure"); + expect(v[18] == 499) catch @panic("test failure"); + expect(v[19] == 500) catch @panic("test failure"); + expect(v[20] == 501) catch @panic("test failure"); + expect(v[21] == 502) catch @panic("test failure"); + expect(v[22] == 503) catch @panic("test failure"); + expect(v[23] == 504) catch @panic("test failure"); + expect(v[24] == 505) catch @panic("test failure"); + expect(v[25] == 506) catch @panic("test failure"); + expect(v[26] == 507) catch @panic("test failure"); + expect(v[27] == 508) catch @panic("test failure"); + expect(v[28] == 509) catch @panic("test failure"); + expect(v[29] == 510) catch @panic("test failure"); + expect(v[30] == 511) catch @panic("test failure"); + expect(v[31] == 512) catch @panic("test failure"); + expect(v[32] == 513) catch @panic("test failure"); + expect(v[33] == 514) catch @panic("test failure"); + expect(v[34] == 515) catch @panic("test failure"); + expect(v[35] == 516) catch @panic("test failure"); + expect(v[36] == 517) catch @panic("test failure"); + expect(v[37] == 518) catch @panic("test failure"); + expect(v[38] == 519) catch @panic("test failure"); + expect(v[39] == 520) catch @panic("test failure"); + expect(v[40] == 521) catch @panic("test failure"); + expect(v[41] == 522) catch @panic("test failure"); + expect(v[42] == 523) catch @panic("test failure"); + expect(v[43] == 524) catch @panic("test failure"); + expect(v[44] == 525) catch @panic("test failure"); + expect(v[45] == 526) catch @panic("test failure"); + expect(v[46] == 527) catch @panic("test failure"); + expect(v[47] == 528) catch @panic("test failure"); + expect(i == 48) catch @panic("test failure"); +} + +extern fn c_ret_vector_48_f32() @Vector(48, f32); +extern fn c_vector_48_f32(@Vector(48, f32), usize) void; +extern fn c_test_vector_48_f32() void; + +test "@Vector(48, f32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_48_f32(); + try expect(v[0] == 529); + try expect(v[1] == 530); + try expect(v[2] == 531); + try expect(v[3] == 532); + try expect(v[4] == 533); + try expect(v[5] == 534); + try expect(v[6] == 535); + try expect(v[7] == 536); + try expect(v[8] == 537); + try expect(v[9] == 538); + try expect(v[10] == 539); + try expect(v[11] == 540); + try expect(v[12] == 541); + try expect(v[13] == 542); + try expect(v[14] == 543); + try expect(v[15] == 544); + try expect(v[16] == 545); + try expect(v[17] == 546); + try expect(v[18] == 547); + try expect(v[19] == 548); + try expect(v[20] == 549); + try expect(v[21] == 550); + try expect(v[22] == 551); + try expect(v[23] == 552); + try expect(v[24] == 553); + try expect(v[25] == 554); + try expect(v[26] == 555); + try expect(v[27] == 556); + try expect(v[28] == 557); + try expect(v[29] == 558); + try expect(v[30] == 559); + try expect(v[31] == 560); + try expect(v[32] == 561); + try expect(v[33] == 562); + try expect(v[34] == 563); + try expect(v[35] == 564); + try expect(v[36] == 565); + try expect(v[37] == 566); + try expect(v[38] == 567); + try expect(v[39] == 568); + try expect(v[40] == 569); + try expect(v[41] == 570); + try expect(v[42] == 571); + try expect(v[43] == 572); + try expect(v[44] == 573); + try expect(v[45] == 574); + try expect(v[46] == 575); + try expect(v[47] == 576); + c_vector_48_f32(.{ + 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, + 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, + 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + }, 48); + c_test_vector_48_f32(); +} + +export fn zig_ret_vector_64_f32() @Vector(64, f32) { + return .{ + 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, + 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, + 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, + 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, + }; +} +export fn zig_vector_64_f32(v: @Vector(64, f32), i: usize) void { + expect(v[0] == 689) catch @panic("test failure"); + expect(v[1] == 690) catch @panic("test failure"); + expect(v[2] == 691) catch @panic("test failure"); + expect(v[3] == 692) catch @panic("test failure"); + expect(v[4] == 693) catch @panic("test failure"); + expect(v[5] == 694) catch @panic("test failure"); + expect(v[6] == 695) catch @panic("test failure"); + expect(v[7] == 696) catch @panic("test failure"); + expect(v[8] == 697) catch @panic("test failure"); + expect(v[9] == 698) catch @panic("test failure"); + expect(v[10] == 699) catch @panic("test failure"); + expect(v[11] == 700) catch @panic("test failure"); + expect(v[12] == 701) catch @panic("test failure"); + expect(v[13] == 702) catch @panic("test failure"); + expect(v[14] == 703) catch @panic("test failure"); + expect(v[15] == 704) catch @panic("test failure"); + expect(v[16] == 705) catch @panic("test failure"); + expect(v[17] == 706) catch @panic("test failure"); + expect(v[18] == 707) catch @panic("test failure"); + expect(v[19] == 708) catch @panic("test failure"); + expect(v[20] == 709) catch @panic("test failure"); + expect(v[21] == 710) catch @panic("test failure"); + expect(v[22] == 711) catch @panic("test failure"); + expect(v[23] == 712) catch @panic("test failure"); + expect(v[24] == 713) catch @panic("test failure"); + expect(v[25] == 714) catch @panic("test failure"); + expect(v[26] == 715) catch @panic("test failure"); + expect(v[27] == 716) catch @panic("test failure"); + expect(v[28] == 717) catch @panic("test failure"); + expect(v[29] == 718) catch @panic("test failure"); + expect(v[30] == 719) catch @panic("test failure"); + expect(v[31] == 720) catch @panic("test failure"); + expect(v[32] == 721) catch @panic("test failure"); + expect(v[33] == 722) catch @panic("test failure"); + expect(v[34] == 723) catch @panic("test failure"); + expect(v[35] == 724) catch @panic("test failure"); + expect(v[36] == 725) catch @panic("test failure"); + expect(v[37] == 726) catch @panic("test failure"); + expect(v[38] == 727) catch @panic("test failure"); + expect(v[39] == 728) catch @panic("test failure"); + expect(v[40] == 729) catch @panic("test failure"); + expect(v[41] == 730) catch @panic("test failure"); + expect(v[42] == 731) catch @panic("test failure"); + expect(v[43] == 732) catch @panic("test failure"); + expect(v[44] == 733) catch @panic("test failure"); + expect(v[45] == 734) catch @panic("test failure"); + expect(v[46] == 735) catch @panic("test failure"); + expect(v[47] == 736) catch @panic("test failure"); + expect(v[48] == 737) catch @panic("test failure"); + expect(v[49] == 738) catch @panic("test failure"); + expect(v[50] == 739) catch @panic("test failure"); + expect(v[51] == 740) catch @panic("test failure"); + expect(v[52] == 741) catch @panic("test failure"); + expect(v[53] == 742) catch @panic("test failure"); + expect(v[54] == 743) catch @panic("test failure"); + expect(v[55] == 744) catch @panic("test failure"); + expect(v[56] == 745) catch @panic("test failure"); + expect(v[57] == 746) catch @panic("test failure"); + expect(v[58] == 747) catch @panic("test failure"); + expect(v[59] == 748) catch @panic("test failure"); + expect(v[60] == 749) catch @panic("test failure"); + expect(v[61] == 750) catch @panic("test failure"); + expect(v[62] == 751) catch @panic("test failure"); + expect(v[63] == 752) catch @panic("test failure"); + expect(i == 64) catch @panic("test failure"); +} + +extern fn c_ret_vector_64_f32() @Vector(64, f32); +extern fn c_vector_64_f32(@Vector(64, f32), usize) void; +extern fn c_test_vector_64_f32() void; + +test "@Vector(64, f32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 754); + try expect(v[2] == 755); + try expect(v[3] == 756); + try expect(v[4] == 757); + try expect(v[5] == 758); + try expect(v[6] == 759); + try expect(v[7] == 760); + try expect(v[8] == 761); + try expect(v[9] == 762); + try expect(v[10] == 763); + try expect(v[11] == 764); + try expect(v[12] == 765); + try expect(v[13] == 766); + try expect(v[14] == 767); + try expect(v[15] == 768); + try expect(v[16] == 769); + try expect(v[17] == 770); + try expect(v[18] == 771); + try expect(v[19] == 772); + try expect(v[20] == 773); + try expect(v[21] == 774); + try expect(v[22] == 775); + try expect(v[23] == 776); + try expect(v[24] == 777); + try expect(v[25] == 778); + try expect(v[26] == 779); + try expect(v[27] == 780); + try expect(v[28] == 781); + try expect(v[29] == 782); + try expect(v[30] == 783); + try expect(v[31] == 784); + try expect(v[32] == 785); + try expect(v[33] == 786); + try expect(v[34] == 787); + try expect(v[35] == 788); + try expect(v[36] == 789); + try expect(v[37] == 790); + try expect(v[38] == 791); + try expect(v[39] == 792); + try expect(v[40] == 793); + try expect(v[41] == 794); + try expect(v[42] == 795); + try expect(v[43] == 796); + try expect(v[44] == 797); + try expect(v[45] == 798); + try expect(v[46] == 799); + try expect(v[47] == 800); + try expect(v[48] == 801); + try expect(v[49] == 802); + try expect(v[50] == 803); + try expect(v[51] == 804); + try expect(v[52] == 805); + try expect(v[53] == 806); + try expect(v[54] == 807); + try expect(v[55] == 808); + try expect(v[56] == 809); + try expect(v[57] == 810); + try expect(v[58] == 811); + try expect(v[59] == 812); + try expect(v[60] == 813); + try expect(v[61] == 814); + try expect(v[62] == 815); + try expect(v[63] == 816); + c_vector_64_f32(.{ + 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, + 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, + 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, + 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, + }, 64); + c_test_vector_64_f32(); +} + +export fn zig_ret_vector_96_f32() @Vector(96, f32) { + return .{ + 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, + 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, + 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, + 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, + 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, + 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, + }; +} +export fn zig_vector_96_f32(v: @Vector(96, f32), i: usize) void { + expect(v[0] == 986) catch @panic("test failure"); + expect(v[1] == 987) catch @panic("test failure"); + expect(v[2] == 988) catch @panic("test failure"); + expect(v[3] == 989) catch @panic("test failure"); + expect(v[4] == 990) catch @panic("test failure"); + expect(v[5] == 991) catch @panic("test failure"); + expect(v[6] == 992) catch @panic("test failure"); + expect(v[7] == 993) catch @panic("test failure"); + expect(v[8] == 994) catch @panic("test failure"); + expect(v[9] == 995) catch @panic("test failure"); + expect(v[10] == 996) catch @panic("test failure"); + expect(v[11] == 997) catch @panic("test failure"); + expect(v[12] == 998) catch @panic("test failure"); + expect(v[13] == 999) catch @panic("test failure"); + expect(v[14] == 1000) catch @panic("test failure"); + expect(v[15] == 1001) catch @panic("test failure"); + expect(v[16] == 1002) catch @panic("test failure"); + expect(v[17] == 1003) catch @panic("test failure"); + expect(v[18] == 1004) catch @panic("test failure"); + expect(v[19] == 1005) catch @panic("test failure"); + expect(v[20] == 1006) catch @panic("test failure"); + expect(v[21] == 1007) catch @panic("test failure"); + expect(v[22] == 1008) catch @panic("test failure"); + expect(v[23] == 1009) catch @panic("test failure"); + expect(v[24] == 1010) catch @panic("test failure"); + expect(v[25] == 1011) catch @panic("test failure"); + expect(v[26] == 1012) catch @panic("test failure"); + expect(v[27] == 1013) catch @panic("test failure"); + expect(v[28] == 1014) catch @panic("test failure"); + expect(v[29] == 1015) catch @panic("test failure"); + expect(v[30] == 1016) catch @panic("test failure"); + expect(v[31] == 1017) catch @panic("test failure"); + expect(v[32] == 1018) catch @panic("test failure"); + expect(v[33] == 1019) catch @panic("test failure"); + expect(v[34] == 1020) catch @panic("test failure"); + expect(v[35] == 1021) catch @panic("test failure"); + expect(v[36] == 1022) catch @panic("test failure"); + expect(v[37] == 1023) catch @panic("test failure"); + expect(v[38] == 1024) catch @panic("test failure"); + expect(v[39] == 1025) catch @panic("test failure"); + expect(v[40] == 1026) catch @panic("test failure"); + expect(v[41] == 1027) catch @panic("test failure"); + expect(v[42] == 1028) catch @panic("test failure"); + expect(v[43] == 1029) catch @panic("test failure"); + expect(v[44] == 1030) catch @panic("test failure"); + expect(v[45] == 1031) catch @panic("test failure"); + expect(v[46] == 1032) catch @panic("test failure"); + expect(v[47] == 1033) catch @panic("test failure"); + expect(v[48] == 1034) catch @panic("test failure"); + expect(v[49] == 1035) catch @panic("test failure"); + expect(v[50] == 1036) catch @panic("test failure"); + expect(v[51] == 1037) catch @panic("test failure"); + expect(v[52] == 1038) catch @panic("test failure"); + expect(v[53] == 1039) catch @panic("test failure"); + expect(v[54] == 1040) catch @panic("test failure"); + expect(v[55] == 1041) catch @panic("test failure"); + expect(v[56] == 1042) catch @panic("test failure"); + expect(v[57] == 1043) catch @panic("test failure"); + expect(v[58] == 1044) catch @panic("test failure"); + expect(v[59] == 1045) catch @panic("test failure"); + expect(v[60] == 1046) catch @panic("test failure"); + expect(v[61] == 1047) catch @panic("test failure"); + expect(v[62] == 1048) catch @panic("test failure"); + expect(v[63] == 1049) catch @panic("test failure"); + expect(v[64] == 1050) catch @panic("test failure"); + expect(v[65] == 1051) catch @panic("test failure"); + expect(v[66] == 1052) catch @panic("test failure"); + expect(v[67] == 1053) catch @panic("test failure"); + expect(v[68] == 1054) catch @panic("test failure"); + expect(v[69] == 1055) catch @panic("test failure"); + expect(v[70] == 1056) catch @panic("test failure"); + expect(v[71] == 1057) catch @panic("test failure"); + expect(v[72] == 1058) catch @panic("test failure"); + expect(v[73] == 1059) catch @panic("test failure"); + expect(v[74] == 1060) catch @panic("test failure"); + expect(v[75] == 1061) catch @panic("test failure"); + expect(v[76] == 1062) catch @panic("test failure"); + expect(v[77] == 1063) catch @panic("test failure"); + expect(v[78] == 1064) catch @panic("test failure"); + expect(v[79] == 1065) catch @panic("test failure"); + expect(v[80] == 1066) catch @panic("test failure"); + expect(v[81] == 1067) catch @panic("test failure"); + expect(v[82] == 1068) catch @panic("test failure"); + expect(v[83] == 1069) catch @panic("test failure"); + expect(v[84] == 1070) catch @panic("test failure"); + expect(v[85] == 1071) catch @panic("test failure"); + expect(v[86] == 1072) catch @panic("test failure"); + expect(v[87] == 1073) catch @panic("test failure"); + expect(v[88] == 1074) catch @panic("test failure"); + expect(v[89] == 1075) catch @panic("test failure"); + expect(v[90] == 1076) catch @panic("test failure"); + expect(v[91] == 1077) catch @panic("test failure"); + expect(v[92] == 1078) catch @panic("test failure"); + expect(v[93] == 1079) catch @panic("test failure"); + expect(v[94] == 1080) catch @panic("test failure"); + expect(v[95] == 1081) catch @panic("test failure"); + expect(i == 96) catch @panic("test failure"); +} + +extern fn c_ret_vector_96_f32() @Vector(96, f32); +extern fn c_vector_96_f32(@Vector(96, f32), usize) void; +extern fn c_test_vector_96_f32() void; + +test "@Vector(96, f32)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_96_f32(); + try expect(v[0] == 1082); + try expect(v[1] == 1083); + try expect(v[2] == 1084); + try expect(v[3] == 1085); + try expect(v[4] == 1086); + try expect(v[5] == 1087); + try expect(v[6] == 1088); + try expect(v[7] == 1089); + try expect(v[8] == 1090); + try expect(v[9] == 1091); + try expect(v[10] == 1092); + try expect(v[11] == 1093); + try expect(v[12] == 1094); + try expect(v[13] == 1095); + try expect(v[14] == 1096); + try expect(v[15] == 1097); + try expect(v[16] == 1098); + try expect(v[17] == 1099); + try expect(v[18] == 1100); + try expect(v[19] == 1101); + try expect(v[20] == 1102); + try expect(v[21] == 1103); + try expect(v[22] == 1104); + try expect(v[23] == 1105); + try expect(v[24] == 1106); + try expect(v[25] == 1107); + try expect(v[26] == 1108); + try expect(v[27] == 1109); + try expect(v[28] == 1110); + try expect(v[29] == 1111); + try expect(v[30] == 1112); + try expect(v[31] == 1113); + try expect(v[32] == 1114); + try expect(v[33] == 1115); + try expect(v[34] == 1116); + try expect(v[35] == 1117); + try expect(v[36] == 1118); + try expect(v[37] == 1119); + try expect(v[38] == 1120); + try expect(v[39] == 1121); + try expect(v[40] == 1122); + try expect(v[41] == 1123); + try expect(v[42] == 1124); + try expect(v[43] == 1125); + try expect(v[44] == 1126); + try expect(v[45] == 1127); + try expect(v[46] == 1128); + try expect(v[47] == 1129); + try expect(v[48] == 1130); + try expect(v[49] == 1131); + try expect(v[50] == 1132); + try expect(v[51] == 1133); + try expect(v[52] == 1134); + try expect(v[53] == 1135); + try expect(v[54] == 1136); + try expect(v[55] == 1137); + try expect(v[56] == 1138); + try expect(v[57] == 1139); + try expect(v[58] == 1140); + try expect(v[59] == 1141); + try expect(v[60] == 1142); + try expect(v[61] == 1143); + try expect(v[62] == 1144); + try expect(v[63] == 1145); + try expect(v[64] == 1146); + try expect(v[65] == 1147); + try expect(v[66] == 1148); + try expect(v[67] == 1149); + try expect(v[68] == 1150); + try expect(v[69] == 1151); + try expect(v[70] == 1152); + try expect(v[71] == 1153); + try expect(v[72] == 1154); + try expect(v[73] == 1155); + try expect(v[74] == 1156); + try expect(v[75] == 1157); + try expect(v[76] == 1158); + try expect(v[77] == 1159); + try expect(v[78] == 1160); + try expect(v[79] == 1161); + try expect(v[80] == 1162); + try expect(v[81] == 1163); + try expect(v[82] == 1164); + try expect(v[83] == 1165); + try expect(v[84] == 1166); + try expect(v[85] == 1167); + try expect(v[86] == 1168); + try expect(v[87] == 1169); + try expect(v[88] == 1170); + try expect(v[89] == 1171); + try expect(v[90] == 1172); + try expect(v[91] == 1173); + try expect(v[92] == 1174); + try expect(v[93] == 1175); + try expect(v[94] == 1176); + try expect(v[95] == 1177); + c_vector_96_f32(.{ + 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, + 1194, 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, + 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 1225, + 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, + 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, + 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, + }, 96); + c_test_vector_96_f32(); +} + +export fn zig_ret_vector_128_f32() @Vector(128, f32) { + return .{ + 1274, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, + 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, + 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, + 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, + 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, + 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, + 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, + 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 1401, + }; +} +export fn zig_vector_128_f32(v: @Vector(128, f32), i: usize) void { + expect(v[0] == 1402) catch @panic("test failure"); + expect(v[1] == 1403) catch @panic("test failure"); + expect(v[2] == 1404) catch @panic("test failure"); + expect(v[3] == 1405) catch @panic("test failure"); + expect(v[4] == 1406) catch @panic("test failure"); + expect(v[5] == 1407) catch @panic("test failure"); + expect(v[6] == 1408) catch @panic("test failure"); + expect(v[7] == 1409) catch @panic("test failure"); + expect(v[8] == 1410) catch @panic("test failure"); + expect(v[9] == 1411) catch @panic("test failure"); + expect(v[10] == 1412) catch @panic("test failure"); + expect(v[11] == 1413) catch @panic("test failure"); + expect(v[12] == 1414) catch @panic("test failure"); + expect(v[13] == 1415) catch @panic("test failure"); + expect(v[14] == 1416) catch @panic("test failure"); + expect(v[15] == 1417) catch @panic("test failure"); + expect(v[16] == 1418) catch @panic("test failure"); + expect(v[17] == 1419) catch @panic("test failure"); + expect(v[18] == 1420) catch @panic("test failure"); + expect(v[19] == 1421) catch @panic("test failure"); + expect(v[20] == 1422) catch @panic("test failure"); + expect(v[21] == 1423) catch @panic("test failure"); + expect(v[22] == 1424) catch @panic("test failure"); + expect(v[23] == 1425) catch @panic("test failure"); + expect(v[24] == 1426) catch @panic("test failure"); + expect(v[25] == 1427) catch @panic("test failure"); + expect(v[26] == 1428) catch @panic("test failure"); + expect(v[27] == 1429) catch @panic("test failure"); + expect(v[28] == 1430) catch @panic("test failure"); + expect(v[29] == 1431) catch @panic("test failure"); + expect(v[30] == 1432) catch @panic("test failure"); + expect(v[31] == 1433) catch @panic("test failure"); + expect(v[32] == 1434) catch @panic("test failure"); + expect(v[33] == 1435) catch @panic("test failure"); + expect(v[34] == 1436) catch @panic("test failure"); + expect(v[35] == 1437) catch @panic("test failure"); + expect(v[36] == 1438) catch @panic("test failure"); + expect(v[37] == 1439) catch @panic("test failure"); + expect(v[38] == 1440) catch @panic("test failure"); + expect(v[39] == 1441) catch @panic("test failure"); + expect(v[40] == 1442) catch @panic("test failure"); + expect(v[41] == 1443) catch @panic("test failure"); + expect(v[42] == 1444) catch @panic("test failure"); + expect(v[43] == 1445) catch @panic("test failure"); + expect(v[44] == 1446) catch @panic("test failure"); + expect(v[45] == 1447) catch @panic("test failure"); + expect(v[46] == 1448) catch @panic("test failure"); + expect(v[47] == 1449) catch @panic("test failure"); + expect(v[48] == 1450) catch @panic("test failure"); + expect(v[49] == 1451) catch @panic("test failure"); + expect(v[50] == 1452) catch @panic("test failure"); + expect(v[51] == 1453) catch @panic("test failure"); + expect(v[52] == 1454) catch @panic("test failure"); + expect(v[53] == 1455) catch @panic("test failure"); + expect(v[54] == 1456) catch @panic("test failure"); + expect(v[55] == 1457) catch @panic("test failure"); + expect(v[56] == 1458) catch @panic("test failure"); + expect(v[57] == 1459) catch @panic("test failure"); + expect(v[58] == 1460) catch @panic("test failure"); + expect(v[59] == 1461) catch @panic("test failure"); + expect(v[60] == 1462) catch @panic("test failure"); + expect(v[61] == 1463) catch @panic("test failure"); + expect(v[62] == 1464) catch @panic("test failure"); + expect(v[63] == 1465) catch @panic("test failure"); + expect(v[64] == 1466) catch @panic("test failure"); + expect(v[65] == 1467) catch @panic("test failure"); + expect(v[66] == 1468) catch @panic("test failure"); + expect(v[67] == 1469) catch @panic("test failure"); + expect(v[68] == 1470) catch @panic("test failure"); + expect(v[69] == 1471) catch @panic("test failure"); + expect(v[70] == 1472) catch @panic("test failure"); + expect(v[71] == 1473) catch @panic("test failure"); + expect(v[72] == 1474) catch @panic("test failure"); + expect(v[73] == 1475) catch @panic("test failure"); + expect(v[74] == 1476) catch @panic("test failure"); + expect(v[75] == 1477) catch @panic("test failure"); + expect(v[76] == 1478) catch @panic("test failure"); + expect(v[77] == 1479) catch @panic("test failure"); + expect(v[78] == 1480) catch @panic("test failure"); + expect(v[79] == 1481) catch @panic("test failure"); + expect(v[80] == 1482) catch @panic("test failure"); + expect(v[81] == 1483) catch @panic("test failure"); + expect(v[82] == 1484) catch @panic("test failure"); + expect(v[83] == 1485) catch @panic("test failure"); + expect(v[84] == 1486) catch @panic("test failure"); + expect(v[85] == 1487) catch @panic("test failure"); + expect(v[86] == 1488) catch @panic("test failure"); + expect(v[87] == 1489) catch @panic("test failure"); + expect(v[88] == 1490) catch @panic("test failure"); + expect(v[89] == 1491) catch @panic("test failure"); + expect(v[90] == 1492) catch @panic("test failure"); + expect(v[91] == 1493) catch @panic("test failure"); + expect(v[92] == 1494) catch @panic("test failure"); + expect(v[93] == 1495) catch @panic("test failure"); + expect(v[94] == 1496) catch @panic("test failure"); + expect(v[95] == 1497) catch @panic("test failure"); + expect(v[96] == 1498) catch @panic("test failure"); + expect(v[97] == 1499) catch @panic("test failure"); + expect(v[98] == 1500) catch @panic("test failure"); + expect(v[99] == 1501) catch @panic("test failure"); + expect(v[100] == 1502) catch @panic("test failure"); + expect(v[101] == 1503) catch @panic("test failure"); + expect(v[102] == 1504) catch @panic("test failure"); + expect(v[103] == 1505) catch @panic("test failure"); + expect(v[104] == 1506) catch @panic("test failure"); + expect(v[105] == 1507) catch @panic("test failure"); + expect(v[106] == 1508) catch @panic("test failure"); + expect(v[107] == 1509) catch @panic("test failure"); + expect(v[108] == 1510) catch @panic("test failure"); + expect(v[109] == 1511) catch @panic("test failure"); + expect(v[110] == 1512) catch @panic("test failure"); + expect(v[111] == 1513) catch @panic("test failure"); + expect(v[112] == 1514) catch @panic("test failure"); + expect(v[113] == 1515) catch @panic("test failure"); + expect(v[114] == 1516) catch @panic("test failure"); + expect(v[115] == 1517) catch @panic("test failure"); + expect(v[116] == 1518) catch @panic("test failure"); + expect(v[117] == 1519) catch @panic("test failure"); + expect(v[118] == 1520) catch @panic("test failure"); + expect(v[119] == 1521) catch @panic("test failure"); + expect(v[120] == 1522) catch @panic("test failure"); + expect(v[121] == 1523) catch @panic("test failure"); + expect(v[122] == 1524) catch @panic("test failure"); + expect(v[123] == 1525) catch @panic("test failure"); + expect(v[124] == 1526) catch @panic("test failure"); + expect(v[125] == 1527) catch @panic("test failure"); + expect(v[126] == 1528) catch @panic("test failure"); + expect(v[127] == 1529) catch @panic("test failure"); + expect(i == 128) catch @panic("test failure"); +} + +extern fn c_ret_vector_128_f32() @Vector(128, f32); +extern fn c_vector_128_f32(@Vector(128, f32), usize) void; +extern fn c_test_vector_128_f32() void; + +test "@Vector(128, f32)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 1531); + try expect(v[2] == 1532); + try expect(v[3] == 1533); + try expect(v[4] == 1534); + try expect(v[5] == 1535); + try expect(v[6] == 1536); + try expect(v[7] == 1537); + try expect(v[8] == 1538); + try expect(v[9] == 1539); + try expect(v[10] == 1540); + try expect(v[11] == 1541); + try expect(v[12] == 1542); + try expect(v[13] == 1543); + try expect(v[14] == 1544); + try expect(v[15] == 1545); + try expect(v[16] == 1546); + try expect(v[17] == 1547); + try expect(v[18] == 1548); + try expect(v[19] == 1549); + try expect(v[20] == 1550); + try expect(v[21] == 1551); + try expect(v[22] == 1552); + try expect(v[23] == 1553); + try expect(v[24] == 1554); + try expect(v[25] == 1555); + try expect(v[26] == 1556); + try expect(v[27] == 1557); + try expect(v[28] == 1558); + try expect(v[29] == 1559); + try expect(v[30] == 1560); + try expect(v[31] == 1561); + try expect(v[32] == 1562); + try expect(v[33] == 1563); + try expect(v[34] == 1564); + try expect(v[35] == 1565); + try expect(v[36] == 1566); + try expect(v[37] == 1567); + try expect(v[38] == 1568); + try expect(v[39] == 1569); + try expect(v[40] == 1570); + try expect(v[41] == 1571); + try expect(v[42] == 1572); + try expect(v[43] == 1573); + try expect(v[44] == 1574); + try expect(v[45] == 1575); + try expect(v[46] == 1576); + try expect(v[47] == 1577); + try expect(v[48] == 1578); + try expect(v[49] == 1579); + try expect(v[50] == 1580); + try expect(v[51] == 1581); + try expect(v[52] == 1582); + try expect(v[53] == 1583); + try expect(v[54] == 1584); + try expect(v[55] == 1585); + try expect(v[56] == 1586); + try expect(v[57] == 1587); + try expect(v[58] == 1588); + try expect(v[59] == 1589); + try expect(v[60] == 1590); + try expect(v[61] == 1591); + try expect(v[62] == 1592); + try expect(v[63] == 1593); + try expect(v[64] == 1594); + try expect(v[65] == 1595); + try expect(v[66] == 1596); + try expect(v[67] == 1597); + try expect(v[68] == 1598); + try expect(v[69] == 1599); + try expect(v[70] == 1600); + try expect(v[71] == 1601); + try expect(v[72] == 1602); + try expect(v[73] == 1603); + try expect(v[74] == 1604); + try expect(v[75] == 1605); + try expect(v[76] == 1606); + try expect(v[77] == 1607); + try expect(v[78] == 1608); + try expect(v[79] == 1609); + try expect(v[80] == 1610); + try expect(v[81] == 1611); + try expect(v[82] == 1612); + try expect(v[83] == 1613); + try expect(v[84] == 1614); + try expect(v[85] == 1615); + try expect(v[86] == 1616); + try expect(v[87] == 1617); + try expect(v[88] == 1618); + try expect(v[89] == 1619); + try expect(v[90] == 1620); + try expect(v[91] == 1621); + try expect(v[92] == 1622); + try expect(v[93] == 1623); + try expect(v[94] == 1624); + try expect(v[95] == 1625); + try expect(v[96] == 1626); + try expect(v[97] == 1627); + try expect(v[98] == 1628); + try expect(v[99] == 1629); + try expect(v[100] == 1630); + try expect(v[101] == 1631); + try expect(v[102] == 1632); + try expect(v[103] == 1633); + try expect(v[104] == 1634); + try expect(v[105] == 1635); + try expect(v[106] == 1636); + try expect(v[107] == 1637); + try expect(v[108] == 1638); + try expect(v[109] == 1639); + try expect(v[110] == 1640); + try expect(v[111] == 1641); + try expect(v[112] == 1642); + try expect(v[113] == 1643); + try expect(v[114] == 1644); + try expect(v[115] == 1645); + try expect(v[116] == 1646); + try expect(v[117] == 1647); + try expect(v[118] == 1648); + try expect(v[119] == 1649); + try expect(v[120] == 1650); + try expect(v[121] == 1651); + try expect(v[122] == 1652); + try expect(v[123] == 1653); + try expect(v[124] == 1654); + try expect(v[125] == 1655); + try expect(v[126] == 1656); + try expect(v[127] == 1657); + c_vector_128_f32(.{ + 1658, 1659, 1660, 1661, 1662, 1663, 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, + 1674, 1675, 1676, 1677, 1678, 1679, 1680, 1681, 1682, 1683, 1684, 1685, 1686, 1687, 1688, 1689, + 1690, 1691, 1692, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701, 1702, 1703, 1704, 1705, + 1706, 1707, 1708, 1709, 1710, 1711, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 1720, 1721, + 1722, 1723, 1724, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, + 1738, 1739, 1740, 1741, 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, 1750, 1751, 1752, 1753, + 1754, 1755, 1756, 1757, 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1769, + 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1784, 1785, + }, 128); + c_test_vector_128_f32(); +} + +export fn zig_ret_vector_1_f64() @Vector(1, f64) { + return .{1}; +} +export fn zig_vector_1_f64(v: @Vector(1, f64), i: usize) void { + expect(v[0] == 2) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_vector_1_f64() @Vector(1, f64); +extern fn c_vector_1_f64(@Vector(1, f64), usize) void; +extern fn c_test_vector_1_f64() void; + +test "@Vector(1, f64)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC64()) return error.SkipZigTest; + + const v = c_ret_vector_1_f64(); + try expect(v[0] == 3); + c_vector_1_f64(.{4}, 1); + c_test_vector_1_f64(); +} + +export fn zig_ret_vector_2_f64() @Vector(2, f64) { + return .{ 5, 6 }; +} +export fn zig_vector_2_f64(v: @Vector(2, f64), i: usize) void { + expect(v[0] == 7) catch @panic("test failure"); + expect(v[1] == 8) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} + +extern fn c_ret_vector_2_f64() @Vector(2, f64); +extern fn c_vector_2_f64(@Vector(2, f64), usize) void; +extern fn c_test_vector_2_f64() void; + +test "@Vector(2, f64)" { + if (builtin.cpu.arch == .loongarch64) return error.SkipZigTest; + + const v = c_ret_vector_2_f64(); + try expect(v[0] == 9); + try expect(v[1] == 10); + c_vector_2_f64(.{ 11, 12 }, 2); + c_test_vector_2_f64(); +} + +export fn zig_ret_vector_3_f64() @Vector(3, f64) { + return .{ 13, 14, 15 }; +} +export fn zig_vector_3_f64(v: @Vector(3, f64), i: usize) void { + expect(v[0] == 16) catch @panic("test failure"); + expect(v[1] == 17) catch @panic("test failure"); + expect(v[2] == 18) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_vector_3_f64() @Vector(3, f64); +extern fn c_vector_3_f64(@Vector(3, f64), usize) void; +extern fn c_test_vector_3_f64() void; + +test "@Vector(3, f64)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_3_f64(); + try expect(v[0] == 19); + try expect(v[1] == 20); + try expect(v[2] == 21); + c_vector_3_f64(.{ 22, 23, 24 }, 3); + c_test_vector_3_f64(); +} + +export fn zig_ret_vector_4_f64() @Vector(4, f64) { + return .{ 25, 26, 27, 28 }; +} +export fn zig_vector_4_f64(v: @Vector(4, f64), i: usize) void { + expect(v[0] == 29) catch @panic("test failure"); + expect(v[1] == 30) catch @panic("test failure"); + expect(v[2] == 31) catch @panic("test failure"); + expect(v[3] == 32) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} + +extern fn c_ret_vector_4_f64() @Vector(4, f64); +extern fn c_vector_4_f64(@Vector(4, f64), usize) void; +extern fn c_test_vector_4_f64() void; + +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); + try expect(v[1] == 34); + try expect(v[2] == 35); + try expect(v[3] == 36); + c_vector_4_f64(.{ 37, 38, 39, 40 }, 4); + c_test_vector_4_f64(); +} + +export fn zig_ret_vector_6_f64() @Vector(6, f64) { + return .{ 41, 42, 43, 44, 45, 46 }; +} +export fn zig_vector_6_f64(v: @Vector(6, f64), i: usize) void { + expect(v[0] == 47) catch @panic("test failure"); + expect(v[1] == 48) catch @panic("test failure"); + expect(v[2] == 49) catch @panic("test failure"); + expect(v[3] == 50) catch @panic("test failure"); + expect(v[4] == 51) catch @panic("test failure"); + expect(v[5] == 52) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} + +extern fn c_ret_vector_6_f64() @Vector(6, f64); +extern fn c_vector_6_f64(@Vector(6, f64), usize) void; +extern fn c_test_vector_6_f64() void; + +test "@Vector(6, f64)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_6_f64(); + try expect(v[0] == 53); + try expect(v[1] == 54); + try expect(v[2] == 55); + try expect(v[3] == 56); + try expect(v[4] == 57); + try expect(v[5] == 58); + c_vector_6_f64(.{ 59, 60, 61, 62, 63, 64 }, 6); + c_test_vector_6_f64(); +} + +export fn zig_ret_vector_8_f64() @Vector(8, f64) { + return .{ 65, 66, 67, 68, 69, 70, 71, 72 }; +} +export fn zig_vector_8_f64(v: @Vector(8, f64), i: usize) void { + expect(v[0] == 73) catch @panic("test failure"); + expect(v[1] == 74) catch @panic("test failure"); + expect(v[2] == 75) catch @panic("test failure"); + expect(v[3] == 76) catch @panic("test failure"); + expect(v[4] == 77) catch @panic("test failure"); + expect(v[5] == 78) catch @panic("test failure"); + expect(v[6] == 79) catch @panic("test failure"); + expect(v[7] == 80) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} + +extern fn c_ret_vector_8_f64() @Vector(8, f64); +extern fn c_vector_8_f64(@Vector(8, f64), usize) void; +extern fn c_test_vector_8_f64() void; + +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); + try expect(v[1] == 82); + try expect(v[2] == 83); + try expect(v[3] == 84); + try expect(v[4] == 85); + try expect(v[5] == 86); + try expect(v[6] == 87); + try expect(v[7] == 88); + c_vector_8_f64(.{ 89, 90, 91, 92, 93, 94, 95, 96 }, 8); + c_test_vector_8_f64(); +} + +export fn zig_ret_vector_12_f64() @Vector(12, f64) { + return .{ 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108 }; +} +export fn zig_vector_12_f64(v: @Vector(12, f64), i: usize) void { + expect(v[0] == 109) catch @panic("test failure"); + expect(v[1] == 110) catch @panic("test failure"); + expect(v[2] == 111) catch @panic("test failure"); + expect(v[3] == 112) catch @panic("test failure"); + expect(v[4] == 113) catch @panic("test failure"); + expect(v[5] == 114) catch @panic("test failure"); + expect(v[6] == 115) catch @panic("test failure"); + expect(v[7] == 116) catch @panic("test failure"); + expect(v[8] == 117) catch @panic("test failure"); + expect(v[9] == 118) catch @panic("test failure"); + expect(v[10] == 119) catch @panic("test failure"); + expect(v[11] == 120) catch @panic("test failure"); + expect(i == 12) catch @panic("test failure"); +} + +extern fn c_ret_vector_12_f64() @Vector(12, f64); +extern fn c_vector_12_f64(@Vector(12, f64), usize) void; +extern fn c_test_vector_12_f64() void; + +test "@Vector(12, f64)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_12_f64(); + try expect(v[0] == 121); + try expect(v[1] == 122); + try expect(v[2] == 123); + try expect(v[3] == 124); + try expect(v[4] == 125); + try expect(v[5] == 126); + try expect(v[6] == 127); + try expect(v[7] == 128); + try expect(v[8] == 129); + try expect(v[9] == 130); + try expect(v[10] == 131); + try expect(v[11] == 132); + c_vector_12_f64(.{ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144 }, 12); + c_test_vector_12_f64(); +} + +export fn zig_ret_vector_16_f64() @Vector(16, f64) { + return .{ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 }; +} +export fn zig_vector_16_f64(v: @Vector(16, f64), i: usize) void { + expect(v[0] == 161) catch @panic("test failure"); + expect(v[1] == 162) catch @panic("test failure"); + expect(v[2] == 163) catch @panic("test failure"); + expect(v[3] == 164) catch @panic("test failure"); + expect(v[4] == 165) catch @panic("test failure"); + expect(v[5] == 166) catch @panic("test failure"); + expect(v[6] == 167) catch @panic("test failure"); + expect(v[7] == 168) catch @panic("test failure"); + expect(v[8] == 169) catch @panic("test failure"); + expect(v[9] == 170) catch @panic("test failure"); + expect(v[10] == 171) catch @panic("test failure"); + expect(v[11] == 172) catch @panic("test failure"); + expect(v[12] == 173) catch @panic("test failure"); + expect(v[13] == 174) catch @panic("test failure"); + expect(v[14] == 175) catch @panic("test failure"); + expect(v[15] == 176) catch @panic("test failure"); + expect(i == 16) catch @panic("test failure"); +} + +extern fn c_ret_vector_16_f64() @Vector(16, f64); +extern fn c_vector_16_f64(@Vector(16, f64), usize) void; +extern fn c_test_vector_16_f64() void; + +test "@Vector(16, f64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 178); + try expect(v[2] == 179); + try expect(v[3] == 180); + try expect(v[4] == 181); + try expect(v[5] == 182); + try expect(v[6] == 183); + try expect(v[7] == 184); + try expect(v[8] == 185); + try expect(v[9] == 186); + try expect(v[10] == 187); + try expect(v[11] == 188); + try expect(v[12] == 189); + try expect(v[13] == 190); + try expect(v[14] == 191); + try expect(v[15] == 192); + c_vector_16_f64(.{ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208 }, 16); + c_test_vector_16_f64(); +} + +export fn zig_ret_vector_24_f64() @Vector(24, f64) { + return .{ + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, + }; +} +export fn zig_vector_24_f64(v: @Vector(24, f64), i: usize) void { + expect(v[0] == 233) catch @panic("test failure"); + expect(v[1] == 234) catch @panic("test failure"); + expect(v[2] == 235) catch @panic("test failure"); + expect(v[3] == 236) catch @panic("test failure"); + expect(v[4] == 237) catch @panic("test failure"); + expect(v[5] == 238) catch @panic("test failure"); + expect(v[6] == 239) catch @panic("test failure"); + expect(v[7] == 240) catch @panic("test failure"); + expect(v[8] == 241) catch @panic("test failure"); + expect(v[9] == 242) catch @panic("test failure"); + expect(v[10] == 243) catch @panic("test failure"); + expect(v[11] == 244) catch @panic("test failure"); + expect(v[12] == 245) catch @panic("test failure"); + expect(v[13] == 246) catch @panic("test failure"); + expect(v[14] == 247) catch @panic("test failure"); + expect(v[15] == 248) catch @panic("test failure"); + expect(v[16] == 249) catch @panic("test failure"); + expect(v[17] == 250) catch @panic("test failure"); + expect(v[18] == 251) catch @panic("test failure"); + expect(v[19] == 252) catch @panic("test failure"); + expect(v[20] == 253) catch @panic("test failure"); + expect(v[21] == 254) catch @panic("test failure"); + expect(v[22] == 255) catch @panic("test failure"); + expect(v[23] == 256) catch @panic("test failure"); + expect(i == 24) catch @panic("test failure"); +} + +extern fn c_ret_vector_24_f64() @Vector(24, f64); +extern fn c_vector_24_f64(@Vector(24, f64), usize) void; +extern fn c_test_vector_24_f64() void; + +test "@Vector(24, f64)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_24_f64(); + try expect(v[0] == 257); + try expect(v[1] == 258); + try expect(v[2] == 259); + try expect(v[3] == 260); + try expect(v[4] == 261); + try expect(v[5] == 262); + try expect(v[6] == 263); + try expect(v[7] == 264); + try expect(v[8] == 265); + try expect(v[9] == 266); + try expect(v[10] == 267); + try expect(v[11] == 268); + try expect(v[12] == 269); + try expect(v[13] == 270); + try expect(v[14] == 271); + try expect(v[15] == 272); + try expect(v[16] == 273); + try expect(v[17] == 274); + try expect(v[18] == 275); + try expect(v[19] == 276); + try expect(v[20] == 277); + try expect(v[21] == 278); + try expect(v[22] == 279); + try expect(v[23] == 280); + c_vector_24_f64(.{ + 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, + }, 24); + c_test_vector_24_f64(); +} + +export fn zig_ret_vector_32_f64() @Vector(32, f64) { + return .{ + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, + }; +} +export fn zig_vector_32_f64(v: @Vector(32, f64), i: usize) void { + expect(v[0] == 337) catch @panic("test failure"); + expect(v[1] == 338) catch @panic("test failure"); + expect(v[2] == 339) catch @panic("test failure"); + expect(v[3] == 340) catch @panic("test failure"); + expect(v[4] == 341) catch @panic("test failure"); + expect(v[5] == 342) catch @panic("test failure"); + expect(v[6] == 343) catch @panic("test failure"); + expect(v[7] == 344) catch @panic("test failure"); + expect(v[8] == 345) catch @panic("test failure"); + expect(v[9] == 346) catch @panic("test failure"); + expect(v[10] == 347) catch @panic("test failure"); + expect(v[11] == 348) catch @panic("test failure"); + expect(v[12] == 349) catch @panic("test failure"); + expect(v[13] == 350) catch @panic("test failure"); + expect(v[14] == 351) catch @panic("test failure"); + expect(v[15] == 352) catch @panic("test failure"); + expect(v[16] == 353) catch @panic("test failure"); + expect(v[17] == 354) catch @panic("test failure"); + expect(v[18] == 355) catch @panic("test failure"); + expect(v[19] == 356) catch @panic("test failure"); + expect(v[20] == 357) catch @panic("test failure"); + expect(v[21] == 358) catch @panic("test failure"); + expect(v[22] == 359) catch @panic("test failure"); + expect(v[23] == 360) catch @panic("test failure"); + expect(v[24] == 361) catch @panic("test failure"); + expect(v[25] == 362) catch @panic("test failure"); + expect(v[26] == 363) catch @panic("test failure"); + expect(v[27] == 364) catch @panic("test failure"); + expect(v[28] == 365) catch @panic("test failure"); + expect(v[29] == 366) catch @panic("test failure"); + expect(v[30] == 367) catch @panic("test failure"); + expect(v[31] == 368) catch @panic("test failure"); + expect(i == 32) catch @panic("test failure"); +} + +extern fn c_ret_vector_32_f64() @Vector(32, f64); +extern fn c_vector_32_f64(@Vector(32, f64), usize) void; +extern fn c_test_vector_32_f64() void; + +test "@Vector(32, f64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 370); + try expect(v[2] == 371); + try expect(v[3] == 372); + try expect(v[4] == 373); + try expect(v[5] == 374); + try expect(v[6] == 375); + try expect(v[7] == 376); + try expect(v[8] == 377); + try expect(v[9] == 378); + try expect(v[10] == 379); + try expect(v[11] == 380); + try expect(v[12] == 381); + try expect(v[13] == 382); + try expect(v[14] == 383); + try expect(v[15] == 384); + try expect(v[16] == 385); + try expect(v[17] == 386); + try expect(v[18] == 387); + try expect(v[19] == 388); + try expect(v[20] == 389); + try expect(v[21] == 390); + try expect(v[22] == 391); + try expect(v[23] == 392); + try expect(v[24] == 393); + try expect(v[25] == 394); + try expect(v[26] == 395); + try expect(v[27] == 396); + try expect(v[28] == 397); + try expect(v[29] == 398); + try expect(v[30] == 399); + try expect(v[31] == 400); + c_vector_32_f64(.{ + 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, + }, 32); + c_test_vector_32_f64(); +} + +export fn zig_ret_vector_48_f64() @Vector(48, f64) { + return .{ + 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, + }; +} +export fn zig_vector_48_f64(v: @Vector(48, f64), i: usize) void { + expect(v[0] == 481) catch @panic("test failure"); + expect(v[1] == 482) catch @panic("test failure"); + expect(v[2] == 483) catch @panic("test failure"); + expect(v[3] == 484) catch @panic("test failure"); + expect(v[4] == 485) catch @panic("test failure"); + expect(v[5] == 486) catch @panic("test failure"); + expect(v[6] == 487) catch @panic("test failure"); + expect(v[7] == 488) catch @panic("test failure"); + expect(v[8] == 489) catch @panic("test failure"); + expect(v[9] == 490) catch @panic("test failure"); + expect(v[10] == 491) catch @panic("test failure"); + expect(v[11] == 492) catch @panic("test failure"); + expect(v[12] == 493) catch @panic("test failure"); + expect(v[13] == 494) catch @panic("test failure"); + expect(v[14] == 495) catch @panic("test failure"); + expect(v[15] == 496) catch @panic("test failure"); + expect(v[16] == 497) catch @panic("test failure"); + expect(v[17] == 498) catch @panic("test failure"); + expect(v[18] == 499) catch @panic("test failure"); + expect(v[19] == 500) catch @panic("test failure"); + expect(v[20] == 501) catch @panic("test failure"); + expect(v[21] == 502) catch @panic("test failure"); + expect(v[22] == 503) catch @panic("test failure"); + expect(v[23] == 504) catch @panic("test failure"); + expect(v[24] == 505) catch @panic("test failure"); + expect(v[25] == 506) catch @panic("test failure"); + expect(v[26] == 507) catch @panic("test failure"); + expect(v[27] == 508) catch @panic("test failure"); + expect(v[28] == 509) catch @panic("test failure"); + expect(v[29] == 510) catch @panic("test failure"); + expect(v[30] == 511) catch @panic("test failure"); + expect(v[31] == 512) catch @panic("test failure"); + expect(v[32] == 513) catch @panic("test failure"); + expect(v[33] == 514) catch @panic("test failure"); + expect(v[34] == 515) catch @panic("test failure"); + expect(v[35] == 516) catch @panic("test failure"); + expect(v[36] == 517) catch @panic("test failure"); + expect(v[37] == 518) catch @panic("test failure"); + expect(v[38] == 519) catch @panic("test failure"); + expect(v[39] == 520) catch @panic("test failure"); + expect(v[40] == 521) catch @panic("test failure"); + expect(v[41] == 522) catch @panic("test failure"); + expect(v[42] == 523) catch @panic("test failure"); + expect(v[43] == 524) catch @panic("test failure"); + expect(v[44] == 525) catch @panic("test failure"); + expect(v[45] == 526) catch @panic("test failure"); + expect(v[46] == 527) catch @panic("test failure"); + expect(v[47] == 528) catch @panic("test failure"); + expect(i == 48) catch @panic("test failure"); +} + +extern fn c_ret_vector_48_f64() @Vector(48, f64); +extern fn c_vector_48_f64(@Vector(48, f64), usize) void; +extern fn c_test_vector_48_f64() void; + +test "@Vector(48, f64)" { + if (builtin.cpu.arch.isArm()) 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 == .s390x) return error.SkipZigTest; + + const v = c_ret_vector_48_f64(); + try expect(v[0] == 529); + try expect(v[1] == 530); + try expect(v[2] == 531); + try expect(v[3] == 532); + try expect(v[4] == 533); + try expect(v[5] == 534); + try expect(v[6] == 535); + try expect(v[7] == 536); + try expect(v[8] == 537); + try expect(v[9] == 538); + try expect(v[10] == 539); + try expect(v[11] == 540); + try expect(v[12] == 541); + try expect(v[13] == 542); + try expect(v[14] == 543); + try expect(v[15] == 544); + try expect(v[16] == 545); + try expect(v[17] == 546); + try expect(v[18] == 547); + try expect(v[19] == 548); + try expect(v[20] == 549); + try expect(v[21] == 550); + try expect(v[22] == 551); + try expect(v[23] == 552); + try expect(v[24] == 553); + try expect(v[25] == 554); + try expect(v[26] == 555); + try expect(v[27] == 556); + try expect(v[28] == 557); + try expect(v[29] == 558); + try expect(v[30] == 559); + try expect(v[31] == 560); + try expect(v[32] == 561); + try expect(v[33] == 562); + try expect(v[34] == 563); + try expect(v[35] == 564); + try expect(v[36] == 565); + try expect(v[37] == 566); + try expect(v[38] == 567); + try expect(v[39] == 568); + try expect(v[40] == 569); + try expect(v[41] == 570); + try expect(v[42] == 571); + try expect(v[43] == 572); + try expect(v[44] == 573); + try expect(v[45] == 574); + try expect(v[46] == 575); + try expect(v[47] == 576); + c_vector_48_f64(.{ + 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, + 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, + 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, + }, 48); + c_test_vector_48_f64(); +} + +export fn zig_ret_vector_64_f64() @Vector(64, f64) { + return .{ + 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, + 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, + 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, + 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, + }; +} +export fn zig_vector_64_f64(v: @Vector(64, f64), i: usize) void { + expect(v[0] == 689) catch @panic("test failure"); + expect(v[1] == 690) catch @panic("test failure"); + expect(v[2] == 691) catch @panic("test failure"); + expect(v[3] == 692) catch @panic("test failure"); + expect(v[4] == 693) catch @panic("test failure"); + expect(v[5] == 694) catch @panic("test failure"); + expect(v[6] == 695) catch @panic("test failure"); + expect(v[7] == 696) catch @panic("test failure"); + expect(v[8] == 697) catch @panic("test failure"); + expect(v[9] == 698) catch @panic("test failure"); + expect(v[10] == 699) catch @panic("test failure"); + expect(v[11] == 700) catch @panic("test failure"); + expect(v[12] == 701) catch @panic("test failure"); + expect(v[13] == 702) catch @panic("test failure"); + expect(v[14] == 703) catch @panic("test failure"); + expect(v[15] == 704) catch @panic("test failure"); + expect(v[16] == 705) catch @panic("test failure"); + expect(v[17] == 706) catch @panic("test failure"); + expect(v[18] == 707) catch @panic("test failure"); + expect(v[19] == 708) catch @panic("test failure"); + expect(v[20] == 709) catch @panic("test failure"); + expect(v[21] == 710) catch @panic("test failure"); + expect(v[22] == 711) catch @panic("test failure"); + expect(v[23] == 712) catch @panic("test failure"); + expect(v[24] == 713) catch @panic("test failure"); + expect(v[25] == 714) catch @panic("test failure"); + expect(v[26] == 715) catch @panic("test failure"); + expect(v[27] == 716) catch @panic("test failure"); + expect(v[28] == 717) catch @panic("test failure"); + expect(v[29] == 718) catch @panic("test failure"); + expect(v[30] == 719) catch @panic("test failure"); + expect(v[31] == 720) catch @panic("test failure"); + expect(v[32] == 721) catch @panic("test failure"); + expect(v[33] == 722) catch @panic("test failure"); + expect(v[34] == 723) catch @panic("test failure"); + expect(v[35] == 724) catch @panic("test failure"); + expect(v[36] == 725) catch @panic("test failure"); + expect(v[37] == 726) catch @panic("test failure"); + expect(v[38] == 727) catch @panic("test failure"); + expect(v[39] == 728) catch @panic("test failure"); + expect(v[40] == 729) catch @panic("test failure"); + expect(v[41] == 730) catch @panic("test failure"); + expect(v[42] == 731) catch @panic("test failure"); + expect(v[43] == 732) catch @panic("test failure"); + expect(v[44] == 733) catch @panic("test failure"); + expect(v[45] == 734) catch @panic("test failure"); + expect(v[46] == 735) catch @panic("test failure"); + expect(v[47] == 736) catch @panic("test failure"); + expect(v[48] == 737) catch @panic("test failure"); + expect(v[49] == 738) catch @panic("test failure"); + expect(v[50] == 739) catch @panic("test failure"); + expect(v[51] == 740) catch @panic("test failure"); + expect(v[52] == 741) catch @panic("test failure"); + expect(v[53] == 742) catch @panic("test failure"); + expect(v[54] == 743) catch @panic("test failure"); + expect(v[55] == 744) catch @panic("test failure"); + expect(v[56] == 745) catch @panic("test failure"); + expect(v[57] == 746) catch @panic("test failure"); + expect(v[58] == 747) catch @panic("test failure"); + expect(v[59] == 748) catch @panic("test failure"); + expect(v[60] == 749) catch @panic("test failure"); + expect(v[61] == 750) catch @panic("test failure"); + expect(v[62] == 751) catch @panic("test failure"); + expect(v[63] == 752) catch @panic("test failure"); + expect(i == 64) catch @panic("test failure"); +} + +extern fn c_ret_vector_64_f64() @Vector(64, f64); +extern fn c_vector_64_f64(@Vector(64, f64), usize) void; +extern fn c_test_vector_64_f64() void; + +test "@Vector(64, f64)" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + 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); + try expect(v[1] == 754); + try expect(v[2] == 755); + try expect(v[3] == 756); + try expect(v[4] == 757); + try expect(v[5] == 758); + try expect(v[6] == 759); + try expect(v[7] == 760); + try expect(v[8] == 761); + try expect(v[9] == 762); + try expect(v[10] == 763); + try expect(v[11] == 764); + try expect(v[12] == 765); + try expect(v[13] == 766); + try expect(v[14] == 767); + try expect(v[15] == 768); + try expect(v[16] == 769); + try expect(v[17] == 770); + try expect(v[18] == 771); + try expect(v[19] == 772); + try expect(v[20] == 773); + try expect(v[21] == 774); + try expect(v[22] == 775); + try expect(v[23] == 776); + try expect(v[24] == 777); + try expect(v[25] == 778); + try expect(v[26] == 779); + try expect(v[27] == 780); + try expect(v[28] == 781); + try expect(v[29] == 782); + try expect(v[30] == 783); + try expect(v[31] == 784); + try expect(v[32] == 785); + try expect(v[33] == 786); + try expect(v[34] == 787); + try expect(v[35] == 788); + try expect(v[36] == 789); + try expect(v[37] == 790); + try expect(v[38] == 791); + try expect(v[39] == 792); + try expect(v[40] == 793); + try expect(v[41] == 794); + try expect(v[42] == 795); + try expect(v[43] == 796); + try expect(v[44] == 797); + try expect(v[45] == 798); + try expect(v[46] == 799); + try expect(v[47] == 800); + try expect(v[48] == 801); + try expect(v[49] == 802); + try expect(v[50] == 803); + try expect(v[51] == 804); + try expect(v[52] == 805); + try expect(v[53] == 806); + try expect(v[54] == 807); + try expect(v[55] == 808); + try expect(v[56] == 809); + try expect(v[57] == 810); + try expect(v[58] == 811); + try expect(v[59] == 812); + try expect(v[60] == 813); + try expect(v[61] == 814); + try expect(v[62] == 815); + try expect(v[63] == 816); + c_vector_64_f64(.{ + 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, + 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, + 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, + 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, + }, 64); + c_test_vector_64_f64(); +} + +const Struct_u8 = extern struct { + a: u8, +}; + +export fn zig_ret_struct_u8() Struct_u8 { + return .{ .a = 1 }; +} +export fn zig_struct_u8(s: Struct_u8, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_u8() Struct_u8; +extern fn c_struct_u8(Struct_u8, usize) void; +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(); + try expect(s.a == 4); + c_struct_u8(.{ .a = 5 }, 6); + c_test_struct_u8(); +} + +const Struct_u8_u8 = extern struct { + a: u8, + b: u8, +}; + +export fn zig_ret_struct_u8_u8() Struct_u8_u8 { + return .{ .a = 1, .b = 2 }; +} +export fn zig_struct_u8_u8(s: Struct_u8_u8, i: usize) void { + expect(s.a == 3) catch @panic("test failure"); + expect(s.b == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_u8_u8() Struct_u8_u8; +extern fn c_struct_u8_u8(Struct_u8_u8, usize) void; +extern fn c_test_struct_u8_u8() void; + +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 == .x86) return error.SkipZigTest; + + const s = c_ret_struct_u8_u8(); + try expect(s.a == 6); + try expect(s.b == 7); + c_struct_u8_u8(.{ .a = 8, .b = 9 }, 10); + c_test_struct_u8_u8(); +} + +const Struct_u8_u8_u8 = extern struct { + a: u8, + b: u8, + c: u8, +}; + +export fn zig_ret_struct_u8_u8_u8() Struct_u8_u8_u8 { + return .{ .a = 1, .b = 2, .c = 3 }; +} +export fn zig_struct_u8_u8_u8(s: Struct_u8_u8_u8, i: usize) void { + expect(s.a == 4) catch @panic("test failure"); + expect(s.b == 5) catch @panic("test failure"); + expect(s.c == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_u8_u8_u8() Struct_u8_u8_u8; +extern fn c_struct_u8_u8_u8(Struct_u8_u8_u8, usize) void; +extern fn c_test_struct_u8_u8_u8() void; + +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 == .x86) return error.SkipZigTest; + + const s = c_ret_struct_u8_u8_u8(); + try expect(s.a == 8); + try expect(s.b == 9); + try expect(s.c == 10); + c_struct_u8_u8_u8(.{ .a = 11, .b = 12, .c = 13 }, 14); + c_test_struct_u8_u8_u8(); +} + +const Struct_u8_u8_u8_u8 = extern struct { + a: u8, + b: u8, + c: u8, + d: u8, +}; + +export fn zig_ret_struct_u8_u8_u8_u8() Struct_u8_u8_u8_u8 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4 }; +} +export fn zig_struct_u8_u8_u8_u8(s: Struct_u8_u8_u8_u8, i: usize) void { + expect(s.a == 5) catch @panic("test failure"); + expect(s.b == 6) catch @panic("test failure"); + expect(s.c == 7) catch @panic("test failure"); + expect(s.d == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_u8_u8_u8_u8() Struct_u8_u8_u8_u8; +extern fn c_struct_u8_u8_u8_u8(Struct_u8_u8_u8_u8, usize) void; +extern fn c_test_struct_u8_u8_u8_u8() void; + +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 == .x86) return error.SkipZigTest; + + const s = c_ret_struct_u8_u8_u8_u8(); + try expect(s.a == 10); + try expect(s.b == 11); + try expect(s.c == 12); + try expect(s.d == 13); + c_struct_u8_u8_u8_u8(.{ .a = 14, .b = 15, .c = 16, .d = 17 }, 18); + c_test_struct_u8_u8_u8_u8(); +} + +const Struct_u16 = extern struct { + a: u16, +}; + +export fn zig_ret_struct_u16() Struct_u16 { + return .{ .a = 1 }; +} +export fn zig_struct_u16(s: Struct_u16, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_u16() Struct_u16; +extern fn c_struct_u16(Struct_u16, usize) void; +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(); + try expect(s.a == 4); + c_struct_u16(.{ .a = 5 }, 6); + c_test_struct_u16(); +} + +const Struct_u16_u16 = extern struct { + a: u16, + b: u16, +}; + +export fn zig_ret_struct_u16_u16() Struct_u16_u16 { + return .{ .a = 1, .b = 2 }; +} +export fn zig_struct_u16_u16(s: Struct_u16_u16, i: usize) void { + expect(s.a == 3) catch @panic("test failure"); + expect(s.b == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_u16_u16() Struct_u16_u16; +extern fn c_struct_u16_u16(Struct_u16_u16, usize) void; +extern fn c_test_struct_u16_u16() void; + +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 == .x86) return error.SkipZigTest; + + const s = c_ret_struct_u16_u16(); + try expect(s.a == 6); + try expect(s.b == 7); + c_struct_u16_u16(.{ .a = 8, .b = 9 }, 10); + c_test_struct_u16_u16(); +} + +const Struct_u16_u16_u16 = extern struct { + a: u16, + b: u16, + c: u16, +}; + +export fn zig_ret_struct_u16_u16_u16() Struct_u16_u16_u16 { + return .{ .a = 1, .b = 2, .c = 3 }; +} +export fn zig_struct_u16_u16_u16(s: Struct_u16_u16_u16, i: usize) void { + expect(s.a == 4) catch @panic("test failure"); + expect(s.b == 5) catch @panic("test failure"); + expect(s.c == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_u16_u16_u16() Struct_u16_u16_u16; +extern fn c_struct_u16_u16_u16(Struct_u16_u16_u16, usize) void; +extern fn c_test_struct_u16_u16_u16() void; + +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.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(); + try expect(s.a == 8); + try expect(s.b == 9); + try expect(s.c == 10); + c_struct_u16_u16_u16(.{ .a = 11, .b = 12, .c = 13 }, 14); + c_test_struct_u16_u16_u16(); +} + +const Struct_u16_u16_u16_u16 = extern struct { + a: u16, + b: u16, + c: u16, + d: u16, +}; + +export fn zig_ret_struct_u16_u16_u16_u16() Struct_u16_u16_u16_u16 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4 }; +} +export fn zig_struct_u16_u16_u16_u16(s: Struct_u16_u16_u16_u16, i: usize) void { + expect(s.a == 5) catch @panic("test failure"); + expect(s.b == 6) catch @panic("test failure"); + expect(s.c == 7) catch @panic("test failure"); + expect(s.d == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_u16_u16_u16_u16() Struct_u16_u16_u16_u16; +extern fn c_struct_u16_u16_u16_u16(Struct_u16_u16_u16_u16, usize) void; +extern fn c_test_struct_u16_u16_u16_u16() void; + +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.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(); + try expect(s.a == 10); + try expect(s.b == 11); + try expect(s.c == 12); + try expect(s.d == 13); + c_struct_u16_u16_u16_u16(.{ .a = 14, .b = 15, .c = 16, .d = 17 }, 18); + c_test_struct_u16_u16_u16_u16(); +} + +const Struct_u32 = extern struct { + a: u32, +}; + +export fn zig_ret_struct_u32() Struct_u32 { + return .{ .a = 1 }; +} +export fn zig_struct_u32(s: Struct_u32, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_u32() Struct_u32; +extern fn c_struct_u32(Struct_u32, usize) void; +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(); + try expect(s.a == 4); + c_struct_u32(.{ .a = 5 }, 6); + c_test_struct_u32(); +} + +const Struct_u32_u32 = extern struct { + a: u32, + b: u32, +}; + +export fn zig_ret_struct_u32_u32() Struct_u32_u32 { + return .{ .a = 1, .b = 2 }; +} +export fn zig_struct_u32_u32(s: Struct_u32_u32, i: usize) void { + expect(s.a == 3) catch @panic("test failure"); + expect(s.b == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_u32_u32() Struct_u32_u32; +extern fn c_struct_u32_u32(Struct_u32_u32, usize) void; +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.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(); + try expect(s.a == 6); + try expect(s.b == 7); + c_struct_u32_u32(.{ .a = 8, .b = 9 }, 10); + c_test_struct_u32_u32(); +} + +const Struct_u32_u32_u32 = extern struct { + a: u32, + b: u32, + c: u32, +}; + +export fn zig_ret_struct_u32_u32_u32() Struct_u32_u32_u32 { + return .{ .a = 1, .b = 2, .c = 3 }; +} +export fn zig_struct_u32_u32_u32(s: Struct_u32_u32_u32, i: usize) void { + expect(s.a == 4) catch @panic("test failure"); + expect(s.b == 5) catch @panic("test failure"); + expect(s.c == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_u32_u32_u32() Struct_u32_u32_u32; +extern fn c_struct_u32_u32_u32(Struct_u32_u32_u32, usize) void; +extern fn c_test_struct_u32_u32_u32() void; + +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; + + const s = c_ret_struct_u32_u32_u32(); + try expect(s.a == 8); + try expect(s.b == 9); + try expect(s.c == 10); + c_struct_u32_u32_u32(.{ .a = 11, .b = 12, .c = 13 }, 14); + c_test_struct_u32_u32_u32(); +} + +const Struct_u32_u32_u32_u32 = extern struct { + a: u32, + b: u32, + c: u32, + d: u32, +}; + +export fn zig_ret_struct_u32_u32_u32_u32() Struct_u32_u32_u32_u32 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4 }; +} +export fn zig_struct_u32_u32_u32_u32(s: Struct_u32_u32_u32_u32, i: usize) void { + expect(s.a == 5) catch @panic("test failure"); + expect(s.b == 6) catch @panic("test failure"); + expect(s.c == 7) catch @panic("test failure"); + expect(s.d == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_u32_u32_u32_u32() Struct_u32_u32_u32_u32; +extern fn c_struct_u32_u32_u32_u32(Struct_u32_u32_u32_u32, usize) void; +extern fn c_test_struct_u32_u32_u32_u32() void; + +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; + + const s = c_ret_struct_u32_u32_u32_u32(); + try expect(s.a == 10); + try expect(s.b == 11); + try expect(s.c == 12); + try expect(s.d == 13); + c_struct_u32_u32_u32_u32(.{ .a = 14, .b = 15, .c = 16, .d = 17 }, 18); + c_test_struct_u32_u32_u32_u32(); +} + +const Struct_u64 = extern struct { + a: u64, +}; + +export fn zig_ret_struct_u64() Struct_u64 { + return .{ .a = 1 }; +} +export fn zig_struct_u64(s: Struct_u64, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_u64() Struct_u64; +extern fn c_struct_u64(Struct_u64, usize) void; +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(); + try expect(s.a == 4); + c_struct_u64(.{ .a = 5 }, 6); + c_test_struct_u64(); +} + +const Struct_u64_u64 = extern struct { + a: u64, + b: u64, +}; + +export fn zig_ret_struct_u64_u64() Struct_u64_u64 { + return .{ .a = 1, .b = 2 }; +} +export fn zig_struct_u64_u64(s: Struct_u64_u64, i: usize) void { + expect(s.a == 3) catch @panic("test failure"); + expect(s.b == 4) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} +export fn zig_1_struct_u64_u64(_: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 5) catch @panic("test failure"); + expect(s.b == 6) catch @panic("test failure"); + expect(i == 2) catch @panic("test failure"); +} +export fn zig_2_struct_u64_u64(_: usize, _: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 7) catch @panic("test failure"); + expect(s.b == 8) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} +export fn zig_3_struct_u64_u64(_: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 9) catch @panic("test failure"); + expect(s.b == 10) catch @panic("test failure"); + expect(i == 4) catch @panic("test failure"); +} +export fn zig_4_struct_u64_u64(_: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 11) catch @panic("test failure"); + expect(s.b == 12) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} +export fn zig_5_struct_u64_u64(_: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 13) catch @panic("test failure"); + expect(s.b == 14) catch @panic("test failure"); + expect(i == 6) catch @panic("test failure"); +} +export fn zig_6_struct_u64_u64(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 15) catch @panic("test failure"); + expect(s.b == 16) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} +export fn zig_7_struct_u64_u64(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 17) catch @panic("test failure"); + expect(s.b == 18) catch @panic("test failure"); + expect(i == 8) catch @panic("test failure"); +} +export fn zig_8_struct_u64_u64(_: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, _: usize, s: Struct_u64_u64, i: usize) void { + expect(s.a == 19) catch @panic("test failure"); + expect(s.b == 20) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_u64_u64() Struct_u64_u64; +extern fn c_struct_u64_u64(Struct_u64_u64, usize) void; +extern fn c_1_struct_u64_u64(usize, Struct_u64_u64, usize) void; +extern fn c_2_struct_u64_u64(usize, usize, Struct_u64_u64, usize) void; +extern fn c_3_struct_u64_u64(usize, usize, usize, Struct_u64_u64, usize) void; +extern fn c_4_struct_u64_u64(usize, usize, usize, usize, Struct_u64_u64, usize) void; +extern fn c_5_struct_u64_u64(usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; +extern fn c_6_struct_u64_u64(usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; +extern fn c_7_struct_u64_u64(usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; +extern fn c_8_struct_u64_u64(usize, usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void; +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); + try expect(s.b == 22); + c_struct_u64_u64(.{ .a = 23, .b = 24 }, 1); + c_1_struct_u64_u64(0, .{ .a = 25, .b = 26 }, 2); + c_2_struct_u64_u64(0, 1, .{ .a = 27, .b = 28 }, 3); + c_3_struct_u64_u64(0, 1, 2, .{ .a = 29, .b = 30 }, 4); + c_4_struct_u64_u64(0, 1, 2, 3, .{ .a = 31, .b = 32 }, 5); + c_5_struct_u64_u64(0, 1, 2, 3, 4, .{ .a = 33, .b = 34 }, 6); + c_6_struct_u64_u64(0, 1, 2, 3, 4, 5, .{ .a = 35, .b = 36 }, 7); + c_7_struct_u64_u64(0, 1, 2, 3, 4, 5, 6, .{ .a = 37, .b = 38 }, 8); + c_8_struct_u64_u64(0, 1, 2, 3, 4, 5, 6, 7, .{ .a = 39, .b = 40 }, 9); + c_test_struct_u64_u64(); +} + +const Struct_u64_u64_u64 = extern struct { + a: u64, + b: u64, + c: u64, +}; + +export fn zig_ret_struct_u64_u64_u64() Struct_u64_u64_u64 { + return .{ .a = 1, .b = 2, .c = 3 }; +} +export fn zig_struct_u64_u64_u64(s: Struct_u64_u64_u64, i: usize) void { + expect(s.a == 4) catch @panic("test failure"); + expect(s.b == 5) catch @panic("test failure"); + expect(s.c == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_u64_u64_u64() Struct_u64_u64_u64; +extern fn c_struct_u64_u64_u64(Struct_u64_u64_u64, usize) void; +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; + + const s = c_ret_struct_u64_u64_u64(); + try expect(s.a == 8); + try expect(s.b == 9); + try expect(s.c == 10); + c_struct_u64_u64_u64(.{ .a = 11, .b = 12, .c = 13 }, 14); + c_test_struct_u64_u64_u64(); +} + +const Struct_u64_u64_u64_u64 = extern struct { + a: u64, + b: u64, + c: u64, + d: u64, +}; + +export fn zig_ret_struct_u64_u64_u64_u64() Struct_u64_u64_u64_u64 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4 }; +} +export fn zig_struct_u64_u64_u64_u64(s: Struct_u64_u64_u64_u64, i: usize) void { + expect(s.a == 5) catch @panic("test failure"); + expect(s.b == 6) catch @panic("test failure"); + expect(s.c == 7) catch @panic("test failure"); + expect(s.d == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_u64_u64_u64_u64() Struct_u64_u64_u64_u64; +extern fn c_struct_u64_u64_u64_u64(Struct_u64_u64_u64_u64, usize) void; +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; + + const s = c_ret_struct_u64_u64_u64_u64(); + try expect(s.a == 10); + try expect(s.b == 11); + try expect(s.c == 12); + try expect(s.d == 13); + c_struct_u64_u64_u64_u64(.{ .a = 14, .b = 15, .c = 16, .d = 17 }, 18); + c_test_struct_u64_u64_u64_u64(); +} + +const Struct_f32 = extern struct { + a: f32, +}; + +export fn zig_ret_struct_f32() Struct_f32 { + return .{ .a = 1 }; +} +export fn zig_struct_f32(s: Struct_f32, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32() Struct_f32; +extern fn c_struct_f32(Struct_f32, usize) void; +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 == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + + const s = c_ret_struct_f32(); + try expect(s.a == 4); + c_struct_f32(.{ .a = 5 }, 6); + c_test_struct_f32(); +} + +const Struct_f32_f32 = extern struct { + a: f32, + b: f32, +}; + +export fn zig_ret_struct_f32_f32() Struct_f32_f32 { + return .{ .a = 1, .b = 2 }; +} +export fn zig_struct_f32_f32(s: Struct_f32_f32, i: usize) void { + expect(s.a == 3) catch @panic("test failure"); + expect(s.b == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32_f32() Struct_f32_f32; +extern fn c_struct_f32_f32(Struct_f32_f32, usize) void; +extern fn c_test_struct_f32_f32() void; + +test "struct f32, f32" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) 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.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(); + try expect(s.a == 6); + try expect(s.b == 7); + c_struct_f32_f32(.{ .a = 8, .b = 9 }, 10); + c_test_struct_f32_f32(); +} + +const Struct_f32_f32_f32 = extern struct { + a: f32, + b: f32, + c: f32, +}; + +export fn zig_ret_struct_f32_f32_f32() Struct_f32_f32_f32 { + return .{ .a = 1, .b = 2, .c = 3 }; +} +export fn zig_struct_f32_f32_f32(s: Struct_f32_f32_f32, i: usize) void { + expect(s.a == 4) catch @panic("test failure"); + expect(s.b == 5) catch @panic("test failure"); + expect(s.c == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32_f32_f32() Struct_f32_f32_f32; +extern fn c_struct_f32_f32_f32(Struct_f32_f32_f32, usize) void; +extern fn c_test_struct_f32_f32_f32() void; + +test "struct f32, f32, f32" { + 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 == .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); + try expect(s.b == 9); + try expect(s.c == 10); + c_struct_f32_f32_f32(.{ .a = 11, .b = 12, .c = 13 }, 14); + c_test_struct_f32_f32_f32(); +} + +const Struct_f32_f32_f32_f32 = extern struct { + a: f32, + b: f32, + c: f32, + d: f32, +}; + +export fn zig_ret_struct_f32_f32_f32_f32() Struct_f32_f32_f32_f32 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4 }; +} +export fn zig_struct_f32_f32_f32_f32(s: Struct_f32_f32_f32_f32, i: usize) void { + expect(s.a == 5) catch @panic("test failure"); + expect(s.b == 6) catch @panic("test failure"); + expect(s.c == 7) catch @panic("test failure"); + expect(s.d == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32_f32_f32_f32() Struct_f32_f32_f32_f32; +extern fn c_struct_f32_f32_f32_f32(Struct_f32_f32_f32_f32, usize) void; +extern fn c_test_struct_f32_f32_f32_f32() void; + +test "struct f32, f32, f32, f32" { + 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 == .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); + try expect(s.b == 11); + try expect(s.c == 12); + try expect(s.d == 13); + c_struct_f32_f32_f32_f32(.{ .a = 14, .b = 15, .c = 16, .d = 17 }, 18); + c_test_struct_f32_f32_f32_f32(); +} + +const Struct_f32_f32_f32_f32_f32 = extern struct { + a: f32, + b: f32, + c: f32, + d: f32, + e: f32, +}; + +export fn zig_ret_struct_f32_f32_f32_f32_f32() Struct_f32_f32_f32_f32_f32 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4, .e = 5 }; +} +export fn zig_struct_f32_f32_f32_f32_f32(s: Struct_f32_f32_f32_f32_f32, i: usize) void { + expect(s.a == 6) catch @panic("test failure"); + expect(s.b == 7) catch @panic("test failure"); + expect(s.c == 8) catch @panic("test failure"); + expect(s.d == 9) catch @panic("test failure"); + expect(s.e == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32_f32_f32_f32_f32() Struct_f32_f32_f32_f32_f32; +extern fn c_struct_f32_f32_f32_f32_f32(Struct_f32_f32_f32_f32_f32, usize) void; +extern fn c_test_struct_f32_f32_f32_f32_f32() void; + +test "struct f32, f32, 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.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); + try expect(s.b == 13); + try expect(s.c == 14); + try expect(s.d == 15); + try expect(s.e == 16); + c_struct_f32_f32_f32_f32_f32(.{ .a = 17, .b = 18, .c = 19, .d = 20, .e = 21 }, 22); + c_test_struct_f32_f32_f32_f32_f32(); +} + +const Struct_f32a8 = extern struct { + a: f32 align(8), +}; + +export fn zig_ret_struct_f32a8() Struct_f32a8 { + return .{ .a = 1.25 }; +} +export fn zig_struct_f32a8(s: Struct_f32a8, f: f32) void { + expect(s.a == 2.75) catch @panic("test failure"); + expect(f == 3.5) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32a8() Struct_f32a8; +extern fn c_struct_f32a8(Struct_f32a8, f32) void; +extern fn c_test_struct_f32a8() void; + +test "struct f32 align(8)" { + 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.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(); + try expect(s.a == 4.125); + c_struct_f32a8(.{ .a = 5.375 }, 6.5); + c_test_struct_f32a8(); +} + +const Struct_f32a8_f32a8 = extern struct { + a: f32 align(8), + b: f32 align(8), +}; + +export fn zig_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8 { + return .{ .a = 1.25, .b = 2.75 }; +} +export fn zig_struct_f32a8_f32a8(s: Struct_f32a8_f32a8, f: f32) void { + expect(s.a == 3.125) catch @panic("test failure"); + expect(s.b == 4.375) catch @panic("test failure"); + expect(f == 5.5) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8; +extern fn c_struct_f32a8_f32a8(Struct_f32a8_f32a8, f32) void; +extern fn c_test_struct_f32a8_f32a8() void; + +test "struct f32 align(8), f32 align(8)" { + 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.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(); + try expect(s.a == 6.625); + try expect(s.b == 7.875); + c_struct_f32a8_f32a8(.{ .a = 8.0625, .b = 9.1875 }, 10.5); + c_test_struct_f32a8_f32a8(); +} + +const Struct_f32f32_f32 = extern struct { + a: extern struct { b: f32, c: f32 }, + d: f32, +}; + +export fn zig_ret_struct_f32f32_f32() Struct_f32f32_f32 { + return .{ .a = .{ .b = 1.0, .c = 2.0 }, .d = 3.0 }; +} +export fn zig_struct_f32f32_f32(s: Struct_f32f32_f32) void { + expect(s.a.b == 1.0) catch @panic("test failure"); + expect(s.a.c == 2.0) catch @panic("test failure"); + expect(s.d == 3.0) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32f32_f32() Struct_f32f32_f32; +extern fn c_struct_f32f32_f32(Struct_f32f32_f32) void; +extern fn c_test_struct_f32f32_f32() void; + +test "struct {f32, f32}, f32" { + 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 == .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; + + const s = c_ret_struct_f32f32_f32(); + try expect(s.a.b == 1.0); + try expect(s.a.c == 2.0); + try expect(s.d == 3.0); + c_struct_f32f32_f32(.{ .a = .{ .b = 1.0, .c = 2.0 }, .d = 3.0 }); + c_test_struct_f32f32_f32(); +} + +const Struct_f32_f32f32 = extern struct { + a: f32, + b: extern struct { c: f32, d: f32 }, +}; + +export fn zig_ret_struct_f32_f32f32() Struct_f32_f32f32 { + return .{ .a = 1.0, .b = .{ .c = 2.0, .d = 3.0 } }; +} +export fn zig_struct_f32_f32f32(s: Struct_f32_f32f32) void { + expect(s.a == 1.0) catch @panic("test failure"); + expect(s.b.c == 2.0) catch @panic("test failure"); + expect(s.b.d == 3.0) catch @panic("test failure"); +} + +extern fn c_ret_struct_f32_f32f32() Struct_f32_f32f32; +extern fn c_struct_f32_f32f32(Struct_f32_f32f32) void; +extern fn c_test_struct_f32_f32f32() void; + +test "struct f32, {f32, f32}" { + 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 == .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; + + const s = c_ret_struct_f32_f32f32(); + try expect(s.a == 1.0); + try expect(s.b.c == 2.0); + try expect(s.b.d == 3.0); + c_struct_f32_f32f32(.{ .a = 1.0, .b = .{ .c = 2.0, .d = 3.0 } }); + c_test_struct_f32_f32f32(); +} + +const Struct_f64 = extern struct { + a: f64, +}; + +export fn zig_ret_struct_f64() Struct_f64 { + return .{ .a = 1 }; +} +export fn zig_struct_f64(s: Struct_f64, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_f64() Struct_f64; +extern fn c_struct_f64(Struct_f64, usize) void; +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.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(); + try expect(s.a == 4); + c_struct_f64(.{ .a = 5 }, 6); + c_test_struct_f64(); +} + +const Struct_f64_f64 = extern struct { + a: f64, + b: f64, +}; + +export fn zig_ret_struct_f64_f64() Struct_f64_f64 { + return .{ .a = 1, .b = 2 }; +} +export fn zig_struct_f64_f64(s: Struct_f64_f64, i: usize) void { + expect(s.a == 3) catch @panic("test failure"); + expect(s.b == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_f64_f64() Struct_f64_f64; +extern fn c_struct_f64_f64(Struct_f64_f64, usize) void; +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.isLoongArch() 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; + + const s = c_ret_struct_f64_f64(); + try expect(s.a == 6); + try expect(s.b == 7); + c_struct_f64_f64(.{ .a = 8, .b = 9 }, 10); + c_test_struct_f64_f64(); +} + +const Struct_f64_f64_f64 = extern struct { + a: f64, + b: f64, + c: f64, +}; + +export fn zig_ret_struct_f64_f64_f64() Struct_f64_f64_f64 { + return .{ .a = 1, .b = 2, .c = 3 }; +} +export fn zig_struct_f64_f64_f64(s: Struct_f64_f64_f64, i: usize) void { + expect(s.a == 4) catch @panic("test failure"); + expect(s.b == 5) catch @panic("test failure"); + expect(s.c == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_f64_f64_f64() Struct_f64_f64_f64; +extern fn c_struct_f64_f64_f64(Struct_f64_f64_f64, usize) void; +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; + + const s = c_ret_struct_f64_f64_f64(); + try expect(s.a == 8); + try expect(s.b == 9); + try expect(s.c == 10); + c_struct_f64_f64_f64(.{ .a = 11, .b = 12, .c = 13 }, 14); + c_test_struct_f64_f64_f64(); +} + +const Struct_f64_f64_f64_f64 = extern struct { + a: f64, + b: f64, + c: f64, + d: f64, +}; + +export fn zig_ret_struct_f64_f64_f64_f64() Struct_f64_f64_f64_f64 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4 }; +} +export fn zig_struct_f64_f64_f64_f64(s: Struct_f64_f64_f64_f64, i: usize) void { + expect(s.a == 5) catch @panic("test failure"); + expect(s.b == 6) catch @panic("test failure"); + expect(s.c == 7) catch @panic("test failure"); + expect(s.d == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_f64_f64_f64_f64() Struct_f64_f64_f64_f64; +extern fn c_struct_f64_f64_f64_f64(Struct_f64_f64_f64_f64, usize) void; +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; + + const s = c_ret_struct_f64_f64_f64_f64(); + try expect(s.a == 10); + try expect(s.b == 11); + try expect(s.c == 12); + try expect(s.d == 13); + c_struct_f64_f64_f64_f64(.{ .a = 14, .b = 15, .c = 16, .d = 17 }, 18); + c_test_struct_f64_f64_f64_f64(); +} + +const Struct_f64_f64_f64_f64_f64 = extern struct { + a: f64, + b: f64, + c: f64, + d: f64, + e: f64, +}; + +export fn zig_ret_struct_f64_f64_f64_f64_f64() Struct_f64_f64_f64_f64_f64 { + return .{ .a = 1, .b = 2, .c = 3, .d = 4, .e = 5 }; +} +export fn zig_struct_f64_f64_f64_f64_f64(s: Struct_f64_f64_f64_f64_f64, i: usize) void { + expect(s.a == 6) catch @panic("test failure"); + expect(s.b == 7) catch @panic("test failure"); + expect(s.c == 8) catch @panic("test failure"); + expect(s.d == 9) catch @panic("test failure"); + expect(s.e == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_f64_f64_f64_f64_f64() Struct_f64_f64_f64_f64_f64; +extern fn c_struct_f64_f64_f64_f64_f64(Struct_f64_f64_f64_f64_f64, usize) void; +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; + + const s = c_ret_struct_f64_f64_f64_f64_f64(); + try expect(s.a == 12); + try expect(s.b == 13); + try expect(s.c == 14); + try expect(s.d == 15); + try expect(s.e == 16); + c_struct_f64_f64_f64_f64_f64(.{ .a = 17, .b = 18, .c = 19, .d = 20, .e = 21 }, 22); + c_test_struct_f64_f64_f64_f64_f64(); +} + +const Struct_u32_Union_u32_u32u32 = extern struct { + a: u32, + b: extern union { + c: extern struct { + d: u32, + e: u32, + }, + }, +}; + +export fn zig_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32 { + return .{ .a = 1, .b = .{ .c = .{ .d = 2, .e = 3 } } }; +} +export fn zig_struct_u32_union_u32_u32u32(s: Struct_u32_Union_u32_u32u32) void { + expect(s.a == 1) catch @panic("test failure"); + expect(s.b.c.d == 2) catch @panic("test failure"); + expect(s.b.c.e == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_u32_union_u32_u32u32() Struct_u32_Union_u32_u32u32; +extern fn c_struct_u32_union_u32_u32u32(Struct_u32_Union_u32_u32u32) void; +extern fn c_test_struct_u32_union_u32_u32u32() void; + +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; + + const s = c_ret_struct_u32_union_u32_u32u32(); + try expect(s.a == 1); + try expect(s.b.c.d == 2); + try expect(s.b.c.e == 3); + c_struct_u32_union_u32_u32u32(.{ .a = 1, .b = .{ .c = .{ .d = 2, .e = 3 } } }); + c_test_struct_u32_union_u32_u32u32(); +} + +const Struct_i32_i32 = extern struct { + a: i32, + b: i32, +}; +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.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) 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; - c_ptr_size_float_struct(.{ .x = 1, .y = 2 }); + const s: Struct_i32_i32 = .{ + .a = 1, + .b = 2, + }; + const mut_res = c_mut_struct_i32_i32(s); + try expect(s.a == 1); + try expect(s.b == 2); + try expect(mut_res.a == 101); + try expect(mut_res.b == 252); + c_struct_i32_i32(s); +} + +export fn zig_struct_i32_i32(s: Struct_i32_i32) void { + expect(s.a == 1) catch @panic("test failure: zig_struct_i32_i32 1"); + expect(s.b == 2) catch @panic("test failure: zig_struct_i32_i32 2"); +} + +const BigStruct = extern struct { + a: u64, + b: u64, + c: u64, + d: u64, + e: u8, +}; +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; + + const s = BigStruct{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + .e = 5, + }; + c_big_struct(s); +} + +export fn zig_big_struct(x: BigStruct) void { + expect(x.a == 1) catch @panic("test failure: zig_big_struct 1"); + expect(x.b == 2) catch @panic("test failure: zig_big_struct 2"); + expect(x.c == 3) catch @panic("test failure: zig_big_struct 3"); + expect(x.d == 4) catch @panic("test failure: zig_big_struct 4"); + expect(x.e == 5) catch @panic("test failure: zig_big_struct 5"); +} + +const BigUnion = extern union { + a: BigStruct, +}; +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; + + const x = BigUnion{ + .a = BigStruct{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + .e = 5, + }, + }; + c_big_union(x); +} + +export fn zig_big_union(x: BigUnion) void { + expect(x.a.a == 1) catch @panic("test failure: zig_big_union a"); + expect(x.a.b == 2) catch @panic("test failure: zig_big_union b"); + expect(x.a.c == 3) catch @panic("test failure: zig_big_union c"); + expect(x.a.d == 4) catch @panic("test failure: zig_big_union d"); + expect(x.a.e == 5) catch @panic("test failure: zig_big_union e"); +} + +const MedStructMixed = extern struct { + a: u32, + b: f32, + c: f32, + d: u32 = 0, +}; +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; + + const s = MedStructMixed{ + .a = 1234, + .b = 100.0, + .c = 1337.0, + }; + c_med_struct_mixed(s); + const s2 = c_ret_med_struct_mixed(); + try expect(s2.a == 1234); + try expect(s2.b == 100.0); + try expect(s2.c == 1337.0); +} + +export fn zig_med_struct_mixed(x: MedStructMixed) void { + expect(x.a == 1234) catch @panic("test failure"); + expect(x.b == 100.0) catch @panic("test failure"); + expect(x.c == 1337.0) catch @panic("test failure"); +} + +const SmallPackedStruct = packed struct(u8) { + a: u2, + b: u2, + c: u2, + d: u2, +}; +extern fn c_small_packed_struct(SmallPackedStruct) void; +extern fn c_ret_small_packed_struct() SmallPackedStruct; + +export fn zig_small_packed_struct(x: SmallPackedStruct) void { + expect(x.a == 0) catch @panic("test failure"); + expect(x.b == 1) catch @panic("test failure"); + expect(x.c == 2) catch @panic("test failure"); + expect(x.d == 3) catch @panic("test failure"); +} + +test "small packed struct" { + const s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3 }; + c_small_packed_struct(s); + const s2 = c_ret_small_packed_struct(); + try expect(s2.a == 0); + try expect(s2.b == 1); + try expect(s2.c == 2); + try expect(s2.d == 3); +} + +const BigPackedStruct = packed struct(u128) { + a: u64, + b: u64, +}; +extern fn c_big_packed_struct(BigPackedStruct) void; +extern fn c_ret_big_packed_struct() BigPackedStruct; + +export fn zig_big_packed_struct(x: BigPackedStruct) void { + expect(x.a == 1) catch @panic("test failure"); + expect(x.b == 2) catch @panic("test failure"); +} + +test "big packed struct" { + if (!have_i128) return error.SkipZigTest; + + const s = BigPackedStruct{ .a = 1, .b = 2 }; + c_big_packed_struct(s); + const s2 = c_ret_big_packed_struct(); + try expect(s2.a == 1); + try expect(s2.b == 2); +} + +const SplitStructInt = extern struct { + a: u64, + b: u8, + c: u32, +}; +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; + + const s = SplitStructInt{ + .a = 1234, + .b = 100, + .c = 1337, + }; + c_split_struct_ints(s); +} + +export fn zig_split_struct_ints(x: SplitStructInt) void { + expect(x.a == 1234) catch @panic("test failure"); + expect(x.b == 100) catch @panic("test failure"); + expect(x.c == 1337) catch @panic("test failure"); +} + +const SplitStructMixed = extern struct { + a: u64, + b: u8, + c: f32, +}; +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; + + const s = SplitStructMixed{ + .a = 1234, + .b = 100, + .c = 1337.0, + }; + c_split_struct_mixed(s); + const s2 = c_ret_split_struct_mixed(); + try expect(s2.a == 1234); + try expect(s2.b == 100); + try expect(s2.c == 1337.0); +} + +export fn zig_split_struct_mixed(x: SplitStructMixed) void { + expect(x.a == 1234) catch @panic("test failure"); + expect(x.b == 100) catch @panic("test failure"); + expect(x.c == 1337.0) catch @panic("test failure"); +} + +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; + + const s = BigStruct{ + .a = 1, + .b = 2, + .c = 3, + .d = 4, + .e = 5, + }; + const y = c_big_struct_both(s); + try expect(y.a == 10); + try expect(y.b == 11); + try expect(y.c == 12); + try expect(y.d == 13); + try expect(y.e == 14); +} + +export fn zig_big_struct_both(x: BigStruct) BigStruct { + expect(x.a == 30) catch @panic("test failure"); + expect(x.b == 31) catch @panic("test failure"); + expect(x.c == 32) catch @panic("test failure"); + expect(x.d == 33) catch @panic("test failure"); + expect(x.e == 34) catch @panic("test failure"); + const s = BigStruct{ + .a = 20, + .b = 21, + .c = 22, + .d = 23, + .e = 24, + }; + return s; +} + +export fn zig_ret_bool() bool { + return true; +} +export fn zig_ret_u8() u8 { + return 0xff; +} +export fn zig_ret_u16() u16 { + return 0xffff; +} +export fn zig_ret_u32() u32 { + return 0xffffffff; +} +export fn zig_ret_u64() u64 { + return 0xffffffffffffffff; +} +export fn zig_ret_i8() i8 { + return -1; +} +export fn zig_ret_i16() i16 { + return -1; +} +export fn zig_ret_i32() i32 { + return -1; +} +export fn zig_ret_i64() i64 { + return -1; +} + +export fn zig_ret_med_struct_mixed() MedStructMixed { + return .{ + .a = 1234, + .b = 100.0, + .c = 1337.0, + }; +} + +export fn zig_ret_split_struct_mixed() SplitStructMixed { + return .{ + .a = 1234, + .b = 100, + .c = 1337.0, + }; +} + +extern fn c_ret_bool() bool; +extern fn c_ret_u8() u8; +extern fn c_ret_u16() u16; +extern fn c_ret_u32() u32; +extern fn c_ret_u64() u64; +extern fn c_ret_i8() i8; +extern fn c_ret_i16() i16; +extern fn c_ret_i32() i32; +extern fn c_ret_i64() i64; + +test "integer return types" { + try expect(c_ret_bool() == true); + + try expect(c_ret_u8() == 0xff); + try expect(c_ret_u16() == 0xffff); + try expect(c_ret_u32() == 0xffffffff); + try expect(c_ret_u64() == 0xffffffffffffffff); + + try expect(c_ret_i8() == -1); + try expect(c_ret_i16() == -1); + try expect(c_ret_i32() == -1); + try expect(c_ret_i64() == -1); +} + +const StructWithArray = extern struct { + a: i32, + padding: [4]u8, + b: i64, +}; +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; + + c_struct_with_array(.{ .a = 1, .padding = undefined, .b = 2 }); + + const x = c_ret_struct_with_array(); + try expect(x.a == 4); + try expect(x.b == 155); +} + +const FloatArrayStruct = extern struct { + origin: extern struct { + x: f64, + y: f64, + }, + size: extern struct { + width: f64, + height: f64, + }, +}; + +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; + + c_float_array_struct(.{ + .origin = .{ + .x = 5, + .y = 6, + }, + .size = .{ + .width = 7, + .height = 8, + }, + }); - const x = c_ret_ptr_size_float_struct(); - try expect(x.x == 3); - try expect(x.y == 4); + const x = c_ret_float_array_struct(); + try expect(x.origin.x == 1); + try expect(x.origin.y == 2); + try expect(x.size.width == 3); + try expect(x.size.height == 4); } //=== Helpers for struct test ===// @@ -6135,7 +17111,8 @@ const byval_tail_callsite_attr = struct { } fn cast(self: MyRect) struct_Rect { - return @bitCast(self); + const ptr: *const struct_Rect = @ptrCast(&self); + return ptr.*; } extern fn c_byval_tail_callsite_attr(struct_Rect) f64; @@ -6161,22 +17138,118 @@ test "byval tail callsite attribute" { } test "x86 fastcall calling convention" { - if (builtin.cpu.arch != .x86) return error.SkipZigTest; + if (builtin.cpu.arch != .x86 or builtin.os.tag != .windows or builtin.abi != .msvc) return error.SkipZigTest; + const static = struct { - extern fn c_fastcall_check(a: c_int, b: f32, c: *anyopaque, d: f64, e: c_int) callconv(.{ .x86_fastcall = .{} }) void; - export fn zig_fastcall_check(a: c_int, b: f32, c: *anyopaque, d: f64, e: c_int) callconv(.{ .x86_fastcall = .{} }) void { + const fastcall: std.builtin.CallingConvention = .{ .x86_fastcall = .{} }; + + extern fn c_fastcall_check(a: c_int, b: f32, c: *anyopaque, d: f64, e: c_int) callconv(fastcall) void; + export fn zig_fastcall_check(a: c_int, b: f32, c: *anyopaque, d: f64, e: c_int) callconv(fastcall) void { if (a != 1) @panic("test failure"); if (b != 2.0) @panic("test failure"); if (@intFromPtr(c) != 3) @panic("test failure"); if (d != 4.0) @panic("test failure"); if (e != 5) @panic("test failure"); } + + const SRet = extern struct { + a: i32, + b: i32, + c: i32, + }; + extern fn c_fastcall_sret() callconv(fastcall) SRet; + export fn zig_fastcall_sret() callconv(fastcall) SRet { + return .{ + .a = 1, + .b = 2, + .c = 3, + }; + } + + const NoSRet = extern struct { + a: i8, + b: i16, + }; + extern fn c_fastcall_no_sret() callconv(fastcall) NoSRet; + export fn zig_fastcall_no_sret() callconv(fastcall) NoSRet { + return .{ + .a = 1, + .b = 2, + }; + } + + const NoSRetF32F32 = extern struct { + a: f32, + b: f32, + }; + extern fn c_fastcall_no_sret_f32_f32() callconv(fastcall) NoSRetF32F32; + export fn zig_fastcall_no_sret_f32_f32() callconv(fastcall) NoSRetF32F32 { + return .{ + .a = 1, + .b = 2, + }; + } + + const NoSRetF64 = extern struct { + a: f64, + }; + extern fn c_fastcall_no_sret_f64() callconv(fastcall) NoSRetF64; + export fn zig_fastcall_no_sret_f64() callconv(fastcall) NoSRetF64 { + return .{ + .a = 1, + }; + } + + extern fn c_fastcall_ret_f32() callconv(fastcall) f32; + export fn zig_fastcall_ret_f32() callconv(fastcall) f32 { + return 1; + } + + extern fn c_fastcall_ret_f64() callconv(fastcall) f64; + export fn zig_fastcall_ret_f64() callconv(fastcall) f64 { + return 1; + } + + extern fn run_c_fastcall_tests() void; }; + static.c_fastcall_check(1, 2.0, @ptrFromInt(3), 4.0, 5); + + { + const s = static.c_fastcall_sret(); + try expect(s.a == 1); + try expect(s.b == 2); + try expect(s.c == 3); + } + { + const s = static.c_fastcall_no_sret(); + try expect(s.a == 1); + try expect(s.b == 2); + } + { + const s = static.c_fastcall_no_sret_f32_f32(); + try expect(s.a == 1); + try expect(s.b == 2); + } + { + const s = static.c_fastcall_no_sret_f64(); + try expect(s.a == 1); + } + { + const s = static.c_fastcall_ret_f32(); + try expect(s == 1); + } + { + const s = static.c_fastcall_ret_f64(); + try expect(s == 1); + } + + static.run_c_fastcall_tests(); } test "x86 vectorcall calling convention" { - if (builtin.cpu.arch != .x86) return error.SkipZigTest; + if (builtin.cpu.arch != .x86 or builtin.os.tag != .windows or builtin.abi != .msvc) return error.SkipZigTest; + const static = struct { extern fn c_vectorcall_check(a: c_int, b: f32, c: f64, d: *anyopaque, e: f32, f: f64, g: f64, h: f32, i: f32, j: c_int) callconv(.{ .x86_vectorcall = .{} }) void; export fn zig_vectorcall_check(a: c_int, b: f32, c: f64, d: *anyopaque, e: f32, f: f64, g: f64, h: f32, i: f32, j: c_int) callconv(.{ .x86_vectorcall = .{} }) void { @@ -6194,3 +17267,34 @@ 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_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; + + const Opv = extern struct {}; + c_win64_varargs_u64_f64_u64_f64( + @as(Opv, .{}), + @as(f32, 1), + @as(Opv, .{}), + @as(f32, 2.0), + @as(Opv, .{}), + @as(f64, 3), + @as(Opv, .{}), + @as(f64, 4.0), + @as(Opv, .{}), + ); + c_win64_varargs_f64_u64_f64_u64( + @as(Opv, .{}), + @as(f32, 5), + @as(Opv, .{}), + @as(f32, 6.0), + @as(Opv, .{}), + @as(f64, 7), + @as(Opv, .{}), + @as(f64, 8.0), + @as(Opv, .{}), + ); +} diff --git a/test/cases/callconv_spirv.zig b/test/cases/callconv_spirv.zig new file mode 100644 index 0000000000000000000000000000000000000000..25be9d0c27a7493811da50525ce5de0bf696c001 --- /dev/null +++ b/test/cases/callconv_spirv.zig @@ -0,0 +1,12 @@ +export fn vert() callconv(.spirv_vertex) void {} +export fn frag() callconv(.{ .spirv_fragment = .{ .depth_assumption = .greater } }) void {} +export fn comp() callconv(.{ .spirv_kernel = .{ .x = 8, .y = 8, .z = 1 } }) void {} +export fn task() callconv(.{ .spirv_task = .{ .x = 1, .y = 1, .z = 1 } }) void {} +export fn mesh() callconv(.{ .spirv_mesh = .{ .stage_output = .output_lines, .max_primitives = 1, .max_vertices = 2 } }) void {} + +// compile +// output_mode=Obj +// backend=selfhosted +// target=spirv32-vulkan +// cpu_features=vulkan_v1_2+mesh_shading_ext +// emit_bin=true diff --git a/test/cases/compile_errors/@breakpoint_comptime_call.zig b/test/cases/compile_errors/@breakpoint_comptime_call.zig new file mode 100644 index 0000000000000000000000000000000000000000..7183e83dc9a2bb414ef1ddd751f090cd20ada798 --- /dev/null +++ b/test/cases/compile_errors/@breakpoint_comptime_call.zig @@ -0,0 +1,7 @@ +export fn entry() void { + comptime @breakpoint(); +} + +// error +// +// :2:14: error: encountered @breakpoint at comptime diff --git a/test/cases/compile_errors/SpirvType_is_a_compile_error_in_non-SPIRV_targets.zig b/test/cases/compile_errors/SpirvType_is_a_compile_error_in_non-SPIRV_targets.zig new file mode 100644 index 0000000000000000000000000000000000000000..431c9c1b61297e517a4e414ac40a5963c0204e78 --- /dev/null +++ b/test/cases/compile_errors/SpirvType_is_a_compile_error_in_non-SPIRV_targets.zig @@ -0,0 +1,9 @@ +comptime { + _ = @SpirvType(.{ .runtime_array = u32 }); +} + +// error +// backend=selfhosted +// target=x86_64-native +// +// :2:9: error: builtin @SpirvType is only available when targeting SPIR-V; targeted CPU architecture is x86_64 diff --git a/test/cases/compile_errors/SpirvType_vulkan_target.zig b/test/cases/compile_errors/SpirvType_vulkan_target.zig new file mode 100644 index 0000000000000000000000000000000000000000..fdb53678e3139870df23563a9b2ac5494e524cea --- /dev/null +++ b/test/cases/compile_errors/SpirvType_vulkan_target.zig @@ -0,0 +1,56 @@ +comptime { + _ = @SpirvType(.{ .image = .{ + .usage = .{ .storage = u32 }, + .format = .unknown, + .dim = .@"2d", + .depth = .unknown, + .arrayed = false, + .multisampled = false, + .access = .read_only, + } }); +} + +comptime { + _ = @SpirvType(.{ .image = .{ + .usage = .{ .sampled = bool }, + .format = .unknown, + .dim = .@"2d", + .depth = .unknown, + .arrayed = false, + .multisampled = false, + .access = .unknown, + } }); +} + +comptime { + _ = @SpirvType(.{ .image = .{ + .usage = .{ .sampled = void }, + .format = .unknown, + .dim = .@"2d", + .depth = .unknown, + .arrayed = false, + .multisampled = false, + .access = .unknown, + } }); +} + +comptime { + _ = @SpirvType(.{ .image = .{ + .usage = .{ .sampled = u24 }, + .format = .unknown, + .dim = .@"2d", + .depth = .unknown, + .arrayed = false, + .multisampled = false, + .access = .unknown, + } }); +} + +// error +// backend=selfhosted +// target=spirv32-vulkan +// +// :2:21: error: access qualifier '.read_only' is only valid under the 'opencl' os +// :14:21: error: invalid 'sampled' field value 'bool' +// :26:21: error: 'void' type for 'sampled' field is only valid under the 'opencl' os +// :38:21: error: 'sampled' field value must be a 32-bit int, 64-bit int or 32-bit float under the 'vulkan' os diff --git a/test/cases/compile_errors/asm_output_type_no_guaranteed_in_memory_layout.zig b/test/cases/compile_errors/asm_output_type_no_guaranteed_in_memory_layout.zig index 85be7d3c27ba384a96eb7575bdb579e4a3e3bdff..ddb26058d0e73198537b27708602822eb8678555 100644 --- a/test/cases/compile_errors/asm_output_type_no_guaranteed_in_memory_layout.zig +++ b/test/cases/compile_errors/asm_output_type_no_guaranteed_in_memory_layout.zig @@ -25,14 +25,38 @@ export fn entry4() void { : [_] "=r" (u), ); } +const ES = extern struct { x: u32 }; +export fn entry5() void { + var es: ES = undefined; + asm volatile ("" + : [_] "=r" (es), + ); +} +const EU = extern union { x: u32 }; +export fn entry6() void { + var eu: EU = undefined; + asm volatile ("" + : [_] "=r" (eu), + ); +} // error // -// :4:24: error: invalid inline assembly output type; 'tmp.S' does not have a guaranteed in-memory layout +// :4:24: error: invalid inline assembly output type 'tmp.S' +// :4:24: note: struct types cannot be passed to inline assembly // :1:11: note: struct declared here -// :11:21: error: invalid inline assembly output type; 'tmp.S' does not have a guaranteed in-memory layout +// :11:21: error: invalid inline assembly output type 'tmp.S' +// :11:21: note: struct types cannot be passed to inline assembly // :1:11: note: struct declared here -// :18:24: error: invalid inline assembly output type; 'tmp.U' does not have a guaranteed in-memory layout +// :18:24: error: invalid inline assembly output type 'tmp.U' +// :18:24: note: union types cannot be passed to inline assembly // :15:11: note: union declared here -// :25:21: error: invalid inline assembly output type; 'tmp.U' does not have a guaranteed in-memory layout +// :25:21: error: invalid inline assembly output type 'tmp.U' +// :25:21: note: union types cannot be passed to inline assembly // :15:11: note: union declared here +// :32:21: error: invalid inline assembly output type 'tmp.ES' +// :32:21: note: struct types cannot be passed to inline assembly +// :28:19: note: struct declared here +// :39:21: error: invalid inline assembly output type 'tmp.EU' +// :39:21: note: union types cannot be passed to inline assembly +// :35:19: note: union declared here diff --git a/test/cases/compile_errors/bitCast_extern_struct.zig b/test/cases/compile_errors/bitCast_extern_struct.zig new file mode 100644 index 0000000000000000000000000000000000000000..2c0c9b3cd0fd63ae90fb27bbcd04d7def708373e --- /dev/null +++ b/test/cases/compile_errors/bitCast_extern_struct.zig @@ -0,0 +1,10 @@ +const S = extern struct { x: u32 }; +export fn foo(s: S) void { + const as_int: u32 = @bitCast(s); + _ = as_int; +} + +// error +// +// :3:34: error: cannot @bitCast from 'tmp.S' +// :1:18: note: struct declared here diff --git a/test/cases/compile_errors/bitCast_to_enum_type.zig b/test/cases/compile_errors/bitCast_to_enum_type.zig deleted file mode 100644 index 3ae88d65f95cbd7dc080d56a9fa45c47fb056bc5..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/bitCast_to_enum_type.zig +++ /dev/null @@ -1,10 +0,0 @@ -export fn entry() void { - const E = enum(u32) { a, b }; - const y: E = @bitCast(@as(u32, 3)); - _ = y; -} - -// error -// -// :3:18: error: cannot @bitCast to 'tmp.entry.E' -// :3:18: note: use @enumFromInt to cast from 'u32' diff --git a/test/cases/compile_errors/bitCast_vector_of_pointer.zig b/test/cases/compile_errors/bitCast_vector_of_pointer.zig new file mode 100644 index 0000000000000000000000000000000000000000..d9b5a3f1b3b2f5360215f085c1c48e3aece1d5d4 --- /dev/null +++ b/test/cases/compile_errors/bitCast_vector_of_pointer.zig @@ -0,0 +1,9 @@ +export fn foo(p: *u32) void { + const vec: @Vector(2, *u32) = .{ p, p }; + const raw: [2]usize = @bitCast(vec); + _ = raw; +} + +// error +// +// :3:36: error: cannot @bitCast from '@Vector(2, *u32)' diff --git a/test/cases/compile_errors/bitCast_with_invalid_array_element_type.zig b/test/cases/compile_errors/bitCast_with_invalid_array_element_type.zig index bf1bacda487048439166e853a8d5720c1c4f9bc3..bc04258d26921f4543a7b3b962ee57cab82c9aaa 100644 --- a/test/cases/compile_errors/bitCast_with_invalid_array_element_type.zig +++ b/test/cases/compile_errors/bitCast_with_invalid_array_element_type.zig @@ -18,9 +18,6 @@ export fn baz() void { // error // -// :5:29: error: cannot @bitCast from '[1]tmp.foo.S' -// :5:29: note: array element type 'tmp.foo.S' does not have a guaranteed in-memory layout +// :5:42: error: cannot @bitCast from '[1]tmp.foo.S' // :12:19: error: cannot @bitCast to '[1]tmp.bar.S' -// :12:19: note: array element type 'tmp.bar.S' does not have a guaranteed in-memory layout -// :16:21: error: cannot @bitCast from '[1]comptime_int' -// :16:21: note: array element type 'comptime_int' does not have a guaranteed in-memory layout +// :16:45: error: cannot @bitCast from '[1]comptime_int' diff --git a/test/cases/compile_errors/callconv_spirv_invalid_options.zig b/test/cases/compile_errors/callconv_spirv_invalid_options.zig new file mode 100644 index 0000000000000000000000000000000000000000..a04646f3c20ccc9387d8aea1c70fd5dbdac951d2 --- /dev/null +++ b/test/cases/compile_errors/callconv_spirv_invalid_options.zig @@ -0,0 +1,29 @@ +const F1 = fn () callconv(.{ .spirv_kernel = .{ .x = 0, .y = 1, .z = 1 } }) void; +const F2 = fn () callconv(.{ .spirv_task = .{ .x = 1, .y = 0, .z = 1 } }) void; +const F3 = fn () callconv(.{ .spirv_mesh = .{ .max_vertices = 0 } }) void; +const F4 = fn () callconv(.{ .spirv_fragment = .{ .pixel_centered_integer = true } }) void; +export fn entry1() void { + const a: F1 = undefined; + _ = a; +} +export fn entry2() void { + const a: F2 = undefined; + _ = a; +} +export fn entry3() void { + const a: F3 = undefined; + _ = a; +} +export fn entry4() void { + const a: F4 = undefined; + _ = a; +} + +// error +// backend=selfhosted +// target=spirv32-vulkan +// +// :1:28: error: kernel workgroup dimensions must be at least 1 +// :2:28: error: kernel workgroup dimensions must be at least 1 +// :3:28: error: mesh shader 'max_vertices' and 'max_primitives' must be at least 1 +// :4:28: error: 'pixel_centered_integer' is not supported on this target diff --git a/test/cases/compile_errors/callconv_spirv_on_unsupported_platform.zig b/test/cases/compile_errors/callconv_spirv_on_unsupported_platform.zig new file mode 100644 index 0000000000000000000000000000000000000000..1c41095021ad498dce4178d67556f1eb7b45e8d4 --- /dev/null +++ b/test/cases/compile_errors/callconv_spirv_on_unsupported_platform.zig @@ -0,0 +1,30 @@ +const F1 = fn () callconv(.{ .spirv_fragment = .{} }) void; +const F2 = fn () callconv(.spirv_vertex) void; +const F3 = fn () callconv(.{ .spirv_task = .{ .x = 1, .y = 1, .z = 1 } }) void; +const F4 = fn () callconv(.{ .spirv_mesh = .{} }) void; +export fn entry1() void { + const a: F1 = undefined; + _ = a; +} +export fn entry2() void { + const a: F2 = undefined; + _ = a; +} +export fn entry3() void { + const a: F3 = undefined; + _ = a; +} +export fn entry4() void { + const a: F4 = undefined; + _ = a; +} + +// error +// backend=selfhosted +// target=spirv64-opencl +// cpu_features=opencl_v2+mesh_shading_ext +// +// :1:28: error: calling convention 'spirv_fragment' not supported by compiler backend 'stage2_spirv' +// :2:28: error: calling convention 'spirv_vertex' not supported by compiler backend 'stage2_spirv' +// :3:28: error: calling convention 'spirv_task' not supported by compiler backend 'stage2_spirv' +// :4:28: error: calling convention 'spirv_mesh' not supported by compiler backend 'stage2_spirv' diff --git a/test/cases/compile_errors/callconv_stack_alignment_coerce.zig b/test/cases/compile_errors/callconv_stack_alignment_coerce.zig new file mode 100644 index 0000000000000000000000000000000000000000..0f09ba230038853d395a5d44dc3699df96960628 --- /dev/null +++ b/test/cases/compile_errors/callconv_stack_alignment_coerce.zig @@ -0,0 +1,10 @@ +fn foo() callconv(.{ .x86_64_sysv = .{ .incoming_stack_alignment = 32 } }) void {} +const Bar = *const fn () callconv(.{ .x86_64_sysv = .{ .incoming_stack_alignment = 16 } }) void; +export var p: Bar = &foo; + +// error +// target=x86_64-linux-none +// +// :3:21: error: expected type '*const fn () callconv(.{ .x86_64_sysv = .{ .incoming_stack_alignment = 16 } }) void', found '*const fn () callconv(.{ .x86_64_sysv = .{ .incoming_stack_alignment = 32 } }) void' +// :3:21: note: pointer type child 'fn () callconv(.{ .x86_64_sysv = .{ .incoming_stack_alignment = 32 } }) void' cannot cast into pointer type child 'fn () callconv(.{ .x86_64_sysv = .{ .incoming_stack_alignment = 16 } }) void' +// :3:21: note: calling convention 'x86_64_sysv' cannot cast into calling convention 'x86_64_sysv' diff --git a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig index 603ce497326d547334cf5a99af0ff4fbb1e2c04d..897c298e6181ff75fd866370674e0ea769f7ae2c 100644 --- a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig +++ b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig @@ -71,6 +71,12 @@ export fn bax() void { @memmove(&rt, &x); } +export fn qoo(i: u8) void { + comptime var x: u32 = 123; + const y = .{ .p = &x, .i = i }; + _ = y; +} + // error // // :5:19: error: runtime value contains reference to comptime var @@ -103,3 +109,6 @@ export fn bax() void { // :71:19: error: runtime value contains reference to comptime var // :71:19: note: comptime var pointers are not available at runtime // :67:14: note: 'runtime_value' points to comptime var declared here +// :76:19: error: runtime value contains reference to comptime var +// :76:19: note: comptime var pointers are not available at runtime +// :75:14: note: 'runtime_value' points to comptime var declared here diff --git a/test/cases/compile_errors/deref_ptr_to_comptime_only_type.zig b/test/cases/compile_errors/deref_ptr_to_comptime_only_type.zig new file mode 100644 index 0000000000000000000000000000000000000000..cc453d616fbe4dd836a069a034e61498f1b33dce --- /dev/null +++ b/test/cases/compile_errors/deref_ptr_to_comptime_only_type.zig @@ -0,0 +1,9 @@ +export fn entry(ptr: *anyopaque) void { + const ct_only: *type = @ptrCast(ptr); + _ = ct_only.*; +} + +// error +// +// :3:16: error: cannot load comptime-only type 'type' +// :3:9: note: pointer of type '*type' is runtime-known diff --git a/test/cases/compile_errors/directly_embedding_spirv_type_in_struct_and_union.zig b/test/cases/compile_errors/directly_embedding_spirv_type_in_struct_and_union.zig new file mode 100644 index 0000000000000000000000000000000000000000..732db0b4408883a1e0aaacf019bb6c459d62205f --- /dev/null +++ b/test/cases/compile_errors/directly_embedding_spirv_type_in_struct_and_union.zig @@ -0,0 +1,35 @@ +const Sampler = @SpirvType(.sampler); +const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); +const Foo = struct { + s: Sampler, +}; +const Baz = struct { + a: RuntimeArray, +}; +const Qux = extern struct { + a: RuntimeArray, + b: u32, +}; +export fn a() void { + var foo: Foo = undefined; + _ = &foo; +} +export fn c() void { + var baz: Baz = undefined; + _ = &baz; +} +export fn d() void { + var qux: Qux = undefined; + _ = &qux; +} + +// error +// backend=selfhosted +// target=spirv32-vulkan +// +// :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct +// :4:8: note: opaque types have unknown size +// :6:13: error: non-extern struct cannot contain fields of type 'tmp.RuntimeArray__SpirvType_11' +// :7:5: note: while checking this field +// :9:20: error: struct field of type 'tmp.RuntimeArray__SpirvType_11' must be the last field +// :10:5: note: while checking this field diff --git a/test/cases/compile_errors/error_in_nested_declaration.zig b/test/cases/compile_errors/error_in_nested_declaration.zig new file mode 100644 index 0000000000000000000000000000000000000000..d1eb73a0cc878a11ee29c48fdffa6d9fd991ca17 --- /dev/null +++ b/test/cases/compile_errors/error_in_nested_declaration.zig @@ -0,0 +1,29 @@ +const S = struct { + b: u32, + c: i32, + a: struct { + pub fn str(_: @This(), extra: []u32) []i32 { + return @bitCast(extra); + } + }, +}; + +pub export fn entry() void { + var s: S = undefined; + _ = s.a.str(undefined); +} + +const S2 = struct { + a: [*c]anyopaque, +}; + +pub export fn entry2() void { + var s: S2 = undefined; + _ = &s; +} + +// error +// +// :6:20: error: cannot @bitCast to '[]i32' +// :6:20: note: use @ptrCast to cast from '[]u32' +// :17:12: error: indexable pointer to opaque type 'anyopaque' not allowed diff --git a/test/cases/compile_errors/extern_spirv_decoration_validation.zig b/test/cases/compile_errors/extern_spirv_decoration_validation.zig new file mode 100644 index 0000000000000000000000000000000000000000..ea51feb3b931f5d6a93d8640a9a8819251bb3cfc --- /dev/null +++ b/test/cases/compile_errors/extern_spirv_decoration_validation.zig @@ -0,0 +1,13 @@ +const x = @extern(*addrspace(.output) u32, .{ + .name = "x", + .decoration = .{ .flat = 0 }, +}); +comptime { + _ = x; +} + +// error +// backend=selfhosted +// target=spirv32-vulkan +// +// :1:45: error: 'flat' decoration requires 'input' address space diff --git a/test/cases/compile_errors/illegal_operation_on_logical_ptr.zig b/test/cases/compile_errors/illegal_operation_on_logical_ptr.zig index 85decd8a6c29fb74f56ffefcc5bb99d3fd5e2339..859f0be6d37f1961be9f2bc295daeb330858b3cd 100644 --- a/test/cases/compile_errors/illegal_operation_on_logical_ptr.zig +++ b/test/cases/compile_errors/illegal_operation_on_logical_ptr.zig @@ -1,15 +1,3 @@ -export fn elemPtr() void { - var ptr: [*]u8 = undefined; - ptr[0] = 0; -} - -export fn elemVal() void { - var ptr: [*]u8 = undefined; - var val = ptr[0]; - _ = &ptr; - _ = &val; -} - export fn intFromPtr() void { var value: u8 = 0; _ = @intFromPtr(&value); @@ -37,15 +25,11 @@ export fn ptrIntArithmetic() void { // error // target=spirv64-vulkan // -// :3:8: error: illegal operation on logical pointer of type '[*]u8' -// :3:8: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan -// :8:18: error: illegal operation on logical pointer of type '[*]u8' -// :8:18: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan -// :15:21: error: illegal operation on logical pointer of type '*u8' -// :15:21: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan -// :20:20: error: illegal operation on logical pointer of type '*u8' -// :20:20: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan -// :28:17: error: illegal operation on logical pointer of type '*u8' -// :28:17: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan -// :34:14: error: illegal operation on logical pointer of type '[*]u8' -// :34:14: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan +// :3:21: error: illegal operation on logical pointer of type '*u8' +// :3:21: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan +// :8:20: error: illegal operation on logical pointer of type '*u8' +// :8:20: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan +// :16:17: error: illegal operation on logical pointer of type '*u8' +// :16:17: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan +// :22:14: error: illegal operation on logical pointer of type '[*]u8' +// :22:14: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan diff --git a/test/cases/compile_errors/indexing_non-tuple_struct.zig b/test/cases/compile_errors/indexing_non-tuple_struct.zig index b46852c2660836bf2ac6ff063cf9c36d2bb5626c..d3d792f47f609a1c074a5ff6e3b8cb2355c17f85 100644 --- a/test/cases/compile_errors/indexing_non-tuple_struct.zig +++ b/test/cases/compile_errors/indexing_non-tuple_struct.zig @@ -8,3 +8,4 @@ export fn a() void { // // :4:6: error: type 'tmp.a.S' does not support indexing // :4:6: note: operand must be an array, slice, tuple, or vector +// :2:15: note: struct declared here diff --git a/test/cases/compile_errors/inline_return.zig b/test/cases/compile_errors/inline_return.zig new file mode 100644 index 0000000000000000000000000000000000000000..e761e78e211d1d26a3040cd8afe30eb549caeb8e --- /dev/null +++ b/test/cases/compile_errors/inline_return.zig @@ -0,0 +1,16 @@ +inline fn select(cond: bool, a: anytype, b: anytype) @TypeOf(a, b) { + if (cond) { + return a; + } else { + return b; + } +} +export fn f(x: u32) u32 { + return select(x > 0, 2, 1); +} + +// error +// +// :9:18: error: value with comptime-only type 'comptime_int' depends on runtime control flow +// :2:9: note: runtime control flow here +// :9:18: note: called inline here diff --git a/test/cases/compile_errors/primitive_integer_type_with_leading_zero.zig b/test/cases/compile_errors/primitive_integer_type_with_leading_zero.zig new file mode 100644 index 0000000000000000000000000000000000000000..8492f3444b316338d2d1ad31472e92a589b673d7 --- /dev/null +++ b/test/cases/compile_errors/primitive_integer_type_with_leading_zero.zig @@ -0,0 +1,7 @@ +export fn entry1() void { + _ = u032; +} + +// error +// +// :2:9: error: primitive integer type 'u032' has leading zero diff --git a/test/cases/compile_errors/runtime_align.zig b/test/cases/compile_errors/runtime_align.zig new file mode 100644 index 0000000000000000000000000000000000000000..d9356f7a4169f16e37d2155c5a68869a3738eb12 --- /dev/null +++ b/test/cases/compile_errors/runtime_align.zig @@ -0,0 +1,46 @@ +var alignment: u29 = 4; + +var global: u8 align(alignment) = 0; +export fn globalWithRuntimeAlign() u8 { + return global; +} + +export fn localWithRuntimeAlign() u8 { + const local: u8 align(alignment) = 0; + return local; +} + +export fn destructureWithRuntimeAlign() u8 { + const de: u8 align(alignment), const structure align(alignment) = .{ 0, 0 }; + return de | structure; +} + +export fn structFieldWithRuntimeAlign() u8 { + const @"struct": struct { field: u8 align(alignment) } = .{ .field = 0 }; + return @"struct".field; +} + +export fn unionFieldWithRuntimeAlign() u8 { + const @"union": union { field: u8 align(alignment) } = .{ .field = 0 }; + return @"union".field; +} + +export fn pointerWithRuntimeAlign() u8 { + const ptr: *align(alignment) u8 = &global; + return ptr.*; +} + +// error +// +// :3:22: error: unable to resolve comptime value +// :3:22: note: alignment must be comptime-known +// :9:27: error: unable to resolve comptime value +// :9:27: note: alignment must be comptime-known +// :14:24: error: unable to resolve comptime value +// :14:24: note: alignment must be comptime-known +// :19:47: error: unable to resolve comptime value +// :19:47: note: alignment must be comptime-known +// :24:45: error: unable to resolve comptime value +// :24:45: note: alignment must be comptime-known +// :29:23: error: unable to resolve comptime value +// :29:23: note: alignment must be comptime-known diff --git a/test/cases/compile_errors/runtime_bound_arg_with_comptime_param.zig b/test/cases/compile_errors/runtime_bound_arg_with_comptime_param.zig new file mode 100644 index 0000000000000000000000000000000000000000..398d6c77c89b58f2a6106119999c2f922b23d3d8 --- /dev/null +++ b/test/cases/compile_errors/runtime_bound_arg_with_comptime_param.zig @@ -0,0 +1,22 @@ +pub const A = enum { + a1, + a2, + + pub fn x(comptime _: A) usize { + return 0; + } + + pub fn y(self: A) usize { + return self.x(); + } +}; + +pub fn main() void { + _ = A.y(.a1); +} + +// error +// +// :10:20: error: unable to resolve comptime value +// :10:20: note: argument to comptime parameter must be comptime-known +// :5:14: note: parameter declared comptime here diff --git a/test/cases/compile_errors/spirv_merge_logical_pointers.zig b/test/cases/compile_errors/spirv_merge_logical_pointers.zig index 09ee6dd78cfc9509b5bb3cb3067119ed886ce75c..ccceef8097c8418dcfc363f6baa87c0e04073b3c 100644 --- a/test/cases/compile_errors/spirv_merge_logical_pointers.zig +++ b/test/cases/compile_errors/spirv_merge_logical_pointers.zig @@ -11,8 +11,8 @@ export fn a() void { } // error -// target=spirv64-vulkan +// target=spirv32-vulkan // // :9:13: error: value with non-mergable pointer type '*i32' depends on runtime control flow // :9:17: note: runtime control flow here -// :9:13: note: pointers with address space 'generic' cannot be returned from a branch on target spirv-vulkan by compiler backend stage2_spirv +// :9:13: note: pointers with address space 'generic' cannot be returned from a branch on target 'spirv-vulkan' by compiler backend 'stage2_spirv' 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 5b272e5c84a8d9295697add83d0627a7b22c5fc9..619875c7970ba869cb84ac43cdd1f0789724ec4f 100644 --- a/test/cases/compile_errors/switch_with_overlapping_case_ranges.zig +++ b/test/cases/compile_errors/switch_with_overlapping_case_ranges.zig @@ -1,12 +1,40 @@ -export fn entry() void { - var q: u8 = 0; - switch ((&q).*) { +export fn entry1(x: u8) void { + switch (x) { 1...2 => {}, 0...255 => {}, } } +export fn entry2(x: i8) void { + switch (x) { + -128...5 => {}, + 5...127 => {}, + } +} + +export fn entry3(x: u8) void { + switch (x) { + 0...5 => {}, + 5 => {}, + 6...255 => {}, + } +} + +export fn entry4(x: u8) void { + switch (x) { + 0...5 => {}, + 6 => {}, + 6...255 => {}, + } +} + // error // -// :5:10: error: duplicate switch value -// :4:10: note: previous value here +// :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 +// :18:9: note: previous value here +// :27:10: error: duplicate switch value +// :26:9: note: previous value here diff --git a/test/cases/error_in_nested_declaration.zig b/test/cases/error_in_nested_declaration.zig deleted file mode 100644 index 92759cd151c8e4ef5d97fc2391f8b2cfcbe48010..0000000000000000000000000000000000000000 --- a/test/cases/error_in_nested_declaration.zig +++ /dev/null @@ -1,30 +0,0 @@ -const S = struct { - b: u32, - c: i32, - a: struct { - pub fn str(_: @This(), extra: []u32) []i32 { - return @bitCast(extra); - } - }, -}; - -pub export fn entry() void { - var s: S = undefined; - _ = s.a.str(undefined); -} - -const S2 = struct { - a: [*c]anyopaque, -}; - -pub export fn entry2() void { - var s: S2 = undefined; - _ = &s; -} - -// error -// backend=selfhosted,llvm -// -// :6:20: error: cannot @bitCast to '[]i32' -// :6:20: note: use @ptrCast to cast from '[]u32' -// :17:12: error: indexable pointer to opaque type 'anyopaque' not allowed diff --git a/test/cases/image_sampling_spirv.zig b/test/cases/image_sampling_spirv.zig new file mode 100644 index 0000000000000000000000000000000000000000..030727e95c106b6b2521ab72d07bb608b58a22a8 --- /dev/null +++ b/test/cases/image_sampling_spirv.zig @@ -0,0 +1,42 @@ +pub const Image = @SpirvType(.{ .image = .{ + .usage = .{ .sampled = f32 }, + .format = .unknown, + .dim = .@"2d", + .depth = .not_depth, + .arrayed = false, + .multisampled = false, + .access = .unknown, +} }); +pub const SampledImage = @SpirvType(.{ .sampled_image = Image }); + +const image_in = @extern(*addrspace(.constant) const SampledImage, .{ + .name = "image_in", + .decoration = .{ .descriptor = .{ .set = 2, .binding = 0 } }, +}); +const uv_in = @extern(*addrspace(.input) @Vector(2, f32), .{ .name = "uv", .decoration = .{ .location = 0 } }); +const color_out = @extern(*addrspace(.output) @Vector(4, f32), .{ .name = "color", .decoration = .{ .location = 0 } }); + +export fn main() callconv(.{ .spirv_fragment = .{} }) void { + color_out.* = imageSample(image_in, uv_in.*); +} + +fn imageSample( + sampled_image: *addrspace(.constant) const SampledImage, + uv: @Vector(2, f32), +) @Vector(4, f32) { + return asm volatile ( + \\%loaded_sampler = OpLoad %SampledImage %sampled_image + \\%ret = OpImageSampleImplicitLod %Result %loaded_sampler %uv + : [ret] "" (-> @Vector(4, f32)), + : [SampledImage] "t" (SampledImage), + [sampled_image] "" (sampled_image), + [Result] "t" (@Vector(4, f32)), + [uv] "" (uv), + ); +} + +// compile +// output_mode=Exe +// backend=selfhosted +// target=spirv32-vulkan +// emit_bin=true diff --git a/test/cases/safety/@intCast negative to u0.zig b/test/cases/safety/@intCast negative to u0.zig new file mode 100644 index 0000000000000000000000000000000000000000..a445f755b7b8edb1e2a8f85375d92be95a8875aa --- /dev/null +++ b/test/cases/safety/@intCast negative to u0.zig @@ -0,0 +1,22 @@ +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, "integer does not fit in destination type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +pub fn main() !void { + bar(1, -1); + return error.TestFailed; +} + +fn bar(one: u1, not_zero: i32) void { + const x = one << @intCast(not_zero); + _ = x; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@intCast positive to u0.zig b/test/cases/safety/@intCast positive to u0.zig new file mode 100644 index 0000000000000000000000000000000000000000..180ee78512fccc28ba1b33ef2b78e0570f0044cb --- /dev/null +++ b/test/cases/safety/@intCast positive to u0.zig @@ -0,0 +1,22 @@ +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, "integer does not fit in destination type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +pub fn main() !void { + bar(1, 1); + return error.TestFailed; +} + +fn bar(one: u1, not_zero: i32) void { + const x = one << @intCast(not_zero); + _ = x; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/@intCast to u0.zig b/test/cases/safety/@intCast to u0.zig deleted file mode 100644 index 180ee78512fccc28ba1b33ef2b78e0570f0044cb..0000000000000000000000000000000000000000 --- a/test/cases/safety/@intCast to u0.zig +++ /dev/null @@ -1,22 +0,0 @@ -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, "integer does not fit in destination type")) { - std.process.exit(0); - } - std.process.exit(1); -} - -pub fn main() !void { - bar(1, 1); - return error.TestFailed; -} - -fn bar(one: u1, not_zero: i32) void { - const x = one << @intCast(not_zero); - _ = x; -} -// run -// backend=selfhosted,llvm -// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/deref_null_c_pointer.zig b/test/cases/safety/deref_null_c_pointer.zig new file mode 100644 index 0000000000000000000000000000000000000000..31f81cf76401aa267a5778735b92639d4a74a411 --- /dev/null +++ b/test/cases/safety/deref_null_c_pointer.zig @@ -0,0 +1,17 @@ +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 use null value")) { + std.process.exit(0); + } + std.process.exit(1); +} +pub fn main() !void { + const p: [*c]u8 = null; + _ = p.*; +} + +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/safety/ref_deref_null_c_pointer.zig b/test/cases/safety/ref_deref_null_c_pointer.zig new file mode 100644 index 0000000000000000000000000000000000000000..60b6601d0deae3848aa7a4725f04a74dd4552712 --- /dev/null +++ b/test/cases/safety/ref_deref_null_c_pointer.zig @@ -0,0 +1,17 @@ +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 use null value")) { + std.process.exit(0); + } + std.process.exit(1); +} +pub fn main() !void { + const p: [*c]u8 = null; + _ = &p.*; +} + +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux diff --git a/test/cases/spirv_mergable_pointers.zig b/test/cases/spirv_mergable_pointers.zig index 106ee8efbe2f1ba588ca830d7a5e67bda95d8ee3..e44c1b53cf7ec89926218ceb4fb16b55adfd72b8 100644 --- a/test/cases/spirv_mergable_pointers.zig +++ b/test/cases/spirv_mergable_pointers.zig @@ -13,5 +13,5 @@ export fn a() void { // compile // output_mode=Obj // backend=selfhosted -// target=spirv64-vulkan -// emit_bin=false +// target=spirv32-vulkan +// emit_bin=true diff --git a/test/incremental/increase_array_field_length b/test/incremental/increase_array_field_length new file mode 100644 index 0000000000000000000000000000000000000000..714473dd8302d57b0b2644a90f73442d47e9db2d --- /dev/null +++ b/test/incremental/increase_array_field_length @@ -0,0 +1,31 @@ +#update=initial version +#file=main.zig +const Big = struct { arr: [10]u8 }; +pub fn main(init: std.process.Init) !void { + var big: Big = undefined; + big = .{ .arr = @splat(123) }; + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + const index = big.arr.len - 1; + big.arr[index] = 234; + stdout_writer.interface.print("arr[{d}] = {d}\n", .{ index, big.arr[index] }) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +const std = @import("std"); +#expect_stdout="arr[9] = 234\n" + +#update=increase array length +#file=main.zig +const Big = struct { arr: [1000]u8 }; +pub fn main(init: std.process.Init) !void { + var big: Big = undefined; + big = .{ .arr = @splat(123) }; + var stdout_writer = std.Io.File.stdout().writerStreaming(init.io, &.{}); + const index = big.arr.len - 1; + big.arr[index] = 234; + stdout_writer.interface.print("arr[{d}] = {d}\n", .{ index, big.arr[index] }) catch |err| switch (err) { + error.WriteFailed => return stdout_writer.err.?, + }; +} +const std = @import("std"); +#expect_stdout="arr[999] = 234\n" diff --git a/test/libc.zig b/test/libc.zig index ee72cab75302935780851d8a7caf98775c9f4397..6f5590a543fe9966cd82cc3ed5241ae03f6566b6 100644 --- a/test/libc.zig +++ b/test/libc.zig @@ -151,9 +151,9 @@ pub fn addCases(cases: *tests.LibcContext) void { // cases.addLibcTestCase("math/asinhl.c", true, .{}); cases.addLibcTestCase("math/asinl.c", true, .{}); cases.addLibcTestCase("math/atan.c", true, .{}); - // cases.addLibcTestCase("math/atan2.c", true, .{}); - // cases.addLibcTestCase("math/atan2f.c", true, .{}); - // cases.addLibcTestCase("math/atan2l.c", true, .{}); + cases.addLibcTestCase("math/atan2.c", true, .{}); + cases.addLibcTestCase("math/atan2f.c", true, .{}); + cases.addLibcTestCase("math/atan2l.c", true, .{}); cases.addLibcTestCase("math/atanf.c", true, .{}); cases.addLibcTestCase("math/atanh.c", true, .{}); cases.addLibcTestCase("math/atanhf.c", true, .{}); diff --git a/test/link.zig b/test/link.zig new file mode 100644 index 0000000000000000000000000000000000000000..1dc75f4d0df843be0431092a06dbdcb067cd0ab1 --- /dev/null +++ b/test/link.zig @@ -0,0 +1,341 @@ +pub fn addCases(ctx: *LinkContext) void { + if (ctx.target.result.isMinGW()) + @import("link/mingw.zig").addCases(ctx); + + if (ctx.includeTest("static-lib")) |case| { + const obj1 = case.addObject(.{ + .name = "obj1", + .name_prefix = false, + .name_target = false, + .use_llvm = true, + .use_lld = true, + .c_source_bytes = + \\int foo1 = 1; + \\int foo2 = 2; + \\unsigned int fooBar() { + \\ return foo1 + foo2; + \\} + , + }); + const obj2 = case.addObject(.{ + .name = "this_is_a_long_name", + .name_prefix = false, + .name_target = false, + .zig_source_bytes = + \\fn fooWeak() callconv(.c) usize { + \\ return 0xaabbccddaabbccdd; + \\} + \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd }; + \\export var foo_strong: usize = 0x1122334411223344; + \\comptime { + \\ @export(&fooWeak, .{ .name = "fooWeak", .linkage = .weak }); + \\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong }); + \\} + , + }); + + const lib = case.addLibrary(.static, .{ + .name = "lib", + .name_prefix = false, + .name_target = false, + }); + lib.root_module.addObject(obj1); + lib.root_module.addObject(obj2); + + case.verifyObjdump(lib.getEmittedBin(), &.{ + "-s", + "--elements=file-type", + "--symbols", + "--only-symbol=foo", + }, .{ .use_llvm = true }); + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\extern fn fooBar() c_uint; + \\extern fn fooWeak() usize; + \\extern var foo_array: [2]u16; + \\extern var foo_strong: usize; + \\extern var foo_strong_alias: usize; + \\pub fn main() !u8 { + \\ return @intFromBool(0xcd003365cd00df35 != fooBar() + + \\ fooWeak() + + \\ foo_array[1] + + \\ foo_strong + + \\ foo_strong_alias); + \\} + , + }); + exe.root_module.linkLibrary(lib); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 0 } }); + } + + if (ctx.includeTest("tls")) |case| { + const obj = case.addObject(.{ + .name = "obj", + .zig_source_bytes = + \\threadlocal var threadlocal_var: u32 = 1234; + \\threadlocal var threadlocal_arr: [4]u16 = .{ 0x1111, 0x2222, 0x3333, 0x4444, }; + \\export fn threadlocal_read(a: *u32, b: *u16) void { + \\ a.* = threadlocal_var; + \\ b.* = threadlocal_arr[3]; + \\} + \\export fn threadlocal_write(a: u32, b: u16) void { + \\ threadlocal_var = a; + \\ threadlocal_arr[3] = b; + \\} + , + }); + + case.verifyObjdump(obj.getEmittedBin(), &.{ + "-s", + "--symbols", + "--only-symbol=threadlocal", + "--only-symbol=tls", + }, .{ .use_llvm = true }); + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\extern fn threadlocal_read(a: *u32, b: *u16) void; + \\extern fn threadlocal_write(a: u32, b: u16) void; + \\threadlocal var threadlocal_foo: u64 = 0xcafecafecafecafe; + \\pub fn main() !u8 { + \\ var a: u32 = undefined; + \\ var b: u16 = undefined; + \\ threadlocal_read(&a, &b); + \\ if (a != 1234 or b != 0x4444) return 1; + \\ if (threadlocal_foo != 0xcafecafecafecafe) return 2; + \\ threadlocal_write(0xabcdabcd, 0x5555); + \\ threadlocal_foo = 1; + \\ threadlocal_read(&a, &b); + \\ if (a != 0xabcdabcd or b != 0x5555) return 3; + \\ if (threadlocal_foo != 1) return 4; + \\ return 0; + \\} + , + }); + exe.root_module.addObject(obj); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 0 } }); + } + + if (ctx.includeTest("dynamic-lib-code")) |case| { + const lib = case.addLibrary(.dynamic, .{ + .name = "lib", + .name_target = false, + .zig_source_bytes = + \\export fn foo1() callconv(.c) u64 { + \\ return 0x1122334411223344; + \\} + \\export fn foo2() callconv(.c) u64 { + \\ return 0xaabbccddaabbccdd; + \\} + , + }); + + case.verifyObjdump(lib.getEmittedBin(), &.{ + "-s", + "--exports", + "--only-symbol=foo", + }, .{ .os = true }); + + if (ctx.target.result.os.tag == .windows) { + case.verifyObjdump(lib.getEmittedImplib(), &.{ + "-s", + "--exports=sort", + "--only-symbol=foo", + }, .{ .sub_name = "implib", .os = true, .arch = true }); + } + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\extern fn foo1() u64; + \\pub fn main() !u8 { + \\ const foo2 = @extern( + \\ *const fn () callconv(.c) u64, + \\ .{ .name = "foo2", .is_dll_import = true }, + \\ ); + \\ return @intFromBool(0xbbde0021bbde0021 != foo1() + foo2()); + \\} + , + }); + exe.root_module.linkLibrary(lib); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 0 } }); + } + + if (ctx.includeTest("dynamic-lib-data")) |case| { + const lib = case.addLibrary(.dynamic, .{ + .name = "lib", + .name_target = false, + .zig_source_bytes = + \\export var foo_array: [2]u16 = .{ 0xffff, 0xabcd }; + \\export var foo_strong: usize = 0x1122334411223344; + \\comptime { + \\ @export(&foo_strong, .{ .name = "foo_strong_alias", .linkage = .strong }); + \\} + , + }); + + case.verifyObjdump(lib.getEmittedBin(), &.{ + "-s", + "--exports", + "--only-symbol=foo", + }, .{}); + + if (ctx.target.result.os.tag == .windows) { + case.verifyObjdump(lib.getEmittedImplib(), &.{ + "-s", + "--exports=sort", + "--only-symbol=foo", + }, .{ .sub_name = "implib", .os = true, .arch = true }); + } + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\pub fn main() !u8 { + \\ const foo_array = @extern(*[2]u16, .{ .name = "foo_array", .is_dll_import = true }); + \\ const foo_strong = @extern(*usize, .{ .name = "foo_strong", .is_dll_import = true }); + \\ const foo_strong_alias = @extern(*usize, .{ .name = "foo_strong_alias", .is_dll_import = true }); + \\ return @intFromBool(0x2244668822451255 != + \\ foo_array[1] + + \\ foo_strong.* + + \\ foo_strong_alias.*); + \\} + , + }); + exe.root_module.linkLibrary(lib); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 0 } }); + } + + if (ctx.includeTest("abs-symbol")) |case| { + const abs = case.addObject(.{ + .name = "abs", + .use_llvm = true, // TODO: .globl not supported on self-hosted + .use_lld = true, + .asm_source_bytes = + \\.globl foo + \\foo = 0xcafecafe + \\ + , + }); + + const abs_reloc = case.addObject(.{ + .name = "abs_reloc", + .use_llvm = true, // TODO: .globl not supported on self-hosted + .use_lld = true, + .asm_source_bytes = + \\.data + \\.globl foo_copy + \\foo_copy: + \\.long foo + , + }); + + case.verifyObjdump(abs_reloc.getEmittedBin(), &.{ + "-s", + "--relocs", + }, .{ .arch = true }); + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\extern var foo_copy: u32; + \\pub fn main() !u8 { + \\ return @intFromBool(foo_copy != 0xcafecafe); + \\} + , + }); + exe.root_module.addObject(abs); + exe.root_module.addObject(abs_reloc); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 0 } }); + + if (!ctx.use_llvm) { + const exe_reloc_err = case.addExecutable(.{ + .name = "test-reloc-err", + .zig_source_bytes = + \\extern const foo: u32; + \\pub fn main() !u8 { + \\ return @intFromBool(foo != 0xcafecafe); + \\} + , + }); + exe_reloc_err.root_module.addObject(abs); + case.expectLinkErrors(exe_reloc_err, .{ + .contains = "error: absolute symbol 'foo' targeted by invalid relocation type: /?/", + }); + } + } + + if (ctx.includeTest("explicit-extern-lib-name")) |case| { + // TODO: Lld.zig does not look at explicit inputs to resolve explicit extern lib names + if (ctx.use_llvm) return; + + const lib1 = case.addLibrary(.dynamic, .{ + .name = "lib1", + .name_target = false, + .zig_source_bytes = + \\export fn foo() u8 { + \\ return 43; + \\} + , + }); + + const lib2 = case.addLibrary(.dynamic, .{ + .name = "lib2", + .name_target = false, + .zig_source_bytes = + \\export fn foo() u8 { + \\ return 42; + \\} + , + }); + + const lib3 = case.addLibrary(.static, .{ + .name = "lib3", + .zig_source_bytes = + \\extern fn foo() u8; + \\export fn callFoo() u8 { + \\ return foo(); + \\} + , + }); + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\extern "explicit-extern-lib-name-lib2" fn foo() u8; + \\extern fn callFoo() u8; + \\pub fn main() !u8 { + \\ return foo() + callFoo(); + \\} + , + }); + exe.root_module.linkLibrary(lib1); + exe.root_module.linkLibrary(lib2); + // exe.root_module.addLibraryPath(.{ + // .generated = .{ + // .index = lib2.getEmittedBin().generated.index, + // .up = 1, + // }, + // }); + exe.root_module.linkLibrary(lib3); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 84 } }); + } +} + +const LinkContext = @import("tests.zig").LinkContext; +const std = @import("std"); diff --git a/test/link/exports.zig b/test/link/exports.zig new file mode 100644 index 0000000000000000000000000000000000000000..3f5e4734f45cc1e29472480174beb1d3d90e23cb --- /dev/null +++ b/test/link/exports.zig @@ -0,0 +1,9 @@ +export fn foo_fn() void {} +var foo_var: u32 = 1234; +comptime { + @export(&foo_var, .{ .name = "foo_var", .linkage = .strong }); +} +const foo_const: u64 = 5678; +comptime { + @export(&foo_const, .{ .name = "foo_const", .linkage = .strong }); +} diff --git a/test/link/mingw.zig b/test/link/mingw.zig new file mode 100644 index 0000000000000000000000000000000000000000..e584709de04f5fc21ac2283d2356226c4c0ec36c --- /dev/null +++ b/test/link/mingw.zig @@ -0,0 +1,48 @@ +pub fn addCases(ctx: *LinkContext) void { + if (ctx.includeTest("ctor-dtor")) |case| { + if (!ctx.link_libc) return; + + const obj = case.addObject(.{ + .name = "obj", + .use_llvm = true, + .use_lld = true, + .c_source_bytes = + \\#include + \\int foo; + \\__attribute__((constructor)) + \\static void init_foo() { + \\ foo = 42; + \\} + \\__attribute__((destructor)) + \\static void deinit_foo() { + \\ exit(42); + \\} + , + }); + + const lib = case.addLibrary(.static, .{ + .name = "lib", + .name_prefix = false, + .name_target = false, + }); + lib.root_module.addObject(obj); + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\extern var foo: u32; + \\pub fn main() !u8 { + \\ if (foo != 42) return 1; + \\ return 2; + \\} + , + }); + exe.root_module.addObject(obj); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 42 } }); + } +} + +const LinkContext = @import("../tests.zig").LinkContext; +const std = @import("std"); diff --git a/test/link/snapshots/.gitattributes b/test/link/snapshots/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..699baaf03a7db7fe3ff3dcc2c4986c32e1aa52c3 --- /dev/null +++ b/test/link/snapshots/.gitattributes @@ -0,0 +1 @@ +*.dmp eol=lf diff --git a/test/link/snapshots/abs-symbol.x86_64.dmp b/test/link/snapshots/abs-symbol.x86_64.dmp new file mode 100644 index 0000000000000000000000000000000000000000..747546649b082633b0097b1be311a382e0b98e2b --- /dev/null +++ b/test/link/snapshots/abs-symbol.x86_64.dmp @@ -0,0 +1 @@ +xxxxxxxx ADDR32 xxxxxxxx UNDEF | foo diff --git a/test/link/snapshots/dynamic-lib-code.implib-x86_64-windows.dmp b/test/link/snapshots/dynamic-lib-code.implib-x86_64-windows.dmp new file mode 100644 index 0000000000000000000000000000000000000000..eed30ce985f4c8ab00f7534716ab5bed343edd8d --- /dev/null +++ b/test/link/snapshots/dynamic-lib-code.implib-x86_64-windows.dmp @@ -0,0 +1,32 @@ + 0 date + 0 user_id + 0 group_id + 0 file_mode +xxxxxxxxxxxxxxxx size + second_linker type + | x symbols + | x members +xxxxxxxx __imp_foo1 +xxxxxxxx __imp_foo2 +xxxxxxxx foo1 +xxxxxxxx foo2 + 0 version + 8664 machine (AMD64) + 0 time_date_stamp +xxxxxxxxxxxxxxxx size_of_data +xxxxxxxxxxxxxxxx hint + CODE import_type + NAME name_type + symbol name | foo1 + import name | foo1 + dll | dynamic-lib-code-lib.dll + 0 version + 8664 machine (AMD64) + 0 time_date_stamp +xxxxxxxxxxxxxxxx size_of_data +xxxxxxxxxxxxxxxx hint + CODE import_type + NAME name_type + symbol name | foo2 + import name | foo2 + dll | dynamic-lib-code-lib.dll diff --git a/test/link/snapshots/dynamic-lib-code.windows.dmp b/test/link/snapshots/dynamic-lib-code.windows.dmp new file mode 100644 index 0000000000000000000000000000000000000000..a9396675f8f34175fc4b3a5f488a003cc60bc63d --- /dev/null +++ b/test/link/snapshots/dynamic-lib-code.windows.dmp @@ -0,0 +1,13 @@ +Export directory: + 0 flags + 0 time_date_stamp + 0.00 version +xxxxxxxxxxxxxxxx name_rva + 1 ordinal_base +xxxxxxxxxxxxxxxx number_of_entries +xxxxxxxxxxxxxxxx number_of_names +xxxxxxxxxxxxxxxx export_address_table_rva +xxxxxxxxxxxxxxxx name_pointer_table_rva +xxxxxxxxxxxxxxxx ordinal_table_rva +xxxx xxxx xxxxxxxx | foo1 +xxxx xxxx xxxxxxxx | foo2 diff --git a/test/link/snapshots/dynamic-lib-data.dmp b/test/link/snapshots/dynamic-lib-data.dmp new file mode 100644 index 0000000000000000000000000000000000000000..480b7107582590491d4e1094ff69f39ae9d44a61 --- /dev/null +++ b/test/link/snapshots/dynamic-lib-data.dmp @@ -0,0 +1,14 @@ +Export directory: + 0 flags + 0 time_date_stamp + 0.00 version +xxxxxxxxxxxxxxxx name_rva + 1 ordinal_base +xxxxxxxxxxxxxxxx number_of_entries +xxxxxxxxxxxxxxxx number_of_names +xxxxxxxxxxxxxxxx export_address_table_rva +xxxxxxxxxxxxxxxx name_pointer_table_rva +xxxxxxxxxxxxxxxx ordinal_table_rva +xxxx xxxx xxxxxxxx | foo_array +xxxx xxxx xxxxxxxx | foo_strong +xxxx xxxx xxxxxxxx | foo_strong_alias diff --git a/test/link/snapshots/dynamic-lib-data.implib-x86_64-windows.dmp b/test/link/snapshots/dynamic-lib-data.implib-x86_64-windows.dmp new file mode 100644 index 0000000000000000000000000000000000000000..b273ef44e475ff353e37271a9ec3777332082d5a --- /dev/null +++ b/test/link/snapshots/dynamic-lib-data.implib-x86_64-windows.dmp @@ -0,0 +1,41 @@ + 0 date + 0 user_id + 0 group_id + 0 file_mode +xxxxxxxxxxxxxxxx size + second_linker type + | x symbols + | x members +xxxxxxxx __imp_foo_array +xxxxxxxx __imp_foo_strong +xxxxxxxx __imp_foo_strong_alias + 0 version + 8664 machine (AMD64) + 0 time_date_stamp +xxxxxxxxxxxxxxxx size_of_data +xxxxxxxxxxxxxxxx hint + DATA import_type + NAME name_type + symbol name | foo_array + import name | foo_array + dll | dynamic-lib-data-lib.dll + 0 version + 8664 machine (AMD64) + 0 time_date_stamp +xxxxxxxxxxxxxxxx size_of_data +xxxxxxxxxxxxxxxx hint + DATA import_type + NAME name_type + symbol name | foo_strong + import name | foo_strong + dll | dynamic-lib-data-lib.dll + 0 version + 8664 machine (AMD64) + 0 time_date_stamp +xxxxxxxxxxxxxxxx size_of_data +xxxxxxxxxxxxxxxx hint + DATA import_type + NAME name_type + symbol name | foo_strong_alias + import name | foo_strong_alias + dll | dynamic-lib-data-lib.dll diff --git a/test/link/snapshots/static-lib.llvm.dmp b/test/link/snapshots/static-lib.llvm.dmp new file mode 100644 index 0000000000000000000000000000000000000000..f64e76be1134c735e77bb6e2e10d0983a8858d35 --- /dev/null +++ b/test/link/snapshots/static-lib.llvm.dmp @@ -0,0 +1,15 @@ +lib.lib: COFF archive +lib.lib(obj1.obj): COFF object +xxxx 00000000 1 NULL() EXTERNAL | fooBar +xxxx 00000000 2 NULL EXTERNAL | foo1 +xxxx 00000004 2 NULL EXTERNAL | foo2 +lib.lib(this_is_a_long_name.obj): COFF object +xxxx 00000000 1 NULL() STATIC | this_is_a_long_name.fooWeak +xxxx 00000000 2 NULL STATIC | this_is_a_long_name.foo_strong +xxxx 00000008 2 NULL STATIC | this_is_a_long_name.foo_array +xxxx 00000000 2 NULL EXTERNAL | foo_strong +xxxx 00000000 2 NULL EXTERNAL | foo_strong_alias +xxxx 00000008 2 NULL EXTERNAL | foo_array +xxxx 00000000 UNDEF NULL WEAK_EXTERNAL | fooWeak + | Weak External [falls back to relative ordinal 000000+2 via SEARCH_ALIAS] +xxxx 00000000 1 NULL() EXTERNAL | .weak.fooWeak.default.foo_strong diff --git a/test/link/snapshots/static-lib.no-llvm.dmp b/test/link/snapshots/static-lib.no-llvm.dmp new file mode 100644 index 0000000000000000000000000000000000000000..07e2219bfd57889557bd5eda680dc5de4ba62e42 --- /dev/null +++ b/test/link/snapshots/static-lib.no-llvm.dmp @@ -0,0 +1,12 @@ +lib.lib: COFF archive +lib.lib(obj1.obj): COFF object +xxxx 00000000 1 NULL() EXTERNAL | fooBar +xxxx 00000000 2 NULL EXTERNAL | foo1 +xxxx 00000004 2 NULL EXTERNAL | foo2 +lib.lib(this_is_a_long_name.obj): COFF object +xxxx 00000000 4 NULL() EXTERNAL | this_is_a_long_name.fooWeak +xxxx 00000000 2 NULL EXTERNAL | foo_strong +xxxx 00000000 2 NULL EXTERNAL | foo_strong_alias +xxxx 00000010 2 NULL EXTERNAL | foo_array +xxxx 00000000 UNDEF NULL() WEAK_EXTERNAL | fooWeak + | Weak External [falls back to relative ordinal 000000-4 via SEARCH_ALIAS] diff --git a/test/link/snapshots/tls.llvm.dmp b/test/link/snapshots/tls.llvm.dmp new file mode 100644 index 0000000000000000000000000000000000000000..8e70edb3acc79d3559d05451ab555d01d621d26a --- /dev/null +++ b/test/link/snapshots/tls.llvm.dmp @@ -0,0 +1,9 @@ +xxxx 00000000 6 NULL STATIC | .tls$ + | Section [size xxxxxxxx chksum a194a569 relocs 0000 lines 0000] +xxxx 00000000 1 NULL() STATIC | obj.threadlocal_write +xxxx 00000000 UNDEF NULL EXTERNAL | _tls_index +xxxx 00000000 6 NULL STATIC | obj.threadlocal_var +xxxx 00000004 6 NULL STATIC | obj.threadlocal_arr +xxxx 00000040 1 NULL() STATIC | obj.threadlocal_read +xxxx 00000000 1 NULL() EXTERNAL | threadlocal_write +xxxx 00000040 1 NULL() EXTERNAL | threadlocal_read diff --git a/test/link/snapshots/tls.no-llvm.dmp b/test/link/snapshots/tls.no-llvm.dmp new file mode 100644 index 0000000000000000000000000000000000000000..02ae0d78df3fa5cddafaed1d3dc49a50debf7247 --- /dev/null +++ b/test/link/snapshots/tls.no-llvm.dmp @@ -0,0 +1,7 @@ +xxxx 00000000 5 NULL STATIC | .tls$ + | Section [size xxxxxxxx chksum 00000000 relocs 0000 lines 0000] +xxxx 00000000 5 NULL STATIC | obj.threadlocal_var +xxxx 00000008 5 NULL STATIC | obj.threadlocal_arr +xxxx 00000000 UNDEF NULL EXTERNAL | _tls_index +xxxx 00000000 4 NULL() EXTERNAL | threadlocal_write +xxxx 00000060 4 NULL() EXTERNAL | threadlocal_read diff --git a/test/llvm_targets.zig b/test/llvm_targets.zig index 4f9159eaebc3a49ef97bb742b5870e0e068ddbfd..cbbf4aff7d01adeb6cfbd22a51402f35759b1ea4 100644 --- a/test/llvm_targets.zig +++ b/test/llvm_targets.zig @@ -154,11 +154,13 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musleabihf }, .{ .cpu_arch = .mipsel, .os_tag = .netbsd, .abi = .eabi }, .{ .cpu_arch = .mipsel, .os_tag = .netbsd, .abi = .eabihf }, + // .{ .cpu_arch = .mipsel, .os_tag = .psx, .abi = .eabi }, .{ .cpu_arch = .mipsel, .os_tag = .psp, .abi = .eabihf }, .{ .cpu_arch = .mipsel, .os_tag = .rtems, .abi = .eabi }, .{ .cpu_arch = .mipsel, .os_tag = .rtems, .abi = .eabihf }, .{ .cpu_arch = .mips64, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .abin32 }, .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .gnuabi64 }, .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .gnuabin32 }, .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .muslabi64 }, @@ -167,6 +169,7 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .mips64, .os_tag = .openbsd, .abi = .none }, .{ .cpu_arch = .mips64el, .os_tag = .freestanding, .abi = .none }, + .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .abin32 }, .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .gnuabi64 }, .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .gnuabin32 }, .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .muslabi64 }, @@ -192,6 +195,7 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .powerpc, .os_tag = .openbsd, .abi = .eabihf }, .{ .cpu_arch = .powerpc, .os_tag = .rtems, .abi = .eabi }, .{ .cpu_arch = .powerpc, .os_tag = .rtems, .abi = .eabihf }, + .{ .cpu_arch = .powerpc, .os_tag = .wiiu, .abi = .eabihf }, .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi }, .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf }, @@ -330,6 +334,7 @@ const targets = [_]std.Target.Query{ .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .muslx32 }, .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .none }, .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .ohos }, + .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .x32 }, .{ .cpu_arch = .x86_64, .os_tag = .maccatalyst, .abi = .none }, .{ .cpu_arch = .x86_64, .os_tag = .macos, .abi = .none }, .{ .cpu_arch = .x86_64, .os_tag = .netbsd, .abi = .none }, diff --git a/test/src/Cases.zig b/test/src/Cases.zig index 9ffc5ec61645f2ecc6364389b63b58e2b5717935..f321d15851e117539f78f38681bd20cb8e06b1c4 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -357,7 +357,15 @@ fn addFromDirInner( var manifest = try TestManifest.parse(ctx.arena, src); const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend); - const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", std.Target.Query); + const target_strs = try manifest.getConfigForKeyAlloc(ctx.arena, "target", []const u8); + const cpu_features_str = manifest.config_map.get("cpu_features") orelse ""; + const targets = try ctx.arena.alloc(std.Target.Query, target_strs.len); + for (targets, target_strs) |*query, target_str| { + query.* = try std.Target.Query.parse(.{ + .arch_os_abi = target_str, + .cpu_features = if (cpu_features_str.len == 0) null else cpu_features_str, + }); + } const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool); const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool); const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode); @@ -707,6 +715,8 @@ const TestManifestConfigDefaults = struct { return "null"; } else if (std.mem.eql(u8, key, "imports")) { return ""; + } else if (std.mem.eql(u8, key, "cpu_features")) { + return ""; } else unreachable; } }; @@ -739,6 +749,7 @@ const TestManifest = struct { .{ "is_test", {} }, .{ "output_mode", {} }, .{ "target", {} }, + .{ "cpu_features", {} }, .{ "c_frontend", {} }, .{ "link_libc", {} }, .{ "backend", {} }, diff --git a/test/src/Link.zig b/test/src/Link.zig new file mode 100644 index 0000000000000000000000000000000000000000..16c7dbdf83ace21ba7d92ef0c88ba54e0efb42fa --- /dev/null +++ b/test/src/Link.zig @@ -0,0 +1,281 @@ +b: *Build, +step: *Step, +optimize: std.builtin.OptimizeMode, +target: std.Build.ResolvedTarget, +target_desc: []const u8, +use_llvm: bool, +use_lld: bool, +link_libc: bool, +test_filters: []const []const u8, +update_step: ?*Step.UpdateSourceFiles, +updated_snapshots: std.StringArrayHashMapUnmanaged(void), +max_rss: usize, + +pub fn includeTest(self: *Link, prefix: []const u8) ?Case { + if (for (self.test_filters) |filter| { + if (std.mem.containsAtLeast(u8, prefix, 1, filter)) break false; + } else self.test_filters.len > 0) return null; + + return .{ + .ctx = self, + .prefix = prefix, + }; +} + +pub fn sourcePath(self: *const Link, sub_path: []const u8) std.Build.LazyPath { + return self.b.path(self.b.pathJoin(&.{ "test/link", sub_path })); +} + +pub const Case = struct { + ctx: *Link, + prefix: []const u8, + + fn resolveName(self: *const Case, overlay: *const OverlayOptions) []const u8 { + if (!overlay.name_prefix and !overlay.name_target) + return overlay.name; + + if (overlay.name_prefix == overlay.name_target) + return self.ctx.b.fmt("{s}-{s}-{s}", .{ self.prefix, overlay.name, self.ctx.target_desc }) + else if (overlay.name_prefix) + return self.ctx.b.fmt("{s}-{s}", .{ self.prefix, overlay.name }) + else + return self.ctx.b.fmt("{s}-{s}", .{ overlay.name, self.ctx.target_desc }); + } + + pub fn addLibrary( + self: *const Case, + linkage: std.builtin.LinkMode, + overlay: OverlayOptions, + ) *Step.Compile { + return self.ctx.b.addLibrary(.{ + .linkage = linkage, + .name = self.resolveName(&overlay), + .root_module = self.ctx.createModule(overlay), + .use_llvm = overlay.use_llvm orelse self.ctx.use_llvm, + .use_lld = overlay.use_lld orelse self.ctx.use_lld, + }); + } + + pub fn addExecutable( + self: *const Case, + overlay: OverlayOptions, + ) *Step.Compile { + return self.ctx.b.addExecutable(.{ + .name = self.resolveName(&overlay), + .root_module = self.ctx.createModule(overlay), + .use_llvm = overlay.use_llvm orelse self.ctx.use_llvm, + .use_lld = overlay.use_lld orelse self.ctx.use_lld, + }); + } + + pub fn addRunArtifact( + self: *const Case, + exe: *Step.Compile, + ) *Step.Run { + const run_step = self.ctx.b.addRunArtifact(exe); + run_step.skip_foreign_checks = true; + self.ctx.step.dependOn(&run_step.step); + return run_step; + } + + pub fn addObject( + self: *const Case, + overlay: OverlayOptions, + ) *Step.Compile { + return self.ctx.b.addObject(.{ + .name = self.resolveName(&overlay), + .root_module = self.ctx.createModule(overlay), + .use_llvm = overlay.use_llvm orelse self.ctx.use_llvm, + .use_lld = overlay.use_lld orelse self.ctx.use_lld, + }); + } + + pub fn expectLinkErrors( + self: *const Case, + comp: *Step.Compile, + expected_errors: Step.Compile.ExpectedCompileErrors, + ) void { + comp.expect_errors = expected_errors; + const bin_file = comp.getEmittedBin(); + bin_file.addStepDependencies(self.ctx.step); + } + + const SnapshotScope = struct { + /// If a test case has multiple verifyObjdump calls, `opt_sub_name` should + /// be used to differentiate them. + sub_name: ?[]const u8 = null, + arch: bool = false, + os: bool = false, + abi: bool = false, + optimize: bool = false, + use_llvm: bool = false, + use_lld: bool = false, + link_libc: bool = false, + }; + + /// Verify the results of a `zig objdump` call against a snapshot, which + /// contains the expected output. Snapshots alias between all build + /// configurations by default, but by specifying fields in `scope`, + /// unique snapshot names are generated for each value of that field. + pub fn verifyObjdump( + self: *const Case, + file: Build.LazyPath, + args: []const []const u8, + scope: SnapshotScope, + ) void { + const ctx = self.ctx; + const snapshot_name = self.snapshotName(scope) catch @panic("OOM"); + const snapshot_sub_path = ctx.b.pathJoin(&.{ "test/link/snapshots/", snapshot_name }); + + // Many tests may read the same snapshot, so only use the first one to update. + // If there are differences in output, they will show up on the next test run. + if (ctx.update_step != null) { + const gop = ctx.updated_snapshots.getOrPut(ctx.b.allocator, snapshot_sub_path) catch @panic("OOM"); + if (gop.found_existing) return; + } + + const run_step = Step.Run.create(ctx.b, ctx.b.fmt( + "objdump {s} {s}", + .{ snapshot_name, ctx.target_desc }, + )); + run_step.addArgs(&.{ ctx.b.graph.zig_exe, "objdump" }); + run_step.addFileArg(file); + run_step.addArgs(args); + run_step.addCheck(.{ .expect_term = .{ .exited = 0 } }); + + if (ctx.update_step) |update_step| { + // Workaround for the build system not realizing objdump itself has changed + run_step.has_side_effects = true; + + const snapshot_update_path = run_step.captureStdOut(.{}); + update_step.addCopyFileToSource(snapshot_update_path, snapshot_sub_path); + } else { + run_step.addCheck(.{ .expect_stdout_snapshot = ctx.b.path(snapshot_sub_path) }); + } + + ctx.step.dependOn(&run_step.step); + } + + fn snapshotName( + self: *const Case, + scope: SnapshotScope, + ) ![]const u8 { + const ctx = self.ctx; + var snapshot_name: std.Io.Writer.Allocating = .init(ctx.b.allocator); + const w = &snapshot_name.writer; + + try w.writeAll(self.prefix); + var sep: u8 = '.'; + + if (try snapshotNameInner(w, scope.sub_name != null, &sep)) + try w.writeAll(scope.sub_name.?); + if (try snapshotNameInner(w, scope.arch, &sep)) + try w.print("{t}", .{ctx.target.result.cpu.arch}); + if (try snapshotNameInner(w, scope.os, &sep)) + try w.print("{t}", .{ctx.target.result.os.tag}); + if (try snapshotNameInner(w, scope.abi, &sep)) + try w.print("{t}", .{ctx.target.result.abi}); + if (try snapshotNameInner(w, scope.optimize, &sep)) + try w.print("{t}", .{ctx.optimize}); + if (try snapshotNameInner(w, scope.use_llvm, &sep)) + try w.writeAll(if (ctx.use_llvm) "llvm" else "no-llvm"); + if (try snapshotNameInner(w, scope.use_lld, &sep)) + try w.writeAll(if (ctx.use_lld) "lld" else "no-lld"); + if (try snapshotNameInner(w, scope.link_libc, &sep)) + try w.writeAll(if (ctx.link_libc) "libc" else "no-libc"); + + if (sep == '-') sep = '.'; + try w.writeByte(sep); + try w.writeAll("dmp"); + + return try snapshot_name.toOwnedSlice(); + } + + fn snapshotNameInner(w: *std.Io.Writer, cond: bool, sep: *u8) !bool { + if (cond) { + try w.writeByte(sep.*); + sep.* = '-'; + } + + return cond; + } +}; + +fn createModule(self: *const Link, overlay: OverlayOptions) *Build.Module { + const write_files = self.b.addWriteFiles(); + + const mod = self.b.createModule(.{ + .target = self.target, + .optimize = self.optimize, + .root_source_file = overlay.zig_source_file orelse rsf: { + const bytes = overlay.zig_source_bytes orelse break :rsf null; + const name = self.b.fmt("{s}.zig", .{overlay.name}); + break :rsf write_files.add(name, bytes); + }, + .link_libc = self.link_libc, // TODO: Should this be in overlay instead? + .pic = overlay.pic, + .strip = overlay.strip, + }); + + if (overlay.objcpp_source_bytes) |bytes| { + mod.addCSourceFile(.{ + .file = write_files.add("a.mm", bytes), + .flags = overlay.objcpp_source_flags, + }); + } + if (overlay.objc_source_bytes) |bytes| { + mod.addCSourceFile(.{ + .file = write_files.add("a.m", bytes), + .flags = overlay.objc_source_flags, + }); + } + if (overlay.cpp_source_bytes) |bytes| { + mod.addCSourceFile(.{ + .file = write_files.add("a.cpp", bytes), + .flags = overlay.cpp_source_flags, + }); + } + if (overlay.c_source_bytes) |bytes| { + mod.addCSourceFile(.{ + .file = write_files.add("a.c", bytes), + .flags = overlay.c_source_flags, + }); + } + if (overlay.asm_source_bytes) |bytes| { + mod.addAssemblyFile(write_files.add("a.s", bytes)); + } + + return mod; +} + +const OverlayOptions = struct { + name: []const u8, + /// Prefix the name with the test case prefix. + /// Unset if names with specific lengths are needed. + name_prefix: bool = true, + /// Prefix the name with `target_desc`. + /// Can be unset when the snapshot needs to contain the name, + /// so that snapshots can alias between targets. + name_target: bool = true, + asm_source_bytes: ?[]const u8 = null, + c_source_bytes: ?[]const u8 = null, + c_source_flags: []const []const u8 = &.{}, + cpp_source_bytes: ?[]const u8 = null, + cpp_source_flags: []const []const u8 = &.{}, + objc_source_bytes: ?[]const u8 = null, + objc_source_flags: []const []const u8 = &.{}, + objcpp_source_bytes: ?[]const u8 = null, + objcpp_source_flags: []const []const u8 = &.{}, + zig_source_bytes: ?[]const u8 = null, + zig_source_file: ?std.Build.LazyPath = null, + pic: ?bool = null, + strip: ?bool = null, + use_llvm: ?bool = null, + use_lld: ?bool = null, +}; + +const std = @import("std"); +const Build = std.Build; +const Step = Build.Step; + +const Link = @This(); diff --git a/test/standalone/build.zig b/test/standalone/build.zig index e36e802979d5fcb3bf593399413c835f91938af8..c5376b2e0df839ff498ad712c657b624611d34bd 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/check_mingw.zig", "../../tools/dump-cov.zig", "../../tools/fetch_them_macos_headers.zig", "../../tools/gen_macos_headers_c.zig", @@ -61,6 +62,21 @@ pub fn build(b: *std.Build) void { .target = tools_target, }), }); + if (std.mem.endsWith(u8, tool_src_path, "check_mingw.zig")) { + const mingw_preprocessor_mod = b.createModule(.{ + .root_source_file = b.path("../../src/libs/mingw/Preprocessor.zig"), + .target = tools_target, + }); + tool.root_module.addImport("preprocessor", mingw_preprocessor_mod); + } + if (std.mem.endsWith(u8, tool_src_path, "update_cpu_features.zig")) { + const spirv_spec = b.createModule(.{ + .root_source_file = b.path("../../src/codegen/spirv/spec.zig"), + .target = tools_target, + }); + tool.root_module.addImport("spirv_spec", spirv_spec); + } + tools_tests_step.dependOn(&tool.step); } for ([_][]const u8{ diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index de1b97d60bdbe995992a69fe4eb9f55d99e7e3c8..190394704ae48cd28406511353905a2f8675dd63 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -193,6 +193,9 @@ .elf2 = .{ .path = "elf2", }, + .run_args = .{ + .path = "run_args", + }, }, .paths = .{ "build.zig", diff --git a/test/standalone/load_dynamic_library/add.zig b/test/standalone/load_dynamic_library/add.zig deleted file mode 100644 index a04ec1544dc82e27afb137de2672a48d726a72fc..0000000000000000000000000000000000000000 --- a/test/standalone/load_dynamic_library/add.zig +++ /dev/null @@ -1,3 +0,0 @@ -export fn add(a: i32, b: i32) i32 { - return a + b; -} diff --git a/test/standalone/load_dynamic_library/build.zig b/test/standalone/load_dynamic_library/build.zig index 2160b2b3e474a558725d9f2c39eb98f7a1be9d8a..8af976e9929eef069673e71c0bb1c1a738ef4e7d 100644 --- a/test/standalone/load_dynamic_library/build.zig +++ b/test/standalone/load_dynamic_library/build.zig @@ -11,12 +11,16 @@ pub fn build(b: *std.Build) void { if (builtin.os.tag == .wasi) return; if (builtin.os.tag == .windows) return; + // ld and lld do not agree on the format of the .hash section + // Tracked by https://codeberg.org/ziglang/zig/issues/35746 + if (builtin.cpu.arch == .s390x and builtin.os.tag == .linux) return; + const lib = b.addLibrary(.{ .linkage = .dynamic, - .name = "add", + .name = "lib", .version = .{ .major = 1, .minor = 0, .patch = 0 }, .root_module = b.createModule(.{ - .root_source_file = b.path("add.zig"), + .root_source_file = b.path("lib.zig"), .optimize = optimize, .target = target, }), diff --git a/test/standalone/load_dynamic_library/lib.zig b/test/standalone/load_dynamic_library/lib.zig new file mode 100644 index 0000000000000000000000000000000000000000..d5f45bce7ccb715ed1ef1902780caaf65b1a5875 --- /dev/null +++ b/test/standalone/load_dynamic_library/lib.zig @@ -0,0 +1,8 @@ +export fn addInts(a: i32, b: i32) i32 { + return a + b; +} + +var forty_two: i32 = 42; +export fn fortyTwo() i32 { + return forty_two; +} diff --git a/test/standalone/load_dynamic_library/main.zig b/test/standalone/load_dynamic_library/main.zig index ac64e67cdaddf18d0904f5ecff78306542930fef..a8e9e9b6d6661a8536178be3148347ea7448c634 100644 --- a/test/standalone/load_dynamic_library/main.zig +++ b/test/standalone/load_dynamic_library/main.zig @@ -8,9 +8,11 @@ pub fn main(init: std.process.Init) !void { var lib = try std.DynLib.open(dynlib_name); defer lib.close(); - const Add = *const fn (i32, i32) callconv(.c) i32; - const addFn = lib.lookup(Add, "add") orelse return error.SymbolNotFound; + const AddInts = *const fn (i32, i32) callconv(.c) i32; + const addInts = lib.lookup(AddInts, "addInts").?; + std.debug.assert(addInts(12, 34) == 46); - const result = addFn(12, 34); - std.debug.assert(result == 46); + const FortyTwo = *const fn () callconv(.c) i32; + const fortyTwo = lib.lookup(FortyTwo, "fortyTwo").?; + std.debug.assert(fortyTwo() == 42); } diff --git a/test/standalone/run_args/build.zig b/test/standalone/run_args/build.zig new file mode 100644 index 0000000000000000000000000000000000000000..fdc3c1f0237743329edaaf7b0c15f8c4ea8a134c --- /dev/null +++ b/test/standalone/run_args/build.zig @@ -0,0 +1,160 @@ +const std = @import("std"); + +/// Tests that args are passed to run steps correctly. +/// +/// Note that when `make_absolute` is true we make sure the resulting path argument is absolute, but +/// when it is false we allow either absolute or relative paths. This is because the maker receives +/// absolute paths when build is run from anywhere other than the build root. +pub fn build(b: *std.Build) !void { + const step = b.step("test", "Run artifact args standalone test cases"); + b.default_step = step; + + const exe = b.addExecutable(.{ + .name = "exe", + .root_module = b.createModule(.{ + .root_source_file = b.path("main.zig"), + .target = b.graph.host, + }), + }); + + // Arg + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + run.addArg("arg1"); + run.expectStdErrEqual("arg1\n"); + } + + // Args + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + run.addArgs(&.{ "arg1", "arg2" }); + run.expectStdErrEqual("arg1\narg2\n"); + } + + // Artifact Args + { + // Absolute + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addArtifactArg2(exe, .{ .prefix = "path^", .make_absolute = true, .suffix = "$" }); + run.expectStdErrMatch("abs exe"); + } + // Relative + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addArtifactArg2(exe, .{ .prefix = "path^", .make_absolute = false, .suffix = "$" }); + run.expectStdErrMatch("exe\n"); + } + } + + // File Args + { + const write_files = b.addWriteFiles(); + const file = write_files.add("file", ""); + + // Absolute + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addFileArg2(file, .{ .prefix = "path^", .make_absolute = true, .suffix = "$" }); + run.expectStdErrEqual("abs file\n"); + } + // Relative + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addFileArg2(file, .{ .prefix = "path^", .make_absolute = false, .suffix = "$" }); + run.expectStdErrMatch("file\n"); + } + } + + // File Content + { + const write_files = b.addWriteFiles(); + const file = write_files.add("file", "foo bar baz"); + + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addFileContentArg2(file, .{ .prefix = "content-prefix ", .suffix = " content-suffix" }); + run.expectStdErrEqual("content-prefix foo bar baz content-suffix\n"); + } + + // Output File Args + { + // Absolute + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addOutputFileArg2("output-file", .{ .prefix = "path^", .make_absolute = true, .suffix = "$" }); + run.expectStdErrEqual("abs output-file\n"); + } + // Relative + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addOutputFileArg2("output-file", .{ .prefix = "path^", .make_absolute = false, .suffix = "$" }); + run.expectStdErrMatch("output-file\n"); + } + } + + // Output Directory Args + { + // Absolute + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addOutputDirectoryArg2("output-dir", .{ .prefix = "path^", .make_absolute = true, .suffix = "$" }); + run.expectStdErrEqual("abs output-dir\n"); + } + // Relative + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addOutputDirectoryArg2("output-dir", .{ .prefix = "path^", .make_absolute = false, .suffix = "$" }); + run.expectStdErrMatch("output-dir\n"); + } + } + + // Directory Args + { + const write_files = b.addWriteFiles(); + const directory = try write_files.getDirectory().join(b.graph.arena, "dir"); + + // Absolute + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addDirectoryArg2(directory, .{ .prefix = "path^", .make_absolute = true, .suffix = "$" }); + run.expectStdErrEqual("abs dir\n"); + } + // Relative + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addDirectoryArg2(directory, .{ .prefix = "path^", .make_absolute = false, .suffix = "$" }); + run.expectStdErrMatch("dir\n"); + } + } + + // Dep File Args + { + // Absolute + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addDepFileOutputArg2("deps.d", .{ .prefix = "path^", .make_absolute = true, .suffix = "$" }); + run.expectStdErrEqual("abs deps.d\n"); + } + // Relative + { + const run = b.addRunArtifact(exe); + step.dependOn(&run.step); + _ = run.addDepFileOutputArg2("deps.d", .{ .prefix = "path^", .make_absolute = false, .suffix = "$" }); + run.expectStdErrMatch("deps.d\n"); + } + } +} diff --git a/test/standalone/run_args/main.zig b/test/standalone/run_args/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..008f9dd57676baf6d8d960b796a1972aed2c672f --- /dev/null +++ b/test/standalone/run_args/main.zig @@ -0,0 +1,32 @@ +const std = @import("std"); + +pub fn main(init: std.process.Init) !void { + const io = init.io; + const arena = init.arena.allocator(); + + var iter = try init.minimal.args.iterateAllocator(arena); + std.debug.assert(iter.skip()); + while (iter.next()) |arg| { + const path_prefix = "path^"; + const path_suffix = "$"; + if (std.mem.startsWith(u8, arg, path_prefix) and std.mem.endsWith(u8, arg, path_suffix)) { + // If we're a path, log whether we're absolute or relative, and log the basename + const path = arg[path_prefix.len..][0 .. arg.len - path_prefix.len - path_suffix.len]; + if (std.fs.path.isAbsolute(path)) { + std.debug.print("abs ", .{}); + } else { + std.debug.print("rel ", .{}); + } + std.debug.print("{s}\n", .{std.fs.path.basename(path)}); + + // Create an empty dep file if necessary + if (std.mem.endsWith(u8, path, ".d")) { + const file = try std.Io.Dir.cwd().createFile(io, path, .{}); + defer file.close(io); + } + } else { + // If it's not a path, log the arg as is + std.debug.print("{s}\n", .{arg}); + } + } +} diff --git a/test/standalone/shared_library/build.zig b/test/standalone/shared_library/build.zig index 444f5fd7bc7d2415a309958671b5c565383f52cd..20b9df685f8b58798eec82a8d2559b07689e66e4 100644 --- a/test/standalone/shared_library/build.zig +++ b/test/standalone/shared_library/build.zig @@ -7,11 +7,47 @@ pub fn build(b: *std.Build) void { const optimize: std.builtin.OptimizeMode = .Debug; const target = b.standardTargetOptions(.{}); - const exe_names: []const []const u8 = &.{ "test", "test-dync" }; - const lib_names: []const []const u8 = &.{ "mathtest", "mathtest-dync" }; - const lib_link_libc: []const bool = &.{ false, true }; + const exe_names: []const []const u8 = &.{ + "test", + "test-dync", + "test-no-llvm", + "test-no-llvm-dync", + "test-exe-no-llvm", + "test-dync-exe-no-llvm", + "test-no-llvm-exe-no-llvm", + "test-no-llvm-dync-exe-no-llvm", + }; + const lib_names: []const []const u8 = &.{ + "mathtest", + "mathtest-dync", + "mathtest-no-llvm", + "mathtest-no-llvm-dync", + "mathtest-exe-no-llvm", + "mathtest-dync-exe-no-llvm", + "mathtest-no-llvm-exe-no-llvm", + "mathtest-no-llvm-dync-exe-no-llvm", + }; + const lib_link_libc: []const bool = &.{ false, true, false, true, false, true, false, true }; + const lib_use_llvm: []const bool = &.{ true, true, false, false, true, true, false, false }; + const exe_use_llvm: []const bool = &.{ true, true, true, true, false, false, false, false }; + + for ( + exe_names, + lib_names, + lib_link_libc, + lib_use_llvm, + exe_use_llvm, + ) |exe_name, lib_name, dyn_libc, lib_llvm, exe_llvm| { + const no_llvm = !lib_llvm or !exe_llvm; + if (no_llvm and target.result.os.tag == .macos) continue; // TODO + if (no_llvm and target.result.os.tag == .freebsd) continue; // TODO + if (no_llvm and target.result.os.tag == .netbsd) continue; // TODO + if (no_llvm and target.result.os.tag == .openbsd) continue; // TODO + if (no_llvm and target.result.cpu.arch == .aarch64) continue; // TODO + if (no_llvm and target.result.cpu.arch == .loongarch64) continue; // TODO + if (no_llvm and target.result.cpu.arch == .powerpc64le) continue; // TODO + if (no_llvm and target.result.cpu.arch == .s390x) continue; // TODO - for (exe_names, lib_names, lib_link_libc) |exe_name, lib_name, dyn_libc| { const lib = b.addLibrary(.{ .linkage = .dynamic, .name = lib_name, @@ -22,6 +58,7 @@ pub fn build(b: *std.Build) void { .optimize = optimize, .link_libc = dyn_libc, }), + .use_llvm = lib_llvm, }); const exe = b.addExecutable(.{ @@ -32,6 +69,7 @@ pub fn build(b: *std.Build) void { .optimize = optimize, .link_libc = true, }), + .use_llvm = exe_llvm, }); exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), diff --git a/test/standalone/shared_library/mathtest.zig b/test/standalone/shared_library/mathtest.zig index a04ec1544dc82e27afb137de2672a48d726a72fc..9c33bf8370c44ea1ec3b59fcd24f1d5a1765608a 100644 --- a/test/standalone/shared_library/mathtest.zig +++ b/test/standalone/shared_library/mathtest.zig @@ -1,3 +1,5 @@ +export var exported_var: i32 = 9999; + export fn add(a: i32, b: i32) i32 { return a + b; } diff --git a/test/standalone/shared_library/test.c b/test/standalone/shared_library/test.c index f178f78b4583339b65ae51a14fdb58830b0015db..b1b3672d0a48c9c521e98dbdf14f1f52610a9655 100644 --- a/test/standalone/shared_library/test.c +++ b/test/standalone/shared_library/test.c @@ -7,7 +7,16 @@ #include int32_t add(int32_t a, int32_t b); +#if _WIN32 +#define IMPORT __declspec(dllimport) +#else +#define IMPORT +#endif + +extern IMPORT int32_t exported_var; + int main(int argc, char **argv) { assert(add(42, 1337) == 1379); + assert(exported_var == 9999); return 0; } diff --git a/test/standalone/static_c_lib/build.zig b/test/standalone/static_c_lib/build.zig index 4bed5cdefa5f496c702b60a051646d9e8979b177..5b35871dceca1a00abbac632adab8f0edc4add69 100644 --- a/test/standalone/static_c_lib/build.zig +++ b/test/standalone/static_c_lib/build.zig @@ -5,26 +5,76 @@ pub fn build(b: *std.Build) void { b.default_step = test_step; const optimize: std.builtin.OptimizeMode = .Debug; + const target = b.standardTargetOptions(.{}); - const foo = b.addLibrary(.{ - .linkage = .static, - .name = "foo", - .root_module = b.createModule(.{ - .root_source_file = null, - .optimize = optimize, - .target = b.graph.host, - }), - }); - foo.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &[_][]const u8{} }); - foo.root_module.addIncludePath(b.path(".")); + const exe_names: []const []const u8 = &.{ + "test", + "test-dync", + "test-no-llvm", + "test-no-llvm-dync", + "test-exe-no-llvm", + "test-dync-exe-no-llvm", + "test-no-llvm-exe-no-llvm", + "test-no-llvm-dync-exe-no-llvm", + }; + const lib_names: []const []const u8 = &.{ + "foo", + "foo-dync", + "foo-no-llvm", + "foo-no-llvm-dync", + "foo-exe-no-llvm", + "foo-dync-exe-no-llvm", + "foo-no-llvm-exe-no-llvm", + "foo-no-llvm-dync-exe-no-llvm", + }; + const lib_link_libc: []const bool = &.{ false, true, false, true, false, true, false, true }; + const lib_use_llvm: []const bool = &.{ true, true, false, false, true, true, false, false }; + const exe_use_llvm: []const bool = &.{ true, true, true, true, false, false, false, false }; - const test_exe = b.addTest(.{ .root_module = b.createModule(.{ - .root_source_file = b.path("foo.zig"), - .target = b.graph.host, - .optimize = optimize, - }) }); - test_exe.root_module.linkLibrary(foo); - test_exe.root_module.addIncludePath(b.path(".")); + for ( + exe_names, + lib_names, + lib_link_libc, + lib_use_llvm, + exe_use_llvm, + ) |exe_name, lib_name, dyn_libc, lib_llvm, exe_llvm| { + const no_llvm = !lib_llvm or !exe_llvm; + if (no_llvm and target.result.os.tag == .macos) continue; // TODO + if (no_llvm and target.result.os.tag == .freebsd) continue; // TODO + if (no_llvm and target.result.os.tag == .netbsd) continue; // TODO + if (no_llvm and target.result.os.tag == .openbsd) continue; // TODO + if (no_llvm and target.result.cpu.arch == .aarch64) continue; // TODO + if (no_llvm and target.result.cpu.arch == .loongarch64) continue; // TODO + if (no_llvm and target.result.cpu.arch == .powerpc64le) continue; // TODO + if (no_llvm and target.result.cpu.arch == .s390x) continue; // TODO - test_step.dependOn(&b.addRunArtifact(test_exe).step); + const foo = b.addLibrary(.{ + .linkage = .static, + .name = lib_name, + .root_module = b.createModule(.{ + .root_source_file = null, + .optimize = optimize, + .target = target, + .link_libc = dyn_libc, + }), + .use_llvm = lib_llvm, + }); + foo.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &[_][]const u8{} }); + foo.root_module.addIncludePath(b.path(".")); + + const test_exe = b.addTest(.{ + .name = exe_name, + .root_module = b.createModule(.{ + .root_source_file = b.path("foo.zig"), + .target = target, + .optimize = optimize, + .link_libc = dyn_libc, + }), + .use_llvm = exe_llvm, + }); + test_exe.root_module.linkLibrary(foo); + test_exe.root_module.addIncludePath(b.path(".")); + + test_step.dependOn(&b.addRunArtifact(test_exe).step); + } } diff --git a/test/tests.zig b/test/tests.zig index 9136d1434f11e13087d163a31058e6ae5f5ba895..6166444b9b33bdcafc034cfb26bc55aa9c48a916 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -10,6 +10,7 @@ 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"); // Implementations pub const ErrorTracesContext = @import("src/ErrorTrace.zig"); @@ -17,6 +18,7 @@ pub const StackTracesContext = @import("src/StackTrace.zig"); pub const DebuggerContext = @import("src/Debugger.zig"); pub const LlvmIrContext = @import("src/LlvmIr.zig"); pub const LibcContext = @import("src/Libc.zig"); +pub const LinkContext = @import("src/Link.zig"); const ModuleTestTarget = struct { linkage: ?std.builtin.LinkMode = null, @@ -272,36 +274,34 @@ const module_test_targets = blk: { }, .link_libc = true, }, - // Crashes in weird ways when applying relocations. - // .{ - // .target = .{ - // .cpu_arch = .arm, - // .os_tag = .linux, - // .abi = .musleabi, - // }, - // .linkage = .dynamic, - // .link_libc = true, - // .extra_target = true, - // }, + .{ + .target = .{ + .cpu_arch = .arm, + .os_tag = .linux, + .abi = .musleabi, + }, + .linkage = .dynamic, + .link_libc = true, + .extra_target = true, + }, + .{ + .target = .{ + .cpu_arch = .arm, + .os_tag = .linux, + .abi = .musleabihf, + }, + .link_libc = true, + }, .{ .target = .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .musleabihf, }, + .linkage = .dynamic, .link_libc = true, + .extra_target = true, }, - // Crashes in weird ways when applying relocations. - // .{ - // .target = .{ - // .cpu_arch = .arm, - // .os_tag = .linux, - // .abi = .musleabihf, - // }, - // .linkage = .dynamic, - // .link_libc = true, - // .extra_target = true, - // }, .{ .target = .{ .cpu_arch = .arm, @@ -623,6 +623,13 @@ const module_test_targets = blk: { .abi = .none, }, }, + .{ + .target = .{ + .cpu_arch = .mips64, + .os_tag = .linux, + .abi = .abin32, + }, + }, .{ .target = .{ .cpu_arch = .mips64, @@ -648,7 +655,6 @@ const module_test_targets = blk: { .abi = .muslabin32, }, .link_libc = true, - .extra_target = true, }, .{ .target = .{ @@ -675,7 +681,6 @@ const module_test_targets = blk: { .abi = .gnuabin32, }, .link_libc = true, - .extra_target = true, }, .{ @@ -685,6 +690,14 @@ const module_test_targets = blk: { .abi = .none, }, }, + .{ + .target = .{ + .cpu_arch = .mips64el, + .os_tag = .linux, + .abi = .abin32, + }, + .extra_target = true, + }, .{ .target = .{ .cpu_arch = .mips64el, @@ -1147,6 +1160,59 @@ const module_test_targets = blk: { .use_llvm = true, .use_lld = true, }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .x32, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .musl, + }, + .link_libc = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .musl, + }, + .linkage = .dynamic, + .link_libc = true, + .extra_target = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .musl, + }, + .link_libc = true, + .use_llvm = true, + .use_lld = false, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .muslx32, + }, + .link_libc = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .muslx32, + }, + .linkage = .dynamic, + .link_libc = true, + .extra_target = true, + }, .{ .target = .{ .cpu_arch = .x86_64, @@ -1162,54 +1228,6 @@ const module_test_targets = blk: { .abi = .gnux32, }, .link_libc = true, - .extra_target = true, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .musl, - }, - .link_libc = true, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .musl, - }, - .linkage = .dynamic, - .link_libc = true, - .extra_target = true, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .muslx32, - }, - .link_libc = true, - .extra_target = true, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .muslx32, - }, - .linkage = .dynamic, - .link_libc = true, - .extra_target = true, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .musl, - }, - .link_libc = true, - .use_llvm = true, - .use_lld = false, }, // Darwin Targets @@ -2002,12 +2020,133 @@ const c_abi_targets = blk: { .abi = .gnu, }, }, + .{ .target = .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu, }, + .use_llvm = false, + .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v2 }, + .os_tag = .windows, + .abi = .gnu, + }, + .use_llvm = false, + .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v3 }, + .os_tag = .windows, + .abi = .gnu, + }, + .use_llvm = false, + .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"}, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + .use_llvm = true, + }, + }; +}; + +const LinkTarget = struct { + target: std.Target.Query = .{}, + optimize_mode: std.builtin.OptimizeMode = .Debug, + link_libc: bool = false, + use_llvm: bool = false, + use_lld: bool = false, +}; + +const link_targets = blk: { + @setEvalBranchQuota(30000); + break :blk [_]LinkTarget{ + // Native Targets + + // .{ + // .use_llvm = true, + // }, + + // Windows Targets + + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + .link_libc = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + .use_llvm = true, + .use_lld = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + .link_libc = true, + .use_llvm = true, + .use_lld = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .msvc, + }, + .link_libc = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .msvc, + }, + .use_llvm = true, + .use_lld = true, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .msvc, + }, + .link_libc = true, + .use_llvm = true, + .use_lld = true, }, }; }; @@ -3036,6 +3175,77 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step { return step; } +const LinkTestOptions = struct { + test_target_filters: []const []const u8, + test_filters: []const []const u8, + optimize_modes: []const OptimizeMode, + skip_non_native: bool, + skip_windows: bool, + skip_llvm: bool, + max_rss: usize, +}; + +pub fn addLinkTests(b: *std.Build, options: LinkTestOptions) *Step { + const step = b.step("test-link", "Run the linker tests"); + const update_snapshots = b.option( + bool, + "link-snapshot-update", + "Update linker test snapshots in-place instead of testing against them", + ) orelse false; + + for (link_targets) |link_target| { + if (options.skip_non_native and !link_target.target.isNative()) continue; + if (options.skip_windows and link_target.target.os_tag == .windows) continue; + + const resolved_target = b.resolveTargetQuery(link_target.target); + const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"); + const target = &resolved_target.result; + + if (options.test_target_filters.len > 0) { + for (options.test_target_filters) |filter| { + if (std.mem.indexOf(u8, triple_txt, filter) != null) break; + } else continue; + } + + for (options.optimize_modes) |optimize_mode| { + if (link_target.optimize_mode != optimize_mode) continue; + if (link_target.link_libc and target.abi == .msvc and b.graph.host.result.os.tag != .windows) continue; + const would_use_llvm = wouldUseLlvm(link_target.use_llvm, link_target.target, optimize_mode); + if (options.skip_llvm and would_use_llvm) continue; + + const opt_update_step = if (update_snapshots) update: { + const update_step = Step.UpdateSourceFiles.create(b); + step.dependOn(&update_step.step); + break :update update_step; + } else null; + + var context: LinkContext = .{ + .b = b, + .step = step, + .optimize = optimize_mode, + .target = resolved_target, + .target_desc = std.fmt.allocPrint(b.allocator, "{s}-{t}{s}{s}{s}", .{ + target.zigTriple(b.allocator) catch @panic("OOM"), + optimize_mode, + if (link_target.use_llvm) "-llvm" else "", + if (link_target.use_lld) "-lld" else "", + if (link_target.link_libc) "-libc" else "", + }) catch @panic("OOM"), + .use_llvm = link_target.use_llvm, + .use_lld = link_target.use_lld, + .link_libc = link_target.link_libc, + .test_filters = options.test_filters, + .update_step = opt_update_step, + .updated_snapshots = .empty, + .max_rss = options.max_rss, + }; + + link.addCases(&context); + } + } + return step; +} + pub fn addCases( b: *std.Build, parent_step: *Step, diff --git a/tools/check_mingw.zig b/tools/check_mingw.zig new file mode 100644 index 0000000000000000000000000000000000000000..c67b3f2599efaa9592cc238b866a44d2b3e1bf45 --- /dev/null +++ b/tools/check_mingw.zig @@ -0,0 +1,124 @@ +const std = @import("std"); +const Io = std.Io; +const Dir = Io.Dir; +const Preprocessor = @import("preprocessor"); + +pub fn main(init: std.process.Init) !void { + const arena = init.arena.allocator(); + const io = init.io; + const args = try init.minimal.args.toSlice(arena); + + const zig_src_mingw_lib_path = args[1]; + + const mingw_include_path = try Dir.path.join(arena, &.{ + zig_src_mingw_lib_path, "def-include", + }); + const mingw_libcommon_path = try Dir.path.join(arena, &.{ + zig_src_mingw_lib_path, "lib-common", + }); + + var mingw_libcommon_dir = Dir.cwd().openDir(io, mingw_libcommon_path, .{ .iterate = true }) catch |err| { + std.log.err("unable to open directory {s}: {t}", .{ mingw_libcommon_path, err }); + std.process.exit(1); + }; + defer mingw_libcommon_dir.close(io); + + var walker = try mingw_libcommon_dir.walk(arena); + defer walker.deinit(); + + while (try walker.next(io)) |entry| { + if (entry.kind != .file) continue; + // Only .def.in files need preprocessing + if (!std.mem.endsWith(u8, entry.basename, ".def.in")) continue; + + var fail = false; + for (&targets) |*target| { + var target_arena: std.heap.ArenaAllocator = .init(init.gpa); + defer target_arena.deinit(); + + const pp_arena = target_arena.allocator(); + const file_path = try Dir.path.join(pp_arena, &.{ mingw_libcommon_path, entry.path }); + + const aro = pp: { + const target_triple = try target.zigTriple(pp_arena); + const target_arg = try std.fmt.allocPrint(pp_arena, "--target={s}", .{target_triple}); + const result = std.process.run(pp_arena, io, .{ + .argv = &.{ + "arocc", + "-E", + target_arg, + "--no-line-commands", + "-nostdinc", + "-I", + mingw_include_path, + file_path, + }, + }) catch |err| { + std.log.err("unable to execute arocc: {t}", .{err}); + std.process.exit(1); + }; + if (result.term.exited != 0) { + std.log.err("error executing arocc: {s}", .{result.stderr}); + std.process.exit(result.term.exited); + } + break :pp result.stdout; + }; + + const native = pp: { + var aw: Io.Writer.Allocating = .init(pp_arena); + errdefer aw.deinit(); + + var pp: Preprocessor = .{ + .io = io, + .arena = pp_arena, + .include_dir = mingw_include_path, + .target = target, + }; + + pp.preprocess(file_path) catch |err| { + std.log.err("error preprocessing file {s} for target {t}: {t}", .{ entry.path, target.cpu.arch, err }); + fail = true; + continue; + }; + pp.prettyPrintTokens(&aw.writer) catch |err| { + std.log.err("error printing tokens for file {s} for target {t}: {t}", .{ entry.path, target.cpu.arch, err }); + fail = true; + continue; + }; + + break :pp try aw.toOwnedSliceSentinel(0); + }; + + try std.testing.expectEqualStrings(aro, native); + } + + if (fail) std.process.exit(1); + } +} + +const targets = [_]std.Target{ + .{ + .ofmt = .coff, + .abi = .gnu, + .os = .{ .tag = .windows, .version_range = .default(.thumb, .windows, .gnu) }, + .cpu = .{ .arch = .thumb, .model = .generic(.thumb), .features = .empty }, + }, + .{ + .ofmt = .coff, + .abi = .gnu, + .os = .{ .tag = .windows, .version_range = .default(.aarch64, .windows, .gnu) }, + .cpu = .{ .arch = .aarch64, .model = .generic(.aarch64), .features = .empty }, + }, + .{ + .ofmt = .coff, + .abi = .gnu, + .os = .{ .tag = .windows, .version_range = .default(.x86, .windows, .gnu) }, + .cpu = .{ .arch = .x86, .model = .generic(.x86), .features = .empty }, + }, + .{ + .ofmt = .coff, + .abi = .gnu, + .os = .{ .tag = .windows, .version_range = .default(.x86_64, .windows, .gnu) }, + .cpu = .{ .arch = .x86_64, .model = .generic(.x86_64), .features = .empty }, + }, +}; diff --git a/tools/dump-cov.zig b/tools/dump-cov.zig index 4a54d9f5199299a75dd8fcae46a7d3506ee53d50..c9a8aa8a32ccbe2fc063d30bda143f772bef0e19 100644 --- a/tools/dump-cov.zig +++ b/tools/dump-cov.zig @@ -67,7 +67,7 @@ pub fn main(init: std.process.Init) !void { try stdout.print("{any}\n", .{header.*}); const pcs = header.pcAddrs(); - var indexed_pcs: std.AutoArrayHashMapUnmanaged(usize, void) = .empty; + var indexed_pcs: std.array_hash_map.Auto(usize, void) = .empty; try indexed_pcs.entries.resize(arena, pcs.len); @memcpy(indexed_pcs.entries.items(.key), pcs); try indexed_pcs.reIndex(arena); diff --git a/tools/gen_spirv_spec.zig b/tools/gen_spirv_spec.zig index 57e1a64471218d40a49314a1ba44d3a6e846e43c..fbf8fa167ae6fc0ae5dcba040a87046b66d34c5c 100644 --- a/tools/gen_spirv_spec.zig +++ b/tools/gen_spirv_spec.zig @@ -13,6 +13,33 @@ const Operand = g.Operand; const ExtendedStructSet = std.StringHashMap(void); +const allowed_vendors = [_][]const u8{ + "KHR", + "EXT", +}; + +fn isAllowedCapability(name: []const u8) bool { + // core capabilities (no vendor suffix) end in a lowercase letter or digit. + const last = name[name.len - 1]; + if (std.ascii.isLower(last) or std.ascii.isDigit(last)) return true; + for (allowed_vendors) |vendor| { + if (std.mem.endsWith(u8, name, vendor)) return true; + } + return false; +} + +fn isAllowedExtension(name: []const u8) bool { + const spv_prefix = "SPV_"; + if (!std.mem.startsWith(u8, name, spv_prefix)) return false; + const tail = name[spv_prefix.len..]; + for (allowed_vendors) |vendor| { + if (std.mem.startsWith(u8, tail, vendor) and + tail.len > vendor.len and tail[vendor.len] == '_') + return true; + } + return false; +} + const Extension = struct { name: []const u8, opcode_name: []const u8, @@ -325,6 +352,43 @@ fn render( try renderOperandKinds(arena, writer, all_operand_kinds.values(), extended_structs); try renderInstructionSet(writer, registry, extensions, all_operand_kinds); + try renderExtension(arena, writer, all_operand_kinds.values()); +} + +fn renderExtension( + arena: Allocator, + writer: *std.Io.Writer, + kinds: []const OperandKind, +) !void { + try writer.writeAll( + \\pub const Extension = enum { + \\v1_0, + \\v1_1, + \\v1_2, + \\v1_3, + \\v1_4, + \\v1_5, + \\v1_6, + \\ + ); + + var seen_extensions: std.StringHashMapUnmanaged(void) = .empty; + defer seen_extensions.deinit(arena); + + for (kinds) |kind| { + if (std.mem.eql(u8, "Capability", kind.kind)) { + for (kind.enumerants.?) |enumerant| { + if (!isAllowedCapability(enumerant.enumerant)) continue; + for (enumerant.extensions) |ext| { + if (!isAllowedExtension(ext)) continue; + if (seen_extensions.contains(ext)) continue; + try seen_extensions.put(arena, ext, {}); + try writer.print("{s},\n", .{ext}); + } + } + } + } + try writer.writeAll("};\n"); } fn renderInstructionSet( @@ -687,10 +751,13 @@ fn renderValueEnum( const enum_indices = enum_map.values(); + const is_capability = std.mem.eql(u8, "Capability", enumeration.kind); + try writer.print("pub const {f} = enum(u32) {{\n", .{std.zig.fmtId(enumeration.kind)}); for (enum_indices) |i| { const enumerant = enumerants[i]; + if (is_capability and !isAllowedCapability(enumerant.enumerant)) continue; // if (enumerant.value != .int) return error.InvalidRegistry; switch (enumerant.value) { @@ -702,6 +769,8 @@ fn renderValueEnum( try writer.writeByte('\n'); for (aliases.items) |alias| { + if (is_capability and (!isAllowedCapability(enumerants[alias.enumerant].enumerant) or + !isAllowedCapability(enumerants[alias.alias].enumerant))) continue; try writer.print("pub const {f} = {f}.{f};\n", .{ formatId(enumerants[alias.enumerant].enumerant), std.zig.fmtId(enumeration.kind), @@ -709,6 +778,41 @@ fn renderValueEnum( }); } + if (is_capability) { + try writer.writeAll( + \\ + \\pub fn dependencies(self: Capability) []const Extension { + \\ return switch (self) { + ); + + for (enum_indices) |i| { + const enumerant = enumerants[i]; + if (!isAllowedCapability(enumerant.enumerant)) continue; + + // Convert version to enum. + // None is for reserved + // Example: "None" -> .v1_0 + // Example: "1.5" -> .v1_5 + const enum_version = enumerant.version.?; + const version: [4]u8 = .{ 'v', '1', '_', if (enum_version[0] == 'N') '0' else enum_version[2] }; + + try writer.print("\n.{f} => &.{{.{s},", .{ formatId(enumerant.enumerant), version }); + for (enumerant.extensions) |extension| { + if (!isAllowedExtension(extension)) continue; + try writer.print(".{s},", .{extension}); + } + try writer.writeAll("},"); + } + + try writer.writeAll( + \\}; + \\} + \\}; + \\ + ); + return; + } + if (!extended_structs.contains(enumeration.kind)) { try writer.writeAll("};\n"); return; diff --git a/tools/update_cpu_features.zig b/tools/update_cpu_features.zig index ea6a659507a972c3c95492817ac6779a4ced05ba..42432c0c36f48c831524773b882d1da75caaa723 100644 --- a/tools/update_cpu_features.zig +++ b/tools/update_cpu_features.zig @@ -1,4 +1,5 @@ const builtin = @import("builtin"); +const spirv_spec = @import("spirv_spec"); const std = @import("std"); const Io = std.Io; @@ -49,6 +50,43 @@ const ArchTarget = struct { branch_quota: ?usize = null, }; +const spirv_extra_features = blk: { + const caps_info = @typeInfo(spirv_spec.Capability).@"enum"; + const exts_info = @typeInfo(spirv_spec.Extension).@"enum"; + const caps_len = caps_info.field_names.len; + const exts_len = exts_info.field_names.len; + + var features: [caps_len + exts_len]Feature = undefined; + for ( + caps_info.field_names, + caps_info.field_values, + features[0..caps_len], + ) |name, value, *feature| { + feature.* = .{ + .zig_name = name, + .desc = "Enable " ++ name ++ " capability", + .deps = &struct { + const extensions = spirv_spec.Capability.dependencies(@enumFromInt(value)); + const deps: [extensions.len][]const u8 = inner: { + var out: [extensions.len][]const u8 = undefined; + for (extensions, 0..) |ext, i| out[i] = @tagName(ext); + break :inner out; + }; + }.deps, + }; + } + + for (exts_info.field_names, features[caps_len..]) |name, *feature| { + feature.* = .{ + .zig_name = name, + .desc = "Enable " ++ name ++ " extension", + .deps = &.{}, + }; + } + + break :blk features; +}; + const targets = [_]ArchTarget{ .{ .zig_name = "aarch64", @@ -1358,6 +1396,15 @@ const targets = [_]ArchTarget{ }, }, .extra_cpus = &.{ + .{ + .llvm_name = null, + .zig_name = "r3000a", + .features = &.{ + "mips1", + "soft_float", + "notraps", + }, + }, .{ .llvm_name = null, .zig_name = "allegrex", @@ -1434,83 +1481,7 @@ const targets = [_]ArchTarget{ .td_name = "SPIRV", }, .branch_quota = 2000, - .extra_features = &.{ - .{ - .zig_name = "v1_0", - .desc = "Enable version 1.0", - .deps = &.{}, - }, - .{ - .zig_name = "v1_1", - .desc = "Enable version 1.1", - .deps = &.{"v1_0"}, - }, - .{ - .zig_name = "v1_2", - .desc = "Enable version 1.2", - .deps = &.{"v1_1"}, - }, - .{ - .zig_name = "v1_3", - .desc = "Enable version 1.3", - .deps = &.{"v1_2"}, - }, - .{ - .zig_name = "v1_4", - .desc = "Enable version 1.4", - .deps = &.{"v1_3"}, - }, - .{ - .zig_name = "v1_5", - .desc = "Enable version 1.5", - .deps = &.{"v1_4"}, - }, - .{ - .zig_name = "v1_6", - .desc = "Enable version 1.6", - .deps = &.{"v1_5"}, - }, - .{ - .zig_name = "int64", - .desc = "Enable Int64 capability", - .deps = &.{"v1_0"}, - }, - .{ - .zig_name = "float16", - .desc = "Enable Float16 capability", - .deps = &.{"v1_0"}, - }, - .{ - .zig_name = "float64", - .desc = "Enable Float64 capability", - .deps = &.{"v1_0"}, - }, - .{ - .zig_name = "storage_push_constant16", - .desc = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability", - .deps = &.{"v1_3"}, - }, - .{ - .zig_name = "arbitrary_precision_integers", - .desc = "Enable SPV_INTEL_arbitrary_precision_integers extension and the ArbitraryPrecisionIntegersINTEL capability", - .deps = &.{"v1_5"}, - }, - .{ - .zig_name = "generic_pointer", - .desc = "Enable GenericPointer capability", - .deps = &.{"v1_0"}, - }, - .{ - .zig_name = "vector16", - .desc = "Enable Vector16 capability", - .deps = &.{"v1_0"}, - }, - .{ - .zig_name = "variable_pointers", - .desc = "Enable SPV_KHR_variable_pointers extension and the VariablePointers capability", - .deps = &.{"v1_0"}, - }, - }, + .extra_features = &spirv_extra_features, .extra_cpus = &.{ .{ .llvm_name = null, diff --git a/tools/update_crc_catalog.zig b/tools/update_crc_catalog.zig index 57eedf375b29c1195dcfbf4dcea1f42f1235a192..55f51ce92b4f4a36f51fd176b681487de16d1621 100644 --- a/tools/update_crc_catalog.zig +++ b/tools/update_crc_catalog.zig @@ -2,7 +2,6 @@ const std = @import("std"); const Io = std.Io; const Dir = std.Io.Dir; const mem = std.mem; -const ascii = std.ascii; const catalog_txt = @embedFile("crc/catalog.txt"); @@ -32,6 +31,7 @@ fn @"i like cheese"(arena: std.mem.Allocator, io: Io, args: []const []const u8) var zig_code_file = try hash_target_dir.createFile(io, "crc.zig", .{}); defer zig_code_file.close(io); + var zig_code_file_buffer: [4096]u8 = undefined; var zig_code_file_writer = zig_code_file.writer(io, &zig_code_file_buffer); const code_writer = &zig_code_file_writer.interface; @@ -39,23 +39,13 @@ fn @"i like cheese"(arena: std.mem.Allocator, io: Io, args: []const []const u8) try code_writer.writeAll( \\//! This file is auto-generated by tools/update_crc_catalog.zig. \\ - \\const impl = @import("crc/impl.zig"); - \\ - \\pub const Crc = impl.Crc; - \\pub const Polynomial = impl.Polynomial; - \\pub const Crc32WithPoly = impl.Crc32WithPoly; - \\pub const Crc32SmallWithPoly = impl.Crc32SmallWithPoly; - \\ - \\pub const Crc32 = Crc32IsoHdlc; - \\ - \\test { - \\ _ = @import("crc/test.zig"); - \\} + \\const builtin = @import("builtin"); \\ ); var zig_test_file = try crc_target_dir.createFile(io, "test.zig", .{}); defer zig_test_file.close(io); + var zig_test_file_buffer: [4096]u8 = undefined; var zig_test_file_writer = zig_test_file.writer(io, &zig_test_file_buffer); const test_writer = &zig_test_file_writer.interface; @@ -69,24 +59,24 @@ fn @"i like cheese"(arena: std.mem.Allocator, io: Io, args: []const []const u8) \\const crc = @import("../crc.zig"); \\ \\test "crc32 ieee regression" { - \\ const crc32 = crc.Crc32IsoHdlc; - \\ try testing.expectEqual(crc32.hash(""), 0x00000000); - \\ try testing.expectEqual(crc32.hash("a"), 0xe8b7be43); - \\ try testing.expectEqual(crc32.hash("abc"), 0x352441c2); + \\ const Crc = crc.@"CRC-32/ISO-HDLC"; + \\ try testing.expectEqual(Crc.hash(""), 0x00000000); + \\ try testing.expectEqual(Crc.hash("a"), 0xe8b7be43); + \\ try testing.expectEqual(Crc.hash("abc"), 0x352441c2); \\} \\ \\test "crc32 castagnoli regression" { - \\ const crc32 = crc.Crc32Iscsi; - \\ try testing.expectEqual(crc32.hash(""), 0x00000000); - \\ try testing.expectEqual(crc32.hash("a"), 0xc1d04330); - \\ try testing.expectEqual(crc32.hash("abc"), 0x364b3fb7); + \\ const Crc = crc.@"CRC-32/ISCSI"; + \\ try testing.expectEqual(Crc.hash(""), 0x00000000); + \\ try testing.expectEqual(Crc.hash("a"), 0xc1d04330); + \\ try testing.expectEqual(Crc.hash("abc"), 0x364b3fb7); \\} \\ \\test "crc32 koopman regression" { - \\ const crc32 = crc.Koopman; - \\ try testing.expectEqual(crc32.hash(""), 0x00000000); - \\ try testing.expectEqual(crc32.hash("a"), 0x0da2aa8a); - \\ try testing.expectEqual(crc32.hash("abc"), 0xba2322ac); + \\ const Crc = crc.@"CRC-32/KOOPMAN"; + \\ try testing.expectEqual(Crc.hash(""), 0x00000000); + \\ try testing.expectEqual(Crc.hash("a"), 0x0da2aa8a); + \\ try testing.expectEqual(Crc.hash("abc"), 0xba2322ac); \\} \\ ); @@ -135,59 +125,154 @@ fn @"i like cheese"(arena: std.mem.Allocator, io: Io, args: []const []const u8) } } - const snakecase = try ascii.allocLowerString(arena, name); - defer arena.free(snakecase); - - _ = mem.replace(u8, snakecase, "-", "_", snakecase); - _ = mem.replace(u8, snakecase, "/", "_", snakecase); - - var buf = try std.array_list.Managed(u8).initCapacity(arena, snakecase.len); - defer buf.deinit(); - - var prev: u8 = 0; - for (snakecase, 0..) |c, i| { - if (c == '_') { - // do nothing - } else if (i == 0) { - buf.appendAssumeCapacity(ascii.toUpper(c)); - } else if (prev == '_') { - buf.appendAssumeCapacity(ascii.toUpper(c)); - } else { - buf.appendAssumeCapacity(c); - } - prev = c; + if (mem.eql(u8, name, "CRC-32/ISCSI")) { + try code_writer.print( + \\ + \\pub const {f} = if (builtin.cpu.hasAll(.x86, &.{{ .@"64bit", .crc32 }})) + \\ @import("crc/Crc32c.zig") + \\else + \\ Generic(u{s}, .{{ + \\ .polynomial = {s}, + \\ .initial = {s}, + \\ .reflect_input = {s}, + \\ .reflect_output = {s}, + \\ .xor_output = {s}, + \\ }}); + \\ + , .{ std.zig.fmtId(name), width, poly, init, refin, refout, xorout }); + } else { + try code_writer.print( + \\ + \\pub const {f} = Generic(u{s}, .{{ + \\ .polynomial = {s}, + \\ .initial = {s}, + \\ .reflect_input = {s}, + \\ .reflect_output = {s}, + \\ .xor_output = {s}, + \\}}); + \\ + , .{ std.zig.fmtId(name), width, poly, init, refin, refout, xorout }); } - const camelcase = buf.items; - - try code_writer.writeAll(try std.fmt.allocPrint(arena, - \\ - \\pub const {s} = Crc(u{s}, .{{ - \\ .polynomial = {s}, - \\ .initial = {s}, - \\ .reflect_input = {s}, - \\ .reflect_output = {s}, - \\ .xor_output = {s}, - \\}}); - \\ - , .{ camelcase, width, poly, init, refin, refout, xorout })); - - try test_writer.writeAll(try std.fmt.allocPrint(arena, + try test_writer.print( \\ \\test "{0s}" {{ - \\ const {1s} = crc.{1s}; + \\ const Crc = crc.{1f}; \\ - \\ try testing.expectEqual(@as(u{2s}, {3s}), {1s}.hash("123456789")); + \\ try testing.expectEqual(@as(u{2s}, {3s}), Crc.hash("123456789")); \\ - \\ var c = {1s}.init(); + \\ var c = Crc.init(); \\ c.update("1234"); \\ c.update("56789"); \\ try testing.expectEqual(@as(u{2s}, {3s}), c.final()); \\}} \\ - , .{ name, camelcase, width, check })); + , .{ name, std.zig.fmtId(name), width, check }); } + try code_writer.writeAll( + \\ + \\pub fn Algorithm(comptime W: type) type { + \\ return struct { + \\ polynomial: W, + \\ initial: W, + \\ reflect_input: bool, + \\ reflect_output: bool, + \\ xor_output: W, + \\ }; + \\} + \\ + \\pub fn Generic(comptime W: type, comptime algorithm: Algorithm(W)) type { + \\ return struct { + \\ const Self = @This(); + \\ const I = if (@bitSizeOf(W) < 8) u8 else W; + \\ const lookup_table = blk: { + \\ @setEvalBranchQuota(2500); + \\ const poly = reflect(algorithm.polynomial); + \\ var table: [256]I = undefined; + \\ for (&table, 0..) |*e, i| { + \\ var crc: I = i; + \\ if (algorithm.reflect_input) { + \\ var j: usize = 0; + \\ while (j < 8) : (j += 1) { + \\ crc = (crc >> 1) ^ ((crc & 1) * poly); + \\ } + \\ } else { + \\ crc <<= @bitSizeOf(I) - 8; + \\ var j: usize = 0; + \\ while (j < 8) : (j += 1) { + \\ crc = (crc << 1) ^ (((crc >> (@bitSizeOf(I) - 1)) & 1) * poly); + \\ } + \\ } + \\ e.* = crc; + \\ } + \\ break :blk table; + \\ }; + \\ + \\ crc: I, + \\ + \\ pub fn init() Self { + \\ const initial = reflect(algorithm.initial); + \\ return .{ .crc = initial }; + \\ } + \\ + \\ inline fn tableEntry(index: I) I { + \\ const short: u8 = @truncate(index); + \\ return lookup_table[short]; + \\ } + \\ + \\ pub fn update(self: *Self, bytes: []const u8) void { + \\ var i: usize = 0; + \\ if (@bitSizeOf(I) <= 8) { + \\ while (i < bytes.len) : (i += 1) { + \\ self.crc = tableEntry(self.crc ^ bytes[i]); + \\ } + \\ } else if (algorithm.reflect_input) { + \\ while (i < bytes.len) : (i += 1) { + \\ const table_index = self.crc ^ bytes[i]; + \\ self.crc = tableEntry(table_index) ^ (self.crc >> 8); + \\ } + \\ } else { + \\ while (i < bytes.len) : (i += 1) { + \\ const table_index = (self.crc >> (@bitSizeOf(I) - 8)) ^ bytes[i]; + \\ self.crc = tableEntry(table_index) ^ (self.crc << 8); + \\ } + \\ } + \\ } + \\ + \\ pub fn final(self: Self) W { + \\ var c = self.crc; + \\ if (algorithm.reflect_input != algorithm.reflect_output) { + \\ c = @bitReverse(c); + \\ } + \\ if (!algorithm.reflect_output) { + \\ c >>= @bitSizeOf(I) - @bitSizeOf(W); + \\ } + \\ return @intCast(c ^ algorithm.xor_output); + \\ } + \\ + \\ pub fn hash(bytes: []const u8) W { + \\ var c = Self.init(); + \\ c.update(bytes); + \\ return c.final(); + \\ } + \\ + \\ fn reflect(x: I) I { + \\ const offset = @bitSizeOf(I) - @bitSizeOf(W); + \\ if (algorithm.reflect_input) + \\ return @bitReverse(x) >> offset + \\ else + \\ return x << offset; + \\ } + \\ }; + \\} + \\ + \\test { + \\ _ = @import("crc/test.zig"); + \\} + \\ + ); + try code_writer.flush(); try test_writer.flush(); }