diff --git a/doc/langref.html.in b/doc/langref.html.in
index e8189e5c42..de26c7d643 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -3215,7 +3215,7 @@ fn createFoo(param: i32) !Foo {
to increase their development pace.
- Error Return Traces are enabled by default in {#link|Debug#} and {#link|ReleaseSafe#} builds and disabled by default in {#link|ReleaseFast#} and {#link|ReleaseSmall#} builds.
+ Error Return Traces are enabled by default in {#link|Debug#} builds and disabled by default in {#link|ReleaseFast#}, {#link|ReleaseSafe#} and {#link|ReleaseSmall#} builds.
There are a few ways to activate this error return tracing feature:
@@ -4319,7 +4319,7 @@ comptime {
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ an integer, an enum, or a packed struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
{#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}
@@ -4333,7 +4333,7 @@ comptime {
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ an integer, an enum, or a packed struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.
@@ -4347,7 +4347,7 @@ comptime {
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ an integer, an enum, or a packed struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
{#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
@@ -4576,8 +4576,8 @@ comptime {
more efficiently in machine instructions.
- {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
+ an integer, an enum, or a packed struct.
{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
@@ -4608,8 +4608,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
- {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
+ an integer, an enum, or a packed struct.
{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
@@ -4840,7 +4840,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
This builtin can be called from a {#link|comptime#} block to conditionally export symbols.
When ptr points to a function with the C calling convention and
- {#syntax#}options.linkage{#endsyntax#} is {#syntax#}.Strong{#endsyntax#}, this is equivalent to
+ {#syntax#}options.linkage{#endsyntax#} is {#syntax#}.strong{#endsyntax#}, this is equivalent to
the {#syntax#}export{#endsyntax#} keyword used on a function:
{#code|export_builtin.zig#}
@@ -4952,34 +4952,25 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#header_close#}
{#header_open|@import#}
- {#syntax#}@import(comptime path: []const u8) type{#endsyntax#}
-
- This function finds a zig file corresponding to {#syntax#}path{#endsyntax#} and adds it to the build,
- if it is not already added.
-
-
- Zig source files are implicitly structs, with a name equal to the file's basename with the extension
- truncated. {#syntax#}@import{#endsyntax#} returns the struct type corresponding to the file.
-
-
- Declarations which have the {#syntax#}pub{#endsyntax#} keyword may be referenced from a different
- source file than the one they are declared in.
-
-
- {#syntax#}path{#endsyntax#} can be a relative path or it can be the name of a package.
- If it is a relative path, it is relative to the file that contains the {#syntax#}@import{#endsyntax#}
- function call.
-
-
- The following packages are always available:
-
+ {#syntax#}@import(comptime target: []const u8) anytype{#endsyntax#}
+ Imports the file at {#syntax#}target{#endsyntax#}, adding it to the compilation if it is not already
+ added. {#syntax#}target{#endsyntax#} is either a relative path to another file from the file containing
+ the {#syntax#}@import{#endsyntax#} call, or it is the name of a {#link|module|Compilation Model#}, with
+ the import referring to the root source file of that module. Either way, the file path must end in
+ either .zig (for a Zig source file) or .zon (for a ZON data file).
+ If {#syntax#}target{#endsyntax#} refers to a Zig source file, then {#syntax#}@import{#endsyntax#} returns
+ that file's {#link|corresponding struct type|Source File Structs#}, essentially as if the builtin call was
+ replaced by {#syntax#}struct { FILE_CONTENTS }{#endsyntax#}. The return type is {#syntax#}type{#endsyntax#}.
+ If {#syntax#}target{#endsyntax#} refers to a ZON file, then {#syntax#}@import{#endsyntax#} returns the value
+ of the literal in the file. If there is an inferred {#link|result type|Result Types#}, then the return type
+ is that type, and the ZON literal is interpreted as that type ({#link|Result Types#} are propagated through
+ the ZON expression). Otherwise, the return type is the type of the equivalent Zig expression, essentially as
+ if the builtin call was replaced by the ZON file contents.
+ The following modules are always available for import:
- {#syntax#}@import("std"){#endsyntax#} - Zig Standard Library
- - {#syntax#}@import("builtin"){#endsyntax#} - Target-specific information
- The command
zig build-exe --show-builtin outputs the source to stdout for reference.
-
- - {#syntax#}@import("root"){#endsyntax#} - Root source file
- This is usually
src/main.zig but depends on what file is built.
+ - {#syntax#}@import("builtin"){#endsyntax#} - Target-specific information. The command
zig build-exe --show-builtin outputs the source to stdout for reference.
+ - {#syntax#}@import("root"){#endsyntax#} - Alias for the root module. In typical project structures, this means it refers back to
src/main.zig.
{#see_also|Compile Variables|@embedFile#}
@@ -5179,7 +5170,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}
Modulus division. For unsigned integers this is the same as
- {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
+ {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
@@ -5284,7 +5275,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}
Remainder division. For unsigned integers this is the same as
- {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
+ {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
diff --git a/doc/langref/build.zig b/doc/langref/build.zig
index ca729b5b93..19e4b57c08 100644
--- a/doc/langref/build.zig
+++ b/doc/langref/build.zig
@@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "example",
- .root_source_file = b.path("example.zig"),
- .optimize = optimize,
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("example.zig"),
+ .optimize = optimize,
+ }),
});
b.default_step.dependOn(&exe.step);
}
diff --git a/doc/langref/build_c.zig b/doc/langref/build_c.zig
index 08f1683e9f..dc8e5553fc 100644
--- a/doc/langref/build_c.zig
+++ b/doc/langref/build_c.zig
@@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void {
const lib = b.addLibrary(.{
.linkage = .dynamic,
.name = "mathtest",
- .root_source_file = b.path("mathtest.zig"),
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("mathtest.zig"),
+ }),
.version = .{ .major = 1, .minor = 0, .patch = 0 },
});
const exe = b.addExecutable(.{
.name = "test",
+ .root_module = b.createModule(.{
+ .link_libc = true,
+ }),
});
- exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
- exe.linkLibrary(lib);
- exe.linkSystemLibrary("c");
+ exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
+ exe.root_module.linkLibrary(lib);
b.default_step.dependOn(&exe.step);
diff --git a/doc/langref/build_object.zig b/doc/langref/build_object.zig
index c08644b0d6..c9a3588d9b 100644
--- a/doc/langref/build_object.zig
+++ b/doc/langref/build_object.zig
@@ -3,15 +3,19 @@ const std = @import("std");
pub fn build(b: *std.Build) void {
const obj = b.addObject(.{
.name = "base64",
- .root_source_file = b.path("base64.zig"),
+ .root_module = b.createModule(.{
+ .root_source_file = b.path("base64.zig"),
+ }),
});
const exe = b.addExecutable(.{
.name = "test",
+ .root_module = b.createModule(.{
+ .link_libc = true,
+ }),
});
- exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
- exe.addObject(obj);
- exe.linkSystemLibrary("c");
+ exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
+ exe.root_module.addObject(obj);
b.installArtifact(exe);
}
diff --git a/doc/langref/test_coerce_slices_arrays_and_pointers.zig b/doc/langref/test_coerce_slices_arrays_and_pointers.zig
index b2fdb6c787..67b2687163 100644
--- a/doc/langref/test_coerce_slices_arrays_and_pointers.zig
+++ b/doc/langref/test_coerce_slices_arrays_and_pointers.zig
@@ -67,4 +67,11 @@ test "*T to *[1]T" {
try expect(z[0] == 1234);
}
+// Sentinel-terminated slices can be coerced into sentinel-terminated pointers
+test "[:x]T to [*:x]T" {
+ const buf: [:0]const u8 = "hello";
+ const buf2: [*:0]const u8 = buf;
+ try expect(buf2[4] == 'o');
+}
+
// test
diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig
index 7402a4c66d..6b7266ee71 100644
--- a/lib/compiler/build_runner.zig
+++ b/lib/compiler/build_runner.zig
@@ -696,8 +696,11 @@ fn runStepNames(
.failures, .none => true,
else => false,
};
- if (failure_count == 0 and failures_only) {
- return run.cleanExit();
+ if (failure_count == 0) {
+ std.Progress.setStatus(.success);
+ if (failures_only) return run.cleanExit();
+ } else {
+ std.Progress.setStatus(.failure);
}
const ttyconf = run.ttyconf;
@@ -1149,6 +1152,7 @@ fn workerMakeOneStep(
} else |err| switch (err) {
error.MakeFailed => {
@atomicStore(Step.State, &s.state, .failure, .seq_cst);
+ std.Progress.setStatus(.failure_working);
break :handle_result;
},
error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig
index 17e9e04da7..b8723c56ee 100644
--- a/lib/compiler_rt.zig
+++ b/lib/compiler_rt.zig
@@ -240,7 +240,7 @@ comptime {
_ = @import("compiler_rt/udivmodti4.zig");
// extra
- if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/os_version_check.zig");
+ _ = @import("compiler_rt/os_version_check.zig");
_ = @import("compiler_rt/emutls.zig");
_ = @import("compiler_rt/arm.zig");
_ = @import("compiler_rt/aulldiv.zig");
diff --git a/lib/std/Build.zig b/lib/std/Build.zig
index e8db5298a7..7dc1be104b 100644
--- a/lib/std/Build.zig
+++ b/lib/std/Build.zig
@@ -409,104 +409,179 @@ fn createChildOnly(
return child;
}
-fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap {
- var user_input_options = UserInputOptionsMap.init(allocator);
+fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap {
+ var map = UserInputOptionsMap.init(arena);
inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
- const v = @field(args, field.name);
- const T = @TypeOf(v);
- switch (T) {
- Target.Query => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") },
- .used = false,
- }) catch @panic("OOM");
- user_input_options.put("cpu", .{
- .name = "cpu",
- .value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") },
- .used = false,
- }) catch @panic("OOM");
- },
- ResolvedTarget => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") },
- .used = false,
- }) catch @panic("OOM");
- user_input_options.put("cpu", .{
- .name = "cpu",
- .value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") },
- .used = false,
- }) catch @panic("OOM");
- },
- LazyPath => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .lazy_path = v.dupeInner(allocator) },
- .used = false,
- }) catch @panic("OOM");
- },
- []const LazyPath => {
- var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");
- for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .lazy_path_list = list },
- .used = false,
- }) catch @panic("OOM");
- },
- []const u8 => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .scalar = v },
- .used = false,
- }) catch @panic("OOM");
- },
- []const []const u8 => {
- var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM");
- list.appendSliceAssumeCapacity(v);
-
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .list = list },
- .used = false,
- }) catch @panic("OOM");
- },
- else => switch (@typeInfo(T)) {
- .bool => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .scalar = if (v) "true" else "false" },
- .used = false,
- }) catch @panic("OOM");
- },
- .@"enum", .enum_literal => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .scalar = @tagName(v) },
- .used = false,
- }) catch @panic("OOM");
- },
- .comptime_int, .int => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") },
- .used = false,
- }) catch @panic("OOM");
- },
- .comptime_float, .float => {
- user_input_options.put(field.name, .{
- .name = field.name,
- .value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") },
- .used = false,
- }) catch @panic("OOM");
- },
- else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
- },
- }
+ if (field.type == @Type(.null)) continue;
+ addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name));
}
+ return map;
+}
- return user_input_options;
+fn addUserInputOptionFromArg(
+ arena: Allocator,
+ map: *UserInputOptionsMap,
+ field: std.builtin.Type.StructField,
+ comptime T: type,
+ /// If null, the value won't be added, but `T` will still be type-checked.
+ maybe_value: ?T,
+) void {
+ switch (T) {
+ Target.Query => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ map.put("cpu", .{
+ .name = "cpu",
+ .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ ResolvedTarget => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ map.put("cpu", .{
+ .name = "cpu",
+ .value = .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ std.zig.BuildId => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ LazyPath => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .lazy_path = v.dupeInner(arena) },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ []const LazyPath => return if (maybe_value) |v| {
+ var list = ArrayList(LazyPath).initCapacity(arena, v.len) catch @panic("OOM");
+ for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(arena));
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .lazy_path_list = list },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ []const u8 => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ []const []const u8 => return if (maybe_value) |v| {
+ var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
+ for (v) |s| list.appendAssumeCapacity(arena.dupe(u8, s) catch @panic("OOM"));
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .list = list },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ else => switch (@typeInfo(T)) {
+ .bool => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = if (v) "true" else "false" },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ .@"enum", .enum_literal => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = @tagName(v) },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ .comptime_int, .int => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ .comptime_float, .float => return if (maybe_value) |v| {
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ .pointer => |ptr_info| switch (ptr_info.size) {
+ .one => switch (@typeInfo(ptr_info.child)) {
+ .array => |array_info| {
+ comptime var slice_info = ptr_info;
+ slice_info.size = .slice;
+ slice_info.is_const = true;
+ slice_info.child = array_info.child;
+ slice_info.sentinel_ptr = null;
+ addUserInputOptionFromArg(
+ arena,
+ map,
+ field,
+ @Type(.{ .pointer = slice_info }),
+ maybe_value orelse null,
+ );
+ return;
+ },
+ else => {},
+ },
+ .slice => switch (@typeInfo(ptr_info.child)) {
+ .@"enum" => return if (maybe_value) |v| {
+ var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
+ for (v) |tag| list.appendAssumeCapacity(@tagName(tag));
+ map.put(field.name, .{
+ .name = field.name,
+ .value = .{ .list = list },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ else => {
+ comptime var slice_info = ptr_info;
+ slice_info.is_const = true;
+ slice_info.sentinel_ptr = null;
+ addUserInputOptionFromArg(
+ arena,
+ map,
+ field,
+ @Type(.{ .pointer = slice_info }),
+ maybe_value orelse null,
+ );
+ return;
+ },
+ },
+ else => {},
+ },
+ .null => unreachable,
+ .optional => |info| switch (@typeInfo(info.child)) {
+ .optional => {},
+ else => {
+ addUserInputOptionFromArg(
+ arena,
+ map,
+ field,
+ info.child,
+ maybe_value orelse null,
+ );
+ return;
+ },
+ },
+ else => {},
+ },
+ }
+ @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type));
}
const OrderedUserValue = union(enum) {
diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig
index 356ea4e34e..141d18a7bf 100644
--- a/lib/std/Build/Step/Compile.zig
+++ b/lib/std/Build/Step/Compile.zig
@@ -681,10 +681,14 @@ pub fn producesImplib(compile: *Compile) bool {
return compile.isDll();
}
+/// Deprecated; use `compile.root_module.link_libc = true` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn linkLibC(compile: *Compile) void {
compile.root_module.link_libc = true;
}
+/// Deprecated; use `compile.root_module.link_libcpp = true` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn linkLibCpp(compile: *Compile) void {
compile.root_module.link_libcpp = true;
}
@@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {
};
}
+/// Deprecated; use `compile.root_module.linkSystemLibrary(name, .{})` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void {
return compile.root_module.linkSystemLibrary(name, .{});
}
+/// Deprecated; use `compile.root_module.linkSystemLibrary(name, options)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn linkSystemLibrary2(
compile: *Compile,
name: []const u8,
@@ -814,22 +822,26 @@ pub fn linkSystemLibrary2(
return compile.root_module.linkSystemLibrary(name, options);
}
+/// Deprecated; use `c.root_module.linkFramework(name, .{})` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn linkFramework(c: *Compile, name: []const u8) void {
c.root_module.linkFramework(name, .{});
}
-/// Handy when you have many C/C++ source files and want them all to have the same flags.
+/// Deprecated; use `compile.root_module.addCSourceFiles(options)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {
compile.root_module.addCSourceFiles(options);
}
+/// Deprecated; use `compile.root_module.addCSourceFile(source)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {
compile.root_module.addCSourceFile(source);
}
-/// Resource files must have the extension `.rc`.
-/// Can be called regardless of target. The .rc file will be ignored
-/// if the target object format does not support embedded resources.
+/// Deprecated; use `compile.root_module.addWin32ResourceFile(source)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {
compile.root_module.addWin32ResourceFile(source);
}
@@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);
}
+/// Deprecated; use `compile.root_module.addAssemblyFile(source)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {
compile.root_module.addAssemblyFile(source);
}
+/// Deprecated; use `compile.root_module.addObjectFile(source)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addObjectFile(compile: *Compile, source: LazyPath) void {
compile.root_module.addObjectFile(source);
}
+/// Deprecated; use `compile.root_module.addObject(object)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addObject(compile: *Compile, object: *Compile) void {
compile.root_module.addObject(object);
}
+/// Deprecated; use `compile.root_module.linkLibrary(library)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn linkLibrary(compile: *Compile, library: *Compile) void {
compile.root_module.linkLibrary(library);
}
+/// Deprecated; use `compile.root_module.addAfterIncludePath(lazy_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void {
compile.root_module.addAfterIncludePath(lazy_path);
}
+/// Deprecated; use `compile.root_module.addSystemIncludePath(lazy_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void {
compile.root_module.addSystemIncludePath(lazy_path);
}
+/// Deprecated; use `compile.root_module.addIncludePath(lazy_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void {
compile.root_module.addIncludePath(lazy_path);
}
+/// Deprecated; use `compile.root_module.addConfigHeader(config_header)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void {
compile.root_module.addConfigHeader(config_header);
}
+/// Deprecated; use `compile.root_module.addEmbedPath(lazy_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void {
compile.root_module.addEmbedPath(lazy_path);
}
+/// Deprecated; use `compile.root_module.addLibraryPath(directory_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void {
compile.root_module.addLibraryPath(directory_path);
}
+/// Deprecated; use `compile.root_module.addRPath(directory_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addRPath(compile: *Compile, directory_path: LazyPath) void {
compile.root_module.addRPath(directory_path);
}
+/// Deprecated; use `compile.root_module.addSystemFrameworkPath(directory_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
compile.root_module.addSystemFrameworkPath(directory_path);
}
+/// Deprecated; use `compile.root_module.addFrameworkPath(directory_path)` instead.
+/// To be removed after 0.15.0 is tagged.
pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
compile.root_module.addFrameworkPath(directory_path);
}
diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
index 57f5d73f0c..819fc6745d 100644
--- a/lib/std/Build/Step/Run.zig
+++ b/lib/std/Build/Step/Run.zig
@@ -1391,6 +1391,16 @@ fn runCommand(
}
},
else => {
+ // On failure, print stderr if captured.
+ const bad_exit = switch (result.term) {
+ .Exited => |code| code != 0,
+ .Signal, .Stopped, .Unknown => true,
+ };
+
+ if (bad_exit) if (result.stdio.stderr) |err| {
+ try step.addError("stderr:\n{s}", .{err});
+ };
+
try step.handleChildProcessTerm(result.term, cwd, final_argv);
},
}
diff --git a/lib/std/Io.zig b/lib/std/Io.zig
index 988726b3bf..fd13f2fc00 100644
--- a/lib/std/Io.zig
+++ b/lib/std/Io.zig
@@ -354,7 +354,7 @@ pub fn Poller(comptime StreamEnum: type) type {
const unused = r.buffer[r.end..];
if (unused.len >= min_len) return unused;
}
- if (r.seek > 0) r.rebase();
+ if (r.seek > 0) r.rebase(r.buffer.len) catch unreachable;
{
var list: std.ArrayListUnmanaged(u8) = .{
.items = r.buffer[0..r.end],
@@ -544,7 +544,6 @@ pub fn PollFiles(comptime StreamEnum: type) type {
test {
_ = Reader;
- _ = Reader.Limited;
_ = Writer;
_ = tty;
_ = @import("Io/test.zig");
diff --git a/lib/std/Io/DeprecatedReader.zig b/lib/std/Io/DeprecatedReader.zig
index af1eda8415..59f163b39c 100644
--- a/lib/std/Io/DeprecatedReader.zig
+++ b/lib/std/Io/DeprecatedReader.zig
@@ -397,6 +397,7 @@ pub const Adapter = struct {
a.err = err;
return error.ReadFailed;
};
+ if (n == 0) return error.EndOfStream;
w.advance(n);
return n;
}
diff --git a/lib/std/Io/Reader.zig b/lib/std/Io/Reader.zig
index fa05f0275b..05ab489286 100644
--- a/lib/std/Io/Reader.zig
+++ b/lib/std/Io/Reader.zig
@@ -43,8 +43,8 @@ pub const VTable = struct {
///
/// In addition to, or instead of writing to `w`, the implementation may
/// choose to store data in `buffer`, modifying `seek` and `end`
- /// accordingly. Stream implementations are encouraged to take advantage of
- /// this if simplifies the logic.
+ /// accordingly. Implementations are encouraged to take advantage of
+ /// this if it simplifies the logic.
stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,
/// Consumes bytes from the internally tracked stream position without
@@ -67,6 +67,37 @@ pub const VTable = struct {
///
/// This function is only called when `buffer` is empty.
discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard,
+
+ /// Returns number of bytes written to `data`.
+ ///
+ /// `data` may not have nonzero length.
+ ///
+ /// `data` may not contain an alias to `Reader.buffer`.
+ ///
+ /// `data` is mutable because the implementation may to temporarily modify
+ /// the fields in order to handle partial reads. Implementations must
+ /// restore the original value before returning.
+ ///
+ /// Implementations may ignore `data`, writing directly to `Reader.buffer`,
+ /// modifying `seek` and `end` accordingly, and returning 0 from this
+ /// function. Implementations are encouraged to take advantage of this if
+ /// it simplifies the logic.
+ ///
+ /// The default implementation calls `stream` with either `data[0]` or
+ /// `Reader.buffer`, whichever is bigger.
+ readVec: *const fn (r: *Reader, data: [][]u8) Error!usize = defaultReadVec,
+
+ /// Ensures `capacity` more data can be buffered without rebasing.
+ ///
+ /// Asserts `capacity` is within buffer capacity, or that the stream ends
+ /// within `capacity` bytes.
+ ///
+ /// Only called when `capacity` cannot fit into the unused capacity of
+ /// `buffer`.
+ ///
+ /// The default implementation moves buffered data to the start of
+ /// `buffer`, setting `seek` to zero, and cannot fail.
+ rebase: *const fn (r: *Reader, capacity: usize) RebaseError!void = defaultRebase,
};
pub const StreamError = error{
@@ -97,6 +128,10 @@ pub const ShortError = error{
ReadFailed,
};
+pub const RebaseError = error{
+ EndOfStream,
+};
+
pub const failing: Reader = .{
.vtable = &.{
.stream = failingStream,
@@ -122,6 +157,8 @@ pub fn fixed(buffer: []const u8) Reader {
.vtable = &.{
.stream = endingStream,
.discard = endingDiscard,
+ .readVec = endingReadVec,
+ .rebase = endingRebase,
},
// This cast is safe because all potential writes to it will instead
// return `error.EndOfStream`.
@@ -153,18 +190,18 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize {
}
break :l .limited(n - buffered_len);
} else .unlimited;
- r.seek = 0;
- r.end = 0;
+ r.seek = r.end;
const n = try r.vtable.discard(r, remaining);
assert(n <= @intFromEnum(remaining));
return buffered_len + n;
}
pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
- assert(r.seek == 0);
- assert(r.end == 0);
- var dw: Writer.Discarding = .init(r.buffer);
- const n = r.stream(&dw.writer, limit) catch |err| switch (err) {
+ assert(r.seek == r.end);
+ r.seek = 0;
+ r.end = 0;
+ var d: Writer.Discarding = .init(r.buffer);
+ const n = r.stream(&d.writer, limit) catch |err| switch (err) {
error.WriteFailed => unreachable,
error.ReadFailed => return error.ReadFailed,
error.EndOfStream => return error.EndOfStream,
@@ -229,8 +266,7 @@ pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {
/// number of bytes discarded.
pub fn discardRemaining(r: *Reader) ShortError!usize {
var offset: usize = r.end - r.seek;
- r.seek = 0;
- r.end = 0;
+ r.seek = r.end;
while (true) {
offset += r.vtable.discard(r, .unlimited) catch |err| switch (err) {
error.EndOfStream => return offset,
@@ -277,7 +313,8 @@ pub fn appendRemaining(
list: *std.ArrayListAlignedUnmanaged(u8, alignment),
limit: Limit,
) LimitedAllocError!void {
- if (limit != .unlimited) assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
+ if (limit == .unlimited) return appendRemainingUnlimited(r, gpa, alignment, list, 1);
+ assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
const buffer_contents = r.buffer[r.seek..r.end];
const copy_len = limit.minInt(buffer_contents.len);
try list.appendSlice(gpa, r.buffer[0..copy_len]);
@@ -286,32 +323,67 @@ pub fn appendRemaining(
r.seek = 0;
r.end = 0;
var remaining = @intFromEnum(limit) - copy_len;
+ // From here, we leave `buffer` empty, appending directly to `list`.
+ var writer: Writer = .{
+ .buffer = undefined,
+ .end = undefined,
+ .vtable = &.{ .drain = Writer.fixedDrain },
+ };
while (true) {
- try list.ensureUnusedCapacity(gpa, 1);
+ try list.ensureUnusedCapacity(gpa, 2);
const cap = list.unusedCapacitySlice();
- const dest = cap[0..@min(cap.len, remaining)];
- if (remaining - dest.len == 0) {
- // Additionally provides `buffer` to detect end.
- const new_remaining = readVecInner(r, &.{}, dest, remaining) catch |err| switch (err) {
- error.EndOfStream => {
- if (r.bufferedLen() != 0) return error.StreamTooLong;
- return;
- },
- error.ReadFailed => return error.ReadFailed,
- };
- list.items.len += remaining - new_remaining;
- remaining = new_remaining;
- } else {
- // Leave `buffer` empty, appending directly to `list`.
- var dest_w: Writer = .fixed(dest);
- const n = r.vtable.stream(r, &dest_w, .limited(dest.len)) catch |err| switch (err) {
- error.WriteFailed => unreachable, // Prevented by the limit.
- error.EndOfStream => return,
- error.ReadFailed => return error.ReadFailed,
- };
- list.items.len += n;
- remaining -= n;
+ const dest = cap[0..@min(cap.len, remaining + 1)];
+ writer.buffer = list.allocatedSlice();
+ writer.end = list.items.len;
+ const n = r.vtable.stream(r, &writer, .limited(dest.len)) catch |err| switch (err) {
+ error.WriteFailed => unreachable, // Prevented by the limit.
+ error.EndOfStream => return,
+ error.ReadFailed => return error.ReadFailed,
+ };
+ list.items.len += n;
+ if (n > remaining) {
+ // Move the byte to `Reader.buffer` so it is not lost.
+ assert(n - remaining == 1);
+ assert(r.end == 0);
+ r.buffer[0] = list.items[list.items.len - 1];
+ list.items.len -= 1;
+ r.end = 1;
+ return;
}
+ remaining -= n;
+ }
+}
+
+pub const UnlimitedAllocError = Allocator.Error || ShortError;
+
+pub fn appendRemainingUnlimited(
+ r: *Reader,
+ gpa: Allocator,
+ comptime alignment: ?std.mem.Alignment,
+ list: *std.ArrayListAlignedUnmanaged(u8, alignment),
+ bump: usize,
+) UnlimitedAllocError!void {
+ const buffer_contents = r.buffer[r.seek..r.end];
+ try list.ensureUnusedCapacity(gpa, buffer_contents.len + bump);
+ list.appendSliceAssumeCapacity(buffer_contents);
+ r.seek = 0;
+ r.end = 0;
+ // From here, we leave `buffer` empty, appending directly to `list`.
+ var writer: Writer = .{
+ .buffer = undefined,
+ .end = undefined,
+ .vtable = &.{ .drain = Writer.fixedDrain },
+ };
+ while (true) {
+ try list.ensureUnusedCapacity(gpa, bump);
+ writer.buffer = list.allocatedSlice();
+ writer.end = list.items.len;
+ const n = r.vtable.stream(r, &writer, .limited(list.unusedCapacitySlice().len)) catch |err| switch (err) {
+ error.WriteFailed => unreachable, // Prevented by the limit.
+ error.EndOfStream => return,
+ error.ReadFailed => return error.ReadFailed,
+ };
+ list.items.len += n;
}
}
@@ -323,95 +395,50 @@ pub fn appendRemaining(
///
/// The reader's internal logical seek position moves forward in accordance
/// with the number of bytes returned from this function.
-pub fn readVec(r: *Reader, data: []const []u8) Error!usize {
- return readVecLimit(r, data, .unlimited);
-}
-
-/// Equivalent to `readVec` but reads at most `limit` bytes.
-///
-/// This ultimately will lower to a call to `stream`, but it must ensure
-/// that the buffer used has at least as much capacity, in case that function
-/// depends on a minimum buffer capacity. It also ensures that if the `stream`
-/// implementation calls `Writer.writableVector`, it will get this data slice
-/// along with the buffer at the end.
-pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize {
- comptime assert(@intFromEnum(Limit.unlimited) == std.math.maxInt(usize));
- var remaining = @intFromEnum(limit);
+pub fn readVec(r: *Reader, data: [][]u8) Error!usize {
+ var seek = r.seek;
for (data, 0..) |buf, i| {
- const buffer_contents = r.buffer[r.seek..r.end];
- const copy_len = @min(buffer_contents.len, buf.len, remaining);
- @memcpy(buf[0..copy_len], buffer_contents[0..copy_len]);
- r.seek += copy_len;
- remaining -= copy_len;
- if (remaining == 0) break;
+ const contents = r.buffer[seek..r.end];
+ const copy_len = @min(contents.len, buf.len);
+ @memcpy(buf[0..copy_len], contents[0..copy_len]);
+ seek += copy_len;
if (buf.len - copy_len == 0) continue;
- // All of `buffer` has been copied to `data`. We now set up a structure
- // that enables the `Writer.writableVector` API, while also ensuring
- // API that directly operates on the `Writable.buffer` has its minimum
- // buffer capacity requirements met.
- r.seek = 0;
- r.end = 0;
- remaining = try readVecInner(r, data[i + 1 ..], buf[copy_len..], remaining);
- break;
+ // All of `buffer` has been copied to `data`.
+ const n = seek - r.seek;
+ r.seek = seek;
+ data[i] = buf[copy_len..];
+ defer data[i] = buf;
+ return n + (r.vtable.readVec(r, data[i..]) catch |err| switch (err) {
+ error.EndOfStream => if (n == 0) return error.EndOfStream else 0,
+ error.ReadFailed => return error.ReadFailed,
+ });
}
- return @intFromEnum(limit) - remaining;
+ const n = seek - r.seek;
+ r.seek = seek;
+ return n;
}
-fn readVecInner(r: *Reader, middle: []const []u8, first: []u8, remaining: usize) Error!usize {
- var wrapper: Writer.VectorWrapper = .{
- .it = .{
- .first = first,
- .middle = middle,
- .last = r.buffer,
- },
- .writer = .{
- .buffer = if (first.len >= r.buffer.len) first else r.buffer,
- .vtable = Writer.VectorWrapper.vtable,
- },
+/// Writes to `Reader.buffer` or `data`, whichever has larger capacity.
+pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize {
+ assert(r.seek == r.end);
+ r.seek = 0;
+ r.end = 0;
+ const first = data[0];
+ const direct = first.len >= r.buffer.len;
+ var writer: Writer = .{
+ .buffer = if (direct) first else r.buffer,
+ .end = 0,
+ .vtable = &.{ .drain = Writer.fixedDrain },
};
- // If the limit may pass beyond user buffer into Reader buffer, use
- // unlimited, allowing the Reader buffer to fill.
- const limit: Limit = l: {
- var n: usize = first.len;
- for (middle) |m| n += m.len;
- break :l if (remaining >= n) .unlimited else .limited(remaining);
- };
- var n = r.vtable.stream(r, &wrapper.writer, limit) catch |err| switch (err) {
- error.WriteFailed => {
- assert(!wrapper.used);
- if (wrapper.writer.buffer.ptr == first.ptr) {
- return remaining - wrapper.writer.end;
- } else {
- assert(wrapper.writer.end <= r.buffer.len);
- r.end = wrapper.writer.end;
- return remaining;
- }
- },
+ const limit: Limit = .limited(writer.buffer.len - writer.end);
+ const n = r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
+ error.WriteFailed => unreachable,
else => |e| return e,
};
- if (!wrapper.used) {
- if (wrapper.writer.buffer.ptr == first.ptr) {
- return remaining - n;
- } else {
- assert(n <= r.buffer.len);
- r.end = n;
- return remaining;
- }
- }
- if (n < first.len) return remaining - n;
- var result = remaining - first.len;
- n -= first.len;
- for (middle) |mid| {
- if (n < mid.len) {
- return result - n;
- }
- result -= mid.len;
- n -= mid.len;
- }
- assert(n <= r.buffer.len);
- r.end = n;
- return result;
+ if (direct) return n;
+ r.end += n;
+ return 0;
}
pub fn buffered(r: *Reader) []u8 {
@@ -422,8 +449,8 @@ pub fn bufferedLen(r: *const Reader) usize {
return r.end - r.seek;
}
-pub fn hashed(r: *Reader, hasher: anytype) Hashed(@TypeOf(hasher)) {
- return .{ .in = r, .hasher = hasher };
+pub fn hashed(r: *Reader, hasher: anytype, buffer: []u8) Hashed(@TypeOf(hasher)) {
+ return .init(r, hasher, buffer);
}
pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {
@@ -498,8 +525,7 @@ pub fn toss(r: *Reader, n: usize) void {
/// Equivalent to `toss(r.bufferedLen())`.
pub fn tossBuffered(r: *Reader) void {
- r.seek = 0;
- r.end = 0;
+ r.seek = r.end;
}
/// Equivalent to `peek` followed by `toss`.
@@ -586,8 +612,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
return n;
}
var remaining = n - (r.end - r.seek);
- r.end = 0;
- r.seek = 0;
+ r.seek = r.end;
while (true) {
const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {
error.EndOfStream => return n - remaining,
@@ -625,29 +650,24 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
/// See also:
/// * `readSliceAll`
pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
- var i: usize = 0;
+ const contents = r.buffer[r.seek..r.end];
+ const copy_len = @min(buffer.len, contents.len);
+ @memcpy(buffer[0..copy_len], contents[0..copy_len]);
+ r.seek += copy_len;
+ if (buffer.len - copy_len == 0) {
+ @branchHint(.likely);
+ return buffer.len;
+ }
+ var i: usize = copy_len;
+ var data: [1][]u8 = undefined;
while (true) {
- const buffer_contents = r.buffer[r.seek..r.end];
- const dest = buffer[i..];
- const copy_len = @min(dest.len, buffer_contents.len);
- @memcpy(dest[0..copy_len], buffer_contents[0..copy_len]);
- if (dest.len - copy_len == 0) {
- @branchHint(.likely);
- r.seek += copy_len;
- return buffer.len;
- }
- i += copy_len;
- r.end = 0;
- r.seek = 0;
- const remaining = buffer[i..];
- const new_remaining_len = readVecInner(r, &.{}, remaining, remaining.len) catch |err| switch (err) {
+ data[0] = buffer[i..];
+ i += readVec(r, &data) catch |err| switch (err) {
error.EndOfStream => return i,
error.ReadFailed => return error.ReadFailed,
};
- if (new_remaining_len == 0) return buffer.len;
- i += remaining.len - new_remaining_len;
+ if (buffer.len - i == 0) return buffer.len;
}
- return buffer.len;
}
/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing
@@ -780,11 +800,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
@branchHint(.likely);
return buffer[seek .. end + 1];
}
- if (r.vtable.stream == &endingStream) {
- // Protect the `@constCast` of `fixed`.
- return error.EndOfStream;
- }
- r.rebase();
+ // TODO take a parameter for max search length rather than relying on buffer capacity
+ try rebase(r, r.buffer.len);
while (r.buffer.len - r.end != 0) {
const end_cap = r.buffer[r.end..];
var writer: Writer = .fixed(end_cap);
@@ -1041,20 +1058,7 @@ pub fn fill(r: *Reader, n: usize) Error!void {
/// Missing this optimization can result in wall-clock time for the most affected benchmarks
/// increasing by a factor of 5 or more.
fn fillUnbuffered(r: *Reader, n: usize) Error!void {
- if (r.seek + n <= r.buffer.len) while (true) {
- const end_cap = r.buffer[r.end..];
- var writer: Writer = .fixed(end_cap);
- r.end += r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) {
- error.WriteFailed => unreachable,
- else => |e| return e,
- };
- if (r.seek + n <= r.end) return;
- };
- if (r.vtable.stream == &endingStream) {
- // Protect the `@constCast` of `fixed`.
- return error.EndOfStream;
- }
- rebaseCapacity(r, n);
+ try rebase(r, n);
var writer: Writer = .{
.buffer = r.buffer,
.vtable = &.{ .drain = Writer.fixedDrain },
@@ -1074,7 +1078,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
///
/// Asserts buffer capacity is at least 1.
pub fn fillMore(r: *Reader) Error!void {
- rebaseCapacity(r, 1);
+ try rebase(r, 1);
var writer: Writer = .{
.buffer = r.buffer,
.end = r.end,
@@ -1251,7 +1255,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {
if (n <= r.buffer.len) return;
- if (r.seek > 0) rebase(r);
+ if (r.seek > 0) rebase(r, r.buffer.len);
var list: ArrayList(u8) = .{
.items = r.buffer[0..r.end],
.capacity = r.buffer.len,
@@ -1297,37 +1301,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu
}
}
-/// Left-aligns data such that `r.seek` becomes zero.
-///
-/// If `r.seek` is not already zero then `buffer` is mutated, making it illegal
-/// to call this function with a const-casted `buffer`, such as in the case of
-/// `fixed`. This issue can be avoided:
-/// * in implementations, by attempting a read before a rebase, in which
-/// case the read will return `error.EndOfStream`, preventing the rebase.
-/// * in usage, by copying into a mutable buffer before initializing `fixed`.
-pub fn rebase(r: *Reader) void {
- if (r.seek == 0) return;
+/// Ensures `capacity` more data can be buffered without rebasing.
+pub fn rebase(r: *Reader, capacity: usize) RebaseError!void {
+ if (r.end + capacity <= r.buffer.len) return;
+ return r.vtable.rebase(r, capacity);
+}
+
+pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void {
+ if (r.end <= r.buffer.len - capacity) return;
const data = r.buffer[r.seek..r.end];
@memmove(r.buffer[0..data.len], data);
r.seek = 0;
r.end = data.len;
}
-/// Ensures `capacity` more data can be buffered without rebasing, by rebasing
-/// if necessary.
-///
-/// Asserts `capacity` is within the buffer capacity.
-///
-/// If the rebase occurs then `buffer` is mutated, making it illegal to call
-/// this function with a const-casted `buffer`, such as in the case of `fixed`.
-/// This issue can be avoided:
-/// * in implementations, by attempting a read before a rebase, in which
-/// case the read will return `error.EndOfStream`, preventing the rebase.
-/// * in usage, by copying into a mutable buffer before initializing `fixed`.
-pub fn rebaseCapacity(r: *Reader, capacity: usize) void {
- if (r.end > r.buffer.len - capacity) rebase(r);
-}
-
/// Advances the stream and decreases the size of the storage buffer by `n`,
/// returning the range of bytes no longer accessible by `r`.
///
@@ -1648,19 +1635,6 @@ test readVec {
try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]);
}
-test readVecLimit {
- var r: Reader = .fixed(std.ascii.letters);
- var flat_buffer: [52]u8 = undefined;
- var bufs: [2][]u8 = .{
- flat_buffer[0..26],
- flat_buffer[26..],
- };
- // Short reads are possible with this function but not with fixed.
- try testing.expectEqual(50, try r.readVecLimit(&bufs, .limited(50)));
- try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]);
- try testing.expectEqualStrings(std.ascii.letters[26..50], bufs[1][0..24]);
-}
-
test "expected error.EndOfStream" {
// Unit test inspired by https://github.com/ziglang/zig/issues/17733
var buffer: [3]u8 = undefined;
@@ -1670,6 +1644,17 @@ test "expected error.EndOfStream" {
try std.testing.expectError(error.EndOfStream, r.take(3));
}
+test "readVec at end" {
+ var reader_buffer: [8]u8 = "abcd1234".*;
+ var reader: testing.Reader = .init(&reader_buffer, &.{});
+ reader.interface.end = reader_buffer.len;
+
+ var out: [16]u8 = undefined;
+ var vecs: [1][]u8 = .{&out};
+ try testing.expectEqual(8, try reader.interface.readVec(&vecs));
+ try testing.expectEqualStrings("abcd1234", vecs[0][0..8]);
+}
+
fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
_ = r;
_ = w;
@@ -1677,12 +1662,24 @@ fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
return error.EndOfStream;
}
+fn endingReadVec(r: *Reader, data: [][]u8) Error!usize {
+ _ = r;
+ _ = data;
+ return error.EndOfStream;
+}
+
fn endingDiscard(r: *Reader, limit: Limit) Error!usize {
_ = r;
_ = limit;
return error.EndOfStream;
}
+fn endingRebase(r: *Reader, capacity: usize) RebaseError!void {
+ _ = r;
+ _ = capacity;
+ return error.EndOfStream;
+}
+
fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
_ = r;
_ = w;
@@ -1696,6 +1693,15 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
return error.ReadFailed;
}
+pub fn adaptToOldInterface(r: *Reader) std.Io.AnyReader {
+ return .{ .context = r, .readFn = derpRead };
+}
+
+fn derpRead(context: *const anyopaque, buffer: []u8) anyerror!usize {
+ const r: *Reader = @constCast(@alignCast(@ptrCast(context)));
+ return r.readSliceShort(buffer);
+}
+
test "readAlloc when the backing reader provides one byte at a time" {
const str = "This is a test";
var tiny_buffer: [1]u8 = undefined;
@@ -1759,15 +1765,16 @@ pub fn Hashed(comptime Hasher: type) type {
return struct {
in: *Reader,
hasher: Hasher,
- interface: Reader,
+ reader: Reader,
pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {
return .{
.in = in,
.hasher = hasher,
- .interface = .{
+ .reader = .{
.vtable = &.{
- .read = @This().read,
+ .stream = @This().stream,
+ .readVec = @This().readVec,
.discard = @This().discard,
},
.buffer = buffer,
@@ -1777,33 +1784,97 @@ pub fn Hashed(comptime Hasher: type) type {
};
}
- fn read(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
- const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
- const data = w.writableVector(limit);
+ fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
+ const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
+ const data = limit.slice(try w.writableSliceGreedy(1));
+ var vec: [1][]u8 = .{data};
+ const n = try this.in.readVec(&vec);
+ this.hasher.update(data[0..n]);
+ w.advance(n);
+ return n;
+ }
+
+ fn readVec(r: *Reader, data: [][]u8) Error!usize {
+ const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
const n = try this.in.readVec(data);
- const result = w.advanceVector(n);
var remaining: usize = n;
for (data) |slice| {
if (remaining < slice.len) {
this.hasher.update(slice[0..remaining]);
- return result;
+ return n;
} else {
remaining -= slice.len;
this.hasher.update(slice);
}
}
assert(remaining == 0);
- return result;
+ return n;
}
fn discard(r: *Reader, limit: Limit) Error!usize {
- const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
- var w = this.hasher.writer(&.{});
- const n = this.in.stream(&w, limit) catch |err| switch (err) {
- error.WriteFailed => unreachable,
- else => |e| return e,
- };
- return n;
+ const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
+ const peeked = limit.slice(try this.in.peekGreedy(1));
+ this.hasher.update(peeked);
+ this.in.toss(peeked.len);
+ return peeked.len;
}
};
}
+
+pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const []u8) Error!struct { usize, usize } {
+ var i: usize = 0;
+ var n: usize = 0;
+ for (data) |buf| {
+ if (buffer.len - i == 0) return .{ i, n };
+ if (buf.len != 0) {
+ buffer[i] = .{ .base = buf.ptr, .len = buf.len };
+ i += 1;
+ n += buf.len;
+ }
+ }
+ assert(r.seek == r.end);
+ const buf = r.buffer;
+ if (buf.len != 0) {
+ buffer[i] = .{ .base = buf.ptr, .len = buf.len };
+ i += 1;
+ }
+ return .{ i, n };
+}
+
+pub fn writableVectorWsa(
+ r: *Reader,
+ buffer: []std.os.windows.ws2_32.WSABUF,
+ data: []const []u8,
+) Error!struct { usize, usize } {
+ var i: usize = 0;
+ var n: usize = 0;
+ for (data) |buf| {
+ if (buffer.len - i == 0) return .{ i, n };
+ if (buf.len == 0) continue;
+ if (std.math.cast(u32, buf.len)) |len| {
+ buffer[i] = .{ .buf = buf.ptr, .len = len };
+ i += 1;
+ n += len;
+ continue;
+ }
+ buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
+ i += 1;
+ n += std.math.maxInt(u32);
+ return .{ i, n };
+ }
+ assert(r.seek == r.end);
+ const buf = r.buffer;
+ if (buf.len != 0) {
+ if (std.math.cast(u32, buf.len)) |len| {
+ buffer[i] = .{ .buf = buf.ptr, .len = len };
+ } else {
+ buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
+ }
+ i += 1;
+ }
+ return .{ i, n };
+}
+
+test {
+ _ = Limited;
+}
diff --git a/lib/std/Io/Writer.zig b/lib/std/Io/Writer.zig
index 2263e25bb0..5ecaf078a1 100644
--- a/lib/std/Io/Writer.zig
+++ b/lib/std/Io/Writer.zig
@@ -342,97 +342,6 @@ pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error!
return big_slice[0..len];
}
-pub const WritableVectorIterator = struct {
- first: []u8,
- middle: []const []u8 = &.{},
- last: []u8 = &.{},
- index: usize = 0,
-
- pub fn next(it: *WritableVectorIterator) ?[]u8 {
- while (true) {
- const i = it.index;
- it.index += 1;
- if (i == 0) {
- if (it.first.len == 0) continue;
- return it.first;
- }
- const middle_index = i - 1;
- if (middle_index < it.middle.len) {
- const middle = it.middle[middle_index];
- if (middle.len == 0) continue;
- return middle;
- }
- if (middle_index == it.middle.len) {
- if (it.last.len == 0) continue;
- return it.last;
- }
- return null;
- }
- }
-};
-
-pub const VectorWrapper = struct {
- writer: Writer,
- it: WritableVectorIterator,
- /// Tracks whether the "writable vector" API was used.
- used: bool = false,
- pub const vtable: *const VTable = &unique_vtable_allocation;
- /// This is intended to be constant but it must be a unique address for
- /// `@fieldParentPtr` to work.
- var unique_vtable_allocation: VTable = .{ .drain = fixedDrain };
-};
-
-pub fn writableVectorIterator(w: *Writer) Error!WritableVectorIterator {
- if (w.vtable == VectorWrapper.vtable) {
- const wrapper: *VectorWrapper = @fieldParentPtr("writer", w);
- wrapper.used = true;
- return wrapper.it;
- }
- return .{ .first = try writableSliceGreedy(w, 1) };
-}
-
-pub fn writableVectorPosix(w: *Writer, buffer: []std.posix.iovec, limit: Limit) Error![]std.posix.iovec {
- var it = try writableVectorIterator(w);
- var i: usize = 0;
- var remaining = limit;
- while (it.next()) |full_buffer| {
- if (!remaining.nonzero()) break;
- if (buffer.len - i == 0) break;
- const buf = remaining.slice(full_buffer);
- if (buf.len == 0) continue;
- buffer[i] = .{ .base = buf.ptr, .len = buf.len };
- i += 1;
- remaining = remaining.subtract(buf.len).?;
- }
- return buffer[0..i];
-}
-
-pub fn writableVectorWsa(
- w: *Writer,
- buffer: []std.os.windows.ws2_32.WSABUF,
- limit: Limit,
-) Error![]std.os.windows.ws2_32.WSABUF {
- var it = try writableVectorIterator(w);
- var i: usize = 0;
- var remaining = limit;
- while (it.next()) |full_buffer| {
- if (!remaining.nonzero()) break;
- if (buffer.len - i == 0) break;
- const buf = remaining.slice(full_buffer);
- if (buf.len == 0) continue;
- if (std.math.cast(u32, buf.len)) |len| {
- buffer[i] = .{ .buf = buf.ptr, .len = len };
- i += 1;
- remaining = remaining.subtract(len).?;
- continue;
- }
- buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
- i += 1;
- break;
- }
- return buffer[0..i];
-}
-
pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
_ = try writableSliceGreedy(w, n);
}
@@ -451,13 +360,6 @@ pub fn advance(w: *Writer, n: usize) void {
w.end = new_end;
}
-/// After calling `writableVector`, this function tracks how many bytes were
-/// written to it.
-pub fn advanceVector(w: *Writer, n: usize) usize {
- if (w.vtable != VectorWrapper.vtable) advance(w, n);
- return n;
-}
-
/// The `data` parameter is mutable because this function needs to mutate the
/// fields in order to handle partial writes from `VTable.writeSplat`.
pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void {
@@ -1614,17 +1516,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)
}
pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
- if (std.math.signbit(value)) try w.writeByte('-');
- if (std.math.isNan(value)) return w.writeAll(switch (case) {
+ const v = switch (@TypeOf(value)) {
+ // comptime_float internally is a f128; this preserves precision.
+ comptime_float => @as(f128, value),
+ else => value,
+ };
+
+ if (std.math.signbit(v)) try w.writeByte('-');
+ if (std.math.isNan(v)) return w.writeAll(switch (case) {
.lower => "nan",
.upper => "NAN",
});
- if (std.math.isInf(value)) return w.writeAll(switch (case) {
+ if (std.math.isInf(v)) return w.writeAll(switch (case) {
.lower => "inf",
.upper => "INF",
});
- const T = @TypeOf(value);
+ const T = @TypeOf(v);
const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
const mantissa_bits = std.math.floatMantissaBits(T);
@@ -1634,7 +1542,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi
const exponent_mask = (1 << exponent_bits) - 1;
const exponent_bias = (1 << (exponent_bits - 1)) - 1;
- const as_bits: TU = @bitCast(value);
+ const as_bits: TU = @bitCast(v);
var mantissa = as_bits & mantissa_mask;
var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
@@ -2361,7 +2269,7 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
const pattern = data[data.len - 1];
const dest = w.buffer[w.end..];
switch (pattern.len) {
- 0 => return w.end,
+ 0 => return 0,
1 => {
assert(splat >= dest.len);
@memset(dest, pattern[0]);
@@ -2381,6 +2289,13 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
}
}
+pub fn unreachableDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
+ _ = w;
+ _ = data;
+ _ = splat;
+ unreachable;
+}
+
/// Provides a `Writer` implementation based on calling `Hasher.update`, sending
/// all data also to an underlying `Writer`.
///
@@ -2391,6 +2306,8 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
/// generic. A better solution will involve creating a writer for each hash
/// function, where the splat buffer can be tailored to the hash implementation
/// details.
+///
+/// Contrast with `Hashing` which terminates the stream pipeline.
pub fn Hashed(comptime Hasher: type) type {
return struct {
out: *Writer,
@@ -2463,6 +2380,52 @@ pub fn Hashed(comptime Hasher: type) type {
};
}
+/// Provides a `Writer` implementation based on calling `Hasher.update`,
+/// discarding all data.
+///
+/// This implementation makes suboptimal buffering decisions due to being
+/// generic. A better solution will involve creating a writer for each hash
+/// function, where the splat buffer can be tailored to the hash implementation
+/// details.
+///
+/// The total number of bytes written is stored in `hasher`.
+///
+/// Contrast with `Hashed` which also passes the data to an underlying stream.
+pub fn Hashing(comptime Hasher: type) type {
+ return struct {
+ hasher: Hasher,
+ writer: Writer,
+
+ pub fn init(buffer: []u8) @This() {
+ return .initHasher(.init(.{}), buffer);
+ }
+
+ pub fn initHasher(hasher: Hasher, buffer: []u8) @This() {
+ return .{
+ .hasher = hasher,
+ .writer = .{
+ .buffer = buffer,
+ .vtable = &.{ .drain = @This().drain },
+ },
+ };
+ }
+
+ fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
+ const this: *@This() = @alignCast(@fieldParentPtr("writer", w));
+ const hasher = &this.hasher;
+ hasher.update(w.buffered());
+ w.end = 0;
+ var n: usize = 0;
+ for (data[0 .. data.len - 1]) |slice| {
+ hasher.update(slice);
+ n += slice.len;
+ }
+ for (0..splat) |_| hasher.update(data[data.len - 1]);
+ return n + splat * data[data.len - 1].len;
+ }
+ };
+}
+
/// Maintains `Writer` state such that it writes to the unused capacity of an
/// array list, filling it up completely before making a call through the
/// vtable, causing a resize. Consequently, the same, optimized, non-generic
diff --git a/lib/std/Io/test.zig b/lib/std/Io/test.zig
index b6bd835f84..b4d7f51d68 100644
--- a/lib/std/Io/test.zig
+++ b/lib/std/Io/test.zig
@@ -57,51 +57,6 @@ test "write a file, read it, then delete it" {
try tmp.dir.deleteFile(tmp_file_name);
}
-test "BitStreams with File Stream" {
- var tmp = tmpDir(.{});
- defer tmp.cleanup();
-
- const tmp_file_name = "temp_test_file.txt";
- {
- var file = try tmp.dir.createFile(tmp_file_name, .{});
- defer file.close();
-
- var bit_stream = io.bitWriter(native_endian, file.deprecatedWriter());
-
- try bit_stream.writeBits(@as(u2, 1), 1);
- try bit_stream.writeBits(@as(u5, 2), 2);
- try bit_stream.writeBits(@as(u128, 3), 3);
- try bit_stream.writeBits(@as(u8, 4), 4);
- try bit_stream.writeBits(@as(u9, 5), 5);
- try bit_stream.writeBits(@as(u1, 1), 1);
- try bit_stream.flushBits();
- }
- {
- var file = try tmp.dir.openFile(tmp_file_name, .{});
- defer file.close();
-
- var bit_stream = io.bitReader(native_endian, file.deprecatedReader());
-
- var out_bits: u16 = undefined;
-
- try expect(1 == try bit_stream.readBits(u2, 1, &out_bits));
- try expect(out_bits == 1);
- try expect(2 == try bit_stream.readBits(u5, 2, &out_bits));
- try expect(out_bits == 2);
- try expect(3 == try bit_stream.readBits(u128, 3, &out_bits));
- try expect(out_bits == 3);
- try expect(4 == try bit_stream.readBits(u8, 4, &out_bits));
- try expect(out_bits == 4);
- try expect(5 == try bit_stream.readBits(u9, 5, &out_bits));
- try expect(out_bits == 5);
- try expect(1 == try bit_stream.readBits(u1, 1, &out_bits));
- try expect(out_bits == 1);
-
- try expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
- }
- try tmp.dir.deleteFile(tmp_file_name);
-}
-
test "File seek ops" {
var tmp = tmpDir(.{});
defer tmp.cleanup();
diff --git a/lib/std/Progress.zig b/lib/std/Progress.zig
index 5ee5828970..8b741187e7 100644
--- a/lib/std/Progress.zig
+++ b/lib/std/Progress.zig
@@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent,
/// Accessed atomically.
done: bool,
need_clear: bool,
+status: Status,
refresh_rate_ns: u64,
initial_delay_ns: u64,
@@ -47,6 +48,22 @@ node_freelist: Freelist,
/// value may at times temporarily exceed the node count.
node_end_index: u32,
+pub const Status = enum {
+ /// Indicates the application is progressing towards completion of a task.
+ /// Unless the application is interactive, this is the only status the
+ /// program will ever have!
+ working,
+ /// The application has completed an operation, and is now waiting for user
+ /// input rather than calling exit(0).
+ success,
+ /// The application encountered an error, and is now waiting for user input
+ /// rather than calling exit(1).
+ failure,
+ /// The application encountered at least one error, but is still working on
+ /// more tasks.
+ failure_working,
+};
+
const Freelist = packed struct(u32) {
head: Node.OptionalIndex,
/// Whenever `node_freelist` is added to, this generation is incremented
@@ -383,6 +400,7 @@ var global_progress: Progress = .{
.draw_buffer = undefined,
.done = false,
.need_clear = false,
+ .status = .working,
.node_parents = &node_parents_buffer,
.node_storage = &node_storage_buffer,
@@ -498,6 +516,11 @@ pub fn start(options: Options) Node {
return root_node;
}
+pub fn setStatus(new_status: Status) void {
+ if (noop_impl) return;
+ @atomicStore(Status, &global_progress.status, new_status, .monotonic);
+}
+
/// Returns whether a resize is needed to learn the terminal size.
fn wait(timeout_ns: u64) bool {
const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|
@@ -678,6 +701,14 @@ const save = "\x1b7";
const restore = "\x1b8";
const finish_sync = "\x1b[?2026l";
+const progress_remove = "\x1b]9;4;0\x07";
+const @"progress_normal {d}" = "\x1b]9;4;1;{d}\x07";
+const @"progress_error {d}" = "\x1b]9;4;2;{d}\x07";
+const progress_pulsing = "\x1b]9;4;3\x07";
+const progress_pulsing_error = "\x1b]9;4;2\x07";
+const progress_normal_100 = "\x1b]9;4;1;100\x07";
+const progress_error_100 = "\x1b]9;4;2;100\x07";
+
const TreeSymbol = enum {
/// ├─
tee,
@@ -760,7 +791,7 @@ fn clearWrittenWithEscapeCodes() anyerror!void {
if (noop_impl or !global_progress.need_clear) return;
global_progress.need_clear = false;
- try write(clear);
+ try write(clear ++ progress_remove);
}
/// U+25BA or â–º
@@ -1203,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index);
if (global_progress.terminal_mode == .ansi_escape_codes) {
+ {
+ // Set progress state https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
+ const root_storage = &serialized.storage[0];
+ const storage = if (root_storage.name[0] != 0 or children[0].child == .none) root_storage else &serialized.storage[@intFromEnum(children[0].child)];
+ const estimated_total = storage.estimated_total_count;
+ const completed_items = storage.completed_count;
+ const status = @atomicLoad(Status, &global_progress.status, .monotonic);
+ switch (status) {
+ .working => {
+ if (estimated_total == 0) {
+ buf[i..][0..progress_pulsing.len].* = progress_pulsing.*;
+ i += progress_pulsing.len;
+ } else {
+ const percent = completed_items * 100 / estimated_total;
+ i += (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent}) catch &.{}).len;
+ }
+ },
+ .success => {
+ buf[i..][0..progress_remove.len].* = progress_remove.*;
+ i += progress_remove.len;
+ },
+ .failure => {
+ buf[i..][0..progress_error_100.len].* = progress_error_100.*;
+ i += progress_error_100.len;
+ },
+ .failure_working => {
+ if (estimated_total == 0) {
+ buf[i..][0..progress_pulsing_error.len].* = progress_pulsing_error.*;
+ i += progress_pulsing_error.len;
+ } else {
+ const percent = completed_items * 100 / estimated_total;
+ i += (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent}) catch &.{}).len;
+ }
+ },
+ }
+ }
+
if (nl_n > 0) {
buf[i] = '\r';
i += 1;
@@ -1480,6 +1548,7 @@ const have_sigwinch = switch (builtin.os.tag) {
.visionos,
.dragonfly,
.freebsd,
+ .serenity,
=> true,
else => false,
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 13de7aa68e..307bba304e 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -897,8 +897,8 @@ pub const VaList = switch (builtin.cpu.arch) {
.windows => *u8,
.ios, .macos, .tvos, .watchos, .visionos => *u8,
else => switch (builtin.zig_backend) {
- .stage2_aarch64 => VaListAarch64,
- else => @compileError("disabled due to miscompilations"),
+ else => VaListAarch64,
+ .stage2_llvm => @compileError("disabled due to miscompilations"),
},
},
.arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {
@@ -923,7 +923,10 @@ pub const VaList = switch (builtin.cpu.arch) {
.wasm32, .wasm64 => *anyopaque,
.x86 => *u8,
.x86_64 => switch (builtin.os.tag) {
- .windows => @compileError("disabled due to miscompilations"), // *u8,
+ .windows => switch (builtin.zig_backend) {
+ else => *u8,
+ .stage2_llvm => @compileError("disabled due to miscompilations"),
+ },
else => VaListX86_64,
},
.xtensa => VaListXtensa,
diff --git a/lib/std/c.zig b/lib/std/c.zig
index e2f55dd6fb..6a0289f5f0 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -204,6 +204,29 @@ pub const passwd = switch (native_os) {
shell: ?[*:0]const u8, // default shell
expire: time_t, // account expiration
},
+ .dragonfly, .freebsd => extern struct {
+ name: ?[*:0]const u8, // user name
+ passwd: ?[*:0]const u8, // encrypted password
+ uid: uid_t, // user uid
+ gid: gid_t, // user gid
+ change: time_t, // password change time
+ class: ?[*:0]const u8, // user access class
+ gecos: ?[*:0]const u8, // Honeywell login info
+ dir: ?[*:0]const u8, // home directory
+ shell: ?[*:0]const u8, // default shell
+ expire: time_t, // account expiration
+ fields: c_int, // internal
+ },
+ else => void,
+};
+
+pub const group = switch (native_os) {
+ .linux, .freebsd, .openbsd, .dragonfly, .netbsd, .macos => extern struct {
+ name: ?[*:0]const u8,
+ passwd: ?[*:0]const u8,
+ gid: gid_t,
+ mem: [*:null]?[*:0]const u8,
+ },
else => void,
};
@@ -3291,8 +3314,8 @@ pub const T = switch (native_os) {
.macos, .ios, .tvos, .watchos, .visionos => struct {
pub const IOCGWINSZ = ior(0x40000000, 't', 104, @sizeOf(winsize));
- fn ior(inout: u32, group: usize, num: usize, len: usize) usize {
- return (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num));
+ fn ior(inout: u32, group_arg: usize, num: usize, len: usize) usize {
+ return (inout | ((len & IOCPARM_MASK) << 16) | ((group_arg) << 8) | (num));
}
},
.freebsd => struct {
@@ -4121,7 +4144,7 @@ pub const msghdr_const = switch (native_os) {
.serenity => extern struct {
name: ?*const anyopaque,
namelen: socklen_t,
- iov: [*]const iovec,
+ iov: [*]const iovec_const,
iovlen: c_uint,
control: ?*const anyopaque,
controllen: socklen_t,
@@ -8604,7 +8627,7 @@ pub const O = switch (native_os) {
},
// https://github.com/SerenityOS/serenity/blob/2808b0376406a40e31293bb3bcb9170374e90506/Kernel/API/POSIX/fcntl.h#L28-L43
.serenity => packed struct(c_int) {
- ACCMODE: std.posix.ACCMODE = .RDONLY,
+ ACCMODE: std.posix.ACCMODE = .NONE,
EXEC: bool = false,
CREAT: bool = false,
EXCL: bool = false,
@@ -8760,10 +8783,10 @@ pub const MAP = switch (native_os) {
},
// https://github.com/SerenityOS/serenity/blob/6d59d4d3d9e76e39112842ec487840828f1c9bfe/Kernel/API/POSIX/sys/mman.h#L16-L26
.serenity => packed struct(c_int) {
- FILE: bool = false,
- SHARED: bool = false,
- PRIVATE: bool = false,
- _3: u2 = 0,
+ TYPE: enum(u4) {
+ SHARED = 0x01,
+ PRIVATE = 0x02,
+ },
FIXED: bool = false,
ANONYMOUS: bool = false,
STACK: bool = false,
@@ -8771,7 +8794,7 @@ pub const MAP = switch (native_os) {
RANDOMIZED: bool = false,
PURGEABLE: bool = false,
FIXED_NOREPLACE: bool = false,
- _: std.meta.Int(.unsigned, @bitSizeOf(c_int) - 12) = 0,
+ _: std.meta.Int(.unsigned, @bitSizeOf(c_int) - 11) = 0,
},
else => void,
};
@@ -10261,9 +10284,20 @@ pub const fstatat = switch (native_os) {
},
else => private.fstatat,
};
-
+pub extern "c" fn getpwent() ?*passwd;
+pub extern "c" fn endpwent() void;
+pub extern "c" fn setpwent() void;
pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;
+pub extern "c" fn getpwnam_r(name: [*:0]const u8, pwd: *passwd, buf: [*]u8, buflen: usize, result: *?*passwd) c_int;
pub extern "c" fn getpwuid(uid: uid_t) ?*passwd;
+pub extern "c" fn getpwuid_r(uid: uid_t, pwd: *passwd, buf: [*]u8, buflen: usize, result: *?*passwd) c_int;
+pub extern "c" fn getgrent() ?*group;
+pub extern "c" fn setgrent() void;
+pub extern "c" fn endgrent() void;
+pub extern "c" fn getgrnam(name: [*:0]const u8) ?*passwd;
+pub extern "c" fn getgrnam_r(name: [*:0]const u8, grp: *group, buf: [*]u8, buflen: usize, result: *?*group) c_int;
+pub extern "c" fn getgrgid(gid: gid_t) ?*group;
+pub extern "c" fn getgrgid_r(gid: gid_t, grp: *group, buf: [*]u8, buflen: usize, result: *?*group) c_int;
pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
pub extern "c" fn mmap64(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;
@@ -10992,11 +11026,7 @@ pub const bcrypt = openbsd.bcrypt;
pub const bcrypt_checkpass = openbsd.bcrypt_checkpass;
pub const bcrypt_gensalt = openbsd.bcrypt_gensalt;
pub const bcrypt_newhash = openbsd.bcrypt_newhash;
-pub const endpwent = openbsd.endpwent;
-pub const getpwent = openbsd.getpwent;
-pub const getpwnam_r = openbsd.getpwnam_r;
pub const getpwnam_shadow = openbsd.getpwnam_shadow;
-pub const getpwuid_r = openbsd.getpwuid_r;
pub const getpwuid_shadow = openbsd.getpwuid_shadow;
pub const getthrid = openbsd.getthrid;
pub const login_cap_t = openbsd.login_cap_t;
@@ -11013,7 +11043,6 @@ pub const pthread_spinlock_t = openbsd.pthread_spinlock_t;
pub const pw_dup = openbsd.pw_dup;
pub const setclasscontext = openbsd.setclasscontext;
pub const setpassent = openbsd.setpassent;
-pub const setpwent = openbsd.setpwent;
pub const setusercontext = openbsd.setusercontext;
pub const uid_from_user = openbsd.uid_from_user;
pub const unveil = openbsd.unveil;
diff --git a/lib/std/c/openbsd.zig b/lib/std/c/openbsd.zig
index af86d38397..242d988de3 100644
--- a/lib/std/c/openbsd.zig
+++ b/lib/std/c/openbsd.zig
@@ -81,11 +81,6 @@ pub extern "c" fn auth_checknologin(lc: *login_cap_t) void;
pub extern "c" fn getpwuid_shadow(uid: uid_t) ?*passwd;
pub extern "c" fn getpwnam_shadow(name: [*:0]const u8) ?*passwd;
-pub extern "c" fn getpwnam_r(name: [*:0]const u8, pw: *passwd, buf: [*]u8, buflen: usize, pwretp: *?*passwd) c_int;
-pub extern "c" fn getpwuid_r(uid: uid_t, pw: *passwd, buf: [*]u8, buflen: usize, pwretp: *?*passwd) c_int;
-pub extern "c" fn getpwent() ?*passwd;
-pub extern "c" fn setpwent() void;
-pub extern "c" fn endpwent() void;
pub extern "c" fn setpassent(stayopen: c_int) c_int;
pub extern "c" fn uid_from_user(name: [*:0]const u8, uid: *uid_t) c_int;
pub extern "c" fn user_from_uid(uid: uid_t, noname: c_int) ?[*:0]const u8;
diff --git a/lib/std/compress/flate.zig b/lib/std/compress/flate.zig
index b20cced5c0..4391a06787 100644
--- a/lib/std/compress/flate.zig
+++ b/lib/std/compress/flate.zig
@@ -1,7 +1,23 @@
-const builtin = @import("builtin");
const std = @import("../std.zig");
-const testing = std.testing;
-const Writer = std.io.Writer;
+
+/// When decompressing, the output buffer is used as the history window, so
+/// less than this may result in failure to decompress streams that were
+/// compressed with a larger window.
+pub const max_window_len = history_len * 2;
+
+pub const history_len = 32768;
+
+/// Deflate is a lossless data compression file format that uses a combination
+/// of LZ77 and Huffman coding.
+pub const Compress = @import("flate/Compress.zig");
+
+/// Inflate is the decoding process that consumes a Deflate bitstream and
+/// produces the original full-size data.
+pub const Decompress = @import("flate/Decompress.zig");
+
+/// Compression without Lempel-Ziv match searching. Faster compression, less
+/// memory requirements but bigger compressed sizes.
+pub const HuffmanEncoder = @import("flate/HuffmanEncoder.zig");
/// Container of the deflate bit stream body. Container adds header before
/// deflate bit stream and footer after. It can bi gzip, zlib or raw (no header,
@@ -13,7 +29,6 @@ const Writer = std.io.Writer;
/// Gzip format is defined in rfc 1952. Header has 10+ bytes and footer 4 bytes
/// crc32 checksum and 4 bytes of uncompressed data length.
///
-///
/// rfc 1950: https://datatracker.ietf.org/doc/html/rfc1950#page-4
/// rfc 1952: https://datatracker.ietf.org/doc/html/rfc1952#page-5
pub const Container = enum {
@@ -77,14 +92,14 @@ pub const Container = enum {
raw: void,
gzip: struct {
crc: std.hash.Crc32 = .init(),
- count: usize = 0,
+ count: u32 = 0,
},
zlib: std.hash.Adler32,
pub fn init(containter: Container) Hasher {
return switch (containter) {
.gzip => .{ .gzip = .{} },
- .zlib => .{ .zlib = .init() },
+ .zlib => .{ .zlib = .{} },
.raw => .raw,
};
}
@@ -98,7 +113,7 @@ pub const Container = enum {
.raw => {},
.gzip => |*gzip| {
gzip.update(buf);
- gzip.count += buf.len;
+ gzip.count +%= buf.len;
},
.zlib => |*zlib| {
zlib.update(buf);
@@ -107,7 +122,7 @@ pub const Container = enum {
}
}
- pub fn writeFooter(hasher: *Hasher, writer: *Writer) Writer.Error!void {
+ pub fn writeFooter(hasher: *Hasher, writer: *std.Io.Writer) std.Io.Writer.Error!void {
var bits: [4]u8 = undefined;
switch (hasher.*) {
.gzip => |*gzip| {
@@ -133,502 +148,33 @@ pub const Container = enum {
}
}
};
-};
-/// When decompressing, the output buffer is used as the history window, so
-/// less than this may result in failure to decompress streams that were
-/// compressed with a larger window.
-pub const max_window_len = 1 << 16;
+ pub const Metadata = union(Container) {
+ raw: void,
+ gzip: struct {
+ crc: u32 = 0,
+ count: u32 = 0,
+ },
+ zlib: struct {
+ adler: u32 = 0,
+ },
-/// Deflate is a lossless data compression file format that uses a combination
-/// of LZ77 and Huffman coding.
-pub const Compress = @import("flate/Compress.zig");
+ pub fn init(containter: Container) Metadata {
+ return switch (containter) {
+ .gzip => .{ .gzip = .{} },
+ .zlib => .{ .zlib = .{} },
+ .raw => .raw,
+ };
+ }
-/// Inflate is the decoding process that takes a Deflate bitstream for
-/// decompression and correctly produces the original full-size data or file.
-pub const Decompress = @import("flate/Decompress.zig");
-
-/// Huffman only compression. Without Lempel-Ziv match searching. Faster
-/// compression, less memory requirements but bigger compressed sizes.
-pub const huffman = struct {
- // The odd order in which the codegen code sizes are written.
- pub const codegen_order = [_]u32{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
- // The number of codegen codes.
- pub const codegen_code_count = 19;
-
- // The largest distance code.
- pub const distance_code_count = 30;
-
- // Maximum number of literals.
- pub const max_num_lit = 286;
-
- // Max number of frequencies used for a Huffman Code
- // Possible lengths are codegen_code_count (19), distance_code_count (30) and max_num_lit (286).
- // The largest of these is max_num_lit.
- pub const max_num_frequencies = max_num_lit;
-
- // Biggest block size for uncompressed block.
- pub const max_store_block_size = 65535;
- // The special code used to mark the end of a block.
- pub const end_block_marker = 256;
+ pub fn container(m: Metadata) Container {
+ return m;
+ }
+ };
};
test {
+ _ = HuffmanEncoder;
_ = Compress;
_ = Decompress;
}
-
-test "compress/decompress" {
- const print = std.debug.print;
- var cmp_buf: [64 * 1024]u8 = undefined; // compressed data buffer
- var dcm_buf: [64 * 1024]u8 = undefined; // decompressed data buffer
-
- const levels = [_]Compress.Level{ .level_4, .level_5, .level_6, .level_7, .level_8, .level_9 };
- const cases = [_]struct {
- data: []const u8, // uncompressed content
- // compressed data sizes per level 4-9
- gzip_sizes: [levels.len]usize = [_]usize{0} ** levels.len,
- huffman_only_size: usize = 0,
- store_size: usize = 0,
- }{
- .{
- .data = @embedFile("flate/testdata/rfc1951.txt"),
- .gzip_sizes = [_]usize{ 11513, 11217, 11139, 11126, 11122, 11119 },
- .huffman_only_size = 20287,
- .store_size = 36967,
- },
- .{
- .data = @embedFile("flate/testdata/fuzz/roundtrip1.input"),
- .gzip_sizes = [_]usize{ 373, 370, 370, 370, 370, 370 },
- .huffman_only_size = 393,
- .store_size = 393,
- },
- .{
- .data = @embedFile("flate/testdata/fuzz/roundtrip2.input"),
- .gzip_sizes = [_]usize{ 373, 373, 373, 373, 373, 373 },
- .huffman_only_size = 394,
- .store_size = 394,
- },
- .{
- .data = @embedFile("flate/testdata/fuzz/deflate-stream.expect"),
- .gzip_sizes = [_]usize{ 351, 347, 347, 347, 347, 347 },
- .huffman_only_size = 498,
- .store_size = 747,
- },
- };
-
- for (cases, 0..) |case, case_no| { // for each case
- const data = case.data;
-
- for (levels, 0..) |level, i| { // for each compression level
-
- inline for (Container.list) |container| { // for each wrapping
- var compressed_size: usize = if (case.gzip_sizes[i] > 0)
- case.gzip_sizes[i] - Container.gzip.size() + container.size()
- else
- 0;
-
- // compress original stream to compressed stream
- {
- var original: std.io.Reader = .fixed(data);
- var compressed: Writer = .fixed(&cmp_buf);
- var compress: Compress = .init(&original, &.{}, .{ .container = .raw, .level = level });
- const n = try compress.reader.streamRemaining(&compressed);
- if (compressed_size == 0) {
- if (container == .gzip)
- print("case {d} gzip level {} compressed size: {d}\n", .{ case_no, level, compressed.pos });
- compressed_size = compressed.end;
- }
- try testing.expectEqual(compressed_size, n);
- try testing.expectEqual(compressed_size, compressed.end);
- }
- // decompress compressed stream to decompressed stream
- {
- var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
- var decompressed: Writer = .fixed(&dcm_buf);
- try Decompress.pump(container, &compressed, &decompressed);
- try testing.expectEqualSlices(u8, data, decompressed.getWritten());
- }
-
- // compressor writer interface
- {
- var compressed: Writer = .fixed(&cmp_buf);
- var cmp = try Compress.init(container, &compressed, .{ .level = level });
- var cmp_wrt = cmp.writer();
- try cmp_wrt.writeAll(data);
- try cmp.finish();
-
- try testing.expectEqual(compressed_size, compressed.pos);
- }
- // decompressor reader interface
- {
- var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
- var dcm = Decompress.pump(container, &compressed);
- var dcm_rdr = dcm.reader();
- const n = try dcm_rdr.readAll(&dcm_buf);
- try testing.expectEqual(data.len, n);
- try testing.expectEqualSlices(u8, data, dcm_buf[0..n]);
- }
- }
- }
- // huffman only compression
- {
- inline for (Container.list) |container| { // for each wrapping
- var compressed_size: usize = if (case.huffman_only_size > 0)
- case.huffman_only_size - Container.gzip.size() + container.size()
- else
- 0;
-
- // compress original stream to compressed stream
- {
- var original: std.io.Reader = .fixed(data);
- var compressed: Writer = .fixed(&cmp_buf);
- var cmp = try Compress.Huffman.init(container, &compressed);
- try cmp.compress(original.reader());
- try cmp.finish();
- if (compressed_size == 0) {
- if (container == .gzip)
- print("case {d} huffman only compressed size: {d}\n", .{ case_no, compressed.pos });
- compressed_size = compressed.pos;
- }
- try testing.expectEqual(compressed_size, compressed.pos);
- }
- // decompress compressed stream to decompressed stream
- {
- var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
- var decompressed: Writer = .fixed(&dcm_buf);
- try Decompress.pump(container, &compressed, &decompressed);
- try testing.expectEqualSlices(u8, data, decompressed.getWritten());
- }
- }
- }
-
- // store only
- {
- inline for (Container.list) |container| { // for each wrapping
- var compressed_size: usize = if (case.store_size > 0)
- case.store_size - Container.gzip.size() + container.size()
- else
- 0;
-
- // compress original stream to compressed stream
- {
- var original: std.io.Reader = .fixed(data);
- var compressed: Writer = .fixed(&cmp_buf);
- var cmp = try Compress.SimpleCompressor(.store, container).init(&compressed);
- try cmp.compress(original.reader());
- try cmp.finish();
- if (compressed_size == 0) {
- if (container == .gzip)
- print("case {d} store only compressed size: {d}\n", .{ case_no, compressed.pos });
- compressed_size = compressed.pos;
- }
-
- try testing.expectEqual(compressed_size, compressed.pos);
- }
- // decompress compressed stream to decompressed stream
- {
- var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
- var decompressed: Writer = .fixed(&dcm_buf);
- try Decompress.pump(container, &compressed, &decompressed);
- try testing.expectEqualSlices(u8, data, decompressed.getWritten());
- }
- }
- }
- }
-}
-
-fn testDecompress(comptime container: Container, compressed: []const u8, expected_plain: []const u8) !void {
- var in: std.io.Reader = .fixed(compressed);
- var out: std.io.Writer.Allocating = .init(testing.allocator);
- defer out.deinit();
-
- try Decompress.pump(container, &in, &out.interface);
- try testing.expectEqualSlices(u8, expected_plain, out.items);
-}
-
-test "don't read past deflate stream's end" {
- try testDecompress(.zlib, &[_]u8{
- 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0xc0, 0x00, 0xc1, 0xff,
- 0xff, 0x43, 0x30, 0x03, 0x03, 0xc3, 0xff, 0xff, 0xff, 0x01,
- 0x83, 0x95, 0x0b, 0xf5,
- }, &[_]u8{
- 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
- 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
- 0x00, 0x00, 0xff, 0xff, 0xff,
- });
-}
-
-test "zlib header" {
- // Truncated header
- try testing.expectError(
- error.EndOfStream,
- testDecompress(.zlib, &[_]u8{0x78}, ""),
- );
- // Wrong CM
- try testing.expectError(
- error.BadZlibHeader,
- testDecompress(.zlib, &[_]u8{ 0x79, 0x94 }, ""),
- );
- // Wrong CINFO
- try testing.expectError(
- error.BadZlibHeader,
- testDecompress(.zlib, &[_]u8{ 0x88, 0x98 }, ""),
- );
- // Wrong checksum
- try testing.expectError(
- error.WrongZlibChecksum,
- testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, ""),
- );
- // Truncated checksum
- try testing.expectError(
- error.EndOfStream,
- testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, ""),
- );
-}
-
-test "gzip header" {
- // Truncated header
- try testing.expectError(
- error.EndOfStream,
- testDecompress(.gzip, &[_]u8{ 0x1f, 0x8B }, undefined),
- );
- // Wrong CM
- try testing.expectError(
- error.BadGzipHeader,
- testDecompress(.gzip, &[_]u8{
- 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x03,
- }, undefined),
- );
-
- // Wrong checksum
- try testing.expectError(
- error.WrongGzipChecksum,
- testDecompress(.gzip, &[_]u8{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- }, undefined),
- );
- // Truncated checksum
- try testing.expectError(
- error.EndOfStream,
- testDecompress(.gzip, &[_]u8{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
- }, undefined),
- );
- // Wrong initial size
- try testing.expectError(
- error.WrongGzipSize,
- testDecompress(.gzip, &[_]u8{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- }, undefined),
- );
- // Truncated initial size field
- try testing.expectError(
- error.EndOfStream,
- testDecompress(.gzip, &[_]u8{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- }, undefined),
- );
-
- try testDecompress(.gzip, &[_]u8{
- // GZIP header
- 0x1f, 0x8b, 0x08, 0x12, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00,
- // header.FHCRC (should cover entire header)
- 0x99, 0xd6,
- // GZIP data
- 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- }, "");
-}
-
-test "public interface" {
- const plain_data_buf = [_]u8{ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a };
-
- // deflate final stored block, header + plain (stored) data
- const deflate_block = [_]u8{
- 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
- } ++ plain_data_buf;
-
- const plain_data: []const u8 = &plain_data_buf;
- const gzip_data: []const u8 = &deflate_block;
-
- //// gzip header/footer + deflate block
- //const gzip_data =
- // [_]u8{ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 } ++ // gzip header (10 bytes)
- // deflate_block ++
- // [_]u8{ 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00 }; // gzip footer checksum (4 byte), size (4 bytes)
-
- //// zlib header/footer + deflate block
- //const zlib_data = [_]u8{ 0x78, 0b10_0_11100 } ++ // zlib header (2 bytes)}
- // deflate_block ++
- // [_]u8{ 0x1c, 0xf2, 0x04, 0x47 }; // zlib footer: checksum
-
- // TODO
- //const gzip = @import("gzip.zig");
- //const zlib = @import("zlib.zig");
-
- var buffer1: [64]u8 = undefined;
- var buffer2: [64]u8 = undefined;
-
- // TODO These used to be functions, need to migrate the tests
- const decompress = void;
- const compress = void;
- const store = void;
-
- // decompress
- {
- var plain: Writer = .fixed(&buffer2);
-
- var in: std.io.Reader = .fixed(gzip_data);
- try decompress(&in, &plain);
- try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
- }
-
- // compress/decompress
- {
- var plain: Writer = .fixed(&buffer2);
- var compressed: Writer = .fixed(&buffer1);
-
- var in: std.io.Reader = .fixed(plain_data);
- try compress(&in, &compressed, .{});
-
- var compressed_br: std.io.Reader = .fixed(&buffer1);
- try decompress(&compressed_br, &plain);
- try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
- }
-
- // compressor/decompressor
- {
- var plain: Writer = .fixed(&buffer2);
- var compressed: Writer = .fixed(&buffer1);
-
- var in: std.io.Reader = .fixed(plain_data);
- var cmp = try Compress(&compressed, .{});
- try cmp.compress(&in);
- try cmp.finish();
-
- var compressed_br: std.io.Reader = .fixed(&buffer1);
- var dcp = Decompress(&compressed_br);
- try dcp.decompress(&plain);
- try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
- }
-
- // huffman
- {
- // huffman compress/decompress
- {
- var plain: Writer = .fixed(&buffer2);
- var compressed: Writer = .fixed(&buffer1);
-
- var in: std.io.Reader = .fixed(plain_data);
- try huffman.compress(&in, &compressed);
-
- var compressed_br: std.io.Reader = .fixed(&buffer1);
- try decompress(&compressed_br, &plain);
- try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
- }
-
- // huffman compressor/decompressor
- {
- var plain: Writer = .fixed(&buffer2);
- var compressed: Writer = .fixed(&buffer1);
-
- var in: std.io.Reader = .fixed(plain_data);
- var cmp = try huffman.Compressor(&compressed);
- try cmp.compress(&in);
- try cmp.finish();
-
- var compressed_br: std.io.Reader = .fixed(&buffer1);
- try decompress(&compressed_br, &plain);
- try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
- }
- }
-
- // store
- {
- // store compress/decompress
- {
- var plain: Writer = .fixed(&buffer2);
- var compressed: Writer = .fixed(&buffer1);
-
- var in: std.io.Reader = .fixed(plain_data);
- try store.compress(&in, &compressed);
-
- var compressed_br: std.io.Reader = .fixed(&buffer1);
- try decompress(&compressed_br, &plain);
- try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
- }
-
- // store compressor/decompressor
- {
- var plain: Writer = .fixed(&buffer2);
- var compressed: Writer = .fixed(&buffer1);
-
- var in: std.io.Reader = .fixed(plain_data);
- var cmp = try store.compressor(&compressed);
- try cmp.compress(&in);
- try cmp.finish();
-
- var compressed_br: std.io.Reader = .fixed(&buffer1);
- try decompress(&compressed_br, &plain);
- try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
- }
- }
-}
-
-pub const match = struct {
- pub const base_length = 3; // smallest match length per the RFC section 3.2.5
- pub const min_length = 4; // min length used in this algorithm
- pub const max_length = 258;
-
- pub const min_distance = 1;
- pub const max_distance = 32768;
-};
-
-pub const history_len = match.max_distance;
-
-pub const lookup = struct {
- pub const bits = 15;
- pub const len = 1 << bits;
- pub const shift = 32 - bits;
-};
-
-test "zlib should not overshoot" {
- // Compressed zlib data with extra 4 bytes at the end.
- const data = [_]u8{
- 0x78, 0x9c, 0x73, 0xce, 0x2f, 0xa8, 0x2c, 0xca, 0x4c, 0xcf, 0x28, 0x51, 0x08, 0xcf, 0xcc, 0xc9,
- 0x49, 0xcd, 0x55, 0x28, 0x4b, 0xcc, 0x53, 0x08, 0x4e, 0xce, 0x48, 0xcc, 0xcc, 0xd6, 0x51, 0x08,
- 0xce, 0xcc, 0x4b, 0x4f, 0x2c, 0xc8, 0x2f, 0x4a, 0x55, 0x30, 0xb4, 0xb4, 0x34, 0xd5, 0xb5, 0x34,
- 0x03, 0x00, 0x8b, 0x61, 0x0f, 0xa4, 0x52, 0x5a, 0x94, 0x12,
- };
-
- var stream: std.io.Reader = .fixed(&data);
- const reader = stream.reader();
-
- var dcp = Decompress.init(reader);
- var out: [128]u8 = undefined;
-
- // Decompress
- var n = try dcp.reader().readAll(out[0..]);
-
- // Expected decompressed data
- try std.testing.expectEqual(46, n);
- try std.testing.expectEqualStrings("Copyright Willem van Schaik, Singapore 1995-96", out[0..n]);
-
- // Decompressor don't overshoot underlying reader.
- // It is leaving it at the end of compressed data chunk.
- try std.testing.expectEqual(data.len - 4, stream.getPos());
- try std.testing.expectEqual(0, dcp.unreadBytes());
-
- // 4 bytes after compressed chunk are available in reader.
- n = try reader.readAll(out[0..]);
- try std.testing.expectEqual(n, 4);
- try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]);
-}
diff --git a/lib/std/compress/flate/BlockWriter.zig b/lib/std/compress/flate/BlockWriter.zig
index d1eb3a068e..d0e9dc1203 100644
--- a/lib/std/compress/flate/BlockWriter.zig
+++ b/lib/std/compress/flate/BlockWriter.zig
@@ -8,34 +8,54 @@ const Writer = std.io.Writer;
const BlockWriter = @This();
const flate = @import("../flate.zig");
const Compress = flate.Compress;
-const huffman = flate.huffman;
+const HuffmanEncoder = flate.HuffmanEncoder;
const Token = @import("Token.zig");
-const codegen_order = huffman.codegen_order;
+const codegen_order = HuffmanEncoder.codegen_order;
const end_code_mark = 255;
output: *Writer,
-codegen_freq: [huffman.codegen_code_count]u16 = undefined,
-literal_freq: [huffman.max_num_lit]u16 = undefined,
-distance_freq: [huffman.distance_code_count]u16 = undefined,
-codegen: [huffman.max_num_lit + huffman.distance_code_count + 1]u8 = undefined,
-literal_encoding: Compress.LiteralEncoder = .{},
-distance_encoding: Compress.DistanceEncoder = .{},
-codegen_encoding: Compress.CodegenEncoder = .{},
-fixed_literal_encoding: Compress.LiteralEncoder,
-fixed_distance_encoding: Compress.DistanceEncoder,
-huff_distance: Compress.DistanceEncoder,
+codegen_freq: [HuffmanEncoder.codegen_code_count]u16,
+literal_freq: [HuffmanEncoder.max_num_lit]u16,
+distance_freq: [HuffmanEncoder.distance_code_count]u16,
+codegen: [HuffmanEncoder.max_num_lit + HuffmanEncoder.distance_code_count + 1]u8,
+literal_encoding: HuffmanEncoder,
+distance_encoding: HuffmanEncoder,
+codegen_encoding: HuffmanEncoder,
+fixed_literal_encoding: HuffmanEncoder,
+fixed_distance_encoding: HuffmanEncoder,
+huff_distance: HuffmanEncoder,
+
+fixed_literal_codes: [HuffmanEncoder.max_num_frequencies]HuffmanEncoder.Code,
+fixed_distance_codes: [HuffmanEncoder.distance_code_count]HuffmanEncoder.Code,
+distance_codes: [HuffmanEncoder.distance_code_count]HuffmanEncoder.Code,
pub fn init(output: *Writer) BlockWriter {
return .{
.output = output,
- .fixed_literal_encoding = Compress.fixedLiteralEncoder(),
- .fixed_distance_encoding = Compress.fixedDistanceEncoder(),
- .huff_distance = Compress.huffmanDistanceEncoder(),
+ .codegen_freq = undefined,
+ .literal_freq = undefined,
+ .distance_freq = undefined,
+ .codegen = undefined,
+ .literal_encoding = undefined,
+ .distance_encoding = undefined,
+ .codegen_encoding = undefined,
+ .fixed_literal_encoding = undefined,
+ .fixed_distance_encoding = undefined,
+ .huff_distance = undefined,
+ .fixed_literal_codes = undefined,
+ .fixed_distance_codes = undefined,
+ .distance_codes = undefined,
};
}
+pub fn initBuffers(bw: *BlockWriter) void {
+ bw.fixed_literal_encoding = .fixedLiteralEncoder(&bw.fixed_literal_codes);
+ bw.fixed_distance_encoding = .fixedDistanceEncoder(&bw.fixed_distance_codes);
+ bw.huff_distance = .huffmanDistanceEncoder(&bw.distance_codes);
+}
+
/// Flush intrenal bit buffer to the writer.
/// Should be called only when bit stream is at byte boundary.
///
@@ -46,27 +66,23 @@ pub fn flush(self: *BlockWriter) Writer.Error!void {
try self.bit_writer.flush();
}
-pub fn setWriter(self: *BlockWriter, new_writer: *Writer) void {
- self.bit_writer.setWriter(new_writer);
-}
-
fn writeCode(self: *BlockWriter, c: Compress.HuffCode) Writer.Error!void {
try self.bit_writer.writeBits(c.code, c.len);
}
-// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
-// the literal and distance lengths arrays (which are concatenated into a single
-// array). This method generates that run-length encoding.
-//
-// The result is written into the codegen array, and the frequencies
-// of each code is written into the codegen_freq array.
-// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
-// information. Code bad_code is an end marker
-//
-// num_literals: The number of literals in literal_encoding
-// num_distances: The number of distances in distance_encoding
-// lit_enc: The literal encoder to use
-// dist_enc: The distance encoder to use
+/// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
+/// the literal and distance lengths arrays (which are concatenated into a single
+/// array). This method generates that run-length encoding.
+///
+/// The result is written into the codegen array, and the frequencies
+/// of each code is written into the codegen_freq array.
+/// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
+/// information. Code bad_code is an end marker
+///
+/// num_literals: The number of literals in literal_encoding
+/// num_distances: The number of distances in distance_encoding
+/// lit_enc: The literal encoder to use
+/// dist_enc: The distance encoder to use
fn generateCodegen(
self: *BlockWriter,
num_literals: u32,
@@ -167,7 +183,7 @@ const DynamicSize = struct {
num_codegens: u32,
};
-// dynamicSize returns the size of dynamically encoded data in bits.
+/// dynamicSize returns the size of dynamically encoded data in bits.
fn dynamicSize(
self: *BlockWriter,
lit_enc: *Compress.LiteralEncoder, // literal encoder
@@ -194,7 +210,7 @@ fn dynamicSize(
};
}
-// fixedSize returns the size of dynamically encoded data in bits.
+/// fixedSize returns the size of dynamically encoded data in bits.
fn fixedSize(self: *BlockWriter, extra_bits: u32) u32 {
return 3 +
self.fixed_literal_encoding.bitLength(&self.literal_freq) +
@@ -207,25 +223,25 @@ const StoredSize = struct {
storable: bool,
};
-// storedSizeFits calculates the stored size, including header.
-// The function returns the size in bits and whether the block
-// fits inside a single block.
+/// storedSizeFits calculates the stored size, including header.
+/// The function returns the size in bits and whether the block
+/// fits inside a single block.
fn storedSizeFits(in: ?[]const u8) StoredSize {
if (in == null) {
return .{ .size = 0, .storable = false };
}
- if (in.?.len <= huffman.max_store_block_size) {
+ if (in.?.len <= HuffmanEncoder.max_store_block_size) {
return .{ .size = @as(u32, @intCast((in.?.len + 5) * 8)), .storable = true };
}
return .{ .size = 0, .storable = false };
}
-// Write the header of a dynamic Huffman block to the output stream.
-//
-// num_literals: The number of literals specified in codegen
-// num_distances: The number of distances specified in codegen
-// num_codegens: The number of codegens used in codegen
-// eof: Is it the end-of-file? (end of stream)
+/// Write the header of a dynamic Huffman block to the output stream.
+///
+/// num_literals: The number of literals specified in codegen
+/// num_distances: The number of distances specified in codegen
+/// num_codegens: The number of codegens used in codegen
+/// eof: Is it the end-of-file? (end of stream)
fn dynamicHeader(
self: *BlockWriter,
num_literals: u32,
@@ -291,11 +307,11 @@ fn fixedHeader(self: *BlockWriter, eof: bool) Writer.Error!void {
try self.bit_writer.writeBits(value, 3);
}
-// Write a block of tokens with the smallest encoding. Will choose block type.
-// The original input can be supplied, and if the huffman encoded data
-// is larger than the original bytes, the data will be written as a
-// stored block.
-// If the input is null, the tokens will always be Huffman encoded.
+/// Write a block of tokens with the smallest encoding. Will choose block type.
+/// The original input can be supplied, and if the huffman encoded data
+/// is larger than the original bytes, the data will be written as a
+/// stored block.
+/// If the input is null, the tokens will always be Huffman encoded.
pub fn write(self: *BlockWriter, tokens: []const Token, eof: bool, input: ?[]const u8) Writer.Error!void {
const lit_and_dist = self.indexTokens(tokens);
const num_literals = lit_and_dist.num_literals;
@@ -379,11 +395,11 @@ pub fn storedBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Erro
try self.bit_writer.writeBytes(input);
}
-// writeBlockDynamic encodes a block using a dynamic Huffman table.
-// This should be used if the symbols used have a disproportionate
-// histogram distribution.
-// If input is supplied and the compression savings are below 1/16th of the
-// input size the block is stored.
+/// writeBlockDynamic encodes a block using a dynamic Huffman table.
+/// This should be used if the symbols used have a disproportionate
+/// histogram distribution.
+/// If input is supplied and the compression savings are below 1/16th of the
+/// input size the block is stored.
fn dynamicBlock(
self: *BlockWriter,
tokens: []const Token,
@@ -429,10 +445,10 @@ const TotalIndexedTokens = struct {
num_distances: u32,
};
-// Indexes a slice of tokens followed by an end_block_marker, and updates
-// literal_freq and distance_freq, and generates literal_encoding
-// and distance_encoding.
-// The number of literal and distance tokens is returned.
+/// Indexes a slice of tokens followed by an end_block_marker, and updates
+/// literal_freq and distance_freq, and generates literal_encoding
+/// and distance_encoding.
+/// The number of literal and distance tokens is returned.
fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
var num_literals: u32 = 0;
var num_distances: u32 = 0;
@@ -453,7 +469,7 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
self.distance_freq[t.distanceCode()] += 1;
}
// add end_block_marker token at the end
- self.literal_freq[huffman.end_block_marker] += 1;
+ self.literal_freq[HuffmanEncoder.end_block_marker] += 1;
// get the number of literals
num_literals = @as(u32, @intCast(self.literal_freq.len));
@@ -479,8 +495,8 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
};
}
-// Writes a slice of tokens to the output followed by and end_block_marker.
-// codes for literal and distance encoding must be supplied.
+/// Writes a slice of tokens to the output followed by and end_block_marker.
+/// codes for literal and distance encoding must be supplied.
fn writeTokens(
self: *BlockWriter,
tokens: []const Token,
@@ -508,18 +524,18 @@ fn writeTokens(
}
}
// add end_block_marker at the end
- try self.writeCode(le_codes[huffman.end_block_marker]);
+ try self.writeCode(le_codes[HuffmanEncoder.end_block_marker]);
}
-// Encodes a block of bytes as either Huffman encoded literals or uncompressed bytes
-// if the results only gains very little from compression.
+/// Encodes a block of bytes as either Huffman encoded literals or uncompressed bytes
+/// if the results only gains very little from compression.
pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Error!void {
// Add everything as literals
histogram(input, &self.literal_freq);
- self.literal_freq[huffman.end_block_marker] = 1;
+ self.literal_freq[HuffmanEncoder.end_block_marker] = 1;
- const num_literals = huffman.end_block_marker + 1;
+ const num_literals = HuffmanEncoder.end_block_marker + 1;
self.distance_freq[0] = 1;
const num_distances = 1;
@@ -560,10 +576,9 @@ pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Err
const c = encoding[t];
try self.bit_writer.writeBits(c.code, c.len);
}
- try self.writeCode(encoding[huffman.end_block_marker]);
+ try self.writeCode(encoding[HuffmanEncoder.end_block_marker]);
}
-// histogram accumulates a histogram of b in h.
fn histogram(b: []const u8, h: *[286]u16) void {
// Clear histogram
for (h, 0..) |_, i| {
@@ -575,122 +590,3 @@ fn histogram(b: []const u8, h: *[286]u16) void {
lh[t] += 1;
}
}
-
-// tests
-const expect = std.testing.expect;
-const fmt = std.fmt;
-const testing = std.testing;
-const ArrayList = std.ArrayList;
-
-const TestCase = @import("testdata/block_writer.zig").TestCase;
-const testCases = @import("testdata/block_writer.zig").testCases;
-
-// tests if the writeBlock encoding has changed.
-test "write" {
- inline for (0..testCases.len) |i| {
- try testBlock(testCases[i], .write_block);
- }
-}
-
-// tests if the writeBlockDynamic encoding has changed.
-test "dynamicBlock" {
- inline for (0..testCases.len) |i| {
- try testBlock(testCases[i], .write_dyn_block);
- }
-}
-
-test "huffmanBlock" {
- inline for (0..testCases.len) |i| {
- try testBlock(testCases[i], .write_huffman_block);
- }
- try testBlock(.{
- .tokens = &[_]Token{},
- .input = "huffman-rand-max.input",
- .want = "huffman-rand-max.{s}.expect",
- }, .write_huffman_block);
-}
-
-const TestFn = enum {
- write_block,
- write_dyn_block, // write dynamic block
- write_huffman_block,
-
- fn to_s(self: TestFn) []const u8 {
- return switch (self) {
- .write_block => "wb",
- .write_dyn_block => "dyn",
- .write_huffman_block => "huff",
- };
- }
-
- fn write(
- comptime self: TestFn,
- bw: anytype,
- tok: []const Token,
- input: ?[]const u8,
- final: bool,
- ) !void {
- switch (self) {
- .write_block => try bw.write(tok, final, input),
- .write_dyn_block => try bw.dynamicBlock(tok, final, input),
- .write_huffman_block => try bw.huffmanBlock(input.?, final),
- }
- try bw.flush();
- }
-};
-
-// testBlock tests a block against its references
-//
-// size
-// 64K [file-name].input - input non compressed file
-// 8.1K [file-name].golden -
-// 78 [file-name].dyn.expect - output with writeBlockDynamic
-// 78 [file-name].wb.expect - output with writeBlock
-// 8.1K [file-name].huff.expect - output with writeBlockHuff
-// 78 [file-name].dyn.expect-noinput - output with writeBlockDynamic when input is null
-// 78 [file-name].wb.expect-noinput - output with writeBlock when input is null
-//
-// wb - writeBlock
-// dyn - writeBlockDynamic
-// huff - writeBlockHuff
-//
-fn testBlock(comptime tc: TestCase, comptime tfn: TestFn) !void {
- if (tc.input.len != 0 and tc.want.len != 0) {
- const want_name = comptime fmt.comptimePrint(tc.want, .{tfn.to_s()});
- const input = @embedFile("testdata/block_writer/" ++ tc.input);
- const want = @embedFile("testdata/block_writer/" ++ want_name);
- try testWriteBlock(tfn, input, want, tc.tokens);
- }
-
- if (tfn == .write_huffman_block) {
- return;
- }
-
- const want_name_no_input = comptime fmt.comptimePrint(tc.want_no_input, .{tfn.to_s()});
- const want = @embedFile("testdata/block_writer/" ++ want_name_no_input);
- try testWriteBlock(tfn, null, want, tc.tokens);
-}
-
-// Uses writer function `tfn` to write `tokens`, tests that we got `want` as output.
-fn testWriteBlock(comptime tfn: TestFn, input: ?[]const u8, want: []const u8, tokens: []const Token) !void {
- var buf = ArrayList(u8).init(testing.allocator);
- var bw: BlockWriter = .init(buf.writer());
- try tfn.write(&bw, tokens, input, false);
- var got = buf.items;
- try testing.expectEqualSlices(u8, want, got); // expect writeBlock to yield expected result
- try expect(got[0] & 0b0000_0001 == 0); // bfinal is not set
- //
- // Test if the writer produces the same output after reset.
- buf.deinit();
- buf = ArrayList(u8).init(testing.allocator);
- defer buf.deinit();
- bw.setWriter(buf.writer());
-
- try tfn.write(&bw, tokens, input, true);
- try bw.flush();
- got = buf.items;
-
- try expect(got[0] & 1 == 1); // bfinal is set
- buf.items[0] &= 0b1111_1110; // remove bfinal bit, so we can run test slices
- try testing.expectEqualSlices(u8, want, got); // expect writeBlock to yield expected result
-}
diff --git a/lib/std/compress/flate/Compress.zig b/lib/std/compress/flate/Compress.zig
index 045f0ab237..2249ece4c0 100644
--- a/lib/std/compress/flate/Compress.zig
+++ b/lib/std/compress/flate/Compress.zig
@@ -39,16 +39,15 @@
//!
//!
//! Allocates statically ~400K (192K lookup, 128K tokens, 64K window).
+
const builtin = @import("builtin");
const std = @import("std");
-const io = std.io;
const assert = std.debug.assert;
const testing = std.testing;
const expect = testing.expect;
const mem = std.mem;
const math = std.math;
-const Writer = std.io.Writer;
-const Reader = std.io.Reader;
+const Writer = std.Io.Writer;
const Compress = @This();
const Token = @import("Token.zig");
@@ -56,26 +55,23 @@ const BlockWriter = @import("BlockWriter.zig");
const flate = @import("../flate.zig");
const Container = flate.Container;
const Lookup = @import("Lookup.zig");
-const huffman = flate.huffman;
+const HuffmanEncoder = flate.HuffmanEncoder;
+const LiteralNode = HuffmanEncoder.LiteralNode;
lookup: Lookup = .{},
tokens: Tokens = .{},
-/// Asserted to have a buffer capacity of at least `flate.max_window_len`.
-input: *std.io.Reader,
block_writer: BlockWriter,
level: LevelArgs,
hasher: Container.Hasher,
-reader: std.io.Reader,
+writer: Writer,
+state: State,
// Match and literal at the previous position.
// Used for lazy match finding in processWindow.
prev_match: ?Token = null,
prev_literal: ?u8 = null,
-pub const Options = struct {
- level: Level = .default,
- container: Container = .raw,
-};
+pub const State = enum { header, middle, ended };
/// Trades between speed and compression size.
/// Starts with level 4: in [zlib](https://github.com/madler/zlib/blob/abd3d1a28930f89375d4b41408b39f6c1be157b2/deflate.c#L115C1-L117C43)
@@ -119,188 +115,24 @@ const LevelArgs = struct {
}
};
-pub fn init(input: *std.io.Reader, buffer: []u8, options: Options) Compress {
+pub const Options = struct {
+ level: Level = .default,
+ container: Container = .raw,
+};
+
+pub fn init(output: *Writer, buffer: []u8, options: Options) Compress {
return .{
- .input = input,
- .block_writer = undefined,
+ .block_writer = .init(output),
.level = .get(options.level),
.hasher = .init(options.container),
.state = .header,
- .reader = .{
+ .writer = .{
.buffer = buffer,
- .stream = stream,
+ .vtable = &.{ .drain = drain },
},
};
}
-const FlushOption = enum { none, flush, final };
-
-/// Process data in window and create tokens. If token buffer is full
-/// flush tokens to the token writer.
-///
-/// Returns number of bytes consumed from `lh`.
-fn tokenizeSlice(c: *Compress, bw: *Writer, limit: std.io.Limit, lh: []const u8) !usize {
- _ = bw;
- _ = limit;
- if (true) @panic("TODO");
- var step: u16 = 1; // 1 in the case of literal, match length otherwise
- const pos: u16 = c.win.pos();
- const literal = lh[0]; // literal at current position
- const min_len: u16 = if (c.prev_match) |m| m.length() else 0;
-
- // Try to find match at least min_len long.
- if (c.findMatch(pos, lh, min_len)) |match| {
- // Found better match than previous.
- try c.addPrevLiteral();
-
- // Is found match length good enough?
- if (match.length() >= c.level.lazy) {
- // Don't try to lazy find better match, use this.
- step = try c.addMatch(match);
- } else {
- // Store this match.
- c.prev_literal = literal;
- c.prev_match = match;
- }
- } else {
- // There is no better match at current pos then it was previous.
- // Write previous match or literal.
- if (c.prev_match) |m| {
- // Write match from previous position.
- step = try c.addMatch(m) - 1; // we already advanced 1 from previous position
- } else {
- // No match at previous position.
- // Write previous literal if any, and remember this literal.
- try c.addPrevLiteral();
- c.prev_literal = literal;
- }
- }
- // Advance window and add hashes.
- c.windowAdvance(step, lh, pos);
-}
-
-fn windowAdvance(self: *Compress, step: u16, lh: []const u8, pos: u16) void {
- // current position is already added in findMatch
- self.lookup.bulkAdd(lh[1..], step - 1, pos + 1);
- self.win.advance(step);
-}
-
-// Add previous literal (if any) to the tokens list.
-fn addPrevLiteral(self: *Compress) !void {
- if (self.prev_literal) |l| try self.addToken(Token.initLiteral(l));
-}
-
-// Add match to the tokens list, reset prev pointers.
-// Returns length of the added match.
-fn addMatch(self: *Compress, m: Token) !u16 {
- try self.addToken(m);
- self.prev_literal = null;
- self.prev_match = null;
- return m.length();
-}
-
-fn addToken(self: *Compress, token: Token) !void {
- self.tokens.add(token);
- if (self.tokens.full()) try self.flushTokens(.none);
-}
-
-// Finds largest match in the history window with the data at current pos.
-fn findMatch(self: *Compress, pos: u16, lh: []const u8, min_len: u16) ?Token {
- var len: u16 = min_len;
- // Previous location with the same hash (same 4 bytes).
- var prev_pos = self.lookup.add(lh, pos);
- // Last found match.
- var match: ?Token = null;
-
- // How much back-references to try, performance knob.
- var chain: usize = self.level.chain;
- if (len >= self.level.good) {
- // If we've got a match that's good enough, only look in 1/4 the chain.
- chain >>= 2;
- }
-
- // Hot path loop!
- while (prev_pos > 0 and chain > 0) : (chain -= 1) {
- const distance = pos - prev_pos;
- if (distance > flate.match.max_distance)
- break;
-
- const new_len = self.win.match(prev_pos, pos, len);
- if (new_len > len) {
- match = Token.initMatch(@intCast(distance), new_len);
- if (new_len >= self.level.nice) {
- // The match is good enough that we don't try to find a better one.
- return match;
- }
- len = new_len;
- }
- prev_pos = self.lookup.prev(prev_pos);
- }
-
- return match;
-}
-
-fn flushTokens(self: *Compress, flush_opt: FlushOption) !void {
- // Pass tokens to the token writer
- try self.block_writer.write(self.tokens.tokens(), flush_opt == .final, self.win.tokensBuffer());
- // Stored block ensures byte alignment.
- // It has 3 bits (final, block_type) and then padding until byte boundary.
- // After that everything is aligned to the boundary in the stored block.
- // Empty stored block is Ob000 + (0-7) bits of padding + 0x00 0x00 0xFF 0xFF.
- // Last 4 bytes are byte aligned.
- if (flush_opt == .flush) {
- try self.block_writer.storedBlock("", false);
- }
- if (flush_opt != .none) {
- // Safe to call only when byte aligned or it is OK to add
- // padding bits (on last byte of the final block).
- try self.block_writer.flush();
- }
- // Reset internal tokens store.
- self.tokens.reset();
- // Notify win that tokens are flushed.
- self.win.flush();
-}
-
-// Slide win and if needed lookup tables.
-fn slide(self: *Compress) void {
- const n = self.win.slide();
- self.lookup.slide(n);
-}
-
-/// Flushes internal buffers to the output writer. Outputs empty stored
-/// block to sync bit stream to the byte boundary, so that the
-/// decompressor can get all input data available so far.
-///
-/// It is useful mainly in compressed network protocols, to ensure that
-/// deflate bit stream can be used as byte stream. May degrade
-/// compression so it should be used only when necessary.
-///
-/// Completes the current deflate block and follows it with an empty
-/// stored block that is three zero bits plus filler bits to the next
-/// byte, followed by four bytes (00 00 ff ff).
-///
-pub fn flush(c: *Compress) !void {
- try c.tokenize(.flush);
-}
-
-/// Completes deflate bit stream by writing any pending data as deflate
-/// final deflate block. HAS to be called once all data are written to
-/// the compressor as a signal that next block has to have final bit
-/// set.
-///
-pub fn finish(c: *Compress) !void {
- _ = c;
- @panic("TODO");
-}
-
-/// Use another writer while preserving history. Most probably flush
-/// should be called on old writer before setting new.
-pub fn setWriter(self: *Compress, new_writer: *Writer) void {
- self.block_writer.setWriter(new_writer);
- self.output = new_writer;
-}
-
// Tokens store
const Tokens = struct {
list: [n_tokens]Token = undefined,
@@ -324,528 +156,113 @@ const Tokens = struct {
}
};
-/// Creates huffman only deflate blocks. Disables Lempel-Ziv match searching and
-/// only performs Huffman entropy encoding. Results in faster compression, much
-/// less memory requirements during compression but bigger compressed sizes.
-pub const Huffman = SimpleCompressor(.huffman, .raw);
-
-/// Creates store blocks only. Data are not compressed only packed into deflate
-/// store blocks. That adds 9 bytes of header for each block. Max stored block
-/// size is 64K. Block is emitted when flush is called on on finish.
-pub const store = struct {
- pub fn Compressor(comptime container: Container, comptime WriterType: type) type {
- return SimpleCompressor(.store, container, WriterType);
- }
-
- pub fn compressor(comptime container: Container, writer: anytype) !store.Compressor(container, @TypeOf(writer)) {
- return try store.Compressor(container, @TypeOf(writer)).init(writer);
- }
-};
-
-const SimpleCompressorKind = enum {
- huffman,
- store,
-};
-
-fn simpleCompressor(
- comptime kind: SimpleCompressorKind,
- comptime container: Container,
- writer: anytype,
-) !SimpleCompressor(kind, container, @TypeOf(writer)) {
- return try SimpleCompressor(kind, container, @TypeOf(writer)).init(writer);
-}
-
-fn SimpleCompressor(
- comptime kind: SimpleCompressorKind,
- comptime container: Container,
- comptime WriterType: type,
-) type {
- const BlockWriterType = BlockWriter(WriterType);
- return struct {
- buffer: [65535]u8 = undefined, // because store blocks are limited to 65535 bytes
- wp: usize = 0,
-
- output: WriterType,
- block_writer: BlockWriterType,
- hasher: container.Hasher() = .{},
-
- const Self = @This();
-
- pub fn init(output: WriterType) !Self {
- const self = Self{
- .output = output,
- .block_writer = BlockWriterType.init(output),
- };
- try container.writeHeader(self.output);
- return self;
- }
-
- pub fn flush(self: *Self) !void {
- try self.flushBuffer(false);
- try self.block_writer.storedBlock("", false);
- try self.block_writer.flush();
- }
-
- pub fn finish(self: *Self) !void {
- try self.flushBuffer(true);
- try self.block_writer.flush();
- try container.writeFooter(&self.hasher, self.output);
- }
-
- fn flushBuffer(self: *Self, final: bool) !void {
- const buf = self.buffer[0..self.wp];
- switch (kind) {
- .huffman => try self.block_writer.huffmanBlock(buf, final),
- .store => try self.block_writer.storedBlock(buf, final),
- }
- self.wp = 0;
- }
- };
-}
-
-const LiteralNode = struct {
- literal: u16,
- freq: u16,
-};
-
-// Describes the state of the constructed tree for a given depth.
-const LevelInfo = struct {
- // Our level. for better printing
- level: u32,
-
- // The frequency of the last node at this level
- last_freq: u32,
-
- // The frequency of the next character to add to this level
- next_char_freq: u32,
-
- // The frequency of the next pair (from level below) to add to this level.
- // Only valid if the "needed" value of the next lower level is 0.
- next_pair_freq: u32,
-
- // The number of chains remaining to generate for this level before moving
- // up to the next level
- needed: u32,
-};
-
-// hcode is a huffman code with a bit code and bit length.
-pub const HuffCode = struct {
- code: u16 = 0,
- len: u16 = 0,
-
- // set sets the code and length of an hcode.
- fn set(self: *HuffCode, code: u16, length: u16) void {
- self.len = length;
- self.code = code;
- }
-};
-
-pub fn HuffmanEncoder(comptime size: usize) type {
- return struct {
- codes: [size]HuffCode = undefined,
- // Reusable buffer with the longest possible frequency table.
- freq_cache: [huffman.max_num_frequencies + 1]LiteralNode = undefined,
- bit_count: [17]u32 = undefined,
- lns: []LiteralNode = undefined, // sorted by literal, stored to avoid repeated allocation in generate
- lfs: []LiteralNode = undefined, // sorted by frequency, stored to avoid repeated allocation in generate
-
- const Self = @This();
-
- // Update this Huffman Code object to be the minimum code for the specified frequency count.
- //
- // freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
- // max_bits The maximum number of bits to use for any literal.
- pub fn generate(self: *Self, freq: []u16, max_bits: u32) void {
- var list = self.freq_cache[0 .. freq.len + 1];
- // Number of non-zero literals
- var count: u32 = 0;
- // Set list to be the set of all non-zero literals and their frequencies
- for (freq, 0..) |f, i| {
- if (f != 0) {
- list[count] = LiteralNode{ .literal = @as(u16, @intCast(i)), .freq = f };
- count += 1;
- } else {
- list[count] = LiteralNode{ .literal = 0x00, .freq = 0 };
- self.codes[i].len = 0;
- }
- }
- list[freq.len] = LiteralNode{ .literal = 0x00, .freq = 0 };
-
- list = list[0..count];
- if (count <= 2) {
- // Handle the small cases here, because they are awkward for the general case code. With
- // two or fewer literals, everything has bit length 1.
- for (list, 0..) |node, i| {
- // "list" is in order of increasing literal value.
- self.codes[node.literal].set(@as(u16, @intCast(i)), 1);
- }
- return;
- }
- self.lfs = list;
- mem.sort(LiteralNode, self.lfs, {}, byFreq);
-
- // Get the number of literals for each bit count
- const bit_count = self.bitCounts(list, max_bits);
- // And do the assignment
- self.assignEncodingAndSize(bit_count, list);
- }
-
- pub fn bitLength(self: *Self, freq: []u16) u32 {
- var total: u32 = 0;
- for (freq, 0..) |f, i| {
- if (f != 0) {
- total += @as(u32, @intCast(f)) * @as(u32, @intCast(self.codes[i].len));
- }
- }
- return total;
- }
-
- // Return the number of literals assigned to each bit size in the Huffman encoding
- //
- // This method is only called when list.len >= 3
- // The cases of 0, 1, and 2 literals are handled by special case code.
- //
- // list: An array of the literals with non-zero frequencies
- // and their associated frequencies. The array is in order of increasing
- // frequency, and has as its last element a special element with frequency
- // `math.maxInt(i32)`
- //
- // max_bits: The maximum number of bits that should be used to encode any literal.
- // Must be less than 16.
- //
- // Returns an integer array in which array[i] indicates the number of literals
- // that should be encoded in i bits.
- fn bitCounts(self: *Self, list: []LiteralNode, max_bits_to_use: usize) []u32 {
- var max_bits = max_bits_to_use;
- const n = list.len;
- const max_bits_limit = 16;
-
- assert(max_bits < max_bits_limit);
-
- // The tree can't have greater depth than n - 1, no matter what. This
- // saves a little bit of work in some small cases
- max_bits = @min(max_bits, n - 1);
-
- // Create information about each of the levels.
- // A bogus "Level 0" whose sole purpose is so that
- // level1.prev.needed == 0. This makes level1.next_pair_freq
- // be a legitimate value that never gets chosen.
- var levels: [max_bits_limit]LevelInfo = mem.zeroes([max_bits_limit]LevelInfo);
- // leaf_counts[i] counts the number of literals at the left
- // of ancestors of the rightmost node at level i.
- // leaf_counts[i][j] is the number of literals at the left
- // of the level j ancestor.
- var leaf_counts: [max_bits_limit][max_bits_limit]u32 = mem.zeroes([max_bits_limit][max_bits_limit]u32);
-
- {
- var level = @as(u32, 1);
- while (level <= max_bits) : (level += 1) {
- // For every level, the first two items are the first two characters.
- // We initialize the levels as if we had already figured this out.
- levels[level] = LevelInfo{
- .level = level,
- .last_freq = list[1].freq,
- .next_char_freq = list[2].freq,
- .next_pair_freq = list[0].freq + list[1].freq,
- .needed = 0,
- };
- leaf_counts[level][level] = 2;
- if (level == 1) {
- levels[level].next_pair_freq = math.maxInt(i32);
- }
- }
- }
-
- // We need a total of 2*n - 2 items at top level and have already generated 2.
- levels[max_bits].needed = 2 * @as(u32, @intCast(n)) - 4;
-
- {
- var level = max_bits;
- while (true) {
- var l = &levels[level];
- if (l.next_pair_freq == math.maxInt(i32) and l.next_char_freq == math.maxInt(i32)) {
- // We've run out of both leaves and pairs.
- // End all calculations for this level.
- // To make sure we never come back to this level or any lower level,
- // set next_pair_freq impossibly large.
- l.needed = 0;
- levels[level + 1].next_pair_freq = math.maxInt(i32);
- level += 1;
- continue;
- }
-
- const prev_freq = l.last_freq;
- if (l.next_char_freq < l.next_pair_freq) {
- // The next item on this row is a leaf node.
- const next = leaf_counts[level][level] + 1;
- l.last_freq = l.next_char_freq;
- // Lower leaf_counts are the same of the previous node.
- leaf_counts[level][level] = next;
- if (next >= list.len) {
- l.next_char_freq = maxNode().freq;
- } else {
- l.next_char_freq = list[next].freq;
- }
- } else {
- // The next item on this row is a pair from the previous row.
- // next_pair_freq isn't valid until we generate two
- // more values in the level below
- l.last_freq = l.next_pair_freq;
- // Take leaf counts from the lower level, except counts[level] remains the same.
- @memcpy(leaf_counts[level][0..level], leaf_counts[level - 1][0..level]);
- levels[l.level - 1].needed = 2;
- }
-
- l.needed -= 1;
- if (l.needed == 0) {
- // We've done everything we need to do for this level.
- // Continue calculating one level up. Fill in next_pair_freq
- // of that level with the sum of the two nodes we've just calculated on
- // this level.
- if (l.level == max_bits) {
- // All done!
- break;
- }
- levels[l.level + 1].next_pair_freq = prev_freq + l.last_freq;
- level += 1;
- } else {
- // If we stole from below, move down temporarily to replenish it.
- while (levels[level - 1].needed > 0) {
- level -= 1;
- if (level == 0) {
- break;
- }
- }
- }
- }
- }
-
- // Somethings is wrong if at the end, the top level is null or hasn't used
- // all of the leaves.
- assert(leaf_counts[max_bits][max_bits] == n);
-
- var bit_count = self.bit_count[0 .. max_bits + 1];
- var bits: u32 = 1;
- const counts = &leaf_counts[max_bits];
- {
- var level = max_bits;
- while (level > 0) : (level -= 1) {
- // counts[level] gives the number of literals requiring at least "bits"
- // bits to encode.
- bit_count[bits] = counts[level] - counts[level - 1];
- bits += 1;
- if (level == 0) {
- break;
- }
- }
- }
- return bit_count;
- }
-
- // Look at the leaves and assign them a bit count and an encoding as specified
- // in RFC 1951 3.2.2
- fn assignEncodingAndSize(self: *Self, bit_count: []u32, list_arg: []LiteralNode) void {
- var code = @as(u16, 0);
- var list = list_arg;
-
- for (bit_count, 0..) |bits, n| {
- code <<= 1;
- if (n == 0 or bits == 0) {
- continue;
- }
- // The literals list[list.len-bits] .. list[list.len-bits]
- // are encoded using "bits" bits, and get the values
- // code, code + 1, .... The code values are
- // assigned in literal order (not frequency order).
- const chunk = list[list.len - @as(u32, @intCast(bits)) ..];
-
- self.lns = chunk;
- mem.sort(LiteralNode, self.lns, {}, byLiteral);
-
- for (chunk) |node| {
- self.codes[node.literal] = HuffCode{
- .code = bitReverse(u16, code, @as(u5, @intCast(n))),
- .len = @as(u16, @intCast(n)),
- };
- code += 1;
- }
- list = list[0 .. list.len - @as(u32, @intCast(bits))];
- }
- }
- };
-}
-
-fn maxNode() LiteralNode {
- return LiteralNode{
- .literal = math.maxInt(u16),
- .freq = math.maxInt(u16),
- };
-}
-
-pub fn huffmanEncoder(comptime size: u32) HuffmanEncoder(size) {
- return .{};
-}
-
-pub const LiteralEncoder = HuffmanEncoder(huffman.max_num_frequencies);
-pub const DistanceEncoder = HuffmanEncoder(huffman.distance_code_count);
-pub const CodegenEncoder = HuffmanEncoder(19);
-
-// Generates a HuffmanCode corresponding to the fixed literal table
-pub fn fixedLiteralEncoder() LiteralEncoder {
- var h: LiteralEncoder = undefined;
- var ch: u16 = 0;
-
- while (ch < huffman.max_num_frequencies) : (ch += 1) {
- var bits: u16 = undefined;
- var size: u16 = undefined;
- switch (ch) {
- 0...143 => {
- // size 8, 000110000 .. 10111111
- bits = ch + 48;
- size = 8;
- },
- 144...255 => {
- // size 9, 110010000 .. 111111111
- bits = ch + 400 - 144;
- size = 9;
- },
- 256...279 => {
- // size 7, 0000000 .. 0010111
- bits = ch - 256;
- size = 7;
- },
- else => {
- // size 8, 11000000 .. 11000111
- bits = ch + 192 - 280;
- size = 8;
- },
- }
- h.codes[ch] = HuffCode{ .code = bitReverse(u16, bits, @as(u5, @intCast(size))), .len = size };
- }
- return h;
-}
-
-pub fn fixedDistanceEncoder() DistanceEncoder {
- var h: DistanceEncoder = undefined;
- for (h.codes, 0..) |_, ch| {
- h.codes[ch] = HuffCode{ .code = bitReverse(u16, @as(u16, @intCast(ch)), 5), .len = 5 };
- }
- return h;
-}
-
-pub fn huffmanDistanceEncoder() DistanceEncoder {
- var distance_freq = [1]u16{0} ** huffman.distance_code_count;
- distance_freq[0] = 1;
- // huff_distance is a static distance encoder used for huffman only encoding.
- // It can be reused since we will not be encoding distance values.
- var h: DistanceEncoder = .{};
- h.generate(distance_freq[0..], 15);
- return h;
-}
-
-fn byLiteral(context: void, a: LiteralNode, b: LiteralNode) bool {
- _ = context;
- return a.literal < b.literal;
-}
-
-fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool {
- _ = context;
- if (a.freq == b.freq) {
- return a.literal < b.literal;
- }
- return a.freq < b.freq;
-}
-
-fn stream(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {
- const c: *Compress = @fieldParentPtr("reader", r);
+fn drain(me: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {
+ _ = data;
+ _ = splat;
+ const c: *Compress = @fieldParentPtr("writer", me);
+ const out = c.block_writer.output;
switch (c.state) {
- .header => |i| {
+ .header => {
+ c.state = .middle;
const header = c.hasher.container().header();
- const n = try w.write(header[i..]);
- if (header.len - i - n == 0) {
- c.state = .middle;
- } else {
- c.state.header += n;
- }
- return n;
+ try out.writeAll(header);
+ return header.len;
},
- .middle => {
- c.input.fillMore() catch |err| switch (err) {
- error.EndOfStream => {
- c.state = .final;
- return 0;
- },
- else => |e| return e,
- };
- const buffer_contents = c.input.buffered();
- const min_lookahead = flate.match.min_length + flate.match.max_length;
- const history_plus_lookahead_len = flate.history_len + min_lookahead;
- if (buffer_contents.len < history_plus_lookahead_len) return 0;
- const lookahead = buffer_contents[flate.history_len..];
- const start = w.count;
- const n = try c.tokenizeSlice(w, limit, lookahead) catch |err| switch (err) {
- error.WriteFailed => return error.WriteFailed,
- };
- c.hasher.update(lookahead[0..n]);
- c.input.toss(n);
- return w.count - start;
- },
- .final => {
- const buffer_contents = c.input.buffered();
- const start = w.count;
- const n = c.tokenizeSlice(w, limit, buffer_contents) catch |err| switch (err) {
- error.WriteFailed => return error.WriteFailed,
- };
- if (buffer_contents.len - n == 0) {
- c.hasher.update(buffer_contents);
- c.input.tossAll();
- {
- // In the case of flushing, last few lookahead buffers were
- // smaller than min match len, so only last literal can be
- // unwritten.
- assert(c.prev_match == null);
- try c.addPrevLiteral();
- c.prev_literal = null;
+ .middle => {},
+ .ended => unreachable,
+ }
- try c.flushTokens(.final);
- }
- switch (c.hasher) {
- .gzip => |*gzip| {
- // GZIP 8 bytes footer
- // - 4 bytes, CRC32 (CRC-32)
- // - 4 bytes, ISIZE (Input SIZE) - size of the original (uncompressed) input data modulo 2^32
- comptime assert(c.footer_buffer.len == 8);
- std.mem.writeInt(u32, c.footer_buffer[0..4], gzip.final(), .little);
- std.mem.writeInt(u32, c.footer_buffer[4..8], gzip.bytes_read, .little);
- c.state = .{ .footer = 0 };
- },
- .zlib => |*zlib| {
- // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
- // 4 bytes of ADLER32 (Adler-32 checksum)
- // Checksum value of the uncompressed data (excluding any
- // dictionary data) computed according to Adler-32
- // algorithm.
- comptime assert(c.footer_buffer.len == 8);
- std.mem.writeInt(u32, c.footer_buffer[4..8], zlib.final, .big);
- c.state = .{ .footer = 4 };
- },
- .raw => {
- c.state = .ended;
- },
- }
- }
- return w.count - start;
+ const buffered = me.buffered();
+ const min_lookahead = Token.min_length + Token.max_length;
+ const history_plus_lookahead_len = flate.history_len + min_lookahead;
+ if (buffered.len < history_plus_lookahead_len) return 0;
+ const lookahead = buffered[flate.history_len..];
+
+ // TODO tokenize
+ _ = lookahead;
+ //c.hasher.update(lookahead[0..n]);
+ @panic("TODO");
+}
+
+pub fn end(c: *Compress) !void {
+ try endUnflushed(c);
+ const out = c.block_writer.output;
+ try out.flush();
+}
+
+pub fn endUnflushed(c: *Compress) !void {
+ while (c.writer.end != 0) _ = try drain(&c.writer, &.{""}, 1);
+ c.state = .ended;
+
+ const out = c.block_writer.output;
+
+ // TODO flush tokens
+
+ switch (c.hasher) {
+ .gzip => |*gzip| {
+ // GZIP 8 bytes footer
+ // - 4 bytes, CRC32 (CRC-32)
+ // - 4 bytes, ISIZE (Input SIZE) - size of the original (uncompressed) input data modulo 2^32
+ const footer = try out.writableArray(8);
+ std.mem.writeInt(u32, footer[0..4], gzip.crc.final(), .little);
+ std.mem.writeInt(u32, footer[4..8], @truncate(gzip.count), .little);
},
- .ended => return error.EndOfStream,
- .footer => |i| {
- const remaining = c.footer_buffer[i..];
- const n = try w.write(limit.slice(remaining));
- c.state = if (n == remaining) .ended else .{ .footer = i - n };
- return n;
+ .zlib => |*zlib| {
+ // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
+ // 4 bytes of ADLER32 (Adler-32 checksum)
+ // Checksum value of the uncompressed data (excluding any
+ // dictionary data) computed according to Adler-32
+ // algorithm.
+ std.mem.writeInt(u32, try out.writableArray(4), zlib.adler, .big);
},
+ .raw => {},
}
}
+pub const Simple = struct {
+ /// Note that store blocks are limited to 65535 bytes.
+ buffer: []u8,
+ wp: usize,
+ block_writer: BlockWriter,
+ hasher: Container.Hasher,
+ strategy: Strategy,
+
+ pub const Strategy = enum { huffman, store };
+
+ pub fn init(output: *Writer, buffer: []u8, container: Container, strategy: Strategy) !Simple {
+ const header = container.header();
+ try output.writeAll(header);
+ return .{
+ .buffer = buffer,
+ .wp = 0,
+ .block_writer = .init(output),
+ .hasher = .init(container),
+ .strategy = strategy,
+ };
+ }
+
+ pub fn flush(self: *Simple) !void {
+ try self.flushBuffer(false);
+ try self.block_writer.storedBlock("", false);
+ try self.block_writer.flush();
+ }
+
+ pub fn finish(self: *Simple) !void {
+ try self.flushBuffer(true);
+ try self.block_writer.flush();
+ try self.hasher.container().writeFooter(&self.hasher, self.block_writer.output);
+ }
+
+ fn flushBuffer(self: *Simple, final: bool) !void {
+ const buf = self.buffer[0..self.wp];
+ switch (self.strategy) {
+ .huffman => try self.block_writer.huffmanBlock(buf, final),
+ .store => try self.block_writer.storedBlock(buf, final),
+ }
+ self.wp = 0;
+ }
+};
+
test "generate a Huffman code from an array of frequencies" {
var freqs: [19]u16 = [_]u16{
8, // 0
@@ -869,7 +286,14 @@ test "generate a Huffman code from an array of frequencies" {
5, // 18
};
- var enc = huffmanEncoder(19);
+ var codes: [19]HuffmanEncoder.Code = undefined;
+ var enc: HuffmanEncoder = .{
+ .codes = &codes,
+ .freq_cache = undefined,
+ .bit_count = undefined,
+ .lns = undefined,
+ .lfs = undefined,
+ };
enc.generate(freqs[0..], 7);
try testing.expectEqual(@as(u32, 141), enc.bitLength(freqs[0..]));
@@ -906,360 +330,3 @@ test "generate a Huffman code from an array of frequencies" {
try testing.expectEqual(@as(u16, 0x1f), enc.codes[7].code);
try testing.expectEqual(@as(u16, 0x3f), enc.codes[16].code);
}
-
-test "generate a Huffman code for the fixed literal table specific to Deflate" {
- const enc = fixedLiteralEncoder();
- for (enc.codes) |c| {
- switch (c.len) {
- 7 => {
- const v = @bitReverse(@as(u7, @intCast(c.code)));
- try testing.expect(v <= 0b0010111);
- },
- 8 => {
- const v = @bitReverse(@as(u8, @intCast(c.code)));
- try testing.expect((v >= 0b000110000 and v <= 0b10111111) or
- (v >= 0b11000000 and v <= 11000111));
- },
- 9 => {
- const v = @bitReverse(@as(u9, @intCast(c.code)));
- try testing.expect(v >= 0b110010000 and v <= 0b111111111);
- },
- else => unreachable,
- }
- }
-}
-
-test "generate a Huffman code for the 30 possible relative distances (LZ77 distances) of Deflate" {
- const enc = fixedDistanceEncoder();
- for (enc.codes) |c| {
- const v = @bitReverse(@as(u5, @intCast(c.code)));
- try testing.expect(v <= 29);
- try testing.expect(c.len == 5);
- }
-}
-
-// Reverse bit-by-bit a N-bit code.
-fn bitReverse(comptime T: type, value: T, n: usize) T {
- const r = @bitReverse(value);
- return r >> @as(math.Log2Int(T), @intCast(@typeInfo(T).int.bits - n));
-}
-
-test bitReverse {
- const ReverseBitsTest = struct {
- in: u16,
- bit_count: u5,
- out: u16,
- };
-
- const reverse_bits_tests = [_]ReverseBitsTest{
- .{ .in = 1, .bit_count = 1, .out = 1 },
- .{ .in = 1, .bit_count = 2, .out = 2 },
- .{ .in = 1, .bit_count = 3, .out = 4 },
- .{ .in = 1, .bit_count = 4, .out = 8 },
- .{ .in = 1, .bit_count = 5, .out = 16 },
- .{ .in = 17, .bit_count = 5, .out = 17 },
- .{ .in = 257, .bit_count = 9, .out = 257 },
- .{ .in = 29, .bit_count = 5, .out = 23 },
- };
-
- for (reverse_bits_tests) |h| {
- const v = bitReverse(u16, h.in, h.bit_count);
- try std.testing.expectEqual(h.out, v);
- }
-}
-
-test "fixedLiteralEncoder codes" {
- var al = std.ArrayList(u8).init(testing.allocator);
- defer al.deinit();
- var bw = std.io.bitWriter(.little, al.writer());
-
- const f = fixedLiteralEncoder();
- for (f.codes) |c| {
- try bw.writeBits(c.code, c.len);
- }
- try testing.expectEqualSlices(u8, &fixed_codes, al.items);
-}
-
-pub const fixed_codes = [_]u8{
- 0b00001100, 0b10001100, 0b01001100, 0b11001100, 0b00101100, 0b10101100, 0b01101100, 0b11101100,
- 0b00011100, 0b10011100, 0b01011100, 0b11011100, 0b00111100, 0b10111100, 0b01111100, 0b11111100,
- 0b00000010, 0b10000010, 0b01000010, 0b11000010, 0b00100010, 0b10100010, 0b01100010, 0b11100010,
- 0b00010010, 0b10010010, 0b01010010, 0b11010010, 0b00110010, 0b10110010, 0b01110010, 0b11110010,
- 0b00001010, 0b10001010, 0b01001010, 0b11001010, 0b00101010, 0b10101010, 0b01101010, 0b11101010,
- 0b00011010, 0b10011010, 0b01011010, 0b11011010, 0b00111010, 0b10111010, 0b01111010, 0b11111010,
- 0b00000110, 0b10000110, 0b01000110, 0b11000110, 0b00100110, 0b10100110, 0b01100110, 0b11100110,
- 0b00010110, 0b10010110, 0b01010110, 0b11010110, 0b00110110, 0b10110110, 0b01110110, 0b11110110,
- 0b00001110, 0b10001110, 0b01001110, 0b11001110, 0b00101110, 0b10101110, 0b01101110, 0b11101110,
- 0b00011110, 0b10011110, 0b01011110, 0b11011110, 0b00111110, 0b10111110, 0b01111110, 0b11111110,
- 0b00000001, 0b10000001, 0b01000001, 0b11000001, 0b00100001, 0b10100001, 0b01100001, 0b11100001,
- 0b00010001, 0b10010001, 0b01010001, 0b11010001, 0b00110001, 0b10110001, 0b01110001, 0b11110001,
- 0b00001001, 0b10001001, 0b01001001, 0b11001001, 0b00101001, 0b10101001, 0b01101001, 0b11101001,
- 0b00011001, 0b10011001, 0b01011001, 0b11011001, 0b00111001, 0b10111001, 0b01111001, 0b11111001,
- 0b00000101, 0b10000101, 0b01000101, 0b11000101, 0b00100101, 0b10100101, 0b01100101, 0b11100101,
- 0b00010101, 0b10010101, 0b01010101, 0b11010101, 0b00110101, 0b10110101, 0b01110101, 0b11110101,
- 0b00001101, 0b10001101, 0b01001101, 0b11001101, 0b00101101, 0b10101101, 0b01101101, 0b11101101,
- 0b00011101, 0b10011101, 0b01011101, 0b11011101, 0b00111101, 0b10111101, 0b01111101, 0b11111101,
- 0b00010011, 0b00100110, 0b01001110, 0b10011010, 0b00111100, 0b01100101, 0b11101010, 0b10110100,
- 0b11101001, 0b00110011, 0b01100110, 0b11001110, 0b10011010, 0b00111101, 0b01100111, 0b11101110,
- 0b10111100, 0b11111001, 0b00001011, 0b00010110, 0b00101110, 0b01011010, 0b10111100, 0b01100100,
- 0b11101001, 0b10110010, 0b11100101, 0b00101011, 0b01010110, 0b10101110, 0b01011010, 0b10111101,
- 0b01100110, 0b11101101, 0b10111010, 0b11110101, 0b00011011, 0b00110110, 0b01101110, 0b11011010,
- 0b10111100, 0b01100101, 0b11101011, 0b10110110, 0b11101101, 0b00111011, 0b01110110, 0b11101110,
- 0b11011010, 0b10111101, 0b01100111, 0b11101111, 0b10111110, 0b11111101, 0b00000111, 0b00001110,
- 0b00011110, 0b00111010, 0b01111100, 0b11100100, 0b11101000, 0b10110001, 0b11100011, 0b00100111,
- 0b01001110, 0b10011110, 0b00111010, 0b01111101, 0b11100110, 0b11101100, 0b10111001, 0b11110011,
- 0b00010111, 0b00101110, 0b01011110, 0b10111010, 0b01111100, 0b11100101, 0b11101010, 0b10110101,
- 0b11101011, 0b00110111, 0b01101110, 0b11011110, 0b10111010, 0b01111101, 0b11100111, 0b11101110,
- 0b10111101, 0b11111011, 0b00001111, 0b00011110, 0b00111110, 0b01111010, 0b11111100, 0b11100100,
- 0b11101001, 0b10110011, 0b11100111, 0b00101111, 0b01011110, 0b10111110, 0b01111010, 0b11111101,
- 0b11100110, 0b11101101, 0b10111011, 0b11110111, 0b00011111, 0b00111110, 0b01111110, 0b11111010,
- 0b11111100, 0b11100101, 0b11101011, 0b10110111, 0b11101111, 0b00111111, 0b01111110, 0b11111110,
- 0b11111010, 0b11111101, 0b11100111, 0b11101111, 0b10111111, 0b11111111, 0b00000000, 0b00100000,
- 0b00001000, 0b00001100, 0b10000001, 0b11000010, 0b11100000, 0b00001000, 0b00100100, 0b00001010,
- 0b10001101, 0b11000001, 0b11100010, 0b11110000, 0b00000100, 0b00100010, 0b10001001, 0b01001100,
- 0b10100001, 0b11010010, 0b11101000, 0b00000011, 0b10000011, 0b01000011, 0b11000011, 0b00100011,
- 0b10100011,
-};
-
-test "tokenization" {
- const L = Token.initLiteral;
- const M = Token.initMatch;
-
- const cases = [_]struct {
- data: []const u8,
- tokens: []const Token,
- }{
- .{
- .data = "Blah blah blah blah blah!",
- .tokens = &[_]Token{ L('B'), L('l'), L('a'), L('h'), L(' '), L('b'), M(5, 18), L('!') },
- },
- .{
- .data = "ABCDEABCD ABCDEABCD",
- .tokens = &[_]Token{
- L('A'), L('B'), L('C'), L('D'), L('E'), L('A'), L('B'), L('C'), L('D'), L(' '),
- L('A'), M(10, 8),
- },
- },
- };
-
- for (cases) |c| {
- inline for (Container.list) |container| { // for each wrapping
-
- var cw = io.countingWriter(io.null_writer);
- const cww = cw.writer();
- var df = try Compress(container, @TypeOf(cww), TestTokenWriter).init(cww, .{});
-
- _ = try df.write(c.data);
- try df.flush();
-
- // df.token_writer.show();
- try expect(df.block_writer.pos == c.tokens.len); // number of tokens written
- try testing.expectEqualSlices(Token, df.block_writer.get(), c.tokens); // tokens match
-
- try testing.expectEqual(container.headerSize(), cw.bytes_written);
- try df.finish();
- try testing.expectEqual(container.size(), cw.bytes_written);
- }
- }
-}
-
-// Tests that tokens written are equal to expected token list.
-const TestTokenWriter = struct {
- const Self = @This();
-
- pos: usize = 0,
- actual: [128]Token = undefined,
-
- pub fn init(_: anytype) Self {
- return .{};
- }
- pub fn write(self: *Self, tokens: []const Token, _: bool, _: ?[]const u8) !void {
- for (tokens) |t| {
- self.actual[self.pos] = t;
- self.pos += 1;
- }
- }
-
- pub fn storedBlock(_: *Self, _: []const u8, _: bool) !void {}
-
- pub fn get(self: *Self) []Token {
- return self.actual[0..self.pos];
- }
-
- pub fn show(self: *Self) void {
- std.debug.print("\n", .{});
- for (self.get()) |t| {
- t.show();
- }
- }
-
- pub fn flush(_: *Self) !void {}
-};
-
-test "file tokenization" {
- const levels = [_]Level{ .level_4, .level_5, .level_6, .level_7, .level_8, .level_9 };
- const cases = [_]struct {
- data: []const u8, // uncompressed content
- // expected number of tokens producet in deflate tokenization
- tokens_count: [levels.len]usize = .{0} ** levels.len,
- }{
- .{
- .data = @embedFile("testdata/rfc1951.txt"),
- .tokens_count = .{ 7675, 7672, 7599, 7594, 7598, 7599 },
- },
-
- .{
- .data = @embedFile("testdata/block_writer/huffman-null-max.input"),
- .tokens_count = .{ 257, 257, 257, 257, 257, 257 },
- },
- .{
- .data = @embedFile("testdata/block_writer/huffman-pi.input"),
- .tokens_count = .{ 2570, 2564, 2564, 2564, 2564, 2564 },
- },
- .{
- .data = @embedFile("testdata/block_writer/huffman-text.input"),
- .tokens_count = .{ 235, 234, 234, 234, 234, 234 },
- },
- .{
- .data = @embedFile("testdata/fuzz/roundtrip1.input"),
- .tokens_count = .{ 333, 331, 331, 331, 331, 331 },
- },
- .{
- .data = @embedFile("testdata/fuzz/roundtrip2.input"),
- .tokens_count = .{ 334, 334, 334, 334, 334, 334 },
- },
- };
-
- for (cases) |case| { // for each case
- const data = case.data;
-
- for (levels, 0..) |level, i| { // for each compression level
- var original: std.io.Reader = .fixed(data);
-
- // buffer for decompressed data
- var al = std.ArrayList(u8).init(testing.allocator);
- defer al.deinit();
- const writer = al.writer();
-
- // create compressor
- const WriterType = @TypeOf(writer);
- const TokenWriter = TokenDecoder(@TypeOf(writer));
- var cmp = try Compress(.raw, WriterType, TokenWriter).init(writer, .{ .level = level });
-
- // Stream uncompressed `original` data to the compressor. It will
- // produce tokens list and pass that list to the TokenDecoder. This
- // TokenDecoder uses CircularBuffer from inflate to convert list of
- // tokens back to the uncompressed stream.
- try cmp.compress(original.reader());
- try cmp.flush();
- const expected_count = case.tokens_count[i];
- const actual = cmp.block_writer.tokens_count;
- if (expected_count == 0) {
- std.debug.print("actual token count {d}\n", .{actual});
- } else {
- try testing.expectEqual(expected_count, actual);
- }
-
- try testing.expectEqual(data.len, al.items.len);
- try testing.expectEqualSlices(u8, data, al.items);
- }
- }
-}
-
-const TokenDecoder = struct {
- output: *Writer,
- tokens_count: usize,
-
- pub fn init(output: *Writer) TokenDecoder {
- return .{
- .output = output,
- .tokens_count = 0,
- };
- }
-
- pub fn write(self: *TokenDecoder, tokens: []const Token, _: bool, _: ?[]const u8) !void {
- self.tokens_count += tokens.len;
- for (tokens) |t| {
- switch (t.kind) {
- .literal => self.hist.write(t.literal()),
- .match => try self.hist.writeMatch(t.length(), t.distance()),
- }
- if (self.hist.free() < 285) try self.flushWin();
- }
- try self.flushWin();
- }
-
- fn flushWin(self: *TokenDecoder) !void {
- while (true) {
- const buf = self.hist.read();
- if (buf.len == 0) break;
- try self.output.writeAll(buf);
- }
- }
-};
-
-test "store simple compressor" {
- const data = "Hello world!";
- const expected = [_]u8{
- 0x1, // block type 0, final bit set
- 0xc, 0x0, // len = 12
- 0xf3, 0xff, // ~len
- 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', //
- //0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
- };
-
- var fbs: std.io.Reader = .fixed(data);
- var al = std.ArrayList(u8).init(testing.allocator);
- defer al.deinit();
-
- var cmp = try store.compressor(.raw, al.writer());
- try cmp.compress(&fbs);
- try cmp.finish();
- try testing.expectEqualSlices(u8, &expected, al.items);
-
- fbs = .fixed(data);
- try al.resize(0);
-
- // huffman only compresoor will also emit store block for this small sample
- var hc = try huffman.compressor(.raw, al.writer());
- try hc.compress(&fbs);
- try hc.finish();
- try testing.expectEqualSlices(u8, &expected, al.items);
-}
-
-test "sliding window match" {
- const data = "Blah blah blah blah blah!";
- var win: Writer = .{};
- try expect(win.write(data) == data.len);
- try expect(win.wp == data.len);
- try expect(win.rp == 0);
-
- // length between l symbols
- try expect(win.match(1, 6, 0) == 18);
- try expect(win.match(1, 11, 0) == 13);
- try expect(win.match(1, 16, 0) == 8);
- try expect(win.match(1, 21, 0) == 0);
-
- // position 15 = "blah blah!"
- // position 20 = "blah!"
- try expect(win.match(15, 20, 0) == 4);
- try expect(win.match(15, 20, 3) == 4);
- try expect(win.match(15, 20, 4) == 0);
-}
-
-test "sliding window slide" {
- var win: Writer = .{};
- win.wp = Writer.buffer_len - 11;
- win.rp = Writer.buffer_len - 111;
- win.buffer[win.rp] = 0xab;
- try expect(win.lookahead().len == 100);
- try expect(win.tokensBuffer().?.len == win.rp);
-
- const n = win.slide();
- try expect(n == 32757);
- try expect(win.buffer[win.rp] == 0xab);
- try expect(win.rp == Writer.hist_len - 111);
- try expect(win.wp == Writer.hist_len - 11);
- try expect(win.lookahead().len == 100);
- try expect(win.tokensBuffer() == null);
-}
diff --git a/lib/std/compress/flate/Decompress.zig b/lib/std/compress/flate/Decompress.zig
index cae246ea96..a51fd05610 100644
--- a/lib/std/compress/flate/Decompress.zig
+++ b/lib/std/compress/flate/Decompress.zig
@@ -1,16 +1,21 @@
const std = @import("../../std.zig");
+const assert = std.debug.assert;
const flate = std.compress.flate;
-const Container = flate.Container;
-const Token = @import("Token.zig");
const testing = std.testing;
+const Writer = std.Io.Writer;
+const Reader = std.Io.Reader;
+const Container = flate.Container;
+
const Decompress = @This();
-const Writer = std.io.Writer;
-const Reader = std.io.Reader;
+const Token = @import("Token.zig");
input: *Reader,
+next_bits: usize,
+remaining_bits: std.math.Log2Int(usize),
+
reader: Reader,
-/// Hashes, produces checksum, of uncompressed data for gzip/zlib footer.
-hasher: Container.Hasher,
+
+container_metadata: Container.Metadata,
lit_dec: LiteralDecoder,
dst_dec: DistanceDecoder,
@@ -18,7 +23,7 @@ dst_dec: DistanceDecoder,
final_block: bool,
state: State,
-read_err: ?Error,
+err: ?Error,
const BlockType = enum(u2) {
stored = 0,
@@ -32,6 +37,8 @@ const State = union(enum) {
stored_block: u16,
fixed_block,
dynamic_block,
+ dynamic_block_literal: u8,
+ dynamic_block_match: u16,
protocol_footer,
end,
};
@@ -39,43 +46,139 @@ const State = union(enum) {
pub const Error = Container.Error || error{
InvalidCode,
InvalidMatch,
- InvalidBlockType,
WrongStoredBlockNlen,
InvalidDynamicBlockHeader,
- EndOfStream,
ReadFailed,
OversubscribedHuffmanTree,
IncompleteHuffmanTree,
MissingEndOfBlockCode,
+ EndOfStream,
+};
+
+const direct_vtable: Reader.VTable = .{
+ .stream = streamDirect,
+ .rebase = rebaseFallible,
+ .discard = discard,
+ .readVec = readVec,
+};
+
+const indirect_vtable: Reader.VTable = .{
+ .stream = streamIndirect,
+ .rebase = rebaseFallible,
+ .discard = discardIndirect,
+ .readVec = readVec,
};
pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
return .{
.reader = .{
- // TODO populate discard so that when an amount is discarded that
- // includes an entire frame, skip decoding that frame.
- .vtable = &.{ .stream = stream },
+ .vtable = if (buffer.len == 0) &direct_vtable else &indirect_vtable,
.buffer = buffer,
.seek = 0,
.end = 0,
},
.input = input,
- .hasher = .init(container),
+ .next_bits = 0,
+ .remaining_bits = 0,
+ .container_metadata = .init(container),
.lit_dec = .{},
.dst_dec = .{},
.final_block = false,
.state = .protocol_header,
- .read_err = null,
+ .err = null,
};
}
+fn rebaseFallible(r: *Reader, capacity: usize) Reader.RebaseError!void {
+ rebase(r, capacity);
+}
+
+fn rebase(r: *Reader, capacity: usize) void {
+ assert(capacity <= r.buffer.len - flate.history_len);
+ assert(r.end + capacity > r.buffer.len);
+ const discard_n = r.end - flate.history_len;
+ const keep = r.buffer[discard_n..r.end];
+ @memmove(r.buffer[0..keep.len], keep);
+ assert(keep.len != 0);
+ r.end = keep.len;
+ r.seek -= discard_n;
+}
+
+/// This could be improved so that when an amount is discarded that includes an
+/// entire frame, skip decoding that frame.
+fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
+ if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len);
+ var writer: Writer = .{
+ .vtable = &.{
+ .drain = std.Io.Writer.Discarding.drain,
+ .sendFile = std.Io.Writer.Discarding.sendFile,
+ },
+ .buffer = r.buffer,
+ .end = r.end,
+ };
+ defer {
+ assert(writer.end != 0);
+ r.end = writer.end;
+ r.seek = r.end;
+ }
+ const n = r.stream(&writer, limit) catch |err| switch (err) {
+ error.WriteFailed => unreachable,
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => return error.EndOfStream,
+ };
+ assert(n <= @intFromEnum(limit));
+ return n;
+}
+
+fn discardIndirect(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
+ const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+ if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len);
+ var writer: Writer = .{
+ .buffer = r.buffer,
+ .end = r.end,
+ .vtable = &.{ .drain = Writer.unreachableDrain },
+ };
+ {
+ defer r.end = writer.end;
+ _ = streamFallible(d, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
+ error.WriteFailed => unreachable,
+ else => |e| return e,
+ };
+ }
+ const n = limit.minInt(r.end - r.seek);
+ r.seek += n;
+ return n;
+}
+
+fn readVec(r: *Reader, data: [][]u8) Reader.Error!usize {
+ _ = data;
+ const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+ return streamIndirectInner(d);
+}
+
+fn streamIndirectInner(d: *Decompress) Reader.Error!usize {
+ const r = &d.reader;
+ if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len);
+ var writer: Writer = .{
+ .buffer = r.buffer,
+ .end = r.end,
+ .vtable = &.{ .drain = Writer.unreachableDrain },
+ };
+ defer r.end = writer.end;
+ _ = streamFallible(d, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
+ error.WriteFailed => unreachable,
+ else => |e| return e,
+ };
+ return 0;
+}
+
fn decodeLength(self: *Decompress, code: u8) !u16 {
if (code > 28) return error.InvalidCode;
const ml = Token.matchLength(code);
return if (ml.extra_bits == 0) // 0 - 5 extra bits
ml.base
else
- ml.base + try self.takeNBitsBuffered(ml.extra_bits);
+ ml.base + try self.takeBitsRuntime(ml.extra_bits);
}
fn decodeDistance(self: *Decompress, code: u8) !u16 {
@@ -84,7 +187,7 @@ fn decodeDistance(self: *Decompress, code: u8) !u16 {
return if (md.extra_bits == 0) // 0 - 13 extra bits
md.base
else
- md.base + try self.takeNBitsBuffered(md.extra_bits);
+ md.base + try self.takeBitsRuntime(md.extra_bits);
}
// Decode code length symbol to code length. Writes decoded length into
@@ -119,34 +222,50 @@ fn dynamicCodeLength(self: *Decompress, code: u16, lens: []u4, pos: usize) !usiz
}
}
-// Peek 15 bits from bits reader (maximum code len is 15 bits). Use
-// decoder to find symbol for that code. We then know how many bits is
-// used. Shift bit reader for that much bits, those bits are used. And
-// return symbol.
fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {
- const sym = try decoder.find(try self.peekBitsReverseBuffered(u15));
- try self.shiftBits(sym.code_bits);
+ // Maximum code len is 15 bits.
+ const sym = try decoder.find(@bitReverse(try self.peekBits(u15)));
+ try self.tossBits(sym.code_bits);
return sym;
}
-pub fn stream(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {
+fn streamDirect(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
- return readInner(d, w, limit) catch |err| switch (err) {
- error.EndOfStream => return error.EndOfStream,
+ return streamFallible(d, w, limit);
+}
+
+fn streamIndirect(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
+ const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+ _ = limit;
+ _ = w;
+ return streamIndirectInner(d);
+}
+
+fn streamFallible(d: *Decompress, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
+ return streamInner(d, w, limit) catch |err| switch (err) {
+ error.EndOfStream => {
+ if (d.state == .end) {
+ return error.EndOfStream;
+ } else {
+ d.err = error.EndOfStream;
+ return error.ReadFailed;
+ }
+ },
error.WriteFailed => return error.WriteFailed,
else => |e| {
// In the event of an error, state is unmodified so that it can be
// better used to diagnose the failure.
- d.read_err = e;
+ d.err = e;
return error.ReadFailed;
},
};
}
-fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.StreamError)!usize {
+fn streamInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.StreamError)!usize {
+ var remaining = @intFromEnum(limit);
const in = d.input;
sw: switch (d.state) {
- .protocol_header => switch (d.hasher.container()) {
+ .protocol_header => switch (d.container_metadata.container()) {
.gzip => {
const Header = extern struct {
magic: u16 align(1),
@@ -163,7 +282,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
xfl: u8,
os: u8,
};
- const header = try in.takeStructEndian(Header, .little);
+ const header = try in.takeStruct(Header, .little);
if (header.magic != 0x8b1f or header.method != 0x08)
return error.BadGzipHeader;
if (header.flags.extra) {
@@ -171,10 +290,10 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
try in.discardAll(extra_len);
}
if (header.flags.name) {
- try in.discardDelimiterInclusive(0);
+ _ = try in.discardDelimiterInclusive(0);
}
if (header.flags.comment) {
- try in.discardDelimiterInclusive(0);
+ _ = try in.discardDelimiterInclusive(0);
}
if (header.flags.hcrc) {
try in.discardAll(2);
@@ -182,25 +301,19 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
continue :sw .block_header;
},
.zlib => {
- const Header = extern struct {
- cmf: packed struct(u8) {
- cm: u4,
- cinfo: u4,
- },
- flg: u8,
- };
- const header = try in.takeStruct(Header);
- if (header.cmf.cm != 8 or header.cmf.cinfo > 7) return error.BadZlibHeader;
+ const header = try in.takeArray(2);
+ const cmf: packed struct(u8) { cm: u4, cinfo: u4 } = @bitCast(header[0]);
+ if (cmf.cm != 8 or cmf.cinfo > 7) return error.BadZlibHeader;
continue :sw .block_header;
},
.raw => continue :sw .block_header,
},
.block_header => {
d.final_block = (try d.takeBits(u1)) != 0;
- const block_type = try d.takeBits(BlockType);
+ const block_type: BlockType = @enumFromInt(try d.takeBits(u2));
switch (block_type) {
.stored => {
- d.alignBitsToByte(); // skip padding until byte boundary
+ d.alignBitsDiscarding();
// everything after this is byte aligned in stored block
const len = try in.takeInt(u16, .little);
const nlen = try in.takeInt(u16, .little);
@@ -217,19 +330,20 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
return error.InvalidDynamicBlockHeader;
// lengths for code lengths
- var cl_lens = [_]u4{0} ** 19;
- for (0..hclen) |i| {
- cl_lens[flate.huffman.codegen_order[i]] = try d.takeBits(u3);
+ var cl_lens: [19]u4 = @splat(0);
+ for (flate.HuffmanEncoder.codegen_order[0..hclen]) |i| {
+ cl_lens[i] = try d.takeBits(u3);
}
var cl_dec: CodegenDecoder = .{};
try cl_dec.generate(&cl_lens);
// decoded code lengths
- var dec_lens = [_]u4{0} ** (286 + 30);
+ var dec_lens: [286 + 30]u4 = @splat(0);
var pos: usize = 0;
while (pos < hlit + hdist) {
- const sym = try cl_dec.find(try d.peekBitsReverse(u7));
- try d.shiftBits(sym.code_bits);
+ const peeked = @bitReverse(try d.peekBits(u7));
+ const sym = try cl_dec.find(peeked);
+ try d.tossBits(sym.code_bits);
pos += try d.dynamicCodeLength(sym.symbol, &dec_lens, pos);
}
if (pos > hlit + hdist) {
@@ -240,7 +354,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
try d.lit_dec.generate(dec_lens[0..hlit]);
// distance code lengths to distance decoder
- try d.dst_dec.generate(dec_lens[hlit .. hlit + hdist]);
+ try d.dst_dec.generate(dec_lens[hlit..][0..hdist]);
continue :sw .dynamic_block;
},
@@ -248,8 +362,8 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
},
.stored_block => |remaining_len| {
const out = try w.writableSliceGreedyPreserve(flate.history_len, 1);
- const limited_out = limit.min(.limited(remaining_len)).slice(out);
- const n = try d.input.readVec(&.{limited_out});
+ var limited_out: [1][]u8 = .{limit.min(.limited(remaining_len)).slice(out)};
+ const n = try d.input.readVec(&limited_out);
if (remaining_len - n == 0) {
d.state = if (d.final_block) .protocol_footer else .block_header;
} else {
@@ -259,68 +373,99 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
return n;
},
.fixed_block => {
- const start = w.count;
- while (@intFromEnum(limit) > w.count - start) {
+ while (remaining > 0) {
const code = try d.readFixedCode();
switch (code) {
- 0...255 => try w.writeBytePreserve(flate.history_len, @intCast(code)),
+ 0...255 => {
+ try w.writeBytePreserve(flate.history_len, @intCast(code));
+ remaining -= 1;
+ },
256 => {
d.state = if (d.final_block) .protocol_footer else .block_header;
- return w.count - start;
+ return @intFromEnum(limit) - remaining;
},
257...285 => {
// Handles fixed block non literal (length) code.
// Length code is followed by 5 bits of distance code.
const length = try d.decodeLength(@intCast(code - 257));
- const distance = try d.decodeDistance(try d.takeBitsReverseBuffered(u5));
+ const distance = try d.decodeDistance(@bitReverse(try d.takeBits(u5)));
try writeMatch(w, length, distance);
+ remaining -= length;
},
else => return error.InvalidCode,
}
}
d.state = .fixed_block;
- return w.count - start;
+ return @intFromEnum(limit) - remaining;
},
.dynamic_block => {
- // In larger archives most blocks are usually dynamic, so decompression
- // performance depends on this logic.
- const start = w.count;
- while (@intFromEnum(limit) > w.count - start) {
- const sym = try d.decodeSymbol(&d.lit_dec);
-
- switch (sym.kind) {
- .literal => try w.writeBytePreserve(flate.history_len, sym.symbol),
- .match => {
- // Decode match backreference
- const length = try d.decodeLength(sym.symbol);
- const dsm = try d.decodeSymbol(&d.dst_dec);
- const distance = try d.decodeDistance(dsm.symbol);
- try writeMatch(w, length, distance);
- },
- .end_of_block => {
- d.state = if (d.final_block) .protocol_footer else .block_header;
- return w.count - start;
- },
- }
+ // In larger archives most blocks are usually dynamic, so
+ // decompression performance depends on this logic.
+ var sym = try d.decodeSymbol(&d.lit_dec);
+ sym: switch (sym.kind) {
+ .literal => {
+ if (remaining != 0) {
+ @branchHint(.likely);
+ remaining -= 1;
+ try w.writeBytePreserve(flate.history_len, sym.symbol);
+ sym = try d.decodeSymbol(&d.lit_dec);
+ continue :sym sym.kind;
+ } else {
+ d.state = .{ .dynamic_block_literal = sym.symbol };
+ return @intFromEnum(limit) - remaining;
+ }
+ },
+ .match => {
+ // Decode match backreference
+ const length = try d.decodeLength(sym.symbol);
+ continue :sw .{ .dynamic_block_match = length };
+ },
+ .end_of_block => {
+ d.state = if (d.final_block) .protocol_footer else .block_header;
+ continue :sw d.state;
+ },
+ }
+ },
+ .dynamic_block_literal => |symbol| {
+ assert(remaining != 0);
+ remaining -= 1;
+ try w.writeBytePreserve(flate.history_len, symbol);
+ continue :sw .dynamic_block;
+ },
+ .dynamic_block_match => |length| {
+ if (remaining >= length) {
+ @branchHint(.likely);
+ remaining -= length;
+ const dsm = try d.decodeSymbol(&d.dst_dec);
+ const distance = try d.decodeDistance(dsm.symbol);
+ try writeMatch(w, length, distance);
+ continue :sw .dynamic_block;
+ } else {
+ d.state = .{ .dynamic_block_match = length };
+ return @intFromEnum(limit) - remaining;
}
- d.state = .dynamic_block;
- return w.count - start;
},
.protocol_footer => {
- d.alignBitsToByte();
- switch (d.hasher) {
+ switch (d.container_metadata) {
.gzip => |*gzip| {
- if (try in.takeInt(u32, .little) != gzip.crc.final()) return error.WrongGzipChecksum;
- if (try in.takeInt(u32, .little) != gzip.count) return error.WrongGzipSize;
+ d.alignBitsDiscarding();
+ gzip.* = .{
+ .crc = try in.takeInt(u32, .little),
+ .count = try in.takeInt(u32, .little),
+ };
},
.zlib => |*zlib| {
- const chksum: u32 = @byteSwap(zlib.final());
- if (try in.takeInt(u32, .big) != chksum) return error.WrongZlibChecksum;
+ d.alignBitsDiscarding();
+ zlib.* = .{
+ .adler = try in.takeInt(u32, .little),
+ };
+ },
+ .raw => {
+ d.alignBitsPreserving();
},
- .raw => {},
}
d.state = .end;
- return 0;
+ return @intFromEnum(limit) - remaining;
},
.end => return error.EndOfStream,
}
@@ -328,53 +473,184 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
/// Write match (back-reference to the same data slice) starting at `distance`
/// back from current write position, and `length` of bytes.
-fn writeMatch(bw: *Writer, length: u16, distance: u16) !void {
- _ = bw;
- _ = length;
- _ = distance;
- @panic("TODO");
+fn writeMatch(w: *Writer, length: u16, distance: u16) !void {
+ if (w.end < distance) return error.InvalidMatch;
+ if (length < Token.base_length) return error.InvalidMatch;
+ if (length > Token.max_length) return error.InvalidMatch;
+ if (distance < Token.min_distance) return error.InvalidMatch;
+ if (distance > Token.max_distance) return error.InvalidMatch;
+
+ // This is not a @memmove; it intentionally repeats patterns caused by
+ // iterating one byte at a time.
+ const dest = try w.writableSlicePreserve(flate.history_len, length);
+ const end = dest.ptr - w.buffer.ptr;
+ const src = w.buffer[end - distance ..][0..length];
+ for (dest, src) |*d, s| d.* = s;
}
-fn takeBits(d: *Decompress, comptime T: type) !T {
- _ = d;
- @panic("TODO");
+fn takeBits(d: *Decompress, comptime U: type) !U {
+ const remaining_bits = d.remaining_bits;
+ const next_bits = d.next_bits;
+ if (remaining_bits >= @bitSizeOf(U)) {
+ const u: U = @truncate(next_bits);
+ d.next_bits = next_bits >> @bitSizeOf(U);
+ d.remaining_bits = remaining_bits - @bitSizeOf(U);
+ return u;
+ }
+ const in = d.input;
+ const next_int = in.takeInt(usize, .little) catch |err| switch (err) {
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => return takeBitsEnding(d, U),
+ };
+ const needed_bits = @bitSizeOf(U) - remaining_bits;
+ const u: U = @intCast(((next_int & ((@as(usize, 1) << needed_bits) - 1)) << remaining_bits) | next_bits);
+ d.next_bits = next_int >> needed_bits;
+ d.remaining_bits = @intCast(@bitSizeOf(usize) - @as(usize, needed_bits));
+ return u;
}
-fn takeBitsReverseBuffered(d: *Decompress, comptime T: type) !T {
- _ = d;
- @panic("TODO");
+fn takeBitsEnding(d: *Decompress, comptime U: type) !U {
+ const remaining_bits = d.remaining_bits;
+ const next_bits = d.next_bits;
+ const in = d.input;
+ const n = in.bufferedLen();
+ assert(n < @sizeOf(usize));
+ const needed_bits = @bitSizeOf(U) - remaining_bits;
+ if (n * 8 < needed_bits) return error.EndOfStream;
+ const next_int = in.takeVarInt(usize, .little, n) catch |err| switch (err) {
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => unreachable,
+ };
+ const u: U = @intCast(((next_int & ((@as(usize, 1) << needed_bits) - 1)) << remaining_bits) | next_bits);
+ d.next_bits = next_int >> needed_bits;
+ d.remaining_bits = @intCast(n * 8 - @as(usize, needed_bits));
+ return u;
}
-fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 {
- _ = d;
- _ = n;
- @panic("TODO");
+fn peekBits(d: *Decompress, comptime U: type) !U {
+ const remaining_bits = d.remaining_bits;
+ const next_bits = d.next_bits;
+ if (remaining_bits >= @bitSizeOf(U)) return @truncate(next_bits);
+ const in = d.input;
+ const next_int = in.peekInt(usize, .little) catch |err| switch (err) {
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => return peekBitsEnding(d, U),
+ };
+ const needed_bits = @bitSizeOf(U) - remaining_bits;
+ return @intCast(((next_int & ((@as(usize, 1) << needed_bits) - 1)) << remaining_bits) | next_bits);
}
-fn peekBitsReverse(d: *Decompress, comptime T: type) !T {
- _ = d;
- @panic("TODO");
+fn peekBitsEnding(d: *Decompress, comptime U: type) !U {
+ const remaining_bits = d.remaining_bits;
+ const next_bits = d.next_bits;
+ const in = d.input;
+ var u: usize = 0;
+ var remaining_needed_bits = @bitSizeOf(U) - remaining_bits;
+ var i: usize = 0;
+ while (remaining_needed_bits >= 8) {
+ const byte = try specialPeek(in, next_bits, i);
+ u |= @as(usize, byte) << @intCast(i * 8);
+ remaining_needed_bits -= 8;
+ i += 1;
+ }
+ if (remaining_needed_bits != 0) {
+ const byte = try specialPeek(in, next_bits, i);
+ u |= @as(usize, byte) << @intCast((i * 8) + remaining_needed_bits);
+ }
+ return @truncate((u << remaining_bits) | next_bits);
}
-fn peekBitsReverseBuffered(d: *Decompress, comptime T: type) !T {
- _ = d;
- @panic("TODO");
+/// If there is any unconsumed data, handles EndOfStream by pretending there
+/// are zeroes afterwards.
+fn specialPeek(in: *Reader, next_bits: usize, i: usize) Reader.Error!u8 {
+ const peeked = in.peek(i + 1) catch |err| switch (err) {
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => if (next_bits == 0 and i == 0) return error.EndOfStream else return 0,
+ };
+ return peeked[i];
}
-fn alignBitsToByte(d: *Decompress) void {
- _ = d;
- @panic("TODO");
+fn tossBits(d: *Decompress, n: u4) !void {
+ const remaining_bits = d.remaining_bits;
+ const next_bits = d.next_bits;
+ if (remaining_bits >= n) {
+ d.next_bits = next_bits >> n;
+ d.remaining_bits = remaining_bits - n;
+ } else {
+ const in = d.input;
+ const next_int = in.takeInt(usize, .little) catch |err| switch (err) {
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => return tossBitsEnding(d, n),
+ };
+ const needed_bits = n - remaining_bits;
+ d.next_bits = next_int >> needed_bits;
+ d.remaining_bits = @intCast(@bitSizeOf(usize) - @as(usize, needed_bits));
+ }
}
-fn shiftBits(d: *Decompress, n: u6) !void {
- _ = d;
- _ = n;
- @panic("TODO");
+fn tossBitsEnding(d: *Decompress, n: u4) !void {
+ const remaining_bits = d.remaining_bits;
+ const in = d.input;
+ const buffered_n = in.bufferedLen();
+ if (buffered_n == 0) return error.EndOfStream;
+ assert(buffered_n < @sizeOf(usize));
+ const needed_bits = n - remaining_bits;
+ const next_int = in.takeVarInt(usize, .little, buffered_n) catch |err| switch (err) {
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => unreachable,
+ };
+ d.next_bits = next_int >> needed_bits;
+ d.remaining_bits = @intCast(@as(usize, n) * 8 -| @as(usize, needed_bits));
}
+fn takeBitsRuntime(d: *Decompress, n: u4) !u16 {
+ const x = try peekBits(d, u16);
+ const mask: u16 = (@as(u16, 1) << n) - 1;
+ const u: u16 = @as(u16, @truncate(x)) & mask;
+ try tossBits(d, n);
+ return u;
+}
+
+fn alignBitsDiscarding(d: *Decompress) void {
+ const remaining_bits = d.remaining_bits;
+ if (remaining_bits == 0) return;
+ const n_bytes = remaining_bits / 8;
+ const in = d.input;
+ in.seek -= n_bytes;
+ d.remaining_bits = 0;
+ d.next_bits = 0;
+}
+
+fn alignBitsPreserving(d: *Decompress) void {
+ const remaining_bits: usize = d.remaining_bits;
+ if (remaining_bits == 0) return;
+ const n_bytes = (remaining_bits + 7) / 8;
+ const in = d.input;
+ in.seek -= n_bytes;
+ d.remaining_bits = 0;
+ d.next_bits = 0;
+}
+
+/// Reads first 7 bits, and then maybe 1 or 2 more to get full 7,8 or 9 bit code.
+/// ref: https://datatracker.ietf.org/doc/html/rfc1951#page-12
+/// 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
fn readFixedCode(d: *Decompress) !u16 {
- _ = d;
- @panic("TODO");
+ const code7 = @bitReverse(try d.takeBits(u7));
+ return switch (code7) {
+ 0...0b0010_111 => @as(u16, code7) + 256,
+ 0b0010_111 + 1...0b1011_111 => (@as(u16, code7) << 1) + @as(u16, try d.takeBits(u1)) - 0b0011_0000,
+ 0b1011_111 + 1...0b1100_011 => (@as(u16, code7 - 0b1100000) << 1) + try d.takeBits(u1) + 280,
+ else => (@as(u16, code7 - 0b1100_100) << 2) + @as(u16, @bitReverse(try d.takeBits(u2))) + 144,
+ };
}
pub const Symbol = packed struct {
@@ -620,10 +896,15 @@ test "init/find" {
}
test "encode/decode literals" {
- const LiteralEncoder = std.compress.flate.Compress.LiteralEncoder;
-
+ var codes: [flate.HuffmanEncoder.max_num_frequencies]flate.HuffmanEncoder.Code = undefined;
for (1..286) |j| { // for all different number of codes
- var enc: LiteralEncoder = .{};
+ var enc: flate.HuffmanEncoder = .{
+ .codes = &codes,
+ .freq_cache = undefined,
+ .bit_count = undefined,
+ .lns = undefined,
+ .lfs = undefined,
+ };
// create frequencies
var freq = [_]u16{0} ** 286;
freq[256] = 1; // ensure we have end of block code
@@ -670,214 +951,210 @@ test "encode/decode literals" {
}
}
-test "decompress" {
- const cases = [_]struct {
- in: []const u8,
- out: []const u8,
- }{
- // non compressed block (type 0)
- .{
- .in = &[_]u8{
- 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
- 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
- },
- .out = "Hello world\n",
- },
- // fixed code block (type 1)
- .{
- .in = &[_]u8{
- 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
- 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
- },
- .out = "Hello world\n",
- },
- // dynamic block (type 2)
- .{
- .in = &[_]u8{
- 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
- 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
- 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
- },
- .out = "ABCDEABCD ABCDEABCD",
- },
- };
- for (cases) |c| {
- var fb: Reader = .fixed(c.in);
- var aw: Writer.Allocating = .init(testing.allocator);
- defer aw.deinit();
-
- var decompress: Decompress = .init(&fb, .raw);
- var decompress_br = decompress.readable(&.{});
- _ = try decompress_br.streamRemaining(&aw.interface);
- try testing.expectEqualStrings(c.out, aw.getWritten());
- }
+test "non compressed block (type 0)" {
+ try testDecompress(.raw, &[_]u8{
+ 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
+ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
+ }, "Hello world\n");
}
-test "gzip decompress" {
- const cases = [_]struct {
- in: []const u8,
- out: []const u8,
- }{
- // non compressed block (type 0)
- .{
- .in = &[_]u8{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
- 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
- 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
- 0xd5, 0xe0, 0x39, 0xb7, // gzip footer: checksum
- 0x0c, 0x00, 0x00, 0x00, // gzip footer: size
- },
- .out = "Hello world\n",
- },
- // fixed code block (type 1)
- .{
- .in = &[_]u8{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, // gzip header (10 bytes)
- 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
- 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
- 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
- },
- .out = "Hello world\n",
- },
- // dynamic block (type 2)
- .{
- .in = &[_]u8{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
- 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
- 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
- 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
- 0x17, 0x1c, 0x39, 0xb4, 0x13, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
- },
- .out = "ABCDEABCD ABCDEABCD",
- },
- // gzip header with name
- .{
- .in = &[_]u8{
- 0x1f, 0x8b, 0x08, 0x08, 0xe5, 0x70, 0xb1, 0x65, 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
- 0x74, 0x78, 0x74, 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
- 0x02, 0x00, 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00,
- },
- .out = "Hello world\n",
- },
- };
- for (cases) |c| {
- var fb: Reader = .fixed(c.in);
- var aw: Writer.Allocating = .init(testing.allocator);
- defer aw.deinit();
-
- var decompress: Decompress = .init(&fb, .gzip);
- var decompress_br = decompress.readable(&.{});
- _ = try decompress_br.streamRemaining(&aw.interface);
- try testing.expectEqualStrings(c.out, aw.getWritten());
- }
+test "fixed code block (type 1)" {
+ try testDecompress(.raw, &[_]u8{
+ 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
+ 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
+ }, "Hello world\n");
}
-test "zlib decompress" {
- const cases = [_]struct {
- in: []const u8,
- out: []const u8,
- }{
- // non compressed block (type 0)
- .{
- .in = &[_]u8{
- 0x78, 0b10_0_11100, // zlib header (2 bytes)
- 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
- 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
- 0x1c, 0xf2, 0x04, 0x47, // zlib footer: checksum
- },
- .out = "Hello world\n",
- },
- };
- for (cases) |c| {
- var fb: Reader = .fixed(c.in);
- var aw: Writer.Allocating = .init(testing.allocator);
- defer aw.deinit();
-
- var decompress: Decompress = .init(&fb, .zlib);
- var decompress_br = decompress.readable(&.{});
- _ = try decompress_br.streamRemaining(&aw.interface);
- try testing.expectEqualStrings(c.out, aw.getWritten());
- }
+test "dynamic block (type 2)" {
+ try testDecompress(.raw, &[_]u8{
+ 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
+ 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
+ 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
+ }, "ABCDEABCD ABCDEABCD");
}
-test "fuzzing tests" {
- const cases = [_]struct {
- input: []const u8,
- out: []const u8 = "",
- err: ?anyerror = null,
- }{
- .{ .input = "deflate-stream", .out = @embedFile("testdata/fuzz/deflate-stream.expect") }, // 0
- .{ .input = "empty-distance-alphabet01" },
- .{ .input = "empty-distance-alphabet02" },
- .{ .input = "end-of-stream", .err = error.EndOfStream },
- .{ .input = "invalid-distance", .err = error.InvalidMatch },
- .{ .input = "invalid-tree01", .err = error.IncompleteHuffmanTree }, // 5
- .{ .input = "invalid-tree02", .err = error.IncompleteHuffmanTree },
- .{ .input = "invalid-tree03", .err = error.IncompleteHuffmanTree },
- .{ .input = "lengths-overflow", .err = error.InvalidDynamicBlockHeader },
- .{ .input = "out-of-codes", .err = error.InvalidCode },
- .{ .input = "puff01", .err = error.WrongStoredBlockNlen }, // 10
- .{ .input = "puff02", .err = error.EndOfStream },
- .{ .input = "puff03", .out = &[_]u8{0xa} },
- .{ .input = "puff04", .err = error.InvalidCode },
- .{ .input = "puff05", .err = error.EndOfStream },
- .{ .input = "puff06", .err = error.EndOfStream },
- .{ .input = "puff08", .err = error.InvalidCode },
- .{ .input = "puff09", .out = "P" },
- .{ .input = "puff10", .err = error.InvalidCode },
- .{ .input = "puff11", .err = error.InvalidMatch },
- .{ .input = "puff12", .err = error.InvalidDynamicBlockHeader }, // 20
- .{ .input = "puff13", .err = error.IncompleteHuffmanTree },
- .{ .input = "puff14", .err = error.EndOfStream },
- .{ .input = "puff15", .err = error.IncompleteHuffmanTree },
- .{ .input = "puff16", .err = error.InvalidDynamicBlockHeader },
- .{ .input = "puff17", .err = error.MissingEndOfBlockCode }, // 25
- .{ .input = "fuzz1", .err = error.InvalidDynamicBlockHeader },
- .{ .input = "fuzz2", .err = error.InvalidDynamicBlockHeader },
- .{ .input = "fuzz3", .err = error.InvalidMatch },
- .{ .input = "fuzz4", .err = error.OversubscribedHuffmanTree },
- .{ .input = "puff18", .err = error.OversubscribedHuffmanTree }, // 30
- .{ .input = "puff19", .err = error.OversubscribedHuffmanTree },
- .{ .input = "puff20", .err = error.OversubscribedHuffmanTree },
- .{ .input = "puff21", .err = error.OversubscribedHuffmanTree },
- .{ .input = "puff22", .err = error.OversubscribedHuffmanTree },
- .{ .input = "puff23", .err = error.OversubscribedHuffmanTree }, // 35
- .{ .input = "puff24", .err = error.IncompleteHuffmanTree },
- .{ .input = "puff25", .err = error.OversubscribedHuffmanTree },
- .{ .input = "puff26", .err = error.InvalidDynamicBlockHeader },
- .{ .input = "puff27", .err = error.InvalidDynamicBlockHeader },
- };
+test "gzip non compressed block (type 0)" {
+ try testDecompress(.gzip, &[_]u8{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
+ 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
+ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
+ 0xd5, 0xe0, 0x39, 0xb7, // gzip footer: checksum
+ 0x0c, 0x00, 0x00, 0x00, // gzip footer: size
+ }, "Hello world\n");
+}
- inline for (cases, 0..) |c, case_no| {
- var in: Reader = .fixed(@embedFile("testdata/fuzz/" ++ c.input ++ ".input"));
- var aw: Writer.Allocating = .init(testing.allocator);
- defer aw.deinit();
- errdefer std.debug.print("test case failed {}\n", .{case_no});
+test "gzip fixed code block (type 1)" {
+ try testDecompress(.gzip, &[_]u8{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, // gzip header (10 bytes)
+ 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
+ 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
+ 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
+ }, "Hello world\n");
+}
- var decompress: Decompress = .init(&in, .raw);
- var decompress_br = decompress.readable(&.{});
- if (c.err) |expected_err| {
- try testing.expectError(error.ReadFailed, decompress_br.streamRemaining(&aw.interface));
- try testing.expectError(expected_err, decompress.read_err.?);
- } else {
- _ = try decompress_br.streamRemaining(&aw.interface);
- try testing.expectEqualStrings(c.out, aw.getWritten());
- }
- }
+test "gzip dynamic block (type 2)" {
+ try testDecompress(.gzip, &[_]u8{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
+ 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
+ 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
+ 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
+ 0x17, 0x1c, 0x39, 0xb4, 0x13, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
+ }, "ABCDEABCD ABCDEABCD");
+}
+
+test "gzip header with name" {
+ try testDecompress(.gzip, &[_]u8{
+ 0x1f, 0x8b, 0x08, 0x08, 0xe5, 0x70, 0xb1, 0x65, 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
+ 0x74, 0x78, 0x74, 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
+ 0x02, 0x00, 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00,
+ }, "Hello world\n");
+}
+
+test "zlib decompress non compressed block (type 0)" {
+ try testDecompress(.zlib, &[_]u8{
+ 0x78, 0b10_0_11100, // zlib header (2 bytes)
+ 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
+ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
+ 0x1c, 0xf2, 0x04, 0x47, // zlib footer: checksum
+ }, "Hello world\n");
+}
+
+test "failing end-of-stream" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/end-of-stream.input"), error.EndOfStream);
+}
+test "failing invalid-distance" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/invalid-distance.input"), error.InvalidMatch);
+}
+test "failing invalid-tree01" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree);
+}
+test "failing invalid-tree02" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree02.input"), error.EndOfStream);
+}
+test "failing invalid-tree03" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree);
+}
+test "failing lengths-overflow" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/lengths-overflow.input"), error.InvalidDynamicBlockHeader);
+}
+test "failing out-of-codes" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/out-of-codes.input"), error.InvalidCode);
+}
+test "failing puff01" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff01.input"), error.WrongStoredBlockNlen);
+}
+test "failing puff02" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff02.input"), error.EndOfStream);
+}
+test "failing puff04" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff04.input"), error.InvalidCode);
+}
+test "failing puff05" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff05.input"), error.EndOfStream);
+}
+test "failing puff06" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff06.input"), error.EndOfStream);
+}
+test "failing puff08" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff08.input"), error.InvalidCode);
+}
+test "failing puff10" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff10.input"), error.InvalidCode);
+}
+test "failing puff11" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff11.input"), error.EndOfStream);
+}
+test "failing puff12" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader);
+}
+test "failing puff13" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff13.input"), error.IncompleteHuffmanTree);
+}
+test "failing puff14" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff14.input"), error.EndOfStream);
+}
+test "failing puff15" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff15.input"), error.IncompleteHuffmanTree);
+}
+test "failing puff16" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff16.input"), error.InvalidDynamicBlockHeader);
+}
+test "failing puff17" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff17.input"), error.MissingEndOfBlockCode);
+}
+test "failing fuzz1" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/fuzz1.input"), error.InvalidDynamicBlockHeader);
+}
+test "failing fuzz2" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/fuzz2.input"), error.InvalidDynamicBlockHeader);
+}
+test "failing fuzz3" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/fuzz3.input"), error.InvalidMatch);
+}
+test "failing fuzz4" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/fuzz4.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff18" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff18.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff19" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff19.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff20" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff20.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff21" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff21.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff22" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff22.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff23" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff23.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff24" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff24.input"), error.IncompleteHuffmanTree);
+}
+test "failing puff25" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff25.input"), error.OversubscribedHuffmanTree);
+}
+test "failing puff26" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff26.input"), error.InvalidDynamicBlockHeader);
+}
+test "failing puff27" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/puff27.input"), error.InvalidDynamicBlockHeader);
+}
+
+test "deflate-stream" {
+ try testDecompress(
+ .raw,
+ @embedFile("testdata/fuzz/deflate-stream.input"),
+ @embedFile("testdata/fuzz/deflate-stream.expect"),
+ );
+}
+
+test "empty-distance-alphabet01" {
+ try testFailure(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), error.EndOfStream);
+}
+
+test "empty-distance-alphabet02" {
+ try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet02.input"), "");
+}
+
+test "puff03" {
+ try testDecompress(.raw, @embedFile("testdata/fuzz/puff03.input"), &.{0xa});
+}
+
+test "puff09" {
+ try testDecompress(.raw, @embedFile("testdata/fuzz/puff09.input"), "P");
}
test "bug 18966" {
- const input = @embedFile("testdata/fuzz/bug_18966.input");
- const expect = @embedFile("testdata/fuzz/bug_18966.expect");
-
- var in: Reader = .fixed(input);
- var aw: Writer.Allocating = .init(testing.allocator);
- defer aw.deinit();
-
- var decompress: Decompress = .init(&in, .gzip);
- var decompress_br = decompress.readable(&.{});
- _ = try decompress_br.streamRemaining(&aw.interface);
- try testing.expectEqualStrings(expect, aw.getWritten());
+ try testDecompress(
+ .gzip,
+ @embedFile("testdata/fuzz/bug_18966.input"),
+ @embedFile("testdata/fuzz/bug_18966.expect"),
+ );
}
test "reading into empty buffer" {
@@ -887,8 +1164,104 @@ test "reading into empty buffer" {
'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
};
var in: Reader = .fixed(input);
- var decomp: Decompress = .init(&in, .raw);
- var decompress_br = decomp.readable(&.{});
- var buf: [0]u8 = undefined;
- try testing.expectEqual(0, try decompress_br.readVec(&.{&buf}));
+ var decomp: Decompress = .init(&in, .raw, &.{});
+ const r = &decomp.reader;
+ var bufs: [1][]u8 = .{&.{}};
+ try testing.expectEqual(0, try r.readVec(&bufs));
+}
+
+test "zlib header" {
+ // Truncated header
+ try testFailure(.zlib, &[_]u8{0x78}, error.EndOfStream);
+
+ // Wrong CM
+ try testFailure(.zlib, &[_]u8{ 0x79, 0x94 }, error.BadZlibHeader);
+
+ // Wrong CINFO
+ try testFailure(.zlib, &[_]u8{ 0x88, 0x98 }, error.BadZlibHeader);
+
+ // Truncated checksum
+ try testFailure(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, error.EndOfStream);
+}
+
+test "gzip header" {
+ // Truncated header
+ try testFailure(.gzip, &[_]u8{ 0x1f, 0x8B }, error.EndOfStream);
+
+ // Wrong CM
+ try testFailure(.gzip, &[_]u8{
+ 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03,
+ }, error.BadGzipHeader);
+
+ // Truncated checksum
+ try testFailure(.gzip, &[_]u8{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
+ }, error.EndOfStream);
+
+ // Truncated initial size field
+ try testFailure(.gzip, &[_]u8{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ }, error.EndOfStream);
+
+ try testDecompress(.gzip, &[_]u8{
+ // GZIP header
+ 0x1f, 0x8b, 0x08, 0x12, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00,
+ // header.FHCRC (should cover entire header)
+ 0x99, 0xd6,
+ // GZIP data
+ 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }, "");
+}
+
+test "zlib should not overshoot" {
+ // Compressed zlib data with extra 4 bytes at the end.
+ const data = [_]u8{
+ 0x78, 0x9c, 0x73, 0xce, 0x2f, 0xa8, 0x2c, 0xca, 0x4c, 0xcf, 0x28, 0x51, 0x08, 0xcf, 0xcc, 0xc9,
+ 0x49, 0xcd, 0x55, 0x28, 0x4b, 0xcc, 0x53, 0x08, 0x4e, 0xce, 0x48, 0xcc, 0xcc, 0xd6, 0x51, 0x08,
+ 0xce, 0xcc, 0x4b, 0x4f, 0x2c, 0xc8, 0x2f, 0x4a, 0x55, 0x30, 0xb4, 0xb4, 0x34, 0xd5, 0xb5, 0x34,
+ 0x03, 0x00, 0x8b, 0x61, 0x0f, 0xa4, 0x52, 0x5a, 0x94, 0x12,
+ };
+
+ var reader: std.Io.Reader = .fixed(&data);
+
+ var decompress_buffer: [flate.max_window_len]u8 = undefined;
+ var decompress: Decompress = .init(&reader, .zlib, &decompress_buffer);
+ var out: [128]u8 = undefined;
+
+ {
+ const n = try decompress.reader.readSliceShort(&out);
+ try std.testing.expectEqual(46, n);
+ try std.testing.expectEqualStrings("Copyright Willem van Schaik, Singapore 1995-96", out[0..n]);
+ }
+
+ // 4 bytes after compressed chunk are available in reader.
+ const n = try reader.readSliceShort(&out);
+ try std.testing.expectEqual(n, 4);
+ try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]);
+}
+
+fn testFailure(container: Container, in: []const u8, expected_err: anyerror) !void {
+ var reader: Reader = .fixed(in);
+ var aw: Writer.Allocating = .init(testing.allocator);
+ try aw.ensureUnusedCapacity(flate.history_len);
+ defer aw.deinit();
+
+ var decompress: Decompress = .init(&reader, container, &.{});
+ try testing.expectError(error.ReadFailed, decompress.reader.streamRemaining(&aw.writer));
+ try testing.expectEqual(expected_err, decompress.err orelse return error.TestFailed);
+}
+
+fn testDecompress(container: Container, compressed: []const u8, expected_plain: []const u8) !void {
+ var in: std.Io.Reader = .fixed(compressed);
+ var aw: std.Io.Writer.Allocating = .init(testing.allocator);
+ try aw.ensureUnusedCapacity(flate.history_len);
+ defer aw.deinit();
+
+ var decompress: Decompress = .init(&in, container, &.{});
+ _ = try decompress.reader.streamRemaining(&aw.writer);
+ try testing.expectEqualSlices(u8, expected_plain, aw.getWritten());
}
diff --git a/lib/std/compress/flate/HuffmanEncoder.zig b/lib/std/compress/flate/HuffmanEncoder.zig
new file mode 100644
index 0000000000..28a405b886
--- /dev/null
+++ b/lib/std/compress/flate/HuffmanEncoder.zig
@@ -0,0 +1,463 @@
+const HuffmanEncoder = @This();
+const std = @import("std");
+const assert = std.debug.assert;
+const testing = std.testing;
+
+codes: []Code,
+// Reusable buffer with the longest possible frequency table.
+freq_cache: [max_num_frequencies + 1]LiteralNode,
+bit_count: [17]u32,
+lns: []LiteralNode, // sorted by literal, stored to avoid repeated allocation in generate
+lfs: []LiteralNode, // sorted by frequency, stored to avoid repeated allocation in generate
+
+pub const LiteralNode = struct {
+ literal: u16,
+ freq: u16,
+
+ pub fn max() LiteralNode {
+ return .{
+ .literal = std.math.maxInt(u16),
+ .freq = std.math.maxInt(u16),
+ };
+ }
+};
+
+pub const Code = struct {
+ code: u16 = 0,
+ len: u16 = 0,
+};
+
+/// The odd order in which the codegen code sizes are written.
+pub const codegen_order = [_]u32{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+/// The number of codegen codes.
+pub const codegen_code_count = 19;
+
+/// The largest distance code.
+pub const distance_code_count = 30;
+
+/// Maximum number of literals.
+pub const max_num_lit = 286;
+
+/// Max number of frequencies used for a Huffman Code
+/// Possible lengths are codegen_code_count (19), distance_code_count (30) and max_num_lit (286).
+/// The largest of these is max_num_lit.
+pub const max_num_frequencies = max_num_lit;
+
+/// Biggest block size for uncompressed block.
+pub const max_store_block_size = 65535;
+/// The special code used to mark the end of a block.
+pub const end_block_marker = 256;
+
+/// Update this Huffman Code object to be the minimum code for the specified frequency count.
+///
+/// freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
+/// max_bits The maximum number of bits to use for any literal.
+pub fn generate(self: *HuffmanEncoder, freq: []u16, max_bits: u32) void {
+ var list = self.freq_cache[0 .. freq.len + 1];
+ // Number of non-zero literals
+ var count: u32 = 0;
+ // Set list to be the set of all non-zero literals and their frequencies
+ for (freq, 0..) |f, i| {
+ if (f != 0) {
+ list[count] = LiteralNode{ .literal = @as(u16, @intCast(i)), .freq = f };
+ count += 1;
+ } else {
+ list[count] = LiteralNode{ .literal = 0x00, .freq = 0 };
+ self.codes[i].len = 0;
+ }
+ }
+ list[freq.len] = LiteralNode{ .literal = 0x00, .freq = 0 };
+
+ list = list[0..count];
+ if (count <= 2) {
+ // Handle the small cases here, because they are awkward for the general case code. With
+ // two or fewer literals, everything has bit length 1.
+ for (list, 0..) |node, i| {
+ // "list" is in order of increasing literal value.
+ self.codes[node.literal] = .{
+ .code = @intCast(i),
+ .len = 1,
+ };
+ }
+ return;
+ }
+ self.lfs = list;
+ std.mem.sort(LiteralNode, self.lfs, {}, byFreq);
+
+ // Get the number of literals for each bit count
+ const bit_count = self.bitCounts(list, max_bits);
+ // And do the assignment
+ self.assignEncodingAndSize(bit_count, list);
+}
+
+pub fn bitLength(self: *HuffmanEncoder, freq: []u16) u32 {
+ var total: u32 = 0;
+ for (freq, 0..) |f, i| {
+ if (f != 0) {
+ total += @as(u32, @intCast(f)) * @as(u32, @intCast(self.codes[i].len));
+ }
+ }
+ return total;
+}
+
+/// Return the number of literals assigned to each bit size in the Huffman encoding
+///
+/// This method is only called when list.len >= 3
+/// The cases of 0, 1, and 2 literals are handled by special case code.
+///
+/// list: An array of the literals with non-zero frequencies
+/// and their associated frequencies. The array is in order of increasing
+/// frequency, and has as its last element a special element with frequency
+/// `math.maxInt(i32)`
+///
+/// max_bits: The maximum number of bits that should be used to encode any literal.
+/// Must be less than 16.
+///
+/// Returns an integer array in which array[i] indicates the number of literals
+/// that should be encoded in i bits.
+fn bitCounts(self: *HuffmanEncoder, list: []LiteralNode, max_bits_to_use: usize) []u32 {
+ var max_bits = max_bits_to_use;
+ const n = list.len;
+ const max_bits_limit = 16;
+
+ assert(max_bits < max_bits_limit);
+
+ // The tree can't have greater depth than n - 1, no matter what. This
+ // saves a little bit of work in some small cases
+ max_bits = @min(max_bits, n - 1);
+
+ // Create information about each of the levels.
+ // A bogus "Level 0" whose sole purpose is so that
+ // level1.prev.needed == 0. This makes level1.next_pair_freq
+ // be a legitimate value that never gets chosen.
+ var levels: [max_bits_limit]LevelInfo = std.mem.zeroes([max_bits_limit]LevelInfo);
+ // leaf_counts[i] counts the number of literals at the left
+ // of ancestors of the rightmost node at level i.
+ // leaf_counts[i][j] is the number of literals at the left
+ // of the level j ancestor.
+ var leaf_counts: [max_bits_limit][max_bits_limit]u32 = @splat(@splat(0));
+
+ {
+ var level = @as(u32, 1);
+ while (level <= max_bits) : (level += 1) {
+ // For every level, the first two items are the first two characters.
+ // We initialize the levels as if we had already figured this out.
+ levels[level] = LevelInfo{
+ .level = level,
+ .last_freq = list[1].freq,
+ .next_char_freq = list[2].freq,
+ .next_pair_freq = list[0].freq + list[1].freq,
+ .needed = 0,
+ };
+ leaf_counts[level][level] = 2;
+ if (level == 1) {
+ levels[level].next_pair_freq = std.math.maxInt(i32);
+ }
+ }
+ }
+
+ // We need a total of 2*n - 2 items at top level and have already generated 2.
+ levels[max_bits].needed = 2 * @as(u32, @intCast(n)) - 4;
+
+ {
+ var level = max_bits;
+ while (true) {
+ var l = &levels[level];
+ if (l.next_pair_freq == std.math.maxInt(i32) and l.next_char_freq == std.math.maxInt(i32)) {
+ // We've run out of both leaves and pairs.
+ // End all calculations for this level.
+ // To make sure we never come back to this level or any lower level,
+ // set next_pair_freq impossibly large.
+ l.needed = 0;
+ levels[level + 1].next_pair_freq = std.math.maxInt(i32);
+ level += 1;
+ continue;
+ }
+
+ const prev_freq = l.last_freq;
+ if (l.next_char_freq < l.next_pair_freq) {
+ // The next item on this row is a leaf node.
+ const next = leaf_counts[level][level] + 1;
+ l.last_freq = l.next_char_freq;
+ // Lower leaf_counts are the same of the previous node.
+ leaf_counts[level][level] = next;
+ if (next >= list.len) {
+ l.next_char_freq = LiteralNode.max().freq;
+ } else {
+ l.next_char_freq = list[next].freq;
+ }
+ } else {
+ // The next item on this row is a pair from the previous row.
+ // next_pair_freq isn't valid until we generate two
+ // more values in the level below
+ l.last_freq = l.next_pair_freq;
+ // Take leaf counts from the lower level, except counts[level] remains the same.
+ @memcpy(leaf_counts[level][0..level], leaf_counts[level - 1][0..level]);
+ levels[l.level - 1].needed = 2;
+ }
+
+ l.needed -= 1;
+ if (l.needed == 0) {
+ // We've done everything we need to do for this level.
+ // Continue calculating one level up. Fill in next_pair_freq
+ // of that level with the sum of the two nodes we've just calculated on
+ // this level.
+ if (l.level == max_bits) {
+ // All done!
+ break;
+ }
+ levels[l.level + 1].next_pair_freq = prev_freq + l.last_freq;
+ level += 1;
+ } else {
+ // If we stole from below, move down temporarily to replenish it.
+ while (levels[level - 1].needed > 0) {
+ level -= 1;
+ if (level == 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Somethings is wrong if at the end, the top level is null or hasn't used
+ // all of the leaves.
+ assert(leaf_counts[max_bits][max_bits] == n);
+
+ var bit_count = self.bit_count[0 .. max_bits + 1];
+ var bits: u32 = 1;
+ const counts = &leaf_counts[max_bits];
+ {
+ var level = max_bits;
+ while (level > 0) : (level -= 1) {
+ // counts[level] gives the number of literals requiring at least "bits"
+ // bits to encode.
+ bit_count[bits] = counts[level] - counts[level - 1];
+ bits += 1;
+ if (level == 0) {
+ break;
+ }
+ }
+ }
+ return bit_count;
+}
+
+/// Look at the leaves and assign them a bit count and an encoding as specified
+/// in RFC 1951 3.2.2
+fn assignEncodingAndSize(self: *HuffmanEncoder, bit_count: []u32, list_arg: []LiteralNode) void {
+ var code = @as(u16, 0);
+ var list = list_arg;
+
+ for (bit_count, 0..) |bits, n| {
+ code <<= 1;
+ if (n == 0 or bits == 0) {
+ continue;
+ }
+ // The literals list[list.len-bits] .. list[list.len-bits]
+ // are encoded using "bits" bits, and get the values
+ // code, code + 1, .... The code values are
+ // assigned in literal order (not frequency order).
+ const chunk = list[list.len - @as(u32, @intCast(bits)) ..];
+
+ self.lns = chunk;
+ std.mem.sort(LiteralNode, self.lns, {}, byLiteral);
+
+ for (chunk) |node| {
+ self.codes[node.literal] = .{
+ .code = bitReverse(u16, code, @as(u5, @intCast(n))),
+ .len = @as(u16, @intCast(n)),
+ };
+ code += 1;
+ }
+ list = list[0 .. list.len - @as(u32, @intCast(bits))];
+ }
+}
+
+fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool {
+ _ = context;
+ if (a.freq == b.freq) {
+ return a.literal < b.literal;
+ }
+ return a.freq < b.freq;
+}
+
+/// Describes the state of the constructed tree for a given depth.
+const LevelInfo = struct {
+ /// Our level. for better printing
+ level: u32,
+ /// The frequency of the last node at this level
+ last_freq: u32,
+ /// The frequency of the next character to add to this level
+ next_char_freq: u32,
+ /// The frequency of the next pair (from level below) to add to this level.
+ /// Only valid if the "needed" value of the next lower level is 0.
+ next_pair_freq: u32,
+ /// The number of chains remaining to generate for this level before moving
+ /// up to the next level
+ needed: u32,
+};
+
+fn byLiteral(context: void, a: LiteralNode, b: LiteralNode) bool {
+ _ = context;
+ return a.literal < b.literal;
+}
+
+/// Reverse bit-by-bit a N-bit code.
+fn bitReverse(comptime T: type, value: T, n: usize) T {
+ const r = @bitReverse(value);
+ return r >> @as(std.math.Log2Int(T), @intCast(@typeInfo(T).int.bits - n));
+}
+
+test bitReverse {
+ const ReverseBitsTest = struct {
+ in: u16,
+ bit_count: u5,
+ out: u16,
+ };
+
+ const reverse_bits_tests = [_]ReverseBitsTest{
+ .{ .in = 1, .bit_count = 1, .out = 1 },
+ .{ .in = 1, .bit_count = 2, .out = 2 },
+ .{ .in = 1, .bit_count = 3, .out = 4 },
+ .{ .in = 1, .bit_count = 4, .out = 8 },
+ .{ .in = 1, .bit_count = 5, .out = 16 },
+ .{ .in = 17, .bit_count = 5, .out = 17 },
+ .{ .in = 257, .bit_count = 9, .out = 257 },
+ .{ .in = 29, .bit_count = 5, .out = 23 },
+ };
+
+ for (reverse_bits_tests) |h| {
+ const v = bitReverse(u16, h.in, h.bit_count);
+ try std.testing.expectEqual(h.out, v);
+ }
+}
+
+/// Generates a HuffmanCode corresponding to the fixed literal table
+pub fn fixedLiteralEncoder(codes: *[max_num_frequencies]Code) HuffmanEncoder {
+ var h: HuffmanEncoder = undefined;
+ h.codes = codes;
+ var ch: u16 = 0;
+
+ while (ch < max_num_frequencies) : (ch += 1) {
+ var bits: u16 = undefined;
+ var size: u16 = undefined;
+ switch (ch) {
+ 0...143 => {
+ // size 8, 000110000 .. 10111111
+ bits = ch + 48;
+ size = 8;
+ },
+ 144...255 => {
+ // size 9, 110010000 .. 111111111
+ bits = ch + 400 - 144;
+ size = 9;
+ },
+ 256...279 => {
+ // size 7, 0000000 .. 0010111
+ bits = ch - 256;
+ size = 7;
+ },
+ else => {
+ // size 8, 11000000 .. 11000111
+ bits = ch + 192 - 280;
+ size = 8;
+ },
+ }
+ h.codes[ch] = .{ .code = bitReverse(u16, bits, @as(u5, @intCast(size))), .len = size };
+ }
+ return h;
+}
+
+pub fn fixedDistanceEncoder(codes: *[distance_code_count]Code) HuffmanEncoder {
+ var h: HuffmanEncoder = undefined;
+ h.codes = codes;
+ for (h.codes, 0..) |_, ch| {
+ h.codes[ch] = .{ .code = bitReverse(u16, @as(u16, @intCast(ch)), 5), .len = 5 };
+ }
+ return h;
+}
+
+pub fn huffmanDistanceEncoder(codes: *[distance_code_count]Code) HuffmanEncoder {
+ var distance_freq: [distance_code_count]u16 = @splat(0);
+ distance_freq[0] = 1;
+ // huff_distance is a static distance encoder used for huffman only encoding.
+ // It can be reused since we will not be encoding distance values.
+ var h: HuffmanEncoder = .{};
+ h.codes = codes;
+ h.generate(distance_freq[0..], 15);
+ return h;
+}
+
+test "generate a Huffman code for the fixed literal table specific to Deflate" {
+ var codes: [max_num_frequencies]Code = undefined;
+ const enc: HuffmanEncoder = .fixedLiteralEncoder(&codes);
+ for (enc.codes) |c| {
+ switch (c.len) {
+ 7 => {
+ const v = @bitReverse(@as(u7, @intCast(c.code)));
+ try testing.expect(v <= 0b0010111);
+ },
+ 8 => {
+ const v = @bitReverse(@as(u8, @intCast(c.code)));
+ try testing.expect((v >= 0b000110000 and v <= 0b10111111) or
+ (v >= 0b11000000 and v <= 11000111));
+ },
+ 9 => {
+ const v = @bitReverse(@as(u9, @intCast(c.code)));
+ try testing.expect(v >= 0b110010000 and v <= 0b111111111);
+ },
+ else => unreachable,
+ }
+ }
+}
+
+test "generate a Huffman code for the 30 possible relative distances (LZ77 distances) of Deflate" {
+ var codes: [distance_code_count]Code = undefined;
+ const enc = fixedDistanceEncoder(&codes);
+ for (enc.codes) |c| {
+ const v = @bitReverse(@as(u5, @intCast(c.code)));
+ try testing.expect(v <= 29);
+ try testing.expect(c.len == 5);
+ }
+}
+
+pub const fixed_codes = [_]u8{
+ 0b00001100, 0b10001100, 0b01001100, 0b11001100, 0b00101100, 0b10101100, 0b01101100, 0b11101100,
+ 0b00011100, 0b10011100, 0b01011100, 0b11011100, 0b00111100, 0b10111100, 0b01111100, 0b11111100,
+ 0b00000010, 0b10000010, 0b01000010, 0b11000010, 0b00100010, 0b10100010, 0b01100010, 0b11100010,
+ 0b00010010, 0b10010010, 0b01010010, 0b11010010, 0b00110010, 0b10110010, 0b01110010, 0b11110010,
+ 0b00001010, 0b10001010, 0b01001010, 0b11001010, 0b00101010, 0b10101010, 0b01101010, 0b11101010,
+ 0b00011010, 0b10011010, 0b01011010, 0b11011010, 0b00111010, 0b10111010, 0b01111010, 0b11111010,
+ 0b00000110, 0b10000110, 0b01000110, 0b11000110, 0b00100110, 0b10100110, 0b01100110, 0b11100110,
+ 0b00010110, 0b10010110, 0b01010110, 0b11010110, 0b00110110, 0b10110110, 0b01110110, 0b11110110,
+ 0b00001110, 0b10001110, 0b01001110, 0b11001110, 0b00101110, 0b10101110, 0b01101110, 0b11101110,
+ 0b00011110, 0b10011110, 0b01011110, 0b11011110, 0b00111110, 0b10111110, 0b01111110, 0b11111110,
+ 0b00000001, 0b10000001, 0b01000001, 0b11000001, 0b00100001, 0b10100001, 0b01100001, 0b11100001,
+ 0b00010001, 0b10010001, 0b01010001, 0b11010001, 0b00110001, 0b10110001, 0b01110001, 0b11110001,
+ 0b00001001, 0b10001001, 0b01001001, 0b11001001, 0b00101001, 0b10101001, 0b01101001, 0b11101001,
+ 0b00011001, 0b10011001, 0b01011001, 0b11011001, 0b00111001, 0b10111001, 0b01111001, 0b11111001,
+ 0b00000101, 0b10000101, 0b01000101, 0b11000101, 0b00100101, 0b10100101, 0b01100101, 0b11100101,
+ 0b00010101, 0b10010101, 0b01010101, 0b11010101, 0b00110101, 0b10110101, 0b01110101, 0b11110101,
+ 0b00001101, 0b10001101, 0b01001101, 0b11001101, 0b00101101, 0b10101101, 0b01101101, 0b11101101,
+ 0b00011101, 0b10011101, 0b01011101, 0b11011101, 0b00111101, 0b10111101, 0b01111101, 0b11111101,
+ 0b00010011, 0b00100110, 0b01001110, 0b10011010, 0b00111100, 0b01100101, 0b11101010, 0b10110100,
+ 0b11101001, 0b00110011, 0b01100110, 0b11001110, 0b10011010, 0b00111101, 0b01100111, 0b11101110,
+ 0b10111100, 0b11111001, 0b00001011, 0b00010110, 0b00101110, 0b01011010, 0b10111100, 0b01100100,
+ 0b11101001, 0b10110010, 0b11100101, 0b00101011, 0b01010110, 0b10101110, 0b01011010, 0b10111101,
+ 0b01100110, 0b11101101, 0b10111010, 0b11110101, 0b00011011, 0b00110110, 0b01101110, 0b11011010,
+ 0b10111100, 0b01100101, 0b11101011, 0b10110110, 0b11101101, 0b00111011, 0b01110110, 0b11101110,
+ 0b11011010, 0b10111101, 0b01100111, 0b11101111, 0b10111110, 0b11111101, 0b00000111, 0b00001110,
+ 0b00011110, 0b00111010, 0b01111100, 0b11100100, 0b11101000, 0b10110001, 0b11100011, 0b00100111,
+ 0b01001110, 0b10011110, 0b00111010, 0b01111101, 0b11100110, 0b11101100, 0b10111001, 0b11110011,
+ 0b00010111, 0b00101110, 0b01011110, 0b10111010, 0b01111100, 0b11100101, 0b11101010, 0b10110101,
+ 0b11101011, 0b00110111, 0b01101110, 0b11011110, 0b10111010, 0b01111101, 0b11100111, 0b11101110,
+ 0b10111101, 0b11111011, 0b00001111, 0b00011110, 0b00111110, 0b01111010, 0b11111100, 0b11100100,
+ 0b11101001, 0b10110011, 0b11100111, 0b00101111, 0b01011110, 0b10111110, 0b01111010, 0b11111101,
+ 0b11100110, 0b11101101, 0b10111011, 0b11110111, 0b00011111, 0b00111110, 0b01111110, 0b11111010,
+ 0b11111100, 0b11100101, 0b11101011, 0b10110111, 0b11101111, 0b00111111, 0b01111110, 0b11111110,
+ 0b11111010, 0b11111101, 0b11100111, 0b11101111, 0b10111111, 0b11111111, 0b00000000, 0b00100000,
+ 0b00001000, 0b00001100, 0b10000001, 0b11000010, 0b11100000, 0b00001000, 0b00100100, 0b00001010,
+ 0b10001101, 0b11000001, 0b11100010, 0b11110000, 0b00000100, 0b00100010, 0b10001001, 0b01001100,
+ 0b10100001, 0b11010010, 0b11101000, 0b00000011, 0b10000011, 0b01000011, 0b11000011, 0b00100011,
+ 0b10100011,
+};
diff --git a/lib/std/compress/flate/Lookup.zig b/lib/std/compress/flate/Lookup.zig
index 722e175c8a..d1d93de50a 100644
--- a/lib/std/compress/flate/Lookup.zig
+++ b/lib/std/compress/flate/Lookup.zig
@@ -6,14 +6,19 @@ const std = @import("std");
const testing = std.testing;
const expect = testing.expect;
const flate = @import("../flate.zig");
+const Token = @import("Token.zig");
const Lookup = @This();
const prime4 = 0x9E3779B1; // 4 bytes prime number 2654435761
const chain_len = 2 * flate.history_len;
+pub const bits = 15;
+pub const len = 1 << bits;
+pub const shift = 32 - bits;
+
// Maps hash => first position
-head: [flate.lookup.len]u16 = [_]u16{0} ** flate.lookup.len,
+head: [len]u16 = [_]u16{0} ** len,
// Maps position => previous positions for the same hash value
chain: [chain_len]u16 = [_]u16{0} ** (chain_len),
@@ -52,8 +57,8 @@ pub fn slide(self: *Lookup, n: u16) void {
// Add `len` 4 bytes hashes from `data` into lookup.
// Position of the first byte is `pos`.
-pub fn bulkAdd(self: *Lookup, data: []const u8, len: u16, pos: u16) void {
- if (len == 0 or data.len < flate.match.min_length) {
+pub fn bulkAdd(self: *Lookup, data: []const u8, length: u16, pos: u16) void {
+ if (length == 0 or data.len < Token.min_length) {
return;
}
var hb =
@@ -64,7 +69,7 @@ pub fn bulkAdd(self: *Lookup, data: []const u8, len: u16, pos: u16) void {
_ = self.set(hashu(hb), pos);
var i = pos;
- for (4..@min(len + 3, data.len)) |j| {
+ for (4..@min(length + 3, data.len)) |j| {
hb = (hb << 8) | @as(u32, data[j]);
i += 1;
_ = self.set(hashu(hb), i);
@@ -80,7 +85,7 @@ fn hash(b: *const [4]u8) u32 {
}
fn hashu(v: u32) u32 {
- return @intCast((v *% prime4) >> flate.lookup.shift);
+ return @intCast((v *% prime4) >> shift);
}
test add {
diff --git a/lib/std/compress/flate/Token.zig b/lib/std/compress/flate/Token.zig
index 293a786cef..1383047693 100644
--- a/lib/std/compress/flate/Token.zig
+++ b/lib/std/compress/flate/Token.zig
@@ -6,7 +6,6 @@ const std = @import("std");
const assert = std.debug.assert;
const print = std.debug.print;
const expect = std.testing.expect;
-const match = std.compress.flate.match;
const Token = @This();
@@ -21,16 +20,23 @@ dist: u15 = 0,
len_lit: u8 = 0,
kind: Kind = .literal,
+pub const base_length = 3; // smallest match length per the RFC section 3.2.5
+pub const min_length = 4; // min length used in this algorithm
+pub const max_length = 258;
+
+pub const min_distance = 1;
+pub const max_distance = std.compress.flate.history_len;
+
pub fn literal(t: Token) u8 {
return t.len_lit;
}
pub fn distance(t: Token) u16 {
- return @as(u16, t.dist) + match.min_distance;
+ return @as(u16, t.dist) + min_distance;
}
pub fn length(t: Token) u16 {
- return @as(u16, t.len_lit) + match.base_length;
+ return @as(u16, t.len_lit) + base_length;
}
pub fn initLiteral(lit: u8) Token {
@@ -40,12 +46,12 @@ pub fn initLiteral(lit: u8) Token {
// distance range 1 - 32768, stored in dist as 0 - 32767 (u15)
// length range 3 - 258, stored in len_lit as 0 - 255 (u8)
pub fn initMatch(dist: u16, len: u16) Token {
- assert(len >= match.min_length and len <= match.max_length);
- assert(dist >= match.min_distance and dist <= match.max_distance);
+ assert(len >= min_length and len <= max_length);
+ assert(dist >= min_distance and dist <= max_distance);
return .{
.kind = .match,
- .dist = @intCast(dist - match.min_distance),
- .len_lit = @intCast(len - match.base_length),
+ .dist = @intCast(dist - min_distance),
+ .len_lit = @intCast(len - base_length),
};
}
diff --git a/lib/std/compress/flate/testdata/block_writer.zig b/lib/std/compress/flate/testdata/block_writer.zig
deleted file mode 100644
index cb8f3028d1..0000000000
--- a/lib/std/compress/flate/testdata/block_writer.zig
+++ /dev/null
@@ -1,606 +0,0 @@
-const Token = @import("../Token.zig");
-
-pub const TestCase = struct {
- tokens: []const Token,
- input: []const u8 = "", // File name of input data matching the tokens.
- want: []const u8 = "", // File name of data with the expected output with input available.
- want_no_input: []const u8 = "", // File name of the expected output when no input is available.
-};
-
-pub const testCases = blk: {
- @setEvalBranchQuota(4096 * 2);
-
- const L = Token.initLiteral;
- const M = Token.initMatch;
- const ml = M(1, 258); // Maximum length token. Used to reduce the size of writeBlockTests
-
- break :blk &[_]TestCase{
- TestCase{
- .input = "huffman-null-max.input",
- .want = "huffman-null-max.{s}.expect",
- .want_no_input = "huffman-null-max.{s}.expect-noinput",
- .tokens = &[_]Token{
- L(0x0), ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, L(0x0), L(0x0),
- },
- },
- TestCase{
- .input = "huffman-pi.input",
- .want = "huffman-pi.{s}.expect",
- .want_no_input = "huffman-pi.{s}.expect-noinput",
- .tokens = &[_]Token{
- L('3'), L('.'), L('1'), L('4'), L('1'), L('5'), L('9'), L('2'),
- L('6'), L('5'), L('3'), L('5'), L('8'), L('9'), L('7'), L('9'),
- L('3'), L('2'), L('3'), L('8'), L('4'), L('6'), L('2'), L('6'),
- L('4'), L('3'), L('3'), L('8'), L('3'), L('2'), L('7'), L('9'),
- L('5'), L('0'), L('2'), L('8'), L('8'), L('4'), L('1'), L('9'),
- L('7'), L('1'), L('6'), L('9'), L('3'), L('9'), L('9'), L('3'),
- L('7'), L('5'), L('1'), L('0'), L('5'), L('8'), L('2'), L('0'),
- L('9'), L('7'), L('4'), L('9'), L('4'), L('4'), L('5'), L('9'),
- L('2'), L('3'), L('0'), L('7'), L('8'), L('1'), L('6'), L('4'),
- L('0'), L('6'), L('2'), L('8'), L('6'), L('2'), L('0'), L('8'),
- L('9'), L('9'), L('8'), L('6'), L('2'), L('8'), L('0'), L('3'),
- L('4'), L('8'), L('2'), L('5'), L('3'), L('4'), L('2'), L('1'),
- L('1'), L('7'), L('0'), L('6'), L('7'), L('9'), L('8'), L('2'),
- L('1'), L('4'), L('8'), L('0'), L('8'), L('6'), L('5'), L('1'),
- L('3'), L('2'), L('8'), L('2'), L('3'), L('0'), L('6'), L('6'),
- L('4'), L('7'), L('0'), L('9'), L('3'), L('8'), L('4'), L('4'),
- L('6'), L('0'), L('9'), L('5'), L('5'), L('0'), L('5'), L('8'),
- L('2'), L('2'), L('3'), L('1'), L('7'), L('2'), L('5'), L('3'),
- L('5'), L('9'), L('4'), L('0'), L('8'), L('1'), L('2'), L('8'),
- L('4'), L('8'), L('1'), L('1'), L('1'), L('7'), L('4'), M(127, 4),
- L('4'), L('1'), L('0'), L('2'), L('7'), L('0'), L('1'), L('9'),
- L('3'), L('8'), L('5'), L('2'), L('1'), L('1'), L('0'), L('5'),
- L('5'), L('5'), L('9'), L('6'), L('4'), L('4'), L('6'), L('2'),
- L('2'), L('9'), L('4'), L('8'), L('9'), L('5'), L('4'), L('9'),
- L('3'), L('0'), L('3'), L('8'), L('1'), M(19, 4), L('2'), L('8'),
- L('8'), L('1'), L('0'), L('9'), L('7'), L('5'), L('6'), L('6'),
- L('5'), L('9'), L('3'), L('3'), L('4'), L('4'), L('6'), M(72, 4),
- L('7'), L('5'), L('6'), L('4'), L('8'), L('2'), L('3'), L('3'),
- L('7'), L('8'), L('6'), L('7'), L('8'), L('3'), L('1'), L('6'),
- L('5'), L('2'), L('7'), L('1'), L('2'), L('0'), L('1'), L('9'),
- L('0'), L('9'), L('1'), L('4'), M(27, 4), L('5'), L('6'), L('6'),
- L('9'), L('2'), L('3'), L('4'), L('6'), M(179, 4), L('6'), L('1'),
- L('0'), L('4'), L('5'), L('4'), L('3'), L('2'), L('6'), M(51, 4),
- L('1'), L('3'), L('3'), L('9'), L('3'), L('6'), L('0'), L('7'),
- L('2'), L('6'), L('0'), L('2'), L('4'), L('9'), L('1'), L('4'),
- L('1'), L('2'), L('7'), L('3'), L('7'), L('2'), L('4'), L('5'),
- L('8'), L('7'), L('0'), L('0'), L('6'), L('6'), L('0'), L('6'),
- L('3'), L('1'), L('5'), L('5'), L('8'), L('8'), L('1'), L('7'),
- L('4'), L('8'), L('8'), L('1'), L('5'), L('2'), L('0'), L('9'),
- L('2'), L('0'), L('9'), L('6'), L('2'), L('8'), L('2'), L('9'),
- L('2'), L('5'), L('4'), L('0'), L('9'), L('1'), L('7'), L('1'),
- L('5'), L('3'), L('6'), L('4'), L('3'), L('6'), L('7'), L('8'),
- L('9'), L('2'), L('5'), L('9'), L('0'), L('3'), L('6'), L('0'),
- L('0'), L('1'), L('1'), L('3'), L('3'), L('0'), L('5'), L('3'),
- L('0'), L('5'), L('4'), L('8'), L('8'), L('2'), L('0'), L('4'),
- L('6'), L('6'), L('5'), L('2'), L('1'), L('3'), L('8'), L('4'),
- L('1'), L('4'), L('6'), L('9'), L('5'), L('1'), L('9'), L('4'),
- L('1'), L('5'), L('1'), L('1'), L('6'), L('0'), L('9'), L('4'),
- L('3'), L('3'), L('0'), L('5'), L('7'), L('2'), L('7'), L('0'),
- L('3'), L('6'), L('5'), L('7'), L('5'), L('9'), L('5'), L('9'),
- L('1'), L('9'), L('5'), L('3'), L('0'), L('9'), L('2'), L('1'),
- L('8'), L('6'), L('1'), L('1'), L('7'), M(234, 4), L('3'), L('2'),
- M(10, 4), L('9'), L('3'), L('1'), L('0'), L('5'), L('1'), L('1'),
- L('8'), L('5'), L('4'), L('8'), L('0'), L('7'), M(271, 4), L('3'),
- L('7'), L('9'), L('9'), L('6'), L('2'), L('7'), L('4'), L('9'),
- L('5'), L('6'), L('7'), L('3'), L('5'), L('1'), L('8'), L('8'),
- L('5'), L('7'), L('5'), L('2'), L('7'), L('2'), L('4'), L('8'),
- L('9'), L('1'), L('2'), L('2'), L('7'), L('9'), L('3'), L('8'),
- L('1'), L('8'), L('3'), L('0'), L('1'), L('1'), L('9'), L('4'),
- L('9'), L('1'), L('2'), L('9'), L('8'), L('3'), L('3'), L('6'),
- L('7'), L('3'), L('3'), L('6'), L('2'), L('4'), L('4'), L('0'),
- L('6'), L('5'), L('6'), L('6'), L('4'), L('3'), L('0'), L('8'),
- L('6'), L('0'), L('2'), L('1'), L('3'), L('9'), L('4'), L('9'),
- L('4'), L('6'), L('3'), L('9'), L('5'), L('2'), L('2'), L('4'),
- L('7'), L('3'), L('7'), L('1'), L('9'), L('0'), L('7'), L('0'),
- L('2'), L('1'), L('7'), L('9'), L('8'), M(154, 5), L('7'), L('0'),
- L('2'), L('7'), L('7'), L('0'), L('5'), L('3'), L('9'), L('2'),
- L('1'), L('7'), L('1'), L('7'), L('6'), L('2'), L('9'), L('3'),
- L('1'), L('7'), L('6'), L('7'), L('5'), M(563, 5), L('7'), L('4'),
- L('8'), L('1'), M(7, 4), L('6'), L('6'), L('9'), L('4'), L('0'),
- M(488, 4), L('0'), L('0'), L('0'), L('5'), L('6'), L('8'), L('1'),
- L('2'), L('7'), L('1'), L('4'), L('5'), L('2'), L('6'), L('3'),
- L('5'), L('6'), L('0'), L('8'), L('2'), L('7'), L('7'), L('8'),
- L('5'), L('7'), L('7'), L('1'), L('3'), L('4'), L('2'), L('7'),
- L('5'), L('7'), L('7'), L('8'), L('9'), L('6'), M(298, 4), L('3'),
- L('6'), L('3'), L('7'), L('1'), L('7'), L('8'), L('7'), L('2'),
- L('1'), L('4'), L('6'), L('8'), L('4'), L('4'), L('0'), L('9'),
- L('0'), L('1'), L('2'), L('2'), L('4'), L('9'), L('5'), L('3'),
- L('4'), L('3'), L('0'), L('1'), L('4'), L('6'), L('5'), L('4'),
- L('9'), L('5'), L('8'), L('5'), L('3'), L('7'), L('1'), L('0'),
- L('5'), L('0'), L('7'), L('9'), M(203, 4), L('6'), M(340, 4), L('8'),
- L('9'), L('2'), L('3'), L('5'), L('4'), M(458, 4), L('9'), L('5'),
- L('6'), L('1'), L('1'), L('2'), L('1'), L('2'), L('9'), L('0'),
- L('2'), L('1'), L('9'), L('6'), L('0'), L('8'), L('6'), L('4'),
- L('0'), L('3'), L('4'), L('4'), L('1'), L('8'), L('1'), L('5'),
- L('9'), L('8'), L('1'), L('3'), L('6'), L('2'), L('9'), L('7'),
- L('7'), L('4'), M(117, 4), L('0'), L('9'), L('9'), L('6'), L('0'),
- L('5'), L('1'), L('8'), L('7'), L('0'), L('7'), L('2'), L('1'),
- L('1'), L('3'), L('4'), L('9'), M(1, 5), L('8'), L('3'), L('7'),
- L('2'), L('9'), L('7'), L('8'), L('0'), L('4'), L('9'), L('9'),
- M(731, 4), L('9'), L('7'), L('3'), L('1'), L('7'), L('3'), L('2'),
- L('8'), M(395, 4), L('6'), L('3'), L('1'), L('8'), L('5'), M(770, 4),
- M(745, 4), L('4'), L('5'), L('5'), L('3'), L('4'), L('6'), L('9'),
- L('0'), L('8'), L('3'), L('0'), L('2'), L('6'), L('4'), L('2'),
- L('5'), L('2'), L('2'), L('3'), L('0'), M(740, 4), M(616, 4), L('8'),
- L('5'), L('0'), L('3'), L('5'), L('2'), L('6'), L('1'), L('9'),
- L('3'), L('1'), L('1'), M(531, 4), L('1'), L('0'), L('1'), L('0'),
- L('0'), L('0'), L('3'), L('1'), L('3'), L('7'), L('8'), L('3'),
- L('8'), L('7'), L('5'), L('2'), L('8'), L('8'), L('6'), L('5'),
- L('8'), L('7'), L('5'), L('3'), L('3'), L('2'), L('0'), L('8'),
- L('3'), L('8'), L('1'), L('4'), L('2'), L('0'), L('6'), M(321, 4),
- M(300, 4), L('1'), L('4'), L('7'), L('3'), L('0'), L('3'), L('5'),
- L('9'), M(815, 5), L('9'), L('0'), L('4'), L('2'), L('8'), L('7'),
- L('5'), L('5'), L('4'), L('6'), L('8'), L('7'), L('3'), L('1'),
- L('1'), L('5'), L('9'), L('5'), M(854, 4), L('3'), L('8'), L('8'),
- L('2'), L('3'), L('5'), L('3'), L('7'), L('8'), L('7'), L('5'),
- M(896, 5), L('9'), M(315, 4), L('1'), M(329, 4), L('8'), L('0'), L('5'),
- L('3'), M(395, 4), L('2'), L('2'), L('6'), L('8'), L('0'), L('6'),
- L('6'), L('1'), L('3'), L('0'), L('0'), L('1'), L('9'), L('2'),
- L('7'), L('8'), L('7'), L('6'), L('6'), L('1'), L('1'), L('1'),
- L('9'), L('5'), L('9'), M(568, 4), L('6'), M(293, 5), L('8'), L('9'),
- L('3'), L('8'), L('0'), L('9'), L('5'), L('2'), L('5'), L('7'),
- L('2'), L('0'), L('1'), L('0'), L('6'), L('5'), L('4'), L('8'),
- L('5'), L('8'), L('6'), L('3'), L('2'), L('7'), M(155, 4), L('9'),
- L('3'), L('6'), L('1'), L('5'), L('3'), M(545, 4), M(349, 5), L('2'),
- L('3'), L('0'), L('3'), L('0'), L('1'), L('9'), L('5'), L('2'),
- L('0'), L('3'), L('5'), L('3'), L('0'), L('1'), L('8'), L('5'),
- L('2'), M(370, 4), M(118, 4), L('3'), L('6'), L('2'), L('2'), L('5'),
- L('9'), L('9'), L('4'), L('1'), L('3'), M(597, 4), L('4'), L('9'),
- L('7'), L('2'), L('1'), L('7'), M(223, 4), L('3'), L('4'), L('7'),
- L('9'), L('1'), L('3'), L('1'), L('5'), L('1'), L('5'), L('5'),
- L('7'), L('4'), L('8'), L('5'), L('7'), L('2'), L('4'), L('2'),
- L('4'), L('5'), L('4'), L('1'), L('5'), L('0'), L('6'), L('9'),
- M(320, 4), L('8'), L('2'), L('9'), L('5'), L('3'), L('3'), L('1'),
- L('1'), L('6'), L('8'), L('6'), L('1'), L('7'), L('2'), L('7'),
- L('8'), M(824, 4), L('9'), L('0'), L('7'), L('5'), L('0'), L('9'),
- M(270, 4), L('7'), L('5'), L('4'), L('6'), L('3'), L('7'), L('4'),
- L('6'), L('4'), L('9'), L('3'), L('9'), L('3'), L('1'), L('9'),
- L('2'), L('5'), L('5'), L('0'), L('6'), L('0'), L('4'), L('0'),
- L('0'), L('9'), M(620, 4), L('1'), L('6'), L('7'), L('1'), L('1'),
- L('3'), L('9'), L('0'), L('0'), L('9'), L('8'), M(822, 4), L('4'),
- L('0'), L('1'), L('2'), L('8'), L('5'), L('8'), L('3'), L('6'),
- L('1'), L('6'), L('0'), L('3'), L('5'), L('6'), L('3'), L('7'),
- L('0'), L('7'), L('6'), L('6'), L('0'), L('1'), L('0'), L('4'),
- M(371, 4), L('8'), L('1'), L('9'), L('4'), L('2'), L('9'), M(1055, 5),
- M(240, 4), M(652, 4), L('7'), L('8'), L('3'), L('7'), L('4'), M(1193, 4),
- L('8'), L('2'), L('5'), L('5'), L('3'), L('7'), M(522, 5), L('2'),
- L('6'), L('8'), M(47, 4), L('4'), L('0'), L('4'), L('7'), M(466, 4),
- L('4'), M(1206, 4), M(910, 4), L('8'), L('4'), M(937, 4), L('6'), M(800, 6),
- L('3'), L('3'), L('1'), L('3'), L('6'), L('7'), L('7'), L('0'),
- L('2'), L('8'), L('9'), L('8'), L('9'), L('1'), L('5'), L('2'),
- M(99, 4), L('5'), L('2'), L('1'), L('6'), L('2'), L('0'), L('5'),
- L('6'), L('9'), L('6'), M(1042, 4), L('0'), L('5'), L('8'), M(1144, 4),
- L('5'), M(1177, 4), L('5'), L('1'), L('1'), M(522, 4), L('8'), L('2'),
- L('4'), L('3'), L('0'), L('0'), L('3'), L('5'), L('5'), L('8'),
- L('7'), L('6'), L('4'), L('0'), L('2'), L('4'), L('7'), L('4'),
- L('9'), L('6'), L('4'), L('7'), L('3'), L('2'), L('6'), L('3'),
- M(1087, 4), L('9'), L('9'), L('2'), M(1100, 4), L('4'), L('2'), L('6'),
- L('9'), M(710, 6), L('7'), M(471, 4), L('4'), M(1342, 4), M(1054, 4), L('9'),
- L('3'), L('4'), L('1'), L('7'), M(430, 4), L('1'), L('2'), M(43, 4),
- L('4'), M(415, 4), L('1'), L('5'), L('0'), L('3'), L('0'), L('2'),
- L('8'), L('6'), L('1'), L('8'), L('2'), L('9'), L('7'), L('4'),
- L('5'), L('5'), L('5'), L('7'), L('0'), L('6'), L('7'), L('4'),
- M(310, 4), L('5'), L('0'), L('5'), L('4'), L('9'), L('4'), L('5'),
- L('8'), M(454, 4), L('9'), M(82, 4), L('5'), L('6'), M(493, 4), L('7'),
- L('2'), L('1'), L('0'), L('7'), L('9'), M(346, 4), L('3'), L('0'),
- M(267, 4), L('3'), L('2'), L('1'), L('1'), L('6'), L('5'), L('3'),
- L('4'), L('4'), L('9'), L('8'), L('7'), L('2'), L('0'), L('2'),
- L('7'), M(284, 4), L('0'), L('2'), L('3'), L('6'), L('4'), M(559, 4),
- L('5'), L('4'), L('9'), L('9'), L('1'), L('1'), L('9'), L('8'),
- M(1049, 4), L('4'), M(284, 4), L('5'), L('3'), L('5'), L('6'), L('6'),
- L('3'), L('6'), L('9'), M(1105, 4), L('2'), L('6'), L('5'), M(741, 4),
- L('7'), L('8'), L('6'), L('2'), L('5'), L('5'), L('1'), M(987, 4),
- L('1'), L('7'), L('5'), L('7'), L('4'), L('6'), L('7'), L('2'),
- L('8'), L('9'), L('0'), L('9'), L('7'), L('7'), L('7'), L('7'),
- M(1108, 5), L('0'), L('0'), L('0'), M(1534, 4), L('7'), L('0'), M(1248, 4),
- L('6'), M(1002, 4), L('4'), L('9'), L('1'), M(1055, 4), M(664, 4), L('2'),
- L('1'), L('4'), L('7'), L('7'), L('2'), L('3'), L('5'), L('0'),
- L('1'), L('4'), L('1'), L('4'), M(1604, 4), L('3'), L('5'), L('6'),
- M(1200, 4), L('1'), L('6'), L('1'), L('3'), L('6'), L('1'), L('1'),
- L('5'), L('7'), L('3'), L('5'), L('2'), L('5'), M(1285, 4), L('3'),
- L('4'), M(92, 4), L('1'), L('8'), M(1148, 4), L('8'), L('4'), M(1512, 4),
- L('3'), L('3'), L('2'), L('3'), L('9'), L('0'), L('7'), L('3'),
- L('9'), L('4'), L('1'), L('4'), L('3'), L('3'), L('3'), L('4'),
- L('5'), L('4'), L('7'), L('7'), L('6'), L('2'), L('4'), M(579, 4),
- L('2'), L('5'), L('1'), L('8'), L('9'), L('8'), L('3'), L('5'),
- L('6'), L('9'), L('4'), L('8'), L('5'), L('5'), L('6'), L('2'),
- L('0'), L('9'), L('9'), L('2'), L('1'), L('9'), L('2'), L('2'),
- L('2'), L('1'), L('8'), L('4'), L('2'), L('7'), M(575, 4), L('2'),
- M(187, 4), L('6'), L('8'), L('8'), L('7'), L('6'), L('7'), L('1'),
- L('7'), L('9'), L('0'), M(86, 4), L('0'), M(263, 5), L('6'), L('6'),
- M(1000, 4), L('8'), L('8'), L('6'), L('2'), L('7'), L('2'), M(1757, 4),
- L('1'), L('7'), L('8'), L('6'), L('0'), L('8'), L('5'), L('7'),
- M(116, 4), L('3'), M(765, 5), L('7'), L('9'), L('7'), L('6'), L('6'),
- L('8'), L('1'), M(702, 4), L('0'), L('0'), L('9'), L('5'), L('3'),
- L('8'), L('8'), M(1593, 4), L('3'), M(1702, 4), L('0'), L('6'), L('8'),
- L('0'), L('0'), L('6'), L('4'), L('2'), L('2'), L('5'), L('1'),
- L('2'), L('5'), L('2'), M(1404, 4), L('7'), L('3'), L('9'), L('2'),
- M(664, 4), M(1141, 4), L('4'), M(1716, 5), L('8'), L('6'), L('2'), L('6'),
- L('9'), L('4'), L('5'), M(486, 4), L('4'), L('1'), L('9'), L('6'),
- L('5'), L('2'), L('8'), L('5'), L('0'), M(154, 4), M(925, 4), L('1'),
- L('8'), L('6'), L('3'), M(447, 4), L('4'), M(341, 5), L('2'), L('0'),
- L('3'), L('9'), M(1420, 4), L('4'), L('5'), M(701, 4), L('2'), L('3'),
- L('7'), M(1069, 4), L('6'), M(1297, 4), L('5'), L('6'), M(1593, 4), L('7'),
- L('1'), L('9'), L('1'), L('7'), L('2'), L('8'), M(370, 4), L('7'),
- L('6'), L('4'), L('6'), L('5'), L('7'), L('5'), L('7'), L('3'),
- L('9'), M(258, 4), L('3'), L('8'), L('9'), M(1865, 4), L('8'), L('3'),
- L('2'), L('6'), L('4'), L('5'), L('9'), L('9'), L('5'), L('8'),
- M(1704, 4), L('0'), L('4'), L('7'), L('8'), M(479, 4), M(809, 4), L('9'),
- M(46, 4), L('6'), L('4'), L('0'), L('7'), L('8'), L('9'), L('5'),
- L('1'), M(143, 4), L('6'), L('8'), L('3'), M(304, 4), L('2'), L('5'),
- L('9'), L('5'), L('7'), L('0'), M(1129, 4), L('8'), L('2'), L('2'),
- M(713, 4), L('2'), M(1564, 4), L('4'), L('0'), L('7'), L('7'), L('2'),
- L('6'), L('7'), L('1'), L('9'), L('4'), L('7'), L('8'), M(794, 4),
- L('8'), L('2'), L('6'), L('0'), L('1'), L('4'), L('7'), L('6'),
- L('9'), L('9'), L('0'), L('9'), M(1257, 4), L('0'), L('1'), L('3'),
- L('6'), L('3'), L('9'), L('4'), L('4'), L('3'), M(640, 4), L('3'),
- L('0'), M(262, 4), L('2'), L('0'), L('3'), L('4'), L('9'), L('6'),
- L('2'), L('5'), L('2'), L('4'), L('5'), L('1'), L('7'), M(950, 4),
- L('9'), L('6'), L('5'), L('1'), L('4'), L('3'), L('1'), L('4'),
- L('2'), L('9'), L('8'), L('0'), L('9'), L('1'), L('9'), L('0'),
- L('6'), L('5'), L('9'), L('2'), M(643, 4), L('7'), L('2'), L('2'),
- L('1'), L('6'), L('9'), L('6'), L('4'), L('6'), M(1050, 4), M(123, 4),
- L('5'), M(1295, 4), L('4'), M(1382, 5), L('8'), M(1370, 4), L('9'), L('7'),
- M(1404, 4), L('5'), L('4'), M(1182, 4), M(575, 4), L('7'), M(1627, 4), L('8'),
- L('4'), L('6'), L('8'), L('1'), L('3'), M(141, 4), L('6'), L('8'),
- L('3'), L('8'), L('6'), L('8'), L('9'), L('4'), L('2'), L('7'),
- L('7'), L('4'), L('1'), L('5'), L('5'), L('9'), L('9'), L('1'),
- L('8'), L('5'), M(91, 4), L('2'), L('4'), L('5'), L('9'), L('5'),
- L('3'), L('9'), L('5'), L('9'), L('4'), L('3'), L('1'), M(1464, 4),
- L('7'), M(19, 4), L('6'), L('8'), L('0'), L('8'), L('4'), L('5'),
- M(744, 4), L('7'), L('3'), M(2079, 4), L('9'), L('5'), L('8'), L('4'),
- L('8'), L('6'), L('5'), L('3'), L('8'), M(1769, 4), L('6'), L('2'),
- M(243, 4), L('6'), L('0'), L('9'), M(1207, 4), L('6'), L('0'), L('8'),
- L('0'), L('5'), L('1'), L('2'), L('4'), L('3'), L('8'), L('8'),
- L('4'), M(315, 4), M(12, 4), L('4'), L('1'), L('3'), M(784, 4), L('7'),
- L('6'), L('2'), L('7'), L('8'), M(834, 4), L('7'), L('1'), L('5'),
- M(1436, 4), L('3'), L('5'), L('9'), L('9'), L('7'), L('7'), L('0'),
- L('0'), L('1'), L('2'), L('9'), M(1139, 4), L('8'), L('9'), L('4'),
- L('4'), L('1'), M(632, 4), L('6'), L('8'), L('5'), L('5'), M(96, 4),
- L('4'), L('0'), L('6'), L('3'), M(2279, 4), L('2'), L('0'), L('7'),
- L('2'), L('2'), M(345, 4), M(516, 5), L('4'), L('8'), L('1'), L('5'),
- L('8'), M(518, 4), M(511, 4), M(635, 4), M(665, 4), L('3'), L('9'), L('4'),
- L('5'), L('2'), L('2'), L('6'), L('7'), M(1175, 6), L('8'), M(1419, 4),
- L('2'), L('1'), M(747, 4), L('2'), M(904, 4), L('5'), L('4'), L('6'),
- L('6'), L('6'), M(1308, 4), L('2'), L('3'), L('9'), L('8'), L('6'),
- L('4'), L('5'), L('6'), M(1221, 4), L('1'), L('6'), L('3'), L('5'),
- M(596, 5), M(2066, 4), L('7'), M(2222, 4), L('9'), L('8'), M(1119, 4), L('9'),
- L('3'), L('6'), L('3'), L('4'), M(1884, 4), L('7'), L('4'), L('3'),
- L('2'), L('4'), M(1148, 4), L('1'), L('5'), L('0'), L('7'), L('6'),
- M(1212, 4), L('7'), L('9'), L('4'), L('5'), L('1'), L('0'), L('9'),
- M(63, 4), L('0'), L('9'), L('4'), L('0'), M(1703, 4), L('8'), L('8'),
- L('7'), L('9'), L('7'), L('1'), L('0'), L('8'), L('9'), L('3'),
- M(2289, 4), L('6'), L('9'), L('1'), L('3'), L('6'), L('8'), L('6'),
- L('7'), L('2'), M(604, 4), M(511, 4), L('5'), M(1344, 4), M(1129, 4), M(2050, 4),
- L('1'), L('7'), L('9'), L('2'), L('8'), L('6'), L('8'), M(2253, 4),
- L('8'), L('7'), L('4'), L('7'), M(1951, 5), L('8'), L('2'), L('4'),
- M(2427, 4), L('8'), M(604, 4), L('7'), L('1'), L('4'), L('9'), L('0'),
- L('9'), L('6'), L('7'), L('5'), L('9'), L('8'), M(1776, 4), L('3'),
- L('6'), L('5'), M(309, 4), L('8'), L('1'), M(93, 4), M(1862, 4), M(2359, 4),
- L('6'), L('8'), L('2'), L('9'), M(1407, 4), L('8'), L('7'), L('2'),
- L('2'), L('6'), L('5'), L('8'), L('8'), L('0'), M(1554, 4), L('5'),
- M(586, 4), L('4'), L('2'), L('7'), L('0'), L('4'), L('7'), L('7'),
- L('5'), L('5'), M(2079, 4), L('3'), L('7'), L('9'), L('6'), L('4'),
- L('1'), L('4'), L('5'), L('1'), L('5'), L('2'), M(1534, 4), L('2'),
- L('3'), L('4'), L('3'), L('6'), L('4'), L('5'), L('4'), M(1503, 4),
- L('4'), L('4'), L('4'), L('7'), L('9'), L('5'), M(61, 4), M(1316, 4),
- M(2279, 5), L('4'), L('1'), M(1323, 4), L('3'), M(773, 4), L('5'), L('2'),
- L('3'), L('1'), M(2114, 5), L('1'), L('6'), L('6'), L('1'), M(2227, 4),
- L('5'), L('9'), L('6'), L('9'), L('5'), L('3'), L('6'), L('2'),
- L('3'), L('1'), L('4'), M(1536, 4), L('2'), L('4'), L('8'), L('4'),
- L('9'), L('3'), L('7'), L('1'), L('8'), L('7'), L('1'), L('1'),
- L('0'), L('1'), L('4'), L('5'), L('7'), L('6'), L('5'), L('4'),
- M(1890, 4), L('0'), L('2'), L('7'), L('9'), L('9'), L('3'), L('4'),
- L('4'), L('0'), L('3'), L('7'), L('4'), L('2'), L('0'), L('0'),
- L('7'), M(2368, 4), L('7'), L('8'), L('5'), L('3'), L('9'), L('0'),
- L('6'), L('2'), L('1'), L('9'), M(666, 5), M(838, 4), L('8'), L('4'),
- L('7'), M(979, 5), L('8'), L('3'), L('3'), L('2'), L('1'), L('4'),
- L('4'), L('5'), L('7'), L('1'), M(645, 4), M(1911, 4), L('4'), L('3'),
- L('5'), L('0'), M(2345, 4), M(1129, 4), L('5'), L('3'), L('1'), L('9'),
- L('1'), L('0'), L('4'), L('8'), L('4'), L('8'), L('1'), L('0'),
- L('0'), L('5'), L('3'), L('7'), L('0'), L('6'), M(2237, 4), M(1438, 5),
- M(1922, 5), L('1'), M(1370, 4), L('7'), M(796, 4), L('5'), M(2029, 4), M(1037, 4),
- L('6'), L('3'), M(2013, 5), L('4'), M(2418, 4), M(847, 5), M(1014, 5), L('8'),
- M(1326, 5), M(2184, 5), L('9'), M(392, 4), L('9'), L('1'), M(2255, 4), L('8'),
- L('1'), L('4'), L('6'), L('7'), L('5'), L('1'), M(1580, 4), L('1'),
- L('2'), L('3'), L('9'), M(426, 6), L('9'), L('0'), L('7'), L('1'),
- L('8'), L('6'), L('4'), L('9'), L('4'), L('2'), L('3'), L('1'),
- L('9'), L('6'), L('1'), L('5'), L('6'), M(493, 4), M(1725, 4), L('9'),
- L('5'), M(2343, 4), M(1130, 4), M(284, 4), L('6'), L('0'), L('3'), L('8'),
- M(2598, 4), M(368, 4), M(901, 4), L('6'), L('2'), M(1115, 4), L('5'), M(2125, 4),
- L('6'), L('3'), L('8'), L('9'), L('3'), L('7'), L('7'), L('8'),
- L('7'), M(2246, 4), M(249, 4), L('9'), L('7'), L('9'), L('2'), L('0'),
- L('7'), L('7'), L('3'), M(1496, 4), L('2'), L('1'), L('8'), L('2'),
- L('5'), L('6'), M(2016, 4), L('6'), L('6'), M(1751, 4), L('4'), L('2'),
- M(1663, 5), L('6'), M(1767, 4), L('4'), L('4'), M(37, 4), L('5'), L('4'),
- L('9'), L('2'), L('0'), L('2'), L('6'), L('0'), L('5'), M(2740, 4),
- M(997, 5), L('2'), L('0'), L('1'), L('4'), L('9'), M(1235, 4), L('8'),
- L('5'), L('0'), L('7'), L('3'), M(1434, 4), L('6'), L('6'), L('6'),
- L('0'), M(405, 4), L('2'), L('4'), L('3'), L('4'), L('0'), M(136, 4),
- L('0'), M(1900, 4), L('8'), L('6'), L('3'), M(2391, 4), M(2021, 4), M(1068, 4),
- M(373, 4), L('5'), L('7'), L('9'), L('6'), L('2'), L('6'), L('8'),
- L('5'), L('6'), M(321, 4), L('5'), L('0'), L('8'), M(1316, 4), L('5'),
- L('8'), L('7'), L('9'), L('6'), L('9'), L('9'), M(1810, 4), L('5'),
- L('7'), L('4'), M(2585, 4), L('8'), L('4'), L('0'), M(2228, 4), L('1'),
- L('4'), L('5'), L('9'), L('1'), M(1933, 4), L('7'), L('0'), M(565, 4),
- L('0'), L('1'), M(3048, 4), L('1'), L('2'), M(3189, 4), L('0'), M(964, 4),
- L('3'), L('9'), M(2859, 4), M(275, 4), L('7'), L('1'), L('5'), M(945, 4),
- L('4'), L('2'), L('0'), M(3059, 5), L('9'), M(3011, 4), L('0'), L('7'),
- M(834, 4), M(1942, 4), M(2736, 4), M(3171, 4), L('2'), L('1'), M(2401, 4), L('2'),
- L('5'), L('1'), M(1404, 4), M(2373, 4), L('9'), L('2'), M(435, 4), L('8'),
- L('2'), L('6'), M(2919, 4), L('2'), M(633, 4), L('3'), L('2'), L('1'),
- L('5'), L('7'), L('9'), L('1'), L('9'), L('8'), L('4'), L('1'),
- L('4'), M(2172, 5), L('9'), L('1'), L('6'), L('4'), M(1769, 5), L('9'),
- M(2905, 5), M(2268, 4), L('7'), L('2'), L('2'), M(802, 4), L('5'), M(2213, 4),
- M(322, 4), L('9'), L('1'), L('0'), M(189, 4), M(3164, 4), L('5'), L('2'),
- L('8'), L('0'), L('1'), L('7'), M(562, 4), L('7'), L('1'), L('2'),
- M(2325, 4), L('8'), L('3'), L('2'), M(884, 4), L('1'), M(1418, 4), L('0'),
- L('9'), L('3'), L('5'), L('3'), L('9'), L('6'), L('5'), L('7'),
- M(1612, 4), L('1'), L('0'), L('8'), L('3'), M(106, 4), L('5'), L('1'),
- M(1915, 4), M(3419, 4), L('1'), L('4'), L('4'), L('4'), L('2'), L('1'),
- L('0'), L('0'), M(515, 4), L('0'), L('3'), M(413, 4), L('1'), L('1'),
- L('0'), L('3'), M(3202, 4), M(10, 4), M(39, 4), M(1539, 6), L('5'), L('1'),
- L('6'), M(1498, 4), M(2180, 5), M(2347, 4), L('5'), M(3139, 5), L('8'), L('5'),
- L('1'), L('7'), L('1'), L('4'), L('3'), L('7'), M(1542, 4), M(110, 4),
- L('1'), L('5'), L('5'), L('6'), L('5'), L('0'), L('8'), L('8'),
- M(954, 4), L('9'), L('8'), L('9'), L('8'), L('5'), L('9'), L('9'),
- L('8'), L('2'), L('3'), L('8'), M(464, 4), M(2491, 4), L('3'), M(365, 4),
- M(1087, 4), M(2500, 4), L('8'), M(3590, 5), L('3'), L('2'), M(264, 4), L('5'),
- M(774, 4), L('3'), M(459, 4), L('9'), M(1052, 4), L('9'), L('8'), M(2174, 4),
- L('4'), M(3257, 4), L('7'), M(1612, 4), L('0'), L('7'), M(230, 4), L('4'),
- L('8'), L('1'), L('4'), L('1'), M(1338, 4), L('8'), L('5'), L('9'),
- L('4'), L('6'), L('1'), M(3018, 4), L('8'), L('0'),
- },
- },
- TestCase{
- .input = "huffman-rand-1k.input",
- .want = "huffman-rand-1k.{s}.expect",
- .want_no_input = "huffman-rand-1k.{s}.expect-noinput",
- .tokens = &[_]Token{
- L(0xf8), L(0x8b), L(0x96), L(0x76), L(0x48), L(0xd), L(0x85), L(0x94), L(0x25), L(0x80), L(0xaf), L(0xc2), L(0xfe), L(0x8d),
- L(0xe8), L(0x20), L(0xeb), L(0x17), L(0x86), L(0xc9), L(0xb7), L(0xc5), L(0xde), L(0x6), L(0xea), L(0x7d), L(0x18), L(0x8b),
- L(0xe7), L(0x3e), L(0x7), L(0xda), L(0xdf), L(0xff), L(0x6c), L(0x73), L(0xde), L(0xcc), L(0xe7), L(0x6d), L(0x8d), L(0x4),
- L(0x19), L(0x49), L(0x7f), L(0x47), L(0x1f), L(0x48), L(0x15), L(0xb0), L(0xe8), L(0x9e), L(0xf2), L(0x31), L(0x59), L(0xde),
- L(0x34), L(0xb4), L(0x5b), L(0xe5), L(0xe0), L(0x9), L(0x11), L(0x30), L(0xc2), L(0x88), L(0x5b), L(0x7c), L(0x5d), L(0x14),
- L(0x13), L(0x6f), L(0x23), L(0xa9), L(0xd), L(0xbc), L(0x2d), L(0x23), L(0xbe), L(0xd9), L(0xed), L(0x75), L(0x4), L(0x6c),
- L(0x99), L(0xdf), L(0xfd), L(0x70), L(0x66), L(0xe6), L(0xee), L(0xd9), L(0xb1), L(0x9e), L(0x6e), L(0x83), L(0x59), L(0xd5),
- L(0xd4), L(0x80), L(0x59), L(0x98), L(0x77), L(0x89), L(0x43), L(0x38), L(0xc9), L(0xaf), L(0x30), L(0x32), L(0x9a), L(0x20),
- L(0x1b), L(0x46), L(0x3d), L(0x67), L(0x6e), L(0xd7), L(0x72), L(0x9e), L(0x4e), L(0x21), L(0x4f), L(0xc6), L(0xe0), L(0xd4),
- L(0x7b), L(0x4), L(0x8d), L(0xa5), L(0x3), L(0xf6), L(0x5), L(0x9b), L(0x6b), L(0xdc), L(0x2a), L(0x93), L(0x77), L(0x28),
- L(0xfd), L(0xb4), L(0x62), L(0xda), L(0x20), L(0xe7), L(0x1f), L(0xab), L(0x6b), L(0x51), L(0x43), L(0x39), L(0x2f), L(0xa0),
- L(0x92), L(0x1), L(0x6c), L(0x75), L(0x3e), L(0xf4), L(0x35), L(0xfd), L(0x43), L(0x2e), L(0xf7), L(0xa4), L(0x75), L(0xda),
- L(0xea), L(0x9b), L(0xa), L(0x64), L(0xb), L(0xe0), L(0x23), L(0x29), L(0xbd), L(0xf7), L(0xe7), L(0x83), L(0x3c), L(0xfb),
- L(0xdf), L(0xb3), L(0xae), L(0x4f), L(0xa4), L(0x47), L(0x55), L(0x99), L(0xde), L(0x2f), L(0x96), L(0x6e), L(0x1c), L(0x43),
- L(0x4c), L(0x87), L(0xe2), L(0x7c), L(0xd9), L(0x5f), L(0x4c), L(0x7c), L(0xe8), L(0x90), L(0x3), L(0xdb), L(0x30), L(0x95),
- L(0xd6), L(0x22), L(0xc), L(0x47), L(0xb8), L(0x4d), L(0x6b), L(0xbd), L(0x24), L(0x11), L(0xab), L(0x2c), L(0xd7), L(0xbe),
- L(0x6e), L(0x7a), L(0xd6), L(0x8), L(0xa3), L(0x98), L(0xd8), L(0xdd), L(0x15), L(0x6a), L(0xfa), L(0x93), L(0x30), L(0x1),
- L(0x25), L(0x1d), L(0xa2), L(0x74), L(0x86), L(0x4b), L(0x6a), L(0x95), L(0xe8), L(0xe1), L(0x4e), L(0xe), L(0x76), L(0xb9),
- L(0x49), L(0xa9), L(0x5f), L(0xa0), L(0xa6), L(0x63), L(0x3c), L(0x7e), L(0x7e), L(0x20), L(0x13), L(0x4f), L(0xbb), L(0x66),
- L(0x92), L(0xb8), L(0x2e), L(0xa4), L(0xfa), L(0x48), L(0xcb), L(0xae), L(0xb9), L(0x3c), L(0xaf), L(0xd3), L(0x1f), L(0xe1),
- L(0xd5), L(0x8d), L(0x42), L(0x6d), L(0xf0), L(0xfc), L(0x8c), L(0xc), L(0x0), L(0xde), L(0x40), L(0xab), L(0x8b), L(0x47),
- L(0x97), L(0x4e), L(0xa8), L(0xcf), L(0x8e), L(0xdb), L(0xa6), L(0x8b), L(0x20), L(0x9), L(0x84), L(0x7a), L(0x66), L(0xe5),
- L(0x98), L(0x29), L(0x2), L(0x95), L(0xe6), L(0x38), L(0x32), L(0x60), L(0x3), L(0xe3), L(0x9a), L(0x1e), L(0x54), L(0xe8),
- L(0x63), L(0x80), L(0x48), L(0x9c), L(0xe7), L(0x63), L(0x33), L(0x6e), L(0xa0), L(0x65), L(0x83), L(0xfa), L(0xc6), L(0xba),
- L(0x7a), L(0x43), L(0x71), L(0x5), L(0xf5), L(0x68), L(0x69), L(0x85), L(0x9c), L(0xba), L(0x45), L(0xcd), L(0x6b), L(0xb),
- L(0x19), L(0xd1), L(0xbb), L(0x7f), L(0x70), L(0x85), L(0x92), L(0xd1), L(0xb4), L(0x64), L(0x82), L(0xb1), L(0xe4), L(0x62),
- L(0xc5), L(0x3c), L(0x46), L(0x1f), L(0x92), L(0x31), L(0x1c), L(0x4e), L(0x41), L(0x77), L(0xf7), L(0xe7), L(0x87), L(0xa2),
- L(0xf), L(0x6e), L(0xe8), L(0x92), L(0x3), L(0x6b), L(0xa), L(0xe7), L(0xa9), L(0x3b), L(0x11), L(0xda), L(0x66), L(0x8a),
- L(0x29), L(0xda), L(0x79), L(0xe1), L(0x64), L(0x8d), L(0xe3), L(0x54), L(0xd4), L(0xf5), L(0xef), L(0x64), L(0x87), L(0x3b),
- L(0xf4), L(0xc2), L(0xf4), L(0x71), L(0x13), L(0xa9), L(0xe9), L(0xe0), L(0xa2), L(0x6), L(0x14), L(0xab), L(0x5d), L(0xa7),
- L(0x96), L(0x0), L(0xd6), L(0xc3), L(0xcc), L(0x57), L(0xed), L(0x39), L(0x6a), L(0x25), L(0xcd), L(0x76), L(0xea), L(0xba),
- L(0x3a), L(0xf2), L(0xa1), L(0x95), L(0x5d), L(0xe5), L(0x71), L(0xcf), L(0x9c), L(0x62), L(0x9e), L(0x6a), L(0xfa), L(0xd5),
- L(0x31), L(0xd1), L(0xa8), L(0x66), L(0x30), L(0x33), L(0xaa), L(0x51), L(0x17), L(0x13), L(0x82), L(0x99), L(0xc8), L(0x14),
- L(0x60), L(0x9f), L(0x4d), L(0x32), L(0x6d), L(0xda), L(0x19), L(0x26), L(0x21), L(0xdc), L(0x7e), L(0x2e), L(0x25), L(0x67),
- L(0x72), L(0xca), L(0xf), L(0x92), L(0xcd), L(0xf6), L(0xd6), L(0xcb), L(0x97), L(0x8a), L(0x33), L(0x58), L(0x73), L(0x70),
- L(0x91), L(0x1d), L(0xbf), L(0x28), L(0x23), L(0xa3), L(0xc), L(0xf1), L(0x83), L(0xc3), L(0xc8), L(0x56), L(0x77), L(0x68),
- L(0xe3), L(0x82), L(0xba), L(0xb9), L(0x57), L(0x56), L(0x57), L(0x9c), L(0xc3), L(0xd6), L(0x14), L(0x5), L(0x3c), L(0xb1),
- L(0xaf), L(0x93), L(0xc8), L(0x8a), L(0x57), L(0x7f), L(0x53), L(0xfa), L(0x2f), L(0xaa), L(0x6e), L(0x66), L(0x83), L(0xfa),
- L(0x33), L(0xd1), L(0x21), L(0xab), L(0x1b), L(0x71), L(0xb4), L(0x7c), L(0xda), L(0xfd), L(0xfb), L(0x7f), L(0x20), L(0xab),
- L(0x5e), L(0xd5), L(0xca), L(0xfd), L(0xdd), L(0xe0), L(0xee), L(0xda), L(0xba), L(0xa8), L(0x27), L(0x99), L(0x97), L(0x69),
- L(0xc1), L(0x3c), L(0x82), L(0x8c), L(0xa), L(0x5c), L(0x2d), L(0x5b), L(0x88), L(0x3e), L(0x34), L(0x35), L(0x86), L(0x37),
- L(0x46), L(0x79), L(0xe1), L(0xaa), L(0x19), L(0xfb), L(0xaa), L(0xde), L(0x15), L(0x9), L(0xd), L(0x1a), L(0x57), L(0xff),
- L(0xb5), L(0xf), L(0xf3), L(0x2b), L(0x5a), L(0x6a), L(0x4d), L(0x19), L(0x77), L(0x71), L(0x45), L(0xdf), L(0x4f), L(0xb3),
- L(0xec), L(0xf1), L(0xeb), L(0x18), L(0x53), L(0x3e), L(0x3b), L(0x47), L(0x8), L(0x9a), L(0x73), L(0xa0), L(0x5c), L(0x8c),
- L(0x5f), L(0xeb), L(0xf), L(0x3a), L(0xc2), L(0x43), L(0x67), L(0xb4), L(0x66), L(0x67), L(0x80), L(0x58), L(0xe), L(0xc1),
- L(0xec), L(0x40), L(0xd4), L(0x22), L(0x94), L(0xca), L(0xf9), L(0xe8), L(0x92), L(0xe4), L(0x69), L(0x38), L(0xbe), L(0x67),
- L(0x64), L(0xca), L(0x50), L(0xc7), L(0x6), L(0x67), L(0x42), L(0x6e), L(0xa3), L(0xf0), L(0xb7), L(0x6c), L(0xf2), L(0xe8),
- L(0x5f), L(0xb1), L(0xaf), L(0xe7), L(0xdb), L(0xbb), L(0x77), L(0xb5), L(0xf8), L(0xcb), L(0x8), L(0xc4), L(0x75), L(0x7e),
- L(0xc0), L(0xf9), L(0x1c), L(0x7f), L(0x3c), L(0x89), L(0x2f), L(0xd2), L(0x58), L(0x3a), L(0xe2), L(0xf8), L(0x91), L(0xb6),
- L(0x7b), L(0x24), L(0x27), L(0xe9), L(0xae), L(0x84), L(0x8b), L(0xde), L(0x74), L(0xac), L(0xfd), L(0xd9), L(0xb7), L(0x69),
- L(0x2a), L(0xec), L(0x32), L(0x6f), L(0xf0), L(0x92), L(0x84), L(0xf1), L(0x40), L(0xc), L(0x8a), L(0xbc), L(0x39), L(0x6e),
- L(0x2e), L(0x73), L(0xd4), L(0x6e), L(0x8a), L(0x74), L(0x2a), L(0xdc), L(0x60), L(0x1f), L(0xa3), L(0x7), L(0xde), L(0x75),
- L(0x8b), L(0x74), L(0xc8), L(0xfe), L(0x63), L(0x75), L(0xf6), L(0x3d), L(0x63), L(0xac), L(0x33), L(0x89), L(0xc3), L(0xf0),
- L(0xf8), L(0x2d), L(0x6b), L(0xb4), L(0x9e), L(0x74), L(0x8b), L(0x5c), L(0x33), L(0xb4), L(0xca), L(0xa8), L(0xe4), L(0x99),
- L(0xb6), L(0x90), L(0xa1), L(0xef), L(0xf), L(0xd3), L(0x61), L(0xb2), L(0xc6), L(0x1a), L(0x94), L(0x7c), L(0x44), L(0x55),
- L(0xf4), L(0x45), L(0xff), L(0x9e), L(0xa5), L(0x5a), L(0xc6), L(0xa0), L(0xe8), L(0x2a), L(0xc1), L(0x8d), L(0x6f), L(0x34),
- L(0x11), L(0xb9), L(0xbe), L(0x4e), L(0xd9), L(0x87), L(0x97), L(0x73), L(0xcf), L(0x3d), L(0x23), L(0xae), L(0xd5), L(0x1a),
- L(0x5e), L(0xae), L(0x5d), L(0x6a), L(0x3), L(0xf9), L(0x22), L(0xd), L(0x10), L(0xd9), L(0x47), L(0x69), L(0x15), L(0x3f),
- L(0xee), L(0x52), L(0xa3), L(0x8), L(0xd2), L(0x3c), L(0x51), L(0xf4), L(0xf8), L(0x9d), L(0xe4), L(0x98), L(0x89), L(0xc8),
- L(0x67), L(0x39), L(0xd5), L(0x5e), L(0x35), L(0x78), L(0x27), L(0xe8), L(0x3c), L(0x80), L(0xae), L(0x79), L(0x71), L(0xd2),
- L(0x93), L(0xf4), L(0xaa), L(0x51), L(0x12), L(0x1c), L(0x4b), L(0x1b), L(0xe5), L(0x6e), L(0x15), L(0x6f), L(0xe4), L(0xbb),
- L(0x51), L(0x9b), L(0x45), L(0x9f), L(0xf9), L(0xc4), L(0x8c), L(0x2a), L(0xfb), L(0x1a), L(0xdf), L(0x55), L(0xd3), L(0x48),
- L(0x93), L(0x27), L(0x1), L(0x26), L(0xc2), L(0x6b), L(0x55), L(0x6d), L(0xa2), L(0xfb), L(0x84), L(0x8b), L(0xc9), L(0x9e),
- L(0x28), L(0xc2), L(0xef), L(0x1a), L(0x24), L(0xec), L(0x9b), L(0xae), L(0xbd), L(0x60), L(0xe9), L(0x15), L(0x35), L(0xee),
- L(0x42), L(0xa4), L(0x33), L(0x5b), L(0xfa), L(0xf), L(0xb6), L(0xf7), L(0x1), L(0xa6), L(0x2), L(0x4c), L(0xca), L(0x90),
- L(0x58), L(0x3a), L(0x96), L(0x41), L(0xe7), L(0xcb), L(0x9), L(0x8c), L(0xdb), L(0x85), L(0x4d), L(0xa8), L(0x89), L(0xf3),
- L(0xb5), L(0x8e), L(0xfd), L(0x75), L(0x5b), L(0x4f), L(0xed), L(0xde), L(0x3f), L(0xeb), L(0x38), L(0xa3), L(0xbe), L(0xb0),
- L(0x73), L(0xfc), L(0xb8), L(0x54), L(0xf7), L(0x4c), L(0x30), L(0x67), L(0x2e), L(0x38), L(0xa2), L(0x54), L(0x18), L(0xba),
- L(0x8), L(0xbf), L(0xf2), L(0x39), L(0xd5), L(0xfe), L(0xa5), L(0x41), L(0xc6), L(0x66), L(0x66), L(0xba), L(0x81), L(0xef),
- L(0x67), L(0xe4), L(0xe6), L(0x3c), L(0xc), L(0xca), L(0xa4), L(0xa), L(0x79), L(0xb3), L(0x57), L(0x8b), L(0x8a), L(0x75),
- L(0x98), L(0x18), L(0x42), L(0x2f), L(0x29), L(0xa3), L(0x82), L(0xef), L(0x9f), L(0x86), L(0x6), L(0x23), L(0xe1), L(0x75),
- L(0xfa), L(0x8), L(0xb1), L(0xde), L(0x17), L(0x4a),
- },
- },
- TestCase{
- .input = "huffman-rand-limit.input",
- .want = "huffman-rand-limit.{s}.expect",
- .want_no_input = "huffman-rand-limit.{s}.expect-noinput",
- .tokens = &[_]Token{
- L(0x61), M(1, 74), L(0xa), L(0xf8), L(0x8b), L(0x96), L(0x76), L(0x48), L(0xa), L(0x85), L(0x94), L(0x25), L(0x80),
- L(0xaf), L(0xc2), L(0xfe), L(0x8d), L(0xe8), L(0x20), L(0xeb), L(0x17), L(0x86), L(0xc9), L(0xb7), L(0xc5), L(0xde),
- L(0x6), L(0xea), L(0x7d), L(0x18), L(0x8b), L(0xe7), L(0x3e), L(0x7), L(0xda), L(0xdf), L(0xff), L(0x6c), L(0x73),
- L(0xde), L(0xcc), L(0xe7), L(0x6d), L(0x8d), L(0x4), L(0x19), L(0x49), L(0x7f), L(0x47), L(0x1f), L(0x48), L(0x15),
- L(0xb0), L(0xe8), L(0x9e), L(0xf2), L(0x31), L(0x59), L(0xde), L(0x34), L(0xb4), L(0x5b), L(0xe5), L(0xe0), L(0x9),
- L(0x11), L(0x30), L(0xc2), L(0x88), L(0x5b), L(0x7c), L(0x5d), L(0x14), L(0x13), L(0x6f), L(0x23), L(0xa9), L(0xa),
- L(0xbc), L(0x2d), L(0x23), L(0xbe), L(0xd9), L(0xed), L(0x75), L(0x4), L(0x6c), L(0x99), L(0xdf), L(0xfd), L(0x70),
- L(0x66), L(0xe6), L(0xee), L(0xd9), L(0xb1), L(0x9e), L(0x6e), L(0x83), L(0x59), L(0xd5), L(0xd4), L(0x80), L(0x59),
- L(0x98), L(0x77), L(0x89), L(0x43), L(0x38), L(0xc9), L(0xaf), L(0x30), L(0x32), L(0x9a), L(0x20), L(0x1b), L(0x46),
- L(0x3d), L(0x67), L(0x6e), L(0xd7), L(0x72), L(0x9e), L(0x4e), L(0x21), L(0x4f), L(0xc6), L(0xe0), L(0xd4), L(0x7b),
- L(0x4), L(0x8d), L(0xa5), L(0x3), L(0xf6), L(0x5), L(0x9b), L(0x6b), L(0xdc), L(0x2a), L(0x93), L(0x77), L(0x28),
- L(0xfd), L(0xb4), L(0x62), L(0xda), L(0x20), L(0xe7), L(0x1f), L(0xab), L(0x6b), L(0x51), L(0x43), L(0x39), L(0x2f),
- L(0xa0), L(0x92), L(0x1), L(0x6c), L(0x75), L(0x3e), L(0xf4), L(0x35), L(0xfd), L(0x43), L(0x2e), L(0xf7), L(0xa4),
- L(0x75), L(0xda), L(0xea), L(0x9b), L(0xa),
- },
- },
- TestCase{
- .input = "huffman-shifts.input",
- .want = "huffman-shifts.{s}.expect",
- .want_no_input = "huffman-shifts.{s}.expect-noinput",
- .tokens = &[_]Token{
- L('1'), L('0'), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258),
- M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258),
- M(2, 258), M(2, 76), L(0xd), L(0xa), L('2'), L('3'), M(2, 258), M(2, 258),
- M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 256),
- },
- },
- TestCase{
- .input = "huffman-text-shift.input",
- .want = "huffman-text-shift.{s}.expect",
- .want_no_input = "huffman-text-shift.{s}.expect-noinput",
- .tokens = &[_]Token{
- L('/'), L('/'), L('C'), L('o'), L('p'), L('y'), L('r'), L('i'),
- L('g'), L('h'), L('t'), L('2'), L('0'), L('0'), L('9'), L('T'),
- L('h'), L('G'), L('o'), L('A'), L('u'), L('t'), L('h'), L('o'),
- L('r'), L('.'), L('A'), L('l'), L('l'), M(23, 5), L('r'), L('r'),
- L('v'), L('d'), L('.'), L(0xd), L(0xa), L('/'), L('/'), L('U'),
- L('o'), L('f'), L('t'), L('h'), L('i'), L('o'), L('u'), L('r'),
- L('c'), L('c'), L('o'), L('d'), L('i'), L('g'), L('o'), L('v'),
- L('r'), L('n'), L('d'), L('b'), L('y'), L('B'), L('S'), L('D'),
- L('-'), L('t'), L('y'), L('l'), M(33, 4), L('l'), L('i'), L('c'),
- L('n'), L('t'), L('h'), L('t'), L('c'), L('n'), L('b'), L('f'),
- L('o'), L('u'), L('n'), L('d'), L('i'), L('n'), L('t'), L('h'),
- L('L'), L('I'), L('C'), L('E'), L('N'), L('S'), L('E'), L('f'),
- L('i'), L('l'), L('.'), L(0xd), L(0xa), L(0xd), L(0xa), L('p'),
- L('c'), L('k'), L('g'), L('m'), L('i'), L('n'), M(11, 4), L('i'),
- L('m'), L('p'), L('o'), L('r'), L('t'), L('"'), L('o'), L('"'),
- M(13, 4), L('f'), L('u'), L('n'), L('c'), L('m'), L('i'), L('n'),
- L('('), L(')'), L('{'), L(0xd), L(0xa), L(0x9), L('v'), L('r'),
- L('b'), L('='), L('m'), L('k'), L('('), L('['), L(']'), L('b'),
- L('y'), L('t'), L(','), L('6'), L('5'), L('5'), L('3'), L('5'),
- L(')'), L(0xd), L(0xa), L(0x9), L('f'), L(','), L('_'), L(':'),
- L('='), L('o'), L('.'), L('C'), L('r'), L('t'), L('('), L('"'),
- L('h'), L('u'), L('f'), L('f'), L('m'), L('n'), L('-'), L('n'),
- L('u'), L('l'), L('l'), L('-'), L('m'), L('x'), L('.'), L('i'),
- L('n'), L('"'), M(34, 5), L('.'), L('W'), L('r'), L('i'), L('t'),
- L('('), L('b'), L(')'), L(0xd), L(0xa), L('}'), L(0xd), L(0xa),
- L('A'), L('B'), L('C'), L('D'), L('E'), L('F'), L('G'), L('H'),
- L('I'), L('J'), L('K'), L('L'), L('M'), L('N'), L('O'), L('P'),
- L('Q'), L('R'), L('S'), L('T'), L('U'), L('V'), L('X'), L('x'),
- L('y'), L('z'), L('!'), L('"'), L('#'), L(0xc2), L(0xa4), L('%'),
- L('&'), L('/'), L('?'), L('"'),
- },
- },
- TestCase{
- .input = "huffman-text.input",
- .want = "huffman-text.{s}.expect",
- .want_no_input = "huffman-text.{s}.expect-noinput",
- .tokens = &[_]Token{
- L('/'), L('/'), L(' '), L('z'), L('i'), L('g'), L(' '), L('v'),
- L('0'), L('.'), L('1'), L('0'), L('.'), L('0'), L(0xa), L('/'),
- L('/'), L(' '), L('c'), L('r'), L('e'), L('a'), L('t'), L('e'),
- L(' '), L('a'), L(' '), L('f'), L('i'), L('l'), L('e'), M(5, 4),
- L('l'), L('e'), L('d'), L(' '), L('w'), L('i'), L('t'), L('h'),
- L(' '), L('0'), L('x'), L('0'), L('0'), L(0xa), L('c'), L('o'),
- L('n'), L('s'), L('t'), L(' '), L('s'), L('t'), L('d'), L(' '),
- L('='), L(' '), L('@'), L('i'), L('m'), L('p'), L('o'), L('r'),
- L('t'), L('('), L('"'), L('s'), L('t'), L('d'), L('"'), L(')'),
- L(';'), L(0xa), L(0xa), L('p'), L('u'), L('b'), L(' '), L('f'),
- L('n'), L(' '), L('m'), L('a'), L('i'), L('n'), L('('), L(')'),
- L(' '), L('!'), L('v'), L('o'), L('i'), L('d'), L(' '), L('{'),
- L(0xa), L(' '), L(' '), L(' '), L(' '), L('v'), L('a'), L('r'),
- L(' '), L('b'), L(' '), L('='), L(' '), L('['), L('1'), L(']'),
- L('u'), L('8'), L('{'), L('0'), L('}'), L(' '), L('*'), L('*'),
- L(' '), L('6'), L('5'), L('5'), L('3'), L('5'), L(';'), M(31, 5),
- M(86, 6), L('f'), L(' '), L('='), L(' '), L('t'), L('r'), L('y'),
- M(94, 4), L('.'), L('f'), L('s'), L('.'), L('c'), L('w'), L('d'),
- L('('), L(')'), L('.'), M(144, 6), L('F'), L('i'), L('l'), L('e'),
- L('('), M(43, 5), M(1, 4), L('"'), L('h'), L('u'), L('f'), L('f'),
- L('m'), L('a'), L('n'), L('-'), L('n'), L('u'), L('l'), L('l'),
- L('-'), L('m'), L('a'), L('x'), L('.'), L('i'), L('n'), L('"'),
- L(','), M(31, 9), L('.'), L('{'), L(' '), L('.'), L('r'), L('e'),
- L('a'), L('d'), M(79, 5), L('u'), L('e'), L(' '), L('}'), M(27, 6),
- L(')'), M(108, 6), L('d'), L('e'), L('f'), L('e'), L('r'), L(' '),
- L('f'), L('.'), L('c'), L('l'), L('o'), L('s'), L('e'), L('('),
- M(183, 4), M(22, 4), L('_'), M(124, 7), L('f'), L('.'), L('w'), L('r'),
- L('i'), L('t'), L('e'), L('A'), L('l'), L('l'), L('('), L('b'),
- L('['), L('0'), L('.'), L('.'), L(']'), L(')'), L(';'), L(0xa),
- L('}'), L(0xa),
- },
- },
- TestCase{
- .input = "huffman-zero.input",
- .want = "huffman-zero.{s}.expect",
- .want_no_input = "huffman-zero.{s}.expect-noinput",
- .tokens = &[_]Token{ L(0x30), ml, M(1, 49) },
- },
- TestCase{
- .input = "",
- .want = "",
- .want_no_input = "null-long-match.{s}.expect-noinput",
- .tokens = &[_]Token{
- L(0x0), ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
- ml, ml, ml, M(1, 8),
- },
- },
- };
-};
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect
deleted file mode 100644
index c08165143f..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect-noinput
deleted file mode 100644
index c08165143f..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-null-max.huff.expect
deleted file mode 100644
index db422ca398..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.input b/lib/std/compress/flate/testdata/block_writer/huffman-null-max.input
deleted file mode 100644
index 5dfddf075b..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.input and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect
deleted file mode 100644
index c08165143f..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect-noinput
deleted file mode 100644
index c08165143f..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect
deleted file mode 100644
index e4396ac6fe..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect-noinput
deleted file mode 100644
index e4396ac6fe..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-pi.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-pi.huff.expect
deleted file mode 100644
index 23d8f7f98b..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-pi.input b/lib/std/compress/flate/testdata/block_writer/huffman-pi.input
deleted file mode 100644
index efaed43431..0000000000
--- a/lib/std/compress/flate/testdata/block_writer/huffman-pi.input
+++ /dev/null
@@ -1 +0,0 @@
-3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955321165344987202755960236480665499119881834797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548161361157352552133475741849468438523323907394143334547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383827967976681454100953883786360950680064225125205117392984896084128488626945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645995813390478027590099465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364542858444795265867821051141354735739523113427166102135969536231442952484937187110145765403590279934403742007310578539062198387447808478489683321445713868751943506430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961567945208095146550225231603881930142093762137855956638937787083039069792077346722182562599661501421503068038447734549202605414665925201497442850732518666002132434088190710486331734649651453905796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007230558763176359421873125147120532928191826186125867321579198414848829164470609575270695722091756711672291098169091528017350671274858322287183520935396572512108357915136988209144421006751033467110314126711136990865851639831501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064204675259070915481416549859461637180
\ No newline at end of file
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect
deleted file mode 100644
index e4396ac6fe..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect-noinput
deleted file mode 100644
index e4396ac6fe..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect
deleted file mode 100644
index 09dc798ee3..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect-noinput
deleted file mode 100644
index 0c24742fde..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.huff.expect
deleted file mode 100644
index 09dc798ee3..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.input b/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.input
deleted file mode 100644
index ce038ebb5b..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.input and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect
deleted file mode 100644
index 09dc798ee3..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect-noinput
deleted file mode 100644
index 0c24742fde..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect
deleted file mode 100644
index 2d6527934e..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect-noinput
deleted file mode 100644
index 2d6527934e..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.huff.expect
deleted file mode 100644
index 57e59322e9..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.input b/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.input
deleted file mode 100644
index fb5b1be619..0000000000
--- a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.input
+++ /dev/null
@@ -1,4 +0,0 @@
-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-ø‹–vH
-…”%€¯Âþè ë†É·ÅÞê}‹ç>ÚßÿlsÞÌçmIGH°èžò1YÞ4´[åà 0ˆ[|]o#©
-¼-#¾Ùíul™ßýpfæîÙ±žnƒYÕÔ€Y˜w‰C8ɯ02š F=gn×ržN!OÆàÔ{¥ö›kÜ*“w(ý´bÚ ç«kQC9/ ’lu>ô5ýC.÷¤uÚê›
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect
deleted file mode 100644
index 881e59c9ab..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect-noinput
deleted file mode 100644
index 881e59c9ab..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.huff.expect
deleted file mode 100644
index 47d53c89c0..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.input b/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.input
deleted file mode 100644
index 8418633d2a..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.input and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect
deleted file mode 100644
index 7812c1c62d..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect-noinput
deleted file mode 100644
index 7812c1c62d..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-shifts.huff.expect
deleted file mode 100644
index f5133778e1..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.input b/lib/std/compress/flate/testdata/block_writer/huffman-shifts.input
deleted file mode 100644
index 7c7a50d158..0000000000
--- a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.input
+++ /dev/null
@@ -1,2 +0,0 @@
-101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010
-232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323
\ No newline at end of file
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect
deleted file mode 100644
index 7812c1c62d..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect-noinput
deleted file mode 100644
index 7812c1c62d..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect
deleted file mode 100644
index 71ce3aeb75..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect-noinput
deleted file mode 100644
index 71ce3aeb75..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.huff.expect
deleted file mode 100644
index ff023114bb..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.input b/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.input
deleted file mode 100644
index cc5c3ad69d..0000000000
--- a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.input
+++ /dev/null
@@ -1,14 +0,0 @@
-//Copyright2009ThGoAuthor.Allrightrrvd.
-//UofthiourccodigovrndbyBSD-tyl
-//licnthtcnbfoundinthLICENSEfil.
-
-pckgmin
-
-import"o"
-
-funcmin(){
- vrb=mk([]byt,65535)
- f,_:=o.Crt("huffmn-null-mx.in")
- f.Writ(b)
-}
-ABCDEFGHIJKLMNOPQRSTUVXxyz!"#¤%&/?"
\ No newline at end of file
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect
deleted file mode 100644
index 71ce3aeb75..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect-noinput
deleted file mode 100644
index 71ce3aeb75..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect
deleted file mode 100644
index fbffc3f36b..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect-noinput
deleted file mode 100644
index fbffc3f36b..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-text.huff.expect
deleted file mode 100644
index 46fa51fdad..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text.input b/lib/std/compress/flate/testdata/block_writer/huffman-text.input
deleted file mode 100644
index df97174253..0000000000
--- a/lib/std/compress/flate/testdata/block_writer/huffman-text.input
+++ /dev/null
@@ -1,14 +0,0 @@
-// zig v0.10.0
-// create a file filled with 0x00
-const std = @import("std");
-
-pub fn main() !void {
- var b = [1]u8{0} ** 65535;
- const f = try std.fs.cwd().createFile(
- "huffman-null-max.in",
- .{ .read = true },
- );
- defer f.close();
-
- _ = try f.writeAll(b[0..]);
-}
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect
deleted file mode 100644
index fbffc3f36b..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect-noinput
deleted file mode 100644
index fbffc3f36b..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect b/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect
deleted file mode 100644
index 830348a79a..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect-noinput
deleted file mode 100644
index 830348a79a..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-zero.huff.expect b/lib/std/compress/flate/testdata/block_writer/huffman-zero.huff.expect
deleted file mode 100644
index 5abdbaff9a..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.huff.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-zero.input b/lib/std/compress/flate/testdata/block_writer/huffman-zero.input
deleted file mode 100644
index 349be0e6ec..0000000000
--- a/lib/std/compress/flate/testdata/block_writer/huffman-zero.input
+++ /dev/null
@@ -1 +0,0 @@
-00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
\ No newline at end of file
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect b/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect
deleted file mode 100644
index dbe401c54c..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect-noinput
deleted file mode 100644
index dbe401c54c..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/null-long-match.dyn.expect-noinput b/lib/std/compress/flate/testdata/block_writer/null-long-match.dyn.expect-noinput
deleted file mode 100644
index 8b92d9fc20..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/null-long-match.dyn.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/flate/testdata/block_writer/null-long-match.wb.expect-noinput b/lib/std/compress/flate/testdata/block_writer/null-long-match.wb.expect-noinput
deleted file mode 100644
index 8b92d9fc20..0000000000
Binary files a/lib/std/compress/flate/testdata/block_writer/null-long-match.wb.expect-noinput and /dev/null differ
diff --git a/lib/std/compress/xz.zig b/lib/std/compress/xz.zig
index c8bc964543..6c99e9f427 100644
--- a/lib/std/compress/xz.zig
+++ b/lib/std/compress/xz.zig
@@ -12,17 +12,11 @@ pub const Check = enum(u4) {
};
fn readStreamFlags(reader: anytype, check: *Check) !void {
- var bit_reader = std.io.bitReader(.little, reader);
-
- const reserved1 = try bit_reader.readBitsNoEof(u8, 8);
- if (reserved1 != 0)
- return error.CorruptInput;
-
- check.* = @as(Check, @enumFromInt(try bit_reader.readBitsNoEof(u4, 4)));
-
- const reserved2 = try bit_reader.readBitsNoEof(u4, 4);
- if (reserved2 != 0)
- return error.CorruptInput;
+ const reserved1 = try reader.readByte();
+ if (reserved1 != 0) return error.CorruptInput;
+ const byte = try reader.readByte();
+ if ((byte >> 4) != 0) return error.CorruptInput;
+ check.* = @enumFromInt(@as(u4, @truncate(byte)));
}
pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) {
diff --git a/lib/std/compress/zstd/Decompress.zig b/lib/std/compress/zstd/Decompress.zig
index b831fe7fb4..bcb8e3b0da 100644
--- a/lib/std/compress/zstd/Decompress.zig
+++ b/lib/std/compress/zstd/Decompress.zig
@@ -31,7 +31,12 @@ pub const Options = struct {
/// Verifying checksums is not implemented yet and will cause a panic if
/// you set this to true.
verify_checksum: bool = false,
- /// Affects the minimum capacity of the provided buffer.
+
+ /// The output buffer is asserted to have capacity for `window_len` plus
+ /// `zstd.block_size_max`.
+ ///
+ /// If `window_len` is too small, then some streams will fail to decompress
+ /// with `error.OutputBufferUndersize`.
window_len: u32 = zstd.default_window_len,
};
@@ -69,8 +74,10 @@ pub const Error = error{
WindowSizeUnknown,
};
-/// If buffer that is written to is not big enough, some streams will fail with
-/// `error.OutputBufferUndersize`. A safe value is `zstd.default_window_len * 2`.
+/// When connecting `reader` to a `Writer`, `buffer` should be empty, and
+/// `Writer.buffer` capacity has requirements based on `Options.window_len`.
+///
+/// Otherwise, `buffer` has those requirements.
pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
return .{
.input = input,
@@ -78,7 +85,12 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
.verify_checksum = options.verify_checksum,
.window_len = options.window_len,
.reader = .{
- .vtable = &.{ .stream = stream },
+ .vtable = &.{
+ .stream = stream,
+ .rebase = rebase,
+ .discard = discard,
+ .readVec = readVec,
+ },
.buffer = buffer,
.seek = 0,
.end = 0,
@@ -86,6 +98,60 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
};
}
+fn rebase(r: *Reader, capacity: usize) Reader.RebaseError!void {
+ const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+ assert(capacity <= r.buffer.len - d.window_len);
+ assert(r.end + capacity > r.buffer.len);
+ const discard_n = r.end - d.window_len;
+ const keep = r.buffer[discard_n..r.end];
+ @memmove(r.buffer[0..keep.len], keep);
+ r.end = keep.len;
+ r.seek -= discard_n;
+}
+
+/// This could be improved so that when an amount is discarded that includes an
+/// entire frame, skip decoding that frame.
+fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
+ const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+ r.rebase(d.window_len) catch unreachable;
+ var writer: Writer = .{
+ .vtable = &.{
+ .drain = std.Io.Writer.Discarding.drain,
+ .sendFile = std.Io.Writer.Discarding.sendFile,
+ },
+ .buffer = r.buffer,
+ .end = r.end,
+ };
+ defer {
+ r.end = writer.end;
+ r.seek = r.end;
+ }
+ const n = r.stream(&writer, limit) catch |err| switch (err) {
+ error.WriteFailed => unreachable,
+ error.ReadFailed => return error.ReadFailed,
+ error.EndOfStream => return error.EndOfStream,
+ };
+ assert(n <= @intFromEnum(limit));
+ return n;
+}
+
+fn readVec(r: *Reader, data: [][]u8) Reader.Error!usize {
+ _ = data;
+ const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
+ assert(r.seek == r.end);
+ r.rebase(d.window_len) catch unreachable;
+ var writer: Writer = .{
+ .buffer = r.buffer,
+ .end = r.end,
+ .vtable = &.{ .drain = Writer.fixedDrain },
+ };
+ r.end += r.vtable.stream(r, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
+ error.WriteFailed => unreachable,
+ else => |e| return e,
+ };
+ return 0;
+}
+
fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
const in = d.input;
diff --git a/lib/std/debug/Dwarf.zig b/lib/std/debug/Dwarf.zig
index ff07698936..3d3f387472 100644
--- a/lib/std/debug/Dwarf.zig
+++ b/lib/std/debug/Dwarf.zig
@@ -2019,10 +2019,14 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 {
/// This function is to make it handy to comment out the return and make it
/// into a crash when working on this file.
pub fn bad() error{InvalidDebugInfo} {
- if (debug_debug_mode) @panic("bad dwarf");
+ invalidDebugInfoDetected();
return error.InvalidDebugInfo;
}
+fn invalidDebugInfoDetected() void {
+ if (debug_debug_mode) @panic("bad dwarf");
+}
+
fn missing() error{MissingDebugInfo} {
if (debug_debug_mode) @panic("missing dwarf");
return error.MissingDebugInfo;
@@ -2235,23 +2239,23 @@ pub const ElfModule = struct {
const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
sections[section_index.?] = if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) blk: {
- var section_reader: std.io.Reader = .fixed(section_bytes);
- const chdr = section_reader.takeStruct(elf.Chdr) catch continue;
+ var section_reader: std.Io.Reader = .fixed(section_bytes);
+ const chdr = section_reader.takeStruct(elf.Chdr, endian) catch continue;
if (chdr.ch_type != .ZLIB) continue;
- const ch_size = chdr.ch_size;
- var zlib_stream: std.compress.flate.Decompress = .init(§ion_reader, .zlib, &.{});
-
- const decompressed_section = zlib_stream.reader.allocRemaining(gpa, .limited(ch_size)) catch
+ var decompress: std.compress.flate.Decompress = .init(§ion_reader, .zlib, &.{});
+ var decompressed_section: std.ArrayListUnmanaged(u8) = .empty;
+ defer decompressed_section.deinit(gpa);
+ decompress.reader.appendRemainingUnlimited(gpa, null, &decompressed_section, std.compress.flate.history_len) catch {
+ invalidDebugInfoDetected();
continue;
- if (decompressed_section.len != ch_size) {
- gpa.free(decompressed_section);
+ };
+ if (chdr.ch_size != decompressed_section.items.len) {
+ invalidDebugInfoDetected();
continue;
}
- errdefer gpa.free(decompressed_section);
-
break :blk .{
- .data = decompressed_section,
+ .data = try decompressed_section.toOwnedSlice(gpa),
.virtual_address = shdr.sh_addr,
.owned = true,
};
diff --git a/lib/std/enums.zig b/lib/std/enums.zig
index e34cf17e07..e47af4aca3 100644
--- a/lib/std/enums.zig
+++ b/lib/std/enums.zig
@@ -1317,9 +1317,9 @@ test "EnumSet non-exhaustive" {
}
pub fn EnumIndexer(comptime E: type) type {
- // Assumes that the enum fields are sorted in ascending order (optimistic).
- // Unsorted enums may require the user to manually increase the quota.
- @setEvalBranchQuota(3 * @typeInfo(E).@"enum".fields.len + eval_branch_quota_cushion);
+ // n log n for `std.mem.sortUnstable` call below.
+ const fields_len = @typeInfo(E).@"enum".fields.len;
+ @setEvalBranchQuota(3 * fields_len * std.math.log2(@max(fields_len, 1)) + eval_branch_quota_cushion);
if (!@typeInfo(E).@"enum".is_exhaustive) {
const BackingInt = @typeInfo(E).@"enum".tag_type;
@@ -1354,10 +1354,6 @@ pub fn EnumIndexer(comptime E: type) type {
};
}
- const const_fields = @typeInfo(E).@"enum".fields;
- var fields = const_fields[0..const_fields.len].*;
- const fields_len = fields.len;
-
if (fields_len == 0) {
return struct {
pub const Key = E;
@@ -1373,22 +1369,17 @@ pub fn EnumIndexer(comptime E: type) type {
};
}
+ var fields: [fields_len]EnumField = @typeInfo(E).@"enum".fields[0..].*;
+
+ std.mem.sortUnstable(EnumField, &fields, {}, struct {
+ fn lessThan(ctx: void, lhs: EnumField, rhs: EnumField) bool {
+ ctx;
+ return lhs.value < rhs.value;
+ }
+ }.lessThan);
+
const min = fields[0].value;
- const max = fields[fields.len - 1].value;
-
- const SortContext = struct {
- fields: []EnumField,
-
- pub fn lessThan(comptime ctx: @This(), comptime a: usize, comptime b: usize) bool {
- return ctx.fields[a].value < ctx.fields[b].value;
- }
-
- pub fn swap(comptime ctx: @This(), comptime a: usize, comptime b: usize) void {
- return std.mem.swap(EnumField, &ctx.fields[a], &ctx.fields[b]);
- }
- };
- std.sort.insertionContext(0, fields_len, SortContext{ .fields = &fields });
-
+ const max = fields[fields_len - 1].value;
if (max - min == fields.len - 1) {
return struct {
pub const Key = E;
@@ -1538,6 +1529,29 @@ test "EnumIndexer empty" {
try testing.expectEqual(0, Indexer.count);
}
+test "EnumIndexer large dense unsorted" {
+ @setEvalBranchQuota(500_000); // many `comptimePrint`s
+ // Make an enum with 500 fields with values in *descending* order.
+ const E = @Type(.{ .@"enum" = .{
+ .tag_type = u32,
+ .fields = comptime fields: {
+ var fields: [500]EnumField = undefined;
+ for (&fields, 0..) |*f, i| f.* = .{
+ .name = std.fmt.comptimePrint("f{d}", .{i}),
+ .value = 500 - i,
+ };
+ break :fields &fields;
+ },
+ .decls = &.{},
+ .is_exhaustive = true,
+ } });
+ const Indexer = EnumIndexer(E);
+ try testing.expectEqual(E.f0, Indexer.keyForIndex(499));
+ try testing.expectEqual(E.f499, Indexer.keyForIndex(0));
+ try testing.expectEqual(499, Indexer.indexOf(.f0));
+ try testing.expectEqual(0, Indexer.indexOf(.f499));
+}
+
test values {
const E = enum {
X,
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 0c51d56e30..b6730e1cf1 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -1101,6 +1101,8 @@ test "float.libc.sanity" {
}
test "union" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
+
const TU = union(enum) {
float: f32,
int: u32,
diff --git a/lib/std/fs/File.zig b/lib/std/fs/File.zig
index 54c8791c67..f90acac015 100644
--- a/lib/std/fs/File.zig
+++ b/lib/std/fs/File.zig
@@ -912,7 +912,7 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError
/// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`)
/// versus plain variants (e.g. `read`).
///
-/// Fulfills the `std.io.Reader` interface.
+/// Fulfills the `std.Io.Reader` interface.
pub const Reader = struct {
file: File,
err: ?ReadError = null,
@@ -923,7 +923,7 @@ pub const Reader = struct {
size: ?u64 = null,
size_err: ?GetEndPosError = null,
seek_err: ?Reader.SeekError = null,
- interface: std.io.Reader,
+ interface: std.Io.Reader,
pub const SeekError = File.SeekError || error{
/// Seeking fell back to reading, and reached the end before the requested seek position.
@@ -960,11 +960,12 @@ pub const Reader = struct {
}
};
- pub fn initInterface(buffer: []u8) std.io.Reader {
+ pub fn initInterface(buffer: []u8) std.Io.Reader {
return .{
.vtable = &.{
.stream = Reader.stream,
.discard = Reader.discard,
+ .readVec = Reader.readVec,
},
.buffer = buffer,
.seek = 0,
@@ -1077,7 +1078,7 @@ pub const Reader = struct {
/// vectors through the underlying read calls as possible.
const max_buffers_len = 16;
- fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
+ fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
switch (r.mode) {
.positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) {
@@ -1088,16 +1089,33 @@ pub const Reader = struct {
else => |e| return e,
},
.positional_reading => {
+ const dest = limit.slice(try w.writableSliceGreedy(1));
+ const n = try readPositional(r, dest);
+ w.advance(n);
+ return n;
+ },
+ .streaming_reading => {
+ const dest = limit.slice(try w.writableSliceGreedy(1));
+ const n = try readStreaming(r, dest);
+ w.advance(n);
+ return n;
+ },
+ .failure => return error.ReadFailed,
+ }
+ }
+
+ fn readVec(io_reader: *std.Io.Reader, data: [][]u8) std.Io.Reader.Error!usize {
+ const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
+ switch (r.mode) {
+ .positional, .positional_reading => {
if (is_windows) {
// Unfortunately, `ReadFileScatter` cannot be used since it
// requires page alignment.
- const dest = limit.slice(try w.writableSliceGreedy(1));
- const n = try readPositional(r, dest);
- w.advance(n);
- return n;
+ return readPositional(r, data[0]);
}
var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
- const dest = try w.writableVectorPosix(&iovecs_buffer, limit);
+ const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);
+ const dest = iovecs_buffer[0..dest_n];
assert(dest[0].len > 0);
const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) {
error.Unseekable => {
@@ -1122,19 +1140,22 @@ pub const Reader = struct {
return error.EndOfStream;
}
r.pos += n;
- return w.advanceVector(n);
+ if (n > data_size) {
+ io_reader.seek = 0;
+ io_reader.end = n - data_size;
+ return data_size;
+ }
+ return n;
},
- .streaming_reading => {
+ .streaming, .streaming_reading => {
if (is_windows) {
// Unfortunately, `ReadFileScatter` cannot be used since it
// requires page alignment.
- const dest = limit.slice(try w.writableSliceGreedy(1));
- const n = try readStreaming(r, dest);
- w.advance(n);
- return n;
+ return readStreaming(r, data[0]);
}
var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
- const dest = try w.writableVectorPosix(&iovecs_buffer, limit);
+ const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);
+ const dest = iovecs_buffer[0..dest_n];
assert(dest[0].len > 0);
const n = posix.readv(r.file.handle, dest) catch |err| {
r.err = err;
@@ -1145,13 +1166,18 @@ pub const Reader = struct {
return error.EndOfStream;
}
r.pos += n;
- return w.advanceVector(n);
+ if (n > data_size) {
+ io_reader.seek = 0;
+ io_reader.end = n - data_size;
+ return data_size;
+ }
+ return n;
},
.failure => return error.ReadFailed,
}
}
- fn discard(io_reader: *std.io.Reader, limit: std.io.Limit) std.io.Reader.Error!usize {
+ fn discard(io_reader: *std.Io.Reader, limit: std.Io.Limit) std.Io.Reader.Error!usize {
const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
const file = r.file;
const pos = r.pos;
@@ -1230,7 +1256,7 @@ pub const Reader = struct {
}
}
- pub fn readPositional(r: *Reader, dest: []u8) std.io.Reader.Error!usize {
+ pub fn readPositional(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
const n = r.file.pread(dest, r.pos) catch |err| switch (err) {
error.Unseekable => {
r.mode = r.mode.toStreaming();
@@ -1257,7 +1283,7 @@ pub const Reader = struct {
return n;
}
- pub fn readStreaming(r: *Reader, dest: []u8) std.io.Reader.Error!usize {
+ pub fn readStreaming(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
const n = r.file.read(dest) catch |err| {
r.err = err;
return error.ReadFailed;
@@ -1270,7 +1296,7 @@ pub const Reader = struct {
return n;
}
- pub fn read(r: *Reader, dest: []u8) std.io.Reader.Error!usize {
+ pub fn read(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
switch (r.mode) {
.positional, .positional_reading => return readPositional(r, dest),
.streaming, .streaming_reading => return readStreaming(r, dest),
@@ -1296,7 +1322,7 @@ pub const Writer = struct {
copy_file_range_err: ?CopyFileRangeError = null,
fcopyfile_err: ?FcopyfileError = null,
seek_err: ?SeekError = null,
- interface: std.io.Writer,
+ interface: std.Io.Writer,
pub const Mode = Reader.Mode;
@@ -1333,13 +1359,13 @@ pub const Writer = struct {
};
}
- pub fn initInterface(buffer: []u8) std.io.Writer {
+ pub fn initInterface(buffer: []u8) std.Io.Writer {
return .{
.vtable = &.{
.drain = drain,
.sendFile = switch (builtin.zig_backend) {
else => sendFile,
- .stage2_aarch64 => std.io.Writer.unimplementedSendFile,
+ .stage2_aarch64 => std.Io.Writer.unimplementedSendFile,
},
},
.buffer = buffer,
@@ -1357,7 +1383,7 @@ pub const Writer = struct {
};
}
- pub fn drain(io_w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
+ pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
const handle = w.file.handle;
const buffered = io_w.buffered();
@@ -1507,10 +1533,10 @@ pub const Writer = struct {
}
pub fn sendFile(
- io_w: *std.io.Writer,
+ io_w: *std.Io.Writer,
file_reader: *Reader,
- limit: std.io.Limit,
- ) std.io.Writer.FileError!usize {
+ limit: std.Io.Limit,
+ ) std.Io.Writer.FileError!usize {
const reader_buffered = file_reader.interface.buffered();
if (reader_buffered.len >= @intFromEnum(limit))
return sendFileBuffered(io_w, file_reader, reader_buffered);
@@ -1772,10 +1798,10 @@ pub const Writer = struct {
}
fn sendFileBuffered(
- io_w: *std.io.Writer,
+ io_w: *std.Io.Writer,
file_reader: *Reader,
reader_buffered: []const u8,
- ) std.io.Writer.FileError!usize {
+ ) std.Io.Writer.FileError!usize {
const n = try drain(io_w, &.{reader_buffered}, 1);
file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed;
return n;
@@ -1798,7 +1824,7 @@ pub const Writer = struct {
}
}
- pub const EndError = SetEndPosError || std.io.Writer.Error;
+ pub const EndError = SetEndPosError || std.Io.Writer.Error;
/// Flushes any buffered data and sets the end position of the file.
///
diff --git a/lib/std/hash.zig b/lib/std/hash.zig
index 77a25550f3..50ef2b011e 100644
--- a/lib/std/hash.zig
+++ b/lib/std/hash.zig
@@ -1,5 +1,4 @@
-const adler = @import("hash/adler.zig");
-pub const Adler32 = adler.Adler32;
+pub const Adler32 = @import("hash/Adler32.zig");
const auto_hash = @import("hash/auto_hash.zig");
pub const autoHash = auto_hash.autoHash;
@@ -115,7 +114,7 @@ test int {
}
test {
- _ = adler;
+ _ = Adler32;
_ = auto_hash;
_ = crc;
_ = fnv;
diff --git a/lib/std/hash/Adler32.zig b/lib/std/hash/Adler32.zig
new file mode 100644
index 0000000000..6932dc59da
--- /dev/null
+++ b/lib/std/hash/Adler32.zig
@@ -0,0 +1,117 @@
+//! https://tools.ietf.org/html/rfc1950#section-9
+//! https://github.com/madler/zlib/blob/master/adler32.c
+
+const Adler32 = @This();
+const std = @import("std");
+const testing = std.testing;
+
+adler: u32 = 1,
+
+pub fn permute(state: u32, input: []const u8) u32 {
+ const base = 65521;
+ const nmax = 5552;
+
+ var s1 = state & 0xffff;
+ var s2 = (state >> 16) & 0xffff;
+
+ if (input.len == 1) {
+ s1 +%= input[0];
+ if (s1 >= base) {
+ s1 -= base;
+ }
+ s2 +%= s1;
+ if (s2 >= base) {
+ s2 -= base;
+ }
+ } else if (input.len < 16) {
+ for (input) |b| {
+ s1 +%= b;
+ s2 +%= s1;
+ }
+ if (s1 >= base) {
+ s1 -= base;
+ }
+
+ s2 %= base;
+ } else {
+ const n = nmax / 16; // note: 16 | nmax
+
+ var i: usize = 0;
+
+ while (i + nmax <= input.len) {
+ var rounds: usize = 0;
+ while (rounds < n) : (rounds += 1) {
+ comptime var j: usize = 0;
+ inline while (j < 16) : (j += 1) {
+ s1 +%= input[i + j];
+ s2 +%= s1;
+ }
+ i += 16;
+ }
+
+ s1 %= base;
+ s2 %= base;
+ }
+
+ if (i < input.len) {
+ while (i + 16 <= input.len) : (i += 16) {
+ comptime var j: usize = 0;
+ inline while (j < 16) : (j += 1) {
+ s1 +%= input[i + j];
+ s2 +%= s1;
+ }
+ }
+ while (i < input.len) : (i += 1) {
+ s1 +%= input[i];
+ s2 +%= s1;
+ }
+
+ s1 %= base;
+ s2 %= base;
+ }
+ }
+
+ return s1 | (s2 << 16);
+}
+
+pub fn update(a: *Adler32, input: []const u8) void {
+ a.adler = permute(a.adler, input);
+}
+
+pub fn hash(input: []const u8) u32 {
+ return permute(1, input);
+}
+
+test "sanity" {
+ try testing.expectEqual(@as(u32, 0x620062), hash("a"));
+ try testing.expectEqual(@as(u32, 0xbc002ed), hash("example"));
+}
+
+test "long" {
+ const long1 = [_]u8{1} ** 1024;
+ try testing.expectEqual(@as(u32, 0x06780401), hash(long1[0..]));
+
+ const long2 = [_]u8{1} ** 1025;
+ try testing.expectEqual(@as(u32, 0x0a7a0402), hash(long2[0..]));
+}
+
+test "very long" {
+ const long = [_]u8{1} ** 5553;
+ try testing.expectEqual(@as(u32, 0x707f15b2), hash(long[0..]));
+}
+
+test "very long with variation" {
+ const long = comptime blk: {
+ @setEvalBranchQuota(7000);
+ var result: [6000]u8 = undefined;
+
+ var i: usize = 0;
+ while (i < result.len) : (i += 1) {
+ result[i] = @as(u8, @truncate(i));
+ }
+
+ break :blk result;
+ };
+
+ try testing.expectEqual(@as(u32, 0x5af38d6e), hash(long[0..]));
+}
diff --git a/lib/std/hash/adler.zig b/lib/std/hash/adler.zig
deleted file mode 100644
index 52f7b2691a..0000000000
--- a/lib/std/hash/adler.zig
+++ /dev/null
@@ -1,134 +0,0 @@
-// Adler32 checksum.
-//
-// https://tools.ietf.org/html/rfc1950#section-9
-// https://github.com/madler/zlib/blob/master/adler32.c
-
-const std = @import("std");
-const testing = std.testing;
-
-pub const Adler32 = struct {
- const base = 65521;
- const nmax = 5552;
-
- adler: u32,
-
- pub fn init() Adler32 {
- return Adler32{ .adler = 1 };
- }
-
- // This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
- // buffer inputs and should be much quicker.
- pub fn update(self: *Adler32, input: []const u8) void {
- var s1 = self.adler & 0xffff;
- var s2 = (self.adler >> 16) & 0xffff;
-
- if (input.len == 1) {
- s1 +%= input[0];
- if (s1 >= base) {
- s1 -= base;
- }
- s2 +%= s1;
- if (s2 >= base) {
- s2 -= base;
- }
- } else if (input.len < 16) {
- for (input) |b| {
- s1 +%= b;
- s2 +%= s1;
- }
- if (s1 >= base) {
- s1 -= base;
- }
-
- s2 %= base;
- } else {
- const n = nmax / 16; // note: 16 | nmax
-
- var i: usize = 0;
-
- while (i + nmax <= input.len) {
- var rounds: usize = 0;
- while (rounds < n) : (rounds += 1) {
- comptime var j: usize = 0;
- inline while (j < 16) : (j += 1) {
- s1 +%= input[i + j];
- s2 +%= s1;
- }
- i += 16;
- }
-
- s1 %= base;
- s2 %= base;
- }
-
- if (i < input.len) {
- while (i + 16 <= input.len) : (i += 16) {
- comptime var j: usize = 0;
- inline while (j < 16) : (j += 1) {
- s1 +%= input[i + j];
- s2 +%= s1;
- }
- }
- while (i < input.len) : (i += 1) {
- s1 +%= input[i];
- s2 +%= s1;
- }
-
- s1 %= base;
- s2 %= base;
- }
- }
-
- self.adler = s1 | (s2 << 16);
- }
-
- pub fn final(self: *Adler32) u32 {
- return self.adler;
- }
-
- pub fn hash(input: []const u8) u32 {
- var c = Adler32.init();
- c.update(input);
- return c.final();
- }
-};
-
-test "adler32 sanity" {
- try testing.expectEqual(@as(u32, 0x620062), Adler32.hash("a"));
- try testing.expectEqual(@as(u32, 0xbc002ed), Adler32.hash("example"));
-}
-
-test "adler32 long" {
- const long1 = [_]u8{1} ** 1024;
- try testing.expectEqual(@as(u32, 0x06780401), Adler32.hash(long1[0..]));
-
- const long2 = [_]u8{1} ** 1025;
- try testing.expectEqual(@as(u32, 0x0a7a0402), Adler32.hash(long2[0..]));
-}
-
-test "adler32 very long" {
- const long = [_]u8{1} ** 5553;
- try testing.expectEqual(@as(u32, 0x707f15b2), Adler32.hash(long[0..]));
-}
-
-test "adler32 very long with variation" {
- const long = comptime blk: {
- @setEvalBranchQuota(7000);
- var result: [6000]u8 = undefined;
-
- var i: usize = 0;
- while (i < result.len) : (i += 1) {
- result[i] = @as(u8, @truncate(i));
- }
-
- break :blk result;
- };
-
- try testing.expectEqual(@as(u32, 0x5af38d6e), std.hash.Adler32.hash(long[0..]));
-}
-
-const verify = @import("verify.zig");
-
-test "adler32 iterative" {
- try verify.iterativeApi(Adler32);
-}
diff --git a/lib/std/hash/verify.zig b/lib/std/hash/verify.zig
index 61f501a881..a96a36c050 100644
--- a/lib/std/hash/verify.zig
+++ b/lib/std/hash/verify.zig
@@ -45,7 +45,7 @@ pub fn smhasher(comptime hash_fn: anytype) u32 {
pub fn iterativeApi(comptime Hash: anytype) !void {
// Sum(1..32) = 528
- var buf: [528]u8 = [_]u8{0} ** 528;
+ var buf: [528]u8 = @splat(0);
var len: usize = 0;
const seed = 0;
diff --git a/lib/std/heap.zig b/lib/std/heap.zig
index 51e4fe44a2..a39cf5e1cb 100644
--- a/lib/std/heap.zig
+++ b/lib/std/heap.zig
@@ -146,7 +146,7 @@ const CAllocator = struct {
else {};
pub const supports_posix_memalign = switch (builtin.os.tag) {
- .dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .linux, .macos, .ios, .tvos, .watchos, .visionos => true,
+ .dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .linux, .macos, .ios, .tvos, .watchos, .visionos, .serenity => true,
else => false,
};
diff --git a/lib/std/math.zig b/lib/std/math.zig
index 9498f6cfe5..a9f87a9619 100644
--- a/lib/std/math.zig
+++ b/lib/std/math.zig
@@ -1358,11 +1358,15 @@ pub fn lossyCast(comptime T: type, value: anytype) T {
}
},
.float, .comptime_float => {
+ // In extreme cases, we probably need a language enhancement to be able to
+ // specify a rounding mode here to prevent `@intFromFloat` panics.
+ const max: @TypeOf(value) = @floatFromInt(maxInt(T));
+ const min: @TypeOf(value) = @floatFromInt(minInt(T));
if (isNan(value)) {
return 0;
- } else if (value >= maxInt(T)) {
+ } else if (value >= max) {
return maxInt(T);
- } else if (value <= minInt(T)) {
+ } else if (value <= min) {
return minInt(T);
} else {
return @intFromFloat(value);
@@ -1379,7 +1383,7 @@ test lossyCast {
try testing.expect(lossyCast(i16, 70000.0) == @as(i16, 32767));
try testing.expect(lossyCast(u32, @as(i16, -255)) == @as(u32, 0));
try testing.expect(lossyCast(i9, @as(u32, 200)) == @as(i9, 200));
- try testing.expect(lossyCast(u32, @as(f32, maxInt(u32))) == maxInt(u32));
+ try testing.expect(lossyCast(u32, @as(f32, @floatFromInt(maxInt(u32)))) == maxInt(u32));
try testing.expect(lossyCast(u32, nan(f32)) == 0);
}
diff --git a/lib/std/math/gamma.zig b/lib/std/math/gamma.zig
index 5577f71461..ce9a2b07f9 100644
--- a/lib/std/math/gamma.zig
+++ b/lib/std/math/gamma.zig
@@ -189,19 +189,19 @@ fn series(comptime T: type, abs: T) T {
2.5066282746310002701649081771338373386264310793408,
};
const denominator = [_]T{
- 0,
- 39916800,
- 120543840,
- 150917976,
- 105258076,
- 45995730,
- 13339535,
- 2637558,
- 357423,
- 32670,
- 1925,
- 66,
- 1,
+ 0.0,
+ 39916800.0,
+ 120543840.0,
+ 150917976.0,
+ 105258076.0,
+ 45995730.0,
+ 13339535.0,
+ 2637558.0,
+ 357423.0,
+ 32670.0,
+ 1925.0,
+ 66.0,
+ 1.0,
};
var num: T = 0;
var den: T = 0;
@@ -244,9 +244,9 @@ const expectApproxEqRel = std.testing.expectApproxEqRel;
test gamma {
inline for (&.{ f32, f64 }) |T| {
const eps = @sqrt(std.math.floatEps(T));
- try expectApproxEqRel(@as(T, 120), gamma(T, 6), eps);
- try expectApproxEqRel(@as(T, 362880), gamma(T, 10), eps);
- try expectApproxEqRel(@as(T, 6402373705728000), gamma(T, 19), eps);
+ try expectApproxEqRel(@as(T, 120.0), gamma(T, 6), eps);
+ try expectApproxEqRel(@as(T, 362880.0), gamma(T, 10), eps);
+ try expectApproxEqRel(@as(T, 6402373705728000.0), gamma(T, 19), eps);
try expectApproxEqRel(@as(T, 332.7590766955334570), gamma(T, 0.003), eps);
try expectApproxEqRel(@as(T, 1.377260301981044573), gamma(T, 0.654), eps);
diff --git a/lib/std/math/modf.zig b/lib/std/math/modf.zig
index 77d58bd34e..dda34454e3 100644
--- a/lib/std/math/modf.zig
+++ b/lib/std/math/modf.zig
@@ -74,7 +74,7 @@ fn ModfTests(comptime T: type) type {
r = modf(@as(T, 43874.3));
try expectEqual(43874.0, r.ipart);
// account for precision error
- const expected_b: T = 43874.3 - @as(T, 43874);
+ const expected_b: T = 43874.3 - @as(T, 43874.0);
try expectApproxEqAbs(expected_b, r.fpart, epsilon);
r = modf(@as(T, 1234.340780));
diff --git a/lib/std/math/pow.zig b/lib/std/math/pow.zig
index acaafe7609..42f28ce465 100644
--- a/lib/std/math/pow.zig
+++ b/lib/std/math/pow.zig
@@ -192,8 +192,8 @@ fn isOddInteger(x: f64) bool {
}
test isOddInteger {
- try expect(isOddInteger(math.maxInt(i64) * 2) == false);
- try expect(isOddInteger(math.maxInt(i64) * 2 + 1) == false);
+ try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2)) == false);
+ try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2 + 1)) == false);
try expect(isOddInteger(1 << 53) == false);
try expect(isOddInteger(12.0) == false);
try expect(isOddInteger(15.0) == true);
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 97a78a28fb..772cace5b8 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -7,7 +7,7 @@ const net = @This();
const mem = std.mem;
const posix = std.posix;
const fs = std.fs;
-const io = std.io;
+const Io = std.Io;
const native_endian = builtin.target.cpu.arch.endian();
const native_os = builtin.os.tag;
const windows = std.os.windows;
@@ -165,7 +165,7 @@ pub const Address = extern union {
}
}
- pub fn format(self: Address, w: *std.io.Writer) std.io.Writer.Error!void {
+ pub fn format(self: Address, w: *Io.Writer) Io.Writer.Error!void {
switch (self.any.family) {
posix.AF.INET => try self.in.format(w),
posix.AF.INET6 => try self.in6.format(w),
@@ -342,7 +342,7 @@ pub const Ip4Address = extern struct {
self.sa.port = mem.nativeToBig(u16, port);
}
- pub fn format(self: Ip4Address, w: *std.io.Writer) std.io.Writer.Error!void {
+ pub fn format(self: Ip4Address, w: *Io.Writer) Io.Writer.Error!void {
const bytes: *const [4]u8 = @ptrCast(&self.sa.addr);
try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], self.getPort() });
}
@@ -633,7 +633,7 @@ pub const Ip6Address = extern struct {
self.sa.port = mem.nativeToBig(u16, port);
}
- pub fn format(self: Ip6Address, w: *std.io.Writer) std.io.Writer.Error!void {
+ pub fn format(self: Ip6Address, w: *Io.Writer) Io.Writer.Error!void {
const port = mem.bigToNative(u16, self.sa.port);
if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
try w.print("[::ffff:{d}.{d}.{d}.{d}]:{d}", .{
@@ -1348,7 +1348,7 @@ fn parseHosts(
name: []const u8,
family: posix.sa_family_t,
port: u16,
- br: *io.Reader,
+ br: *Io.Reader,
) error{ OutOfMemory, ReadFailed }!void {
while (true) {
const line = br.takeDelimiterExclusive('\n') catch |err| switch (err) {
@@ -1402,7 +1402,7 @@ test parseHosts {
// TODO parsing addresses should not have OS dependencies
return error.SkipZigTest;
}
- var reader: std.io.Reader = .fixed(
+ var reader: Io.Reader = .fixed(
\\127.0.0.1 localhost
\\::1 localhost
\\127.0.0.2 abcd
@@ -1583,7 +1583,7 @@ const ResolvConf = struct {
const Directive = enum { options, nameserver, domain, search };
const Option = enum { ndots, attempts, timeout };
- fn parse(rc: *ResolvConf, reader: *io.Reader) !void {
+ fn parse(rc: *ResolvConf, reader: *Io.Reader) !void {
const gpa = rc.gpa;
while (reader.takeSentinel('\n')) |line_with_comment| {
const line = line: {
@@ -1894,7 +1894,7 @@ pub const Stream = struct {
pub const Reader = switch (native_os) {
.windows => struct {
/// Use `interface` for portable code.
- interface_state: io.Reader,
+ interface_state: Io.Reader,
/// Use `getStream` for portable code.
net_stream: Stream,
/// Use `getError` for portable code.
@@ -1910,14 +1910,17 @@ pub const Stream = struct {
return r.error_state;
}
- pub fn interface(r: *Reader) *io.Reader {
+ pub fn interface(r: *Reader) *Io.Reader {
return &r.interface_state;
}
pub fn init(net_stream: Stream, buffer: []u8) Reader {
return .{
.interface_state = .{
- .vtable = &.{ .stream = stream },
+ .vtable = &.{
+ .stream = stream,
+ .readVec = readVec,
+ },
.buffer = buffer,
.seek = 0,
.end = 0,
@@ -1927,16 +1930,30 @@ pub const Stream = struct {
};
}
- fn stream(io_r: *io.Reader, io_w: *io.Writer, limit: io.Limit) io.Reader.StreamError!usize {
+ fn stream(io_r: *Io.Reader, io_w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize {
+ const dest = limit.slice(try io_w.writableSliceGreedy(1));
+ var bufs: [1][]u8 = .{dest};
+ const n = try readVec(io_r, &bufs);
+ io_w.advance(n);
+ return n;
+ }
+
+ fn readVec(io_r: *std.Io.Reader, data: [][]u8) Io.Reader.Error!usize {
const r: *Reader = @alignCast(@fieldParentPtr("interface_state", io_r));
var iovecs: [max_buffers_len]windows.ws2_32.WSABUF = undefined;
- const bufs = try io_w.writableVectorWsa(&iovecs, limit);
+ const bufs_n, const data_size = try io_r.writableVectorWsa(&iovecs, data);
+ const bufs = iovecs[0..bufs_n];
assert(bufs[0].len != 0);
const n = streamBufs(r, bufs) catch |err| {
r.error_state = err;
return error.ReadFailed;
};
if (n == 0) return error.EndOfStream;
+ if (n > data_size) {
+ io_r.seek = 0;
+ io_r.end = n - data_size;
+ return data_size;
+ }
return n;
}
@@ -1968,7 +1985,7 @@ pub const Stream = struct {
pub const Error = ReadError;
- pub fn interface(r: *Reader) *io.Reader {
+ pub fn interface(r: *Reader) *Io.Reader {
return &r.file_reader.interface;
}
@@ -1996,7 +2013,7 @@ pub const Stream = struct {
pub const Writer = switch (native_os) {
.windows => struct {
/// This field is present on all systems.
- interface: io.Writer,
+ interface: Io.Writer,
/// Use `getStream` for cross-platform support.
stream: Stream,
/// This field is present on all systems.
@@ -2034,7 +2051,7 @@ pub const Stream = struct {
}
}
- fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize {
+ fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
const buffered = io_w.buffered();
comptime assert(native_os == .windows);
@@ -2106,7 +2123,7 @@ pub const Stream = struct {
},
else => struct {
/// This field is present on all systems.
- interface: io.Writer,
+ interface: Io.Writer,
err: ?Error = null,
file_writer: File.Writer,
@@ -2138,7 +2155,7 @@ pub const Stream = struct {
i.* += 1;
}
- fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize {
+ fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
const buffered = io_w.buffered();
var iovecs: [max_buffers_len]posix.iovec_const = undefined;
@@ -2190,7 +2207,7 @@ pub const Stream = struct {
});
}
- fn sendFile(io_w: *io.Writer, file_reader: *File.Reader, limit: io.Limit) io.Writer.FileError!usize {
+ fn sendFile(io_w: *Io.Writer, file_reader: *File.Reader, limit: Io.Limit) Io.Writer.FileError!usize {
const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
const n = try w.file_writer.interface.sendFileHeader(io_w.buffered(), file_reader, limit);
return io_w.consume(n);
diff --git a/lib/std/posix.zig b/lib/std/posix.zig
index 83cd446f28..7da1cedd90 100644
--- a/lib/std/posix.zig
+++ b/lib/std/posix.zig
@@ -204,6 +204,7 @@ pub const ACCMODE = switch (native_os) {
// implements this suggestion.
// https://github.com/SerenityOS/serenity/blob/4adc51fdf6af7d50679c48b39362e062f5a3b2cb/Kernel/API/POSIX/fcntl.h#L28-L30
.serenity => enum(u2) {
+ NONE = 0,
RDONLY = 1,
WRONLY = 2,
RDWR = 3,
@@ -1128,8 +1129,9 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
/// * Windows
/// On these systems, the read races with concurrent writes to the same file descriptor.
pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
+ // NOTE: serenity does not have preadv but it *does* have pwritev.
const have_pread_but_not_preadv = switch (native_os) {
- .windows, .macos, .ios, .watchos, .tvos, .visionos, .haiku => true,
+ .windows, .macos, .ios, .watchos, .tvos, .visionos, .haiku, .serenity => true,
else => false,
};
if (have_pread_but_not_preadv) {
diff --git a/lib/std/start.zig b/lib/std/start.zig
index 43355d34f4..30543ead8a 100644
--- a/lib/std/start.zig
+++ b/lib/std/start.zig
@@ -626,7 +626,6 @@ pub inline fn callMain() u8 {
const result = root.main() catch |err| {
switch (builtin.zig_backend) {
- .stage2_aarch64,
.stage2_powerpc,
.stage2_riscv64,
=> {
@@ -700,6 +699,7 @@ fn maybeIgnoreSigpipe() void {
.visionos,
.dragonfly,
.freebsd,
+ .serenity,
=> true,
else => false,
diff --git a/lib/std/zig.zig b/lib/std/zig.zig
index 486947768d..a692a63795 100644
--- a/lib/std/zig.zig
+++ b/lib/std/zig.zig
@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {
try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));
try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));
}
+
+ pub fn format(id: BuildId, writer: *std.io.Writer) std.io.Writer.Error!void {
+ switch (id) {
+ .none, .fast, .uuid, .sha1, .md5 => {
+ try writer.writeAll(@tagName(id));
+ },
+ .hexstring => |hs| {
+ try writer.print("0x{x}", .{hs.toSlice()});
+ },
+ }
+ }
+
+ test format {
+ try std.testing.expectFmt("none", "{f}", .{@as(BuildId, .none)});
+ try std.testing.expectFmt("fast", "{f}", .{@as(BuildId, .fast)});
+ try std.testing.expectFmt("uuid", "{f}", .{@as(BuildId, .uuid)});
+ try std.testing.expectFmt("sha1", "{f}", .{@as(BuildId, .sha1)});
+ try std.testing.expectFmt("md5", "{f}", .{@as(BuildId, .md5)});
+ try std.testing.expectFmt("0x", "{f}", .{BuildId.initHexString("")});
+ try std.testing.expectFmt("0x1234cdef", "{f}", .{BuildId.initHexString("\x12\x34\xcd\xef")});
+ }
};
pub const LtoMode = enum { none, full, thin };
@@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
///
/// See also `fmtIdFlags`.
-pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
- return .{ .data = .{ .bytes = bytes, .flags = .{} } };
+pub fn fmtId(bytes: []const u8) FormatId {
+ return .{ .bytes = bytes, .flags = .{} };
}
/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
///
/// See also `fmtId`.
-pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) {
- return .{ .data = .{ .bytes = bytes, .flags = flags } };
+pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) FormatId {
+ return .{ .bytes = bytes, .flags = flags };
}
-pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
- return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } };
+pub fn fmtIdPU(bytes: []const u8) FormatId {
+ return .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } };
}
-pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
- return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } };
+pub fn fmtIdP(bytes: []const u8) FormatId {
+ return .{ .bytes = bytes, .flags = .{ .allow_primitive = true } };
}
test fmtId {
@@ -426,7 +447,7 @@ pub const FormatId = struct {
};
/// Print the string as a Zig identifier, escaping it with `@""` syntax if needed.
- fn render(ctx: FormatId, writer: *Writer) Writer.Error!void {
+ pub fn format(ctx: FormatId, writer: *Writer) Writer.Error!void {
const bytes = ctx.bytes;
if (isValidId(bytes) and
(ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and
diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig
index c15693fd62..0405e410ee 100644
--- a/lib/std/zig/Ast.zig
+++ b/lib/std/zig/Ast.zig
@@ -3361,7 +3361,7 @@ pub const Node = struct {
/// The `main_token` might be a ** token, which is shared with a
/// parent/child pointer type and may require special handling.
ptr_type_sentinel,
- /// The `data` field is a `.opt_node_and_node`:
+ /// The `data` field is a `.extra_and_node`:
/// 1. a `ExtraIndex` to `PtrType`.
/// 2. a `Node.Index` to the element type expression.
///
@@ -3370,7 +3370,7 @@ pub const Node = struct {
/// The `main_token` might be a ** token, which is shared with a
/// parent/child pointer type and may require special handling.
ptr_type,
- /// The `data` field is a `.opt_node_and_node`:
+ /// The `data` field is a `.extra_and_node`:
/// 1. a `ExtraIndex` to `PtrTypeBitRange`.
/// 2. a `Node.Index` to the element type expression.
///
diff --git a/lib/std/zip.zig b/lib/std/zip.zig
index b13c1d5010..e1e8e04a36 100644
--- a/lib/std/zip.zig
+++ b/lib/std/zip.zig
@@ -7,8 +7,9 @@ const builtin = @import("builtin");
const std = @import("std");
const File = std.fs.File;
const is_le = builtin.target.cpu.arch.endian() == .little;
-const Writer = std.io.Writer;
-const Reader = std.io.Reader;
+const Writer = std.Io.Writer;
+const Reader = std.Io.Reader;
+const flate = std.compress.flate;
pub const CompressionMethod = enum(u16) {
store = 0,
@@ -117,6 +118,7 @@ pub const EndRecord = extern struct {
pub const FindFileError = File.GetEndPosError || File.SeekError || File.ReadError || error{
ZipNoEndRecord,
EndOfStream,
+ ReadFailed,
};
pub fn findFile(fr: *File.Reader) FindFileError!EndRecord {
@@ -137,8 +139,7 @@ pub const EndRecord = extern struct {
try fr.seekTo(end_pos - @as(u64, new_loaded_len));
const read_buf: []u8 = buf[buf.len - new_loaded_len ..][0..read_len];
- var br = fr.interface().unbuffered();
- br.readSlice(read_buf) catch |err| switch (err) {
+ fr.interface.readSliceAll(read_buf) catch |err| switch (err) {
error.ReadFailed => return fr.err.?,
error.EndOfStream => return error.EndOfStream,
};
@@ -164,7 +165,7 @@ pub const EndRecord = extern struct {
pub const Decompress = struct {
interface: Reader,
state: union {
- inflate: std.compress.flate.Decompress,
+ inflate: flate.Decompress,
store: *Reader,
},
@@ -201,7 +202,7 @@ pub const Decompress = struct {
fn streamDeflate(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {
const d: *Decompress = @fieldParentPtr("interface", r);
- return std.compress.flate.Decompress.read(&d.inflate, w, limit);
+ return flate.Decompress.read(&d.inflate, w, limit);
}
};
@@ -305,7 +306,7 @@ pub const Iterator = struct {
if (locator_end_offset > stream_len)
return error.ZipTruncated;
try input.seekTo(stream_len - locator_end_offset);
- const locator = input.interface.takeStructEndian(EndLocator64, .little) catch |err| switch (err) {
+ const locator = input.interface.takeStruct(EndLocator64, .little) catch |err| switch (err) {
error.ReadFailed => return input.err.?,
error.EndOfStream => return error.EndOfStream,
};
@@ -318,7 +319,7 @@ pub const Iterator = struct {
try input.seekTo(locator.record_file_offset);
- const record64 = input.interface.takeStructEndian(EndRecord64, .little) catch |err| switch (err) {
+ const record64 = input.interface.takeStruct(EndRecord64, .little) catch |err| switch (err) {
error.ReadFailed => return input.err.?,
error.EndOfStream => return error.EndOfStream,
};
@@ -374,7 +375,7 @@ pub const Iterator = struct {
const header_zip_offset = self.cd_zip_offset + self.cd_record_offset;
const input = self.input;
try input.seekTo(header_zip_offset);
- const header = input.interface.takeStructEndian(CentralDirectoryFileHeader, .little) catch |err| switch (err) {
+ const header = input.interface.takeStruct(CentralDirectoryFileHeader, .little) catch |err| switch (err) {
error.ReadFailed => return input.err.?,
error.EndOfStream => return error.EndOfStream,
};
@@ -405,7 +406,7 @@ pub const Iterator = struct {
const extra = extra_buf[0..header.extra_len];
try input.seekTo(header_zip_offset + @sizeOf(CentralDirectoryFileHeader) + header.filename_len);
- input.interface.readSlice(extra) catch |err| switch (err) {
+ input.interface.readSliceAll(extra) catch |err| switch (err) {
error.ReadFailed => return input.err.?,
error.EndOfStream => return error.EndOfStream,
};
@@ -460,7 +461,7 @@ pub const Iterator = struct {
options: ExtractOptions,
filename_buf: []u8,
dest: std.fs.Dir,
- ) !u32 {
+ ) !void {
if (filename_buf.len < self.filename_len)
return error.ZipInsufficientBuffer;
switch (self.compression_method) {
@@ -470,13 +471,13 @@ pub const Iterator = struct {
const filename = filename_buf[0..self.filename_len];
{
try stream.seekTo(self.header_zip_offset + @sizeOf(CentralDirectoryFileHeader));
- try stream.interface.readSlice(filename);
+ try stream.interface.readSliceAll(filename);
}
const local_data_header_offset: u64 = local_data_header_offset: {
const local_header = blk: {
try stream.seekTo(self.file_offset);
- break :blk try stream.interface.takeStructEndian(LocalFileHeader, .little);
+ break :blk try stream.interface.takeStruct(LocalFileHeader, .little);
};
if (!std.mem.eql(u8, &local_header.signature, &local_file_header_sig))
return error.ZipBadFileOffset;
@@ -502,7 +503,7 @@ pub const Iterator = struct {
{
try stream.seekTo(self.file_offset + @sizeOf(LocalFileHeader) + local_header.filename_len);
- try stream.interface.readSlice(extra);
+ try stream.interface.readSliceAll(extra);
}
var extra_offset: usize = 0;
@@ -550,7 +551,7 @@ pub const Iterator = struct {
if (self.uncompressed_size != 0)
return error.ZipBadDirectorySize;
try dest.makePath(filename[0 .. filename.len - 1]);
- return std.hash.Crc32.hash(&.{});
+ return;
}
const out_file = blk: {
@@ -564,31 +565,36 @@ pub const Iterator = struct {
break :blk try dest.createFile(filename, .{ .exclusive = true });
};
defer out_file.close();
- var file_writer = out_file.writer();
- var file_bw = file_writer.writer(&.{});
+ var out_file_buffer: [1024]u8 = undefined;
+ var file_writer = out_file.writer(&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);
- var limited_file_reader = stream.interface.limited(.limited(self.compressed_size));
- var file_read_buffer: [1000]u8 = undefined;
- var decompress_read_buffer: [1000]u8 = undefined;
- var limited_br = limited_file_reader.reader().buffered(&file_read_buffer);
- var decompress: Decompress = undefined;
- var decompress_br = decompress.readable(&limited_br, self.compression_method, &decompress_read_buffer);
- const start_out = file_bw.count;
- var hash_writer = file_bw.hashed(std.hash.Crc32.init());
- var hash_bw = hash_writer.writer(&.{});
- decompress_br.readAll(&hash_bw, .limited(self.uncompressed_size)) catch |err| switch (err) {
- error.ReadFailed => return stream.err.?,
- error.WriteFailed => return file_writer.err.?,
- error.EndOfStream => return error.ZipDecompressTruncated,
- };
- if (limited_file_reader.remaining.nonzero()) return error.ZipDecompressTruncated;
- const written = file_bw.count - start_out;
- if (written != self.uncompressed_size) return error.ZipUncompressSizeMismatch;
- return hash_writer.hasher.final();
+
+ // 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,
+ }
+ try file_writer.end();
}
};
};
@@ -636,25 +642,21 @@ pub const ExtractOptions = struct {
/// Allow filenames within the zip to use backslashes. Back slashes are normalized
/// to forward slashes before forwarding them to platform APIs.
allow_backslashes: bool = false,
-
diagnostics: ?*Diagnostics = null,
+ verify_checksums: bool = false,
};
/// Extract the zipped files to the given `dest` directory.
pub fn extract(dest: std.fs.Dir, fr: *File.Reader, options: ExtractOptions) !void {
+ if (options.verify_checksums) @panic("TODO unimplemented");
+
var iter = try Iterator.init(fr);
var filename_buf: [std.fs.max_path_bytes]u8 = undefined;
while (try iter.next()) |entry| {
- const crc32 = try entry.extract(fr, options, &filename_buf, dest);
- if (crc32 != entry.crc32)
- return error.ZipCrcMismatch;
+ try entry.extract(fr, options, &filename_buf, dest);
if (options.diagnostics) |d| {
try d.nextFilename(filename_buf[0..entry.filename_len]);
}
}
}
-
-test {
- _ = @import("zip/test.zig");
-}
diff --git a/lib/std/zip/test.zig b/lib/std/zip/test.zig
deleted file mode 100644
index a45cded83b..0000000000
--- a/lib/std/zip/test.zig
+++ /dev/null
@@ -1,515 +0,0 @@
-const std = @import("std");
-const testing = std.testing;
-const zip = @import("../zip.zig");
-const maxInt = std.math.maxInt;
-const assert = std.debug.assert;
-const Writer = std.io.Writer;
-
-const File = struct {
- name: []const u8,
- content: []const u8,
- compression: zip.CompressionMethod,
-};
-
-fn expectFiles(
- test_files: []const File,
- dir: std.fs.Dir,
- opt: struct {
- strip_prefix: ?[]const u8 = null,
- },
-) !void {
- for (test_files) |test_file| {
- var normalized_sub_path_buf: [std.fs.max_path_bytes]u8 = undefined;
-
- const name = blk: {
- if (opt.strip_prefix) |strip_prefix| {
- try testing.expect(test_file.name.len >= strip_prefix.len);
- try testing.expectEqualStrings(strip_prefix, test_file.name[0..strip_prefix.len]);
- break :blk test_file.name[strip_prefix.len..];
- }
- break :blk test_file.name;
- };
- const normalized_sub_path = normalized_sub_path_buf[0..name.len];
- @memcpy(normalized_sub_path, name);
- std.mem.replaceScalar(u8, normalized_sub_path, '\\', '/');
- var file = try dir.openFile(normalized_sub_path, .{});
- defer file.close();
- var content_buf: [4096]u8 = undefined;
- var file_reader = file.reader(&content_buf);
- const n = try file_reader.interface.readSliceShort(&content_buf);
- try testing.expectEqualStrings(test_file.content, content_buf[0..n]);
- }
-}
-
-// Used to store any data from writing a file to the zip archive that's needed
-// when writing the corresponding central directory record.
-const FileStore = struct {
- compression: zip.CompressionMethod,
- file_offset: u64,
- crc32: u32,
- compressed_size: u32,
- uncompressed_size: usize,
-};
-
-fn makeZip(file_writer: *std.fs.File.Writer, files: []const File, options: WriteZipOptions) !void {
- const store = try std.testing.allocator.alloc(FileStore, files.len);
- defer std.testing.allocator.free(store);
- try makeZipWithStore(file_writer, files, options, store);
-}
-
-fn makeZipWithStore(
- file_writer: *std.fs.File.Writer,
- files: []const File,
- options: WriteZipOptions,
- store: []FileStore,
-) !void {
- try writeZip(&file_writer.interface, files, store, options);
-}
-
-const WriteZipOptions = struct {
- end: ?EndRecordOptions = null,
- local_header: ?LocalHeaderOptions = null,
-};
-const LocalHeaderOptions = struct {
- zip64: ?LocalHeaderZip64Options = null,
- compressed_size: ?u32 = null,
- uncompressed_size: ?u32 = null,
- extra_len: ?u16 = null,
-};
-const LocalHeaderZip64Options = struct {
- data_size: ?u16 = null,
-};
-const EndRecordOptions = struct {
- zip64: ?Zip64Options = null,
- sig: ?[4]u8 = null,
- disk_number: ?u16 = null,
- central_directory_disk_number: ?u16 = null,
- record_count_disk: ?u16 = null,
- record_count_total: ?u16 = null,
- central_directory_size: ?u32 = null,
- central_directory_offset: ?u32 = null,
- comment_len: ?u16 = null,
- comment: ?[]const u8 = null,
-};
-const Zip64Options = struct {
- locator_sig: ?[4]u8 = null,
- locator_zip64_disk_count: ?u32 = null,
- locator_record_file_offset: ?u64 = null,
- locator_total_disk_count: ?u32 = null,
- //record_size: ?u64 = null,
- central_directory_size: ?u64 = null,
-};
-
-fn writeZip(
- writer: *Writer,
- files: []const File,
- store: []FileStore,
- options: WriteZipOptions,
-) !void {
- if (store.len < files.len) return error.FileStoreTooSmall;
- var zipper: Zipper = .init(writer);
- for (files, 0..) |file, i| {
- store[i] = try zipper.writeFile(.{
- .name = file.name,
- .content = file.content,
- .compression = file.compression,
- .write_options = options,
- });
- }
- for (files, 0..) |file, i| {
- try zipper.writeCentralRecord(store[i], .{
- .name = file.name,
- });
- }
- try zipper.writeEndRecord(if (options.end) |e| e else .{});
-}
-
-/// Provides methods to format and write the contents of a zip archive
-/// to the underlying Writer.
-const Zipper = struct {
- writer: *Writer,
- init_count: u64,
- central_count: u64 = 0,
- first_central_offset: ?u64 = null,
- last_central_limit: ?u64 = null,
-
- fn init(writer: *Writer) Zipper {
- return .{ .writer = writer, .init_count = writer.count };
- }
-
- fn writeFile(
- self: *Zipper,
- opt: struct {
- name: []const u8,
- content: []const u8,
- compression: zip.CompressionMethod,
- write_options: WriteZipOptions,
- },
- ) !FileStore {
- const writer = self.writer;
-
- const file_offset: u64 = writer.count - self.init_count;
- const crc32 = std.hash.Crc32.hash(opt.content);
-
- const header_options = opt.write_options.local_header;
- {
- var compressed_size: u32 = 0;
- var uncompressed_size: u32 = 0;
- var extra_len: u16 = 0;
- if (header_options) |hdr_options| {
- compressed_size = if (hdr_options.compressed_size) |size| size else 0;
- uncompressed_size = if (hdr_options.uncompressed_size) |size| size else @intCast(opt.content.len);
- extra_len = if (hdr_options.extra_len) |len| len else 0;
- }
- const hdr: zip.LocalFileHeader = .{
- .signature = zip.local_file_header_sig,
- .version_needed_to_extract = 10,
- .flags = .{ .encrypted = false, ._ = 0 },
- .compression_method = opt.compression,
- .last_modification_time = 0,
- .last_modification_date = 0,
- .crc32 = crc32,
- .compressed_size = compressed_size,
- .uncompressed_size = uncompressed_size,
- .filename_len = @intCast(opt.name.len),
- .extra_len = extra_len,
- };
- try writer.writeStructEndian(hdr, .little);
- }
- try writer.writeAll(opt.name);
-
- if (header_options) |hdr| {
- if (hdr.zip64) |options| {
- try writer.writeInt(u16, 0x0001, .little);
- const data_size = if (options.data_size) |size| size else 8;
- try writer.writeInt(u16, data_size, .little);
- try writer.writeInt(u64, 0, .little);
- try writer.writeInt(u64, @intCast(opt.content.len), .little);
- }
- }
-
- var compressed_size: u32 = undefined;
- switch (opt.compression) {
- .store => {
- try writer.writeAll(opt.content);
- compressed_size = @intCast(opt.content.len);
- },
- .deflate => {
- const offset = writer.count;
- var br: std.io.Reader = .fixed(opt.content);
- var compress: std.compress.flate.Compress = .init(&br, .{});
- var compress_br = compress.reader(&.{});
- const n = try compress_br.streamRemaining(writer);
- assert(br.seek == opt.content.len);
- try testing.expectEqual(n, writer.count - offset);
- compressed_size = @intCast(n);
- },
- else => unreachable,
- }
- return .{
- .compression = opt.compression,
- .file_offset = file_offset,
- .crc32 = crc32,
- .compressed_size = compressed_size,
- .uncompressed_size = opt.content.len,
- };
- }
-
- fn writeCentralRecord(
- self: *Zipper,
- store: FileStore,
- opt: struct {
- name: []const u8,
- version_needed_to_extract: u16 = 10,
- },
- ) !void {
- if (self.first_central_offset == null) {
- self.first_central_offset = self.writer.count - self.init_count;
- }
- self.central_count += 1;
-
- const hdr: zip.CentralDirectoryFileHeader = .{
- .signature = zip.central_file_header_sig,
- .version_made_by = 0,
- .version_needed_to_extract = opt.version_needed_to_extract,
- .flags = .{ .encrypted = false, ._ = 0 },
- .compression_method = store.compression,
- .last_modification_time = 0,
- .last_modification_date = 0,
- .crc32 = store.crc32,
- .compressed_size = store.compressed_size,
- .uncompressed_size = @intCast(store.uncompressed_size),
- .filename_len = @intCast(opt.name.len),
- .extra_len = 0,
- .comment_len = 0,
- .disk_number = 0,
- .internal_file_attributes = 0,
- .external_file_attributes = 0,
- .local_file_header_offset = @intCast(store.file_offset),
- };
- try self.writer.writeStructEndian(hdr, .little);
- try self.writer.writeAll(opt.name);
- self.last_central_limit = self.writer.count - self.init_count;
- }
-
- fn writeEndRecord(self: *Zipper, opt: EndRecordOptions) !void {
- const cd_offset = self.first_central_offset orelse 0;
- const cd_end = self.last_central_limit orelse 0;
-
- if (opt.zip64) |zip64| {
- const end64_off = cd_end;
- const fixed: zip.EndRecord64 = .{
- .signature = zip.end_record64_sig,
- .end_record_size = @sizeOf(zip.EndRecord64) - 12,
- .version_made_by = 0,
- .version_needed_to_extract = 45,
- .disk_number = 0,
- .central_directory_disk_number = 0,
- .record_count_disk = @intCast(self.central_count),
- .record_count_total = @intCast(self.central_count),
- .central_directory_size = @intCast(cd_end - cd_offset),
- .central_directory_offset = @intCast(cd_offset),
- };
- try self.writer.writeStructEndian(fixed, .little);
- const locator: zip.EndLocator64 = .{
- .signature = if (zip64.locator_sig) |s| s else zip.end_locator64_sig,
- .zip64_disk_count = if (zip64.locator_zip64_disk_count) |c| c else 0,
- .record_file_offset = if (zip64.locator_record_file_offset) |o| o else @intCast(end64_off),
- .total_disk_count = if (zip64.locator_total_disk_count) |c| c else 1,
- };
- try self.writer.writeStructEndian(locator, .little);
- }
- const hdr: zip.EndRecord = .{
- .signature = if (opt.sig) |s| s else zip.end_record_sig,
- .disk_number = if (opt.disk_number) |n| n else 0,
- .central_directory_disk_number = if (opt.central_directory_disk_number) |n| n else 0,
- .record_count_disk = if (opt.record_count_disk) |c| c else @intCast(self.central_count),
- .record_count_total = if (opt.record_count_total) |c| c else @intCast(self.central_count),
- .central_directory_size = if (opt.central_directory_size) |s| s else @intCast(cd_end - cd_offset),
- .central_directory_offset = if (opt.central_directory_offset) |o| o else @intCast(cd_offset),
- .comment_len = if (opt.comment_len) |l| l else (if (opt.comment) |c| @as(u16, @intCast(c.len)) else 0),
- };
- try self.writer.writeStructEndian(hdr, .little);
- if (opt.comment) |c|
- try self.writer.writeAll(c);
- }
-};
-
-fn testZip(options: zip.ExtractOptions, comptime files: []const File, write_opt: WriteZipOptions) !void {
- var store: [files.len]FileStore = undefined;
- try testZipWithStore(options, files, write_opt, &store);
-}
-fn testZipWithStore(
- options: zip.ExtractOptions,
- test_files: []const File,
- write_opt: WriteZipOptions,
- store: []FileStore,
-) !void {
- var tmp = testing.tmpDir(.{ .no_follow = true });
- defer tmp.cleanup();
-
- var file = tmp.createFile();
- defer file.close();
- var buffer: [100]u8 = undefined;
- var file_writer = file.writer(&buffer);
- try makeZipWithStore(&file_writer, test_files, write_opt, store);
- var file_reader = file_writer.moveToReader();
- try zip.extract(tmp.dir, &file_reader, options);
- try expectFiles(test_files, tmp.dir, .{});
-}
-fn testZipError(expected_error: anyerror, file: File, options: zip.ExtractOptions) !void {
- var tmp = testing.tmpDir(.{ .no_follow = true });
- defer tmp.cleanup();
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var buffer: [100]u8 = undefined;
- var file_writer = tmp_file.writer(&buffer);
- var store: [1]FileStore = undefined;
- try makeZipWithStore(&file_writer, &[_]File{file}, .{}, &store);
- var file_reader = file_writer.moveToReader();
- try testing.expectError(expected_error, zip.extract(tmp.dir, &file_reader, options));
-}
-
-test "zip one file" {
- try testZip(.{}, &[_]File{
- .{ .name = "onefile.txt", .content = "Just a single file\n", .compression = .store },
- }, .{});
-}
-test "zip multiple files" {
- try testZip(.{ .allow_backslashes = true }, &[_]File{
- .{ .name = "foo", .content = "a foo file\n", .compression = .store },
- .{ .name = "subdir/bar", .content = "bar is this right?\nanother newline\n", .compression = .store },
- .{ .name = "subdir\\whoa", .content = "you can do backslashes", .compression = .store },
- .{ .name = "subdir/another/baz", .content = "bazzy mc bazzerson", .compression = .store },
- }, .{});
-}
-test "zip deflated" {
- try testZip(.{}, &[_]File{
- .{ .name = "deflateme", .content = "This is a deflated file.\nIt should be smaller in the Zip file1\n", .compression = .deflate },
- // TODO: re-enable this if/when we add support for deflate64
- //.{ .name = "deflateme64", .content = "The 64k version of deflate!\n", .compression = .deflate64 },
- .{ .name = "raw", .content = "Not all files need to be deflated in the same Zip.\n", .compression = .store },
- }, .{});
-}
-test "zip verify filenames" {
- // no empty filenames
- try testZipError(error.ZipBadFilename, .{ .name = "", .content = "", .compression = .store }, .{});
- // no absolute paths
- try testZipError(error.ZipBadFilename, .{ .name = "/", .content = "", .compression = .store }, .{});
- try testZipError(error.ZipBadFilename, .{ .name = "/foo", .content = "", .compression = .store }, .{});
- try testZipError(error.ZipBadFilename, .{ .name = "/foo/bar", .content = "", .compression = .store }, .{});
- // no '..' components
- try testZipError(error.ZipBadFilename, .{ .name = "..", .content = "", .compression = .store }, .{});
- try testZipError(error.ZipBadFilename, .{ .name = "foo/..", .content = "", .compression = .store }, .{});
- try testZipError(error.ZipBadFilename, .{ .name = "foo/bar/..", .content = "", .compression = .store }, .{});
- try testZipError(error.ZipBadFilename, .{ .name = "foo/bar/../", .content = "", .compression = .store }, .{});
- // no backslashes
- try testZipError(error.ZipFilenameHasBackslash, .{ .name = "foo\\bar", .content = "", .compression = .store }, .{});
-}
-
-test "zip64" {
- const test_files = [_]File{
- .{ .name = "fram", .content = "fram foo fro fraba", .compression = .store },
- .{ .name = "subdir/barro", .content = "aljdk;jal;jfd;lajkf", .compression = .store },
- };
-
- try testZip(.{}, &test_files, .{
- .end = .{
- .zip64 = .{},
- .record_count_disk = std.math.maxInt(u16), // trigger zip64
- },
- });
- try testZip(.{}, &test_files, .{
- .end = .{
- .zip64 = .{},
- .record_count_total = std.math.maxInt(u16), // trigger zip64
- },
- });
- try testZip(.{}, &test_files, .{
- .end = .{
- .zip64 = .{},
- .record_count_disk = std.math.maxInt(u16), // trigger zip64
- .record_count_total = std.math.maxInt(u16), // trigger zip64
- },
- });
- try testZip(.{}, &test_files, .{
- .end = .{
- .zip64 = .{},
- .central_directory_size = std.math.maxInt(u32), // trigger zip64
- },
- });
- try testZip(.{}, &test_files, .{
- .end = .{
- .zip64 = .{},
- .central_directory_offset = std.math.maxInt(u32), // trigger zip64
- },
- });
- try testZip(.{}, &test_files, .{
- .end = .{
- .zip64 = .{},
- .central_directory_offset = std.math.maxInt(u32), // trigger zip64
- },
- .local_header = .{
- .zip64 = .{ // trigger local header zip64
- .data_size = 16,
- },
- .compressed_size = std.math.maxInt(u32),
- .uncompressed_size = std.math.maxInt(u32),
- .extra_len = 20,
- },
- });
-}
-
-test "bad zip files" {
- var tmp = testing.tmpDir(.{ .no_follow = true });
- defer tmp.cleanup();
- var buffer: [4096]u8 = undefined;
-
- const file_a = [_]File{.{ .name = "a", .content = "", .compression = .store }};
-
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &.{}, .{ .end = .{ .sig = [_]u8{ 1, 2, 3, 4 } } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipNoEndRecord, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &.{}, .{ .end = .{ .comment_len = 1 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipNoEndRecord, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &.{}, .{ .end = .{ .comment = "a", .comment_len = 0 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipNoEndRecord, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &.{}, .{ .end = .{ .disk_number = 1 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipMultiDiskUnsupported, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &.{}, .{ .end = .{ .central_directory_disk_number = 1 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipMultiDiskUnsupported, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &.{}, .{ .end = .{ .record_count_disk = 1 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipDiskRecordCountTooLarge, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &.{}, .{ .end = .{ .central_directory_size = 1 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipCdOversized, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &file_a, .{ .end = .{ .central_directory_size = 0 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipCdUndersized, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &file_a, .{ .end = .{ .central_directory_offset = 0 } });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipBadCdOffset, zip.extract(tmp.dir, &file_reader, .{}));
- }
- {
- const tmp_file = tmp.createFile();
- defer tmp_file.close();
- var file_writer = tmp_file.writer(&buffer);
- try makeZip(&file_writer, &file_a, .{
- .end = .{
- .zip64 = .{ .locator_sig = [_]u8{ 1, 2, 3, 4 } },
- .central_directory_size = std.math.maxInt(u32), // trigger 64
- },
- });
- var file_reader = file_writer.moveToReader();
- try testing.expectError(error.ZipBadLocatorSig, zip.extract(tmp.dir, &file_reader, .{}));
- }
-}
diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig
index 96a7fa6595..5f74400c29 100644
--- a/lib/std/zon/parse.zig
+++ b/lib/std/zon/parse.zig
@@ -2774,11 +2774,11 @@ test "std.zon parse float" {
// Test big integers
try std.testing.expectEqual(
- @as(f32, 36893488147419103231),
+ @as(f32, 36893488147419103231.0),
try fromSlice(f32, gpa, "36893488147419103231", null, .{}),
);
try std.testing.expectEqual(
- @as(f32, -36893488147419103231),
+ @as(f32, -36893488147419103231.0),
try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),
);
try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(
@@ -2788,7 +2788,7 @@ test "std.zon parse float" {
null,
.{},
));
- try std.testing.expectEqual(@as(f32, 0x1ffffffffffffffff), try fromSlice(
+ try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSlice(
f32,
gpa,
"0x1ffffffffffffffff",
diff --git a/src/Compilation.zig b/src/Compilation.zig
index cd0a7e5809..69215d80b1 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
if (options.skip_linker_dependencies) break :s .none;
const want = options.want_compiler_rt orelse is_exe_or_dyn_lib;
if (!want) break :s .none;
- if (have_zcu) {
+ if (have_zcu and target_util.canBuildLibCompilerRt(target, use_llvm, build_options.have_llvm and use_llvm)) {
if (output_mode == .Obj) break :s .zcu;
- if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64)
- break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
+ if (switch (target_util.zigBackend(target, use_llvm)) {
+ else => false,
+ .stage2_aarch64, .stage2_x86_64 => target.ofmt == .coff,
+ }) break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
}
if (is_exe_or_dyn_lib) break :s .lib;
break :s .obj;
@@ -1854,7 +1856,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib);
if (!want_ubsan_rt) break :s .none;
if (options.skip_linker_dependencies) break :s .none;
- if (have_zcu) break :s .zcu;
+ if (have_zcu and target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm and use_llvm)) break :s .zcu;
if (is_exe_or_dyn_lib) break :s .lib;
break :s .obj;
};
diff --git a/src/Package/Fetch.zig b/src/Package/Fetch.zig
index e47b1cd833..c3c69a250b 100644
--- a/src/Package/Fetch.zig
+++ b/src/Package/Fetch.zig
@@ -1203,12 +1203,11 @@ fn unpackResource(
return unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
},
.@"tar.gz" => {
- const reader = resource.reader();
- var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);
- var dcp = std.compress.gzip.decompressor(br.reader());
- var adapter_buffer: [1024]u8 = undefined;
- var adapter = dcp.reader().adaptToNewApi(&adapter_buffer);
- return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
+ var adapter_buffer: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
+ var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
+ var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
+ var decompress: std.compress.flate.Decompress = .init(&adapter.new_interface, .gzip, &flate_buffer);
+ return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
},
.@"tar.xz" => {
const gpa = f.arena.child_allocator;
@@ -1352,7 +1351,10 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {
));
defer zip_file.close();
- std.zip.extract(out_dir, zip_file.seekableStream(), .{
+ var zip_file_buffer: [1024]u8 = undefined;
+ var zip_file_reader = zip_file.reader(&zip_file_buffer);
+
+ std.zip.extract(out_dir, &zip_file_reader, .{
.allow_backslashes = true,
.diagnostics = &diagnostics,
}) catch |err| return f.fail(f.location_tok, try eb.printString(
@@ -1384,25 +1386,28 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
defer pack_dir.close();
var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });
defer pack_file.close();
- _ = try resource.fetch_stream.reader().readRemaining(pack_file.writer());
- try pack_file.sync();
+ var pack_file_buffer: [4096]u8 = undefined;
+ var fifo = std.fifo.LinearFifo(u8, .{ .Slice = {} }).init(&pack_file_buffer);
+ try fifo.pump(resource.fetch_stream.reader(), pack_file.deprecatedWriter());
+
+ var pack_file_reader = pack_file.reader(&pack_file_buffer);
var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });
defer index_file.close();
+ var index_file_buffer: [2000]u8 = undefined;
+ var index_file_writer = index_file.writer(&index_file_buffer);
{
const index_prog_node = f.prog_node.start("Index pack", 0);
defer index_prog_node.end();
- var buffer: [4096]u8 = undefined;
- var index_file_writer = index_file.writer(&buffer);
- try git.indexPack(gpa, object_format, pack_file, &index_file_writer.interface);
- try index_file_writer.flush();
- try index_file.sync();
+ try git.indexPack(gpa, object_format, &pack_file_reader, &index_file_writer);
}
{
+ var index_file_reader = index_file.reader(&index_file_buffer);
const checkout_prog_node = f.prog_node.start("Checkout", 0);
defer checkout_prog_node.end();
- var repository = try git.Repository.init(gpa, object_format, pack_file, index_file);
+ var repository: git.Repository = undefined;
+ try repository.init(gpa, object_format, &pack_file_reader, &index_file_reader);
defer repository.deinit();
var diagnostics: git.Diagnostics = .{ .allocator = arena };
try repository.checkout(out_dir, resource.want_oid, &diagnostics);
@@ -2069,72 +2074,6 @@ const UnpackResult = struct {
}
};
-test "zip" {
- const gpa = std.testing.allocator;
- var tmp = std.testing.tmpDir(.{});
- defer tmp.cleanup();
-
- const test_files = [_]std.zip.testutil.File{
- .{ .name = "foo", .content = "this is just foo\n", .compression = .store },
- .{ .name = "bar", .content = "another file\n", .compression = .deflate },
- };
- {
- var zip_file = try tmp.dir.createFile("test.zip", .{});
- defer zip_file.close();
- var bw = std.io.bufferedWriter(zip_file.deprecatedWriter());
- var store: [test_files.len]std.zip.testutil.FileStore = undefined;
- try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{});
- try bw.flush();
- }
-
- const zip_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/test.zip", .{tmp.sub_path});
- defer gpa.free(zip_path);
-
- var fb: TestFetchBuilder = undefined;
- var fetch = try fb.build(gpa, tmp.dir, zip_path);
- defer fb.deinit();
-
- try fetch.run();
-
- var out = try fb.packageDir();
- defer out.close();
-
- try std.zip.testutil.expectFiles(&test_files, out, .{});
-}
-
-test "zip with one root folder" {
- const gpa = std.testing.allocator;
- var tmp = std.testing.tmpDir(.{});
- defer tmp.cleanup();
-
- const test_files = [_]std.zip.testutil.File{
- .{ .name = "the_root_folder/foo.zig", .content = "// this is foo.zig\n", .compression = .store },
- .{ .name = "the_root_folder/README.md", .content = "# The foo.zig README\n", .compression = .store },
- };
- {
- var zip_file = try tmp.dir.createFile("test.zip", .{});
- defer zip_file.close();
- var bw = std.io.bufferedWriter(zip_file.deprecatedWriter());
- var store: [test_files.len]std.zip.testutil.FileStore = undefined;
- try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{});
- try bw.flush();
- }
-
- const zip_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/test.zip", .{tmp.sub_path});
- defer gpa.free(zip_path);
-
- var fb: TestFetchBuilder = undefined;
- var fetch = try fb.build(gpa, tmp.dir, zip_path);
- defer fb.deinit();
-
- try fetch.run();
-
- var out = try fb.packageDir();
- defer out.close();
-
- try std.zip.testutil.expectFiles(&test_files, out, .{ .strip_prefix = "the_root_folder/" });
-}
-
test "tarball with duplicate paths" {
// This tarball has duplicate path 'dir1/file1' to simulate case sensitve
// file system on any file sytstem.
diff --git a/src/Package/Fetch/git.zig b/src/Package/Fetch/git.zig
index 69cfb3ec66..61919ee883 100644
--- a/src/Package/Fetch/git.zig
+++ b/src/Package/Fetch/git.zig
@@ -73,6 +73,33 @@ pub const Oid = union(Format) {
}
};
+ const Hashing = union(Format) {
+ sha1: std.Io.Writer.Hashing(Sha1),
+ sha256: std.Io.Writer.Hashing(Sha256),
+
+ fn init(oid_format: Format, buffer: []u8) Hashing {
+ return switch (oid_format) {
+ .sha1 => .{ .sha1 = .init(buffer) },
+ .sha256 => .{ .sha256 = .init(buffer) },
+ };
+ }
+
+ fn writer(h: *@This()) *std.Io.Writer {
+ return switch (h.*) {
+ inline else => |*inner| &inner.writer,
+ };
+ }
+
+ fn final(h: *@This()) Oid {
+ switch (h.*) {
+ inline else => |*inner, tag| {
+ inner.writer.flush() catch unreachable; // hashers cannot fail
+ return @unionInit(Oid, @tagName(tag), inner.hasher.finalResult());
+ },
+ }
+ }
+ };
+
pub fn fromBytes(oid_format: Format, bytes: []const u8) Oid {
assert(bytes.len == oid_format.byteLength());
return switch (oid_format) {
@@ -80,8 +107,15 @@ pub const Oid = union(Format) {
};
}
+<<<<<<< HEAD
pub fn readBytes(oid_format: Format, reader: *std.io.Reader) std.io.Reader.Error!Oid {
+||||||| 733b208256
+ pub fn readBytes(oid_format: Format, reader: anytype) @TypeOf(reader).NoEofError!Oid {
+=======
+ pub fn readBytes(oid_format: Format, reader: *std.Io.Reader) !Oid {
+>>>>>>> origin/flate
return switch (oid_format) {
+<<<<<<< HEAD
.sha1 => {
var result: Oid = .{ .sha1 = undefined };
try reader.readSlice(&result.sha1);
@@ -92,6 +126,11 @@ pub const Oid = union(Format) {
try reader.readSlice(&result.sha256);
return result;
},
+||||||| 733b208256
+ inline else => |tag| @unionInit(Oid, @tagName(tag), try reader.readBytesNoEof(tag.byteLength())),
+=======
+ inline else => |tag| @unionInit(Oid, @tagName(tag), (try reader.takeArray(tag.byteLength())).*),
+>>>>>>> origin/flate
};
}
@@ -261,7 +300,6 @@ pub const Repository = struct {
};
defer file.close();
try file.writeAll(file_object.data);
- try file.sync();
},
.symlink => {
try repository.odb.seekOid(entry.oid);
@@ -392,15 +430,27 @@ const Odb = struct {
/// Reads the object at the current position in the database.
fn readObject(odb: *Odb) !Object {
+<<<<<<< HEAD
var base_offset = odb.pack_file.pos;
const pack_br = &odb.pack_file.interface;
+||||||| 733b208256
+ var base_offset = try odb.pack_file.getPos();
+=======
+ var base_offset = odb.pack_file.logicalPos();
+>>>>>>> origin/flate
var base_header: EntryHeader = undefined;
var delta_offsets: std.ArrayListUnmanaged(u64) = .empty;
defer delta_offsets.deinit(odb.allocator);
const base_object = while (true) {
if (odb.cache.get(base_offset)) |base_object| break base_object;
+<<<<<<< HEAD
base_header = try EntryHeader.read(odb.format, pack_br);
+||||||| 733b208256
+ base_header = try EntryHeader.read(odb.format, odb.pack_file.deprecatedReader());
+=======
+ base_header = try EntryHeader.read(odb.format, &odb.pack_file.interface);
+>>>>>>> origin/flate
switch (base_header) {
.ofs_delta => |ofs_delta| {
try delta_offsets.append(odb.allocator, base_offset);
@@ -410,10 +460,22 @@ const Odb = struct {
.ref_delta => |ref_delta| {
try delta_offsets.append(odb.allocator, base_offset);
try odb.seekOid(ref_delta.base_object);
+<<<<<<< HEAD
base_offset = odb.pack_file.pos - pack_br.bufferedLen();
+||||||| 733b208256
+ base_offset = try odb.pack_file.getPos();
+=======
+ base_offset = odb.pack_file.logicalPos();
+>>>>>>> origin/flate
},
else => {
+<<<<<<< HEAD
const base_data = try readObjectRaw(odb.allocator, pack_br, base_header.uncompressedLength());
+||||||| 733b208256
+ const base_data = try readObjectRaw(odb.allocator, odb.pack_file.deprecatedReader(), base_header.uncompressedLength());
+=======
+ const base_data = try readObjectRaw(odb.allocator, &odb.pack_file.interface, base_header.uncompressedLength());
+>>>>>>> origin/flate
errdefer odb.allocator.free(base_data);
const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
try odb.cache.put(odb.allocator, base_offset, base_object);
@@ -443,8 +505,14 @@ const Odb = struct {
const found_index = while (start_index < end_index) {
const mid_index = start_index + (end_index - start_index) / 2;
try odb.index_file.seekTo(IndexHeader.size + mid_index * oid_length);
+<<<<<<< HEAD
var br = odb.index_file.interface().unbuffered();
const mid_oid = try Oid.readBytes(odb.format, &br);
+||||||| 733b208256
+ const mid_oid = try Oid.readBytes(odb.format, odb.index_file.deprecatedReader());
+=======
+ const mid_oid = try Oid.readBytes(odb.format, &odb.index_file.interface);
+>>>>>>> origin/flate
switch (mem.order(u8, mid_oid.slice(), oid.slice())) {
.lt => start_index = mid_index + 1,
.gt => end_index = mid_index,
@@ -456,14 +524,26 @@ const Odb = struct {
const offset_values_start = IndexHeader.size + n_objects * (oid_length + 4);
var buffer: [8]u8 = undefined;
try odb.index_file.seekTo(offset_values_start + found_index * 4);
+<<<<<<< HEAD
var br = odb.index_file.interface().buffered(&buffer);
const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try br.takeInt(u32, .big));
+||||||| 733b208256
+ const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.deprecatedReader().readInt(u32, .big));
+=======
+ const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.interface.takeInt(u32, .big));
+>>>>>>> origin/flate
const pack_offset = pack_offset: {
if (l1_offset.big) {
const l2_offset_values_start = offset_values_start + n_objects * 4;
try odb.index_file.seekTo(l2_offset_values_start + l1_offset.value * 4);
+<<<<<<< HEAD
br = odb.index_file.interface().buffered(&buffer);
break :pack_offset try br.takeInt(u64, .big);
+||||||| 733b208256
+ break :pack_offset try odb.index_file.deprecatedReader().readInt(u64, .big);
+=======
+ break :pack_offset try odb.index_file.interface.takeInt(u64, .big);
+>>>>>>> origin/flate
} else {
break :pack_offset l1_offset.value;
}
@@ -1119,12 +1199,48 @@ const PackHeader = struct {
const signature = "PACK";
const supported_version = 2;
+<<<<<<< HEAD
fn read(reader: *std.io.Reader) !PackHeader {
const actual_signature = try reader.take(4);
if (!mem.eql(u8, actual_signature, signature)) return error.InvalidHeader;
const version = try reader.takeInt(u32, .big);
+||||||| 733b208256
+ fn read(reader: anytype) !PackHeader {
+ const actual_signature = reader.readBytesNoEof(4) catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidHeader,
+ else => |other| return other,
+ };
+ if (!mem.eql(u8, &actual_signature, signature)) return error.InvalidHeader;
+ const version = reader.readInt(u32, .big) catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidHeader,
+ else => |other| return other,
+ };
+=======
+ fn read(reader: *std.Io.Reader) !PackHeader {
+ const actual_signature = reader.take(4) catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidHeader,
+ else => |other| return other,
+ };
+ if (!mem.eql(u8, actual_signature, signature)) return error.InvalidHeader;
+ const version = reader.takeInt(u32, .big) catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidHeader,
+ else => |other| return other,
+ };
+>>>>>>> origin/flate
if (version != supported_version) return error.UnsupportedVersion;
+<<<<<<< HEAD
const total_objects = try reader.takeInt(u32, .big);
+||||||| 733b208256
+ const total_objects = reader.readInt(u32, .big) catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidHeader,
+ else => |other| return other,
+ };
+=======
+ const total_objects = reader.takeInt(u32, .big) catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidHeader,
+ else => |other| return other,
+ };
+>>>>>>> origin/flate
return .{ .total_objects = total_objects };
}
};
@@ -1173,10 +1289,30 @@ const EntryHeader = union(Type) {
};
}
+<<<<<<< HEAD
fn read(format: Oid.Format, reader: *std.io.Reader) !EntryHeader {
+||||||| 733b208256
+ fn read(format: Oid.Format, reader: anytype) !EntryHeader {
+=======
+ fn read(format: Oid.Format, reader: *std.Io.Reader) !EntryHeader {
+>>>>>>> origin/flate
const InitialByte = packed struct { len: u4, type: u3, has_next: bool };
+<<<<<<< HEAD
const initial: InitialByte = @bitCast(try reader.takeByte());
const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;
+||||||| 733b208256
+ const initial: InitialByte = @bitCast(reader.readByte() catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidFormat,
+ else => |other| return other,
+ });
+ const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;
+=======
+ const initial: InitialByte = @bitCast(reader.takeByte() catch |e| switch (e) {
+ error.EndOfStream => return error.InvalidFormat,
+ else => |other| return other,
+ });
+ const rest_len = if (initial.has_next) try reader.takeLeb128(u64) else 0;
+>>>>>>> origin/flate
var uncompressed_length: u64 = initial.len;
uncompressed_length |= std.math.shlExact(u64, rest_len, 4) catch return error.InvalidFormat;
const @"type" = std.enums.fromInt(EntryHeader.Type, initial.type) orelse return error.InvalidFormat;
@@ -1199,8 +1335,15 @@ const EntryHeader = union(Type) {
}
};
+<<<<<<< HEAD
fn readSizeVarInt(r: *std.io.Reader) !u64 {
+||||||| 733b208256
+fn readSizeVarInt(r: anytype) !u64 {
+=======
+fn readOffsetVarInt(r: *std.Io.Reader) !u64 {
+>>>>>>> origin/flate
const Byte = packed struct { value: u7, has_next: bool };
+<<<<<<< HEAD
var b: Byte = @bitCast(try r.takeByte());
var value: u64 = b.value;
var shift: u6 = 0;
@@ -1215,6 +1358,24 @@ fn readSizeVarInt(r: *std.io.Reader) !u64 {
fn readOffsetVarInt(r: *std.io.Reader) !u64 {
const Byte = packed struct { value: u7, has_next: bool };
var b: Byte = @bitCast(try r.takeByte());
+||||||| 733b208256
+ var b: Byte = @bitCast(try r.readByte());
+ var value: u64 = b.value;
+ var shift: u6 = 0;
+ while (b.has_next) {
+ b = @bitCast(try r.readByte());
+ shift = std.math.add(u6, shift, 7) catch return error.InvalidFormat;
+ value |= @as(u64, b.value) << shift;
+ }
+ return value;
+}
+
+fn readOffsetVarInt(r: anytype) !u64 {
+ const Byte = packed struct { value: u7, has_next: bool };
+ var b: Byte = @bitCast(try r.readByte());
+=======
+ var b: Byte = @bitCast(try r.takeByte());
+>>>>>>> origin/flate
var value: u64 = b.value;
while (b.has_next) {
b = @bitCast(try r.takeByte());
@@ -1231,12 +1392,37 @@ const IndexHeader = struct {
const supported_version = 2;
const size = 4 + 4 + @sizeOf([256]u32);
+<<<<<<< HEAD
fn read(index_header: *IndexHeader, br: *std.io.Reader) !void {
const sig = try br.take(4);
if (!mem.eql(u8, sig, signature)) return error.InvalidHeader;
const version = try br.takeInt(u32, .big);
+||||||| 733b208256
+ fn read(reader: anytype) !IndexHeader {
+ var header_bytes = try reader.readBytesNoEof(size);
+ if (!mem.eql(u8, header_bytes[0..4], signature)) return error.InvalidHeader;
+ const version = mem.readInt(u32, header_bytes[4..8], .big);
+=======
+ fn read(index_header: *IndexHeader, reader: *std.Io.Reader) !void {
+ const sig = try reader.take(4);
+ if (!mem.eql(u8, sig, signature)) return error.InvalidHeader;
+ const version = try reader.takeInt(u32, .big);
+>>>>>>> origin/flate
if (version != supported_version) return error.UnsupportedVersion;
+<<<<<<< HEAD
try br.readSliceEndian(u32, &index_header.fan_out_table, .big);
+||||||| 733b208256
+
+ var fan_out_table: [256]u32 = undefined;
+ var fan_out_table_stream = std.io.fixedBufferStream(header_bytes[8..]);
+ const fan_out_table_reader = fan_out_table_stream.reader();
+ for (&fan_out_table) |*entry| {
+ entry.* = fan_out_table_reader.readInt(u32, .big) catch unreachable;
+ }
+ return .{ .fan_out_table = fan_out_table };
+=======
+ try reader.readSliceEndian(u32, &index_header.fan_out_table, .big);
+>>>>>>> origin/flate
}
};
@@ -1305,10 +1491,18 @@ pub fn indexPack(
}
@memset(fan_out_table[fan_out_index..], count);
+<<<<<<< HEAD
var index_writer_bw = index_writer.writer(&.{});
var index_hashed_writer = index_writer_bw.hashed(Oid.Hasher.init(format));
var write_buffer: [256]u8 = undefined;
var writer = index_hashed_writer.writer(&write_buffer);
+||||||| 733b208256
+ var index_hashed_writer = hashedWriter(index_writer, Oid.Hasher.init(format));
+ const writer = index_hashed_writer.writer();
+=======
+ var index_hashed_writer = std.Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{});
+ const writer = &index_hashed_writer.writer;
+>>>>>>> origin/flate
try writer.writeAll(IndexHeader.signature);
try writer.writeInt(u32, IndexHeader.supported_version, .big);
for (fan_out_table) |fan_out_entry| {
@@ -1342,7 +1536,14 @@ pub fn indexPack(
try writer.writeAll(pack_checksum.slice());
try writer.flush();
const index_checksum = index_hashed_writer.hasher.finalResult();
+<<<<<<< HEAD
try index_writer_bw.writeAll(index_checksum.slice());
+||||||| 733b208256
+ try index_writer.writeAll(index_checksum.slice());
+=======
+ try index_writer.interface.writeAll(index_checksum.slice());
+ try index_writer.end();
+>>>>>>> origin/flate
}
/// Performs the first pass over the packfile data for index construction.
@@ -1356,11 +1557,29 @@ fn indexPackFirstPass(
index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),
pending_deltas: *std.ArrayListUnmanaged(IndexEntry),
) !Oid {
+<<<<<<< HEAD
var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);
+||||||| 733b208256
+ var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());
+ var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());
+ var pack_hashed_reader = hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format));
+ const pack_reader = pack_hashed_reader.reader();
+=======
+ var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
+ var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
+ var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);
+>>>>>>> origin/flate
+<<<<<<< HEAD
const pack_header = try PackHeader.read(&pack_hashed.interface);
+||||||| 733b208256
+ const pack_header = try PackHeader.read(pack_reader);
+=======
+ const pack_header = try PackHeader.read(&pack_hashed.reader);
+>>>>>>> origin/flate
+<<<<<<< HEAD
for (0..pack_header.total_objects) |_| {
const entry_offset = pack.pos - pack_hashed.interface.buffered().len;
var entry_buffer: [64]u8 = undefined; // Buffer only needed for loading EntryHeader.
@@ -1370,40 +1589,111 @@ fn indexPackFirstPass(
var entry_decompress_stream: zlib.Decompressor = .init(&entry_crc32_br);
// Decompress uses large output buffer; no input buffer needed.
var entry_decompress_br = entry_decompress_stream.reader(&.{});
+||||||| 733b208256
+ var current_entry: u32 = 0;
+ while (current_entry < pack_header.total_objects) : (current_entry += 1) {
+ const entry_offset = pack_counting_reader.bytes_read;
+ var entry_crc32_reader = hashedReader(pack_reader, std.hash.Crc32.init());
+ const entry_header = try EntryHeader.read(format, entry_crc32_reader.reader());
+=======
+ for (0..pack_header.total_objects) |_| {
+ const entry_offset = pack.logicalPos() - pack_hashed.reader.bufferedLen();
+ const entry_header = try EntryHeader.read(format, &pack_hashed.reader);
+>>>>>>> origin/flate
switch (entry_header) {
.commit, .tree, .blob, .tag => |object| {
+<<<<<<< HEAD
var oid_hasher = Oid.Hasher.init(format);
var oid_hasher_buffer: [zlib.max_window_len]u8 = undefined;
var oid_hasher_bw = oid_hasher.writer(&oid_hasher_buffer);
+||||||| 733b208256
+ var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
+ var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
+ var entry_hashed_writer = hashedWriter(std.io.null_writer, Oid.Hasher.init(format));
+ const entry_writer = entry_hashed_writer.writer();
+=======
+ var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &.{});
+ var oid_hasher: Oid.Hashing = .init(format, &flate_buffer);
+ const oid_hasher_w = oid_hasher.writer();
+>>>>>>> origin/flate
// The object header is not included in the pack data but is
+<<<<<<< HEAD
// part of the object's ID.
try oid_hasher_bw.print("{s} {d}\x00", .{ @tagName(entry_header), object.uncompressed_length });
const n = try entry_decompress_br.readRemaining(&oid_hasher_bw);
if (n != object.uncompressed_length) return error.InvalidObject;
try oid_hasher_bw.flush();
const oid = oid_hasher.finalResult();
+||||||| 733b208256
+ // part of the object's ID
+ try entry_writer.print("{s} {}\x00", .{ @tagName(entry_header), object.uncompressed_length });
+ var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
+ try fifo.pump(entry_counting_reader.reader(), entry_writer);
+ if (entry_counting_reader.bytes_read != object.uncompressed_length) {
+ return error.InvalidObject;
+ }
+ const oid = entry_hashed_writer.hasher.finalResult();
+=======
+ // part of the object's ID
+ try oid_hasher_w.print("{t} {d}\x00", .{ entry_header, object.uncompressed_length });
+ const n = try entry_decompress.reader.streamRemaining(oid_hasher_w);
+ if (n != object.uncompressed_length) return error.InvalidObject;
+ const oid = oid_hasher.final();
+ if (!skip_checksums) @compileError("TODO");
+>>>>>>> origin/flate
try index_entries.put(allocator, oid, .{
.offset = entry_offset,
- .crc32 = entry_crc32_reader.hasher.final(),
+ .crc32 = 0,
});
},
inline .ofs_delta, .ref_delta => |delta| {
+<<<<<<< HEAD
const n = try entry_decompress_br.discardRemaining();
if (n != delta.uncompressed_length) return error.InvalidObject;
+||||||| 733b208256
+ var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
+ var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
+ var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
+ try fifo.pump(entry_counting_reader.reader(), std.io.null_writer);
+ if (entry_counting_reader.bytes_read != delta.uncompressed_length) {
+ return error.InvalidObject;
+ }
+=======
+ var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &flate_buffer);
+ const n = try entry_decompress.reader.discardRemaining();
+ if (n != delta.uncompressed_length) return error.InvalidObject;
+ if (!skip_checksums) @compileError("TODO");
+>>>>>>> origin/flate
try pending_deltas.append(allocator, .{
.offset = entry_offset,
- .crc32 = entry_crc32_reader.hasher.final(),
+ .crc32 = 0,
});
},
}
}
+<<<<<<< HEAD
const pack_checksum = pack_hashed.hasher.finalResult();
const recorded_checksum = try Oid.readBytes(format, &pack.interface);
if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {
return error.CorruptedPack;
}
return pack_checksum;
+||||||| 733b208256
+ const pack_checksum = pack_hashed_reader.hasher.finalResult();
+ const recorded_checksum = try Oid.readBytes(format, pack_buffered_reader.reader());
+ if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {
+ return error.CorruptedPack;
+ }
+ _ = pack_reader.readByte() catch |e| switch (e) {
+ error.EndOfStream => return pack_checksum,
+ else => |other| return other,
+ };
+ return error.InvalidFormat;
+=======
+ if (!skip_checksums) @compileError("TODO");
+ return pack_hashed.hasher.finalResult();
+>>>>>>> origin/flate
}
/// Attempts to determine the final object ID of the given deltified object.
@@ -1448,6 +1738,7 @@ fn indexPackHashDelta(
const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
+<<<<<<< HEAD
var entry_hasher: Oid.Hasher = .init(format);
var entry_hasher_buffer: [64]u8 = undefined;
var entry_hasher_bw = entry_hasher.writer(&entry_hasher_buffer);
@@ -1456,6 +1747,21 @@ fn indexPackHashDelta(
entry_hasher_bw.writeAll(base_data) catch unreachable;
entry_hasher_bw.flush() catch unreachable;
return entry_hasher.finalResult();
+||||||| 733b208256
+ var entry_hasher: Oid.Hasher = .init(format);
+ var entry_hashed_writer = hashedWriter(std.io.null_writer, &entry_hasher);
+ try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });
+ entry_hasher.update(base_data);
+ return entry_hasher.finalResult();
+=======
+ var entry_hasher_buffer: [64]u8 = undefined;
+ var entry_hasher: Oid.Hashing = .init(format, &entry_hasher_buffer);
+ const entry_hasher_w = entry_hasher.writer();
+ // Writes to hashers cannot fail.
+ entry_hasher_w.print("{t} {d}\x00", .{ base_object.type, base_data.len }) catch unreachable;
+ entry_hasher_w.writeAll(base_data) catch unreachable;
+ return entry_hasher.final();
+>>>>>>> origin/flate
}
/// Resolves a chain of deltas, returning the final base object data. `pack` is
@@ -1477,6 +1783,7 @@ fn resolveDeltaChain(
const delta_offset = delta_offsets[i];
try pack.seekTo(delta_offset);
+<<<<<<< HEAD
const delta_header = try EntryHeader.read(format, &pack.interface);
_ = delta_header;
var delta_decompress: zlib.Decompressor = .init(&pack.interface);
@@ -1484,12 +1791,41 @@ fn resolveDeltaChain(
var delta_reader = delta_decompress.reader(&delta_decompress_buffer);
_ = try readSizeVarInt(&delta_reader); // base object size
const expanded_size = try readSizeVarInt(&delta_reader);
+||||||| 733b208256
+ const delta_header = try EntryHeader.read(format, pack.deprecatedReader());
+ const delta_data = try readObjectRaw(allocator, pack.deprecatedReader(), delta_header.uncompressedLength());
+ defer allocator.free(delta_data);
+ var delta_stream = std.io.fixedBufferStream(delta_data);
+ const delta_reader = delta_stream.reader();
+ _ = try readSizeVarInt(delta_reader); // base object size
+ const expanded_size = try readSizeVarInt(delta_reader);
+
+=======
+ const delta_header = try EntryHeader.read(format, &pack.interface);
+ const delta_data = try readObjectRaw(allocator, &pack.interface, delta_header.uncompressedLength());
+ defer allocator.free(delta_data);
+ var delta_reader: std.Io.Reader = .fixed(delta_data);
+ _ = try delta_reader.takeLeb128(u64); // base object size
+ const expanded_size = try delta_reader.takeLeb128(u64);
+
+>>>>>>> origin/flate
const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge;
const expanded_data = try allocator.alloc(u8, expanded_alloc_size);
errdefer allocator.free(expanded_data);
+<<<<<<< HEAD
var expanded_delta_stream: Writer = .fixed(expanded_data);
try expandDelta(base_data, &delta_reader, &expanded_delta_stream);
if (expanded_delta_stream.end != expanded_size) return error.InvalidObject;
+||||||| 733b208256
+ var expanded_delta_stream = std.io.fixedBufferStream(expanded_data);
+ var base_stream = std.io.fixedBufferStream(base_data);
+ try expandDelta(&base_stream, delta_reader, expanded_delta_stream.writer());
+ if (expanded_delta_stream.pos != expanded_size) return error.InvalidObject;
+=======
+ var expanded_delta_stream: std.Io.Writer = .fixed(expanded_data);
+ try expandDelta(base_data, &delta_reader, &expanded_delta_stream);
+ if (expanded_delta_stream.end != expanded_size) return error.InvalidObject;
+>>>>>>> origin/flate
try cache.put(allocator, delta_offset, .{ .type = base_object.type, .data = expanded_data });
base_data = expanded_data;
@@ -1497,21 +1833,68 @@ fn resolveDeltaChain(
return base_data;
}
+<<<<<<< HEAD
/// Reads the complete contents of an object from `reader`.
fn readObjectRaw(gpa: Allocator, reader: *std.io.Reader, size: u64) ![]u8 {
+||||||| 733b208256
+/// Reads the complete contents of an object from `reader`. This function may
+/// read more bytes than required from `reader`, so the reader position after
+/// returning is not reliable.
+fn readObjectRaw(allocator: Allocator, reader: anytype, size: u64) ![]u8 {
+=======
+/// Reads the complete contents of an object from `reader`. This function may
+/// read more bytes than required from `reader`, so the reader position after
+/// returning is not reliable.
+fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 {
+>>>>>>> origin/flate
const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge;
+<<<<<<< HEAD
var decompress: zlib.Decompressor = .init(reader);
var buffer: std.ArrayListUnmanaged(u8) = .empty;
defer buffer.deinit(gpa);
try decompress.reader().readRemainingArrayList(gpa, null, &buffer, .limited(alloc_size), zlib.max_window_len);
if (buffer.items.len < size) return error.EndOfStream;
return buffer.toOwnedSlice(gpa);
+||||||| 733b208256
+ var buffered_reader = std.io.bufferedReader(reader);
+ var decompress_stream = std.compress.zlib.decompressor(buffered_reader.reader());
+ const data = try allocator.alloc(u8, alloc_size);
+ errdefer allocator.free(data);
+ try decompress_stream.reader().readNoEof(data);
+ _ = decompress_stream.reader().readByte() catch |e| switch (e) {
+ error.EndOfStream => return data,
+ else => |other| return other,
+ };
+ return error.InvalidFormat;
+=======
+ var aw: std.Io.Writer.Allocating = .init(allocator);
+ try aw.ensureTotalCapacity(alloc_size + std.compress.flate.max_window_len);
+ defer aw.deinit();
+ var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &.{});
+ try decompress.reader.streamExact(&aw.writer, alloc_size);
+ return aw.toOwnedSlice();
+>>>>>>> origin/flate
}
+<<<<<<< HEAD
+||||||| 733b208256
+/// Expands delta data from `delta_reader` to `writer`. `base_object` must
+/// support `reader` and `seekTo` (such as a `std.io.FixedBufferStream`).
+///
+=======
+/// Expands delta data from `delta_reader` to `writer`.
+///
+>>>>>>> origin/flate
/// The format of the delta data is documented in
/// [pack-format](https://git-scm.com/docs/pack-format).
+<<<<<<< HEAD
fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *Writer) !void {
var base_offset: u32 = 0;
+||||||| 733b208256
+fn expandDelta(base_object: anytype, delta_reader: anytype, writer: anytype) !void {
+=======
+fn expandDelta(base_object: []const u8, delta_reader: *std.Io.Reader, writer: *std.Io.Writer) !void {
+>>>>>>> origin/flate
while (true) {
const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) {
error.EndOfStream => return,
@@ -1533,7 +1916,13 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *W
.offset3 = if (available.offset3) try delta_reader.takeByte() else 0,
.offset4 = if (available.offset4) try delta_reader.takeByte() else 0,
};
+<<<<<<< HEAD
base_offset = @bitCast(offset_parts);
+||||||| 733b208256
+ const offset: u32 = @bitCast(offset_parts);
+=======
+ const base_offset: u32 = @bitCast(offset_parts);
+>>>>>>> origin/flate
const size_parts: packed struct { size1: u8, size2: u8, size3: u8 } = .{
.size1 = if (available.size1) try delta_reader.takeByte() else 0,
.size2 = if (available.size2) try delta_reader.takeByte() else 0,
@@ -1541,11 +1930,28 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *W
};
var size: u24 = @bitCast(size_parts);
if (size == 0) size = 0x10000;
+<<<<<<< HEAD
try writer.writeAll(base_object[base_offset..][0..size]);
base_offset += size;
+||||||| 733b208256
+ try base_object.seekTo(offset);
+ var copy_reader = std.io.limitedReader(base_object.reader(), size);
+ var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
+ try fifo.pump(copy_reader.reader(), writer);
+=======
+ try writer.writeAll(base_object[base_offset..][0..size]);
+>>>>>>> origin/flate
} else if (inst.value != 0) {
+<<<<<<< HEAD
try delta_reader.readAll(writer, .limited(inst.value));
+||||||| 733b208256
+ var data_reader = std.io.limitedReader(delta_reader, inst.value);
+ var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
+ try fifo.pump(data_reader.reader(), writer);
+=======
+ try delta_reader.streamExact(writer, inst.value);
+>>>>>>> origin/flate
} else {
return error.InvalidDeltaInstruction;
}
@@ -1575,25 +1981,46 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
defer pack_file.close();
try pack_file.writeAll(testrepo_pack);
+ var pack_file_buffer: [2000]u8 = undefined;
+ var pack_file_reader = pack_file.reader(&pack_file_buffer);
+
var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });
defer index_file.close();
+<<<<<<< HEAD
var index_file_writer = index_file.writer();
try indexPack(testing.allocator, format, pack_file, &index_file_writer);
+||||||| 733b208256
+ try indexPack(testing.allocator, format, pack_file, index_file.deprecatedWriter());
+=======
+ var index_file_buffer: [2000]u8 = undefined;
+ var index_file_writer = index_file.writer(&index_file_buffer);
+ try indexPack(testing.allocator, format, &pack_file_reader, &index_file_writer);
+>>>>>>> origin/flate
// Arbitrary size limit on files read while checking the repository contents
// (all files in the test repo are known to be smaller than this)
const max_file_size = 8192;
- const index_file_data = try git_dir.dir.readFileAlloc(testing.allocator, "testrepo.idx", max_file_size);
- defer testing.allocator.free(index_file_data);
- // testrepo.idx is generated by Git. The index created by this file should
- // match it exactly. Running `git verify-pack -v testrepo.pack` can verify
- // this.
- const testrepo_idx = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".idx");
- try testing.expectEqualSlices(u8, testrepo_idx, index_file_data);
+ if (!skip_checksums) {
+ const index_file_data = try git_dir.dir.readFileAlloc(testing.allocator, "testrepo.idx", max_file_size);
+ defer testing.allocator.free(index_file_data);
+ // testrepo.idx is generated by Git. The index created by this file should
+ // match it exactly. Running `git verify-pack -v testrepo.pack` can verify
+ // this.
+ const testrepo_idx = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".idx");
+ try testing.expectEqualSlices(u8, testrepo_idx, index_file_data);
+ }
+<<<<<<< HEAD
var index_file_reader = index_file_writer.moveToReader();
var repository = try Repository.init(testing.allocator, format, pack_file, &index_file_reader);
+||||||| 733b208256
+ var repository = try Repository.init(testing.allocator, format, pack_file, index_file);
+=======
+ var index_file_reader = index_file.reader(&index_file_buffer);
+ var repository: Repository = undefined;
+ try repository.init(testing.allocator, format, &pack_file_reader, &index_file_reader);
+>>>>>>> origin/flate
defer repository.deinit();
var worktree = testing.tmpDir(.{ .iterate = true });
@@ -1663,6 +2090,12 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
try testing.expectEqualStrings(expected_file_contents, actual_file_contents);
}
+/// Checksum calculation is useful for troubleshooting and debugging, but it's
+/// redundant since the package manager already does content hashing at the
+/// end. Let's save time by not doing that work, but, I left a cookie crumb
+/// trail here if you want to restore the functionality for tinkering purposes.
+const skip_checksums = true;
+
test "SHA-1 packfile indexing and checkout" {
try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb");
}
@@ -1688,6 +2121,9 @@ pub fn main() !void {
var pack_file = try std.fs.cwd().openFile(args[2], .{});
defer pack_file.close();
+ var pack_file_buffer: [4096]u8 = undefined;
+ var pack_file_reader = pack_file.reader(&pack_file_buffer);
+
const commit = try Oid.parse(format, args[3]);
var worktree = try std.fs.cwd().makeOpenPath(args[4], .{});
defer worktree.close();
@@ -1698,15 +2134,32 @@ pub fn main() !void {
std.debug.print("Starting index...\n", .{});
var index_file = try git_dir.createFile("idx", .{ .read = true });
defer index_file.close();
+<<<<<<< HEAD
var index_file_writer = index_file.writer();
var pack_file_reader = pack_file.reader();
try indexPack(gpa, format, &pack_file_reader, &index_file_writer);
try index_file.sync();
+||||||| 733b208256
+ var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter());
+ try indexPack(allocator, format, pack_file, index_buffered_writer.writer());
+ try index_buffered_writer.flush();
+ try index_file.sync();
+=======
+ var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter());
+ try indexPack(allocator, format, &pack_file_reader, index_buffered_writer.writer());
+ try index_buffered_writer.flush();
+>>>>>>> origin/flate
std.debug.print("Starting checkout...\n", .{});
+<<<<<<< HEAD
var index_file_reader = index_file_writer.moveToReader();
var repository: Repository = undefined;
try repository.init(gpa, format, &pack_file_reader, &index_file_reader);
+||||||| 733b208256
+ var repository = try Repository.init(allocator, format, pack_file, index_file);
+=======
+ var repository = try Repository.init(allocator, format, &pack_file_reader, index_file);
+>>>>>>> origin/flate
defer repository.deinit();
var diagnostics: Diagnostics = .{ .allocator = gpa };
defer diagnostics.deinit();
diff --git a/src/Package/Module.zig b/src/Package/Module.zig
index d829b397ba..1c941f51f4 100644
--- a/src/Package/Module.zig
+++ b/src/Package/Module.zig
@@ -250,7 +250,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
};
const stack_check = b: {
- if (!target_util.supportsStackProbing(target)) {
+ if (!target_util.supportsStackProbing(target, zig_backend)) {
if (options.inherited.stack_check == true)
return error.StackCheckUnsupportedByTarget;
break :b false;
diff --git a/src/Sema.zig b/src/Sema.zig
index 788107f786..d7add0724d 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -1905,8 +1905,12 @@ fn analyzeBodyInner(
const err_union = try sema.resolveInst(extra.data.operand);
const err_union_ty = sema.typeOf(err_union);
if (err_union_ty.zigTypeTag(zcu) != .error_union) {
- return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{
- err_union_ty.fmt(pt),
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(operand_src, "expected error union type, found '{f}'", .{err_union_ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, err_union_ty);
+ try sema.errNote(operand_src, msg, "consider omitting 'try'", .{});
+ break :msg msg;
});
}
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
@@ -3922,7 +3926,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
const ptr_to_map = switch (store_inst.tag) {
.store, .store_safe => store_inst.data.bin_op.lhs.toIndex().?, // Map the pointer being stored to.
- .set_union_tag => continue, // We can completely ignore these: we'll do it implicitly when we get the field pointer.
+ .set_union_tag => continue, // Ignore for now; handled after we map pointers
.optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself.
else => unreachable,
};
@@ -4055,19 +4059,33 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
}
// We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.
- // Any implicit stores performed by `optional_payload_ptr_set`, `errunion_payload_ptr_set`, or
- // `set_union_tag` instructions were already done above.
+ // Any implicit stores performed by `optional_payload_ptr_set` or `errunion_payload_ptr_set`
+ // instructions were already done above.
for (stores) |store_inst_idx| {
const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
switch (store_inst.tag) {
- .set_union_tag => {}, // Handled implicitly by field pointers above
.optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above
+ .set_union_tag => {
+ // Usually, we can ignore these, because the creation of the field pointer above
+ // already did it for us. However, if the field is OPV, this is relevant, because
+ // there is not going to be a store to the field. So we must initialize the union
+ // tag if the field is OPV.
+ const union_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
+ const union_ptr_val: Value = .fromInterned(ptr_mapping.get(union_ptr_inst).?);
+ const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?);
+ const union_ty = union_ptr_val.typeOf(zcu).childType(zcu);
+ const field_ty = union_ty.unionFieldType(tag_val, zcu).?;
+ if (try sema.typeHasOnePossibleValue(field_ty)) |payload_val| {
+ const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val);
+ try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty);
+ }
+ },
.store, .store_safe => {
const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;
const new_ptr = ptr_mapping.get(air_ptr_inst).?;
- try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(new_ptr), store_val, .fromInterned(zcu.intern_pool.typeOf(store_val.toIntern())));
+ try sema.storePtrVal(block, .unneeded, .fromInterned(new_ptr), store_val, store_val.typeOf(zcu));
},
else => unreachable,
}
@@ -4099,14 +4117,13 @@ fn finishResolveComptimeKnownAllocPtr(
// We're almost done - we have the resolved comptime value. We just need to
// eliminate the now-dead runtime instructions.
- // We will rewrite the AIR to eliminate the alloc and all stores to it.
- // This will cause instructions deriving field pointers etc of the alloc to
- // become invalid, however, since we are removing all stores to those pointers,
- // they will be eliminated by Liveness before they reach codegen.
-
- // The specifics of this instruction aren't really important: we just want
- // Liveness to elide it.
- const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ .ty = .u8_type, .operand = .zero_u8 } } };
+ // 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 = .{
+ .ty = .fromIntern(alloc_ty.toIntern()),
+ .operand = .zero_usize,
+ } } };
sema.air_instructions.set(@intFromEnum(alloc_inst), nop_inst);
for (comptime_info.stores.items(.inst)) |store_inst| {
@@ -4829,13 +4846,13 @@ fn zirValidatePtrStructInit(
agg_ty,
init_src,
instrs,
+ object_ptr,
),
.@"union" => return sema.validateUnionInit(
block,
agg_ty,
init_src,
instrs,
- object_ptr,
),
else => unreachable,
}
@@ -4847,164 +4864,28 @@ fn validateUnionInit(
union_ty: Type,
init_src: LazySrcLoc,
instrs: []const Zir.Inst.Index,
- union_ptr: Air.Inst.Ref,
) CompileError!void {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const gpa = sema.gpa;
-
- if (instrs.len != 1) {
- const msg = msg: {
- const msg = try sema.errMsg(
- init_src,
- "cannot initialize multiple union fields at once; unions can only have one active field",
- .{},
- );
- errdefer msg.destroy(gpa);
-
- for (instrs[1..]) |inst| {
- const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
- const inst_src = block.src(.{ .node_offset_initializer = inst_data.src_node });
- try sema.errNote(inst_src, msg, "additional initializer here", .{});
- }
- try sema.addDeclaredHereNote(msg, union_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
-
- if (block.isComptime() and
- (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null)
- {
- // In this case, comptime machinery already did everything. No work to do here.
+ if (instrs.len == 1) {
+ // Trvial validation done, and the union tag was already set by machinery in `unionFieldPtr`.
return;
}
+ const msg = msg: {
+ const msg = try sema.errMsg(
+ init_src,
+ "cannot initialize multiple union fields at once; unions can only have one active field",
+ .{},
+ );
+ errdefer msg.destroy(sema.gpa);
- const field_ptr = instrs[0];
- const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
- const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node });
- const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
- const field_name = try zcu.intern_pool.getOrPutString(
- gpa,
- pt.tid,
- sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
- .no_embedded_nulls,
- );
- const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
- const air_tags = sema.air_instructions.items(.tag);
- const air_datas = sema.air_instructions.items(.data);
- const field_ptr_ref = sema.inst_map.get(field_ptr).?;
-
- // Our task here is to determine if the union is comptime-known. In such case,
- // we erase the runtime AIR instructions for initializing the union, and replace
- // the mapping with the comptime value. Either way, we will need to populate the tag.
-
- // We expect to see something like this in the current block AIR:
- // %a = alloc(*const U)
- // %b = bitcast(*U, %a)
- // %c = field_ptr(..., %b)
- // %e!= store(%c!, %d!)
- // If %d is a comptime operand, the union is comptime.
- // If the union is comptime, we want `first_block_index`
- // to point at %c so that the bitcast becomes the last instruction in the block.
- //
- // Store instruction may be missing; if field type has only one possible value, this case is handled below.
- //
- // In the case of a comptime-known pointer to a union, the
- // the field_ptr instruction is missing, so we have to pattern-match
- // based only on the store instructions.
- // `first_block_index` needs to point to the `field_ptr` if it exists;
- // the `store` otherwise.
- var first_block_index = block.instructions.items.len;
- var block_index = block.instructions.items.len - 1;
- var init_val: ?Value = null;
- var init_ref: ?Air.Inst.Ref = null;
- while (block_index > 0) : (block_index -= 1) {
- const store_inst = block.instructions.items[block_index];
- if (store_inst.toRef() == field_ptr_ref) {
- first_block_index = block_index;
- break;
+ for (instrs[1..]) |inst| {
+ const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
+ const inst_src = block.src(.{ .node_offset_initializer = inst_data.src_node });
+ try sema.errNote(inst_src, msg, "additional initializer here", .{});
}
- switch (air_tags[@intFromEnum(store_inst)]) {
- .store, .store_safe => {},
- else => continue,
- }
- const bin_op = air_datas[@intFromEnum(store_inst)].bin_op;
- var ptr_ref = bin_op.lhs;
- if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
- ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
- };
- if (ptr_ref != field_ptr_ref) continue;
- first_block_index = @min(if (field_ptr_ref.toIndex()) |field_ptr_inst|
- std.mem.lastIndexOfScalar(
- Air.Inst.Index,
- block.instructions.items[0..block_index],
- field_ptr_inst,
- ).?
- else
- block_index, first_block_index);
- init_ref = bin_op.rhs;
- init_val = try sema.resolveValue(bin_op.rhs);
- break;
- }
-
- const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
- const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
- const field_type = union_ty.unionFieldType(tag_val, zcu).?;
-
- if (try sema.typeHasOnePossibleValue(field_type)) |field_only_value| {
- init_val = field_only_value;
- }
-
- if (init_val) |val| {
- // Our task is to delete all the `field_ptr` and `store` instructions, and insert
- // instead a single `store` to the result ptr with a comptime union value.
- block_index = first_block_index;
- for (block.instructions.items[first_block_index..]) |cur_inst| {
- switch (air_tags[@intFromEnum(cur_inst)]) {
- .struct_field_ptr,
- .struct_field_ptr_index_0,
- .struct_field_ptr_index_1,
- .struct_field_ptr_index_2,
- .struct_field_ptr_index_3,
- => if (cur_inst.toRef() == field_ptr_ref) continue,
- .bitcast => if (air_datas[@intFromEnum(cur_inst)].ty_op.operand == field_ptr_ref) continue,
- .store, .store_safe => {
- var ptr_ref = air_datas[@intFromEnum(cur_inst)].bin_op.lhs;
- if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
- ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
- };
- if (ptr_ref == field_ptr_ref) continue;
- },
- else => {},
- }
- block.instructions.items[block_index] = cur_inst;
- block_index += 1;
- }
- block.instructions.shrinkRetainingCapacity(block_index);
-
- const union_val = try pt.internUnion(.{
- .ty = union_ty.toIntern(),
- .tag = tag_val.toIntern(),
- .val = val.toIntern(),
- });
- const union_init = Air.internedToRef(union_val);
- try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
- return;
- } else if (try union_ty.comptimeOnlySema(pt)) {
- const src = block.nodeOffset(field_ptr_data.src_node);
- return sema.failWithNeededComptime(block, src, .{ .comptime_only = .{
- .ty = union_ty,
- .msg = .union_init,
- } });
- }
- if (init_ref) |v| try sema.validateRuntimeValue(block, block.nodeOffset(field_ptr_data.src_node), v);
-
- if ((try sema.typeHasOnePossibleValue(tag_ty)) == null) {
- const new_tag = Air.internedToRef(tag_val.toIntern());
- const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
- try sema.checkComptimeKnownStore(block, set_tag_inst, LazySrcLoc.unneeded); // `unneeded` since this isn't a "proper" store
- }
+ try sema.addDeclaredHereNote(msg, union_ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(block, msg);
}
fn validateStructInit(
@@ -5013,187 +4894,62 @@ fn validateStructInit(
struct_ty: Type,
init_src: LazySrcLoc,
instrs: []const Zir.Inst.Index,
+ struct_ptr: Air.Inst.Ref,
) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
- const field_indices = try gpa.alloc(u32, instrs.len);
- defer gpa.free(field_indices);
-
- // Maps field index to field_ptr index of where it was already initialized.
- const found_fields = try gpa.alloc(Zir.Inst.OptionalIndex, struct_ty.structFieldCount(zcu));
+ // Tracks whether each field was explicitly initialized.
+ const found_fields = try gpa.alloc(bool, struct_ty.structFieldCount(zcu));
defer gpa.free(found_fields);
- @memset(found_fields, .none);
+ @memset(found_fields, false);
- var struct_ptr_zir_ref: Zir.Inst.Ref = undefined;
-
- for (instrs, field_indices) |field_ptr, *field_index| {
+ for (instrs) |field_ptr| {
const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node });
const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
- struct_ptr_zir_ref = field_ptr_extra.lhs;
const field_name = try ip.getOrPutString(
gpa,
pt.tid,
sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
.no_embedded_nulls,
);
- field_index.* = if (struct_ty.isTuple(zcu))
+ const field_index = if (struct_ty.isTuple(zcu))
try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
else
try sema.structFieldIndex(block, struct_ty, field_name, field_src);
- assert(found_fields[field_index.*] == .none);
- found_fields[field_index.*] = field_ptr.toOptional();
+ assert(found_fields[field_index] == false);
+ found_fields[field_index] = true;
}
+ // Our job is simply to deal with default field values. Specifically, any field which was not
+ // explicitly initialized must have its default value stored to the field pointer, or, if the
+ // field has no default value, a compile error must be emitted instead.
+
+ // In the past, this code had other responsibilities, which involved some nasty AIR rewrites. However,
+ // that work was actually all redundant:
+ //
+ // * If the struct value is comptime-known, field stores remain a perfectly valid way of initializing
+ // the struct through RLS; there is no need to turn the field stores into one store. Comptime-known
+ // consts are handled correctly either way thanks to `maybe_comptime_allocs` and friends.
+ //
+ // * If the struct type is comptime-only, we need to make sure all of the fields were comptime-known.
+ // But the comptime-only type means that `struct_ptr` must be a comptime-mutable pointer, so the
+ // field stores were to comptime-mutable pointers, so have already errored if not comptime-known.
+ //
+ // * If the value is runtime-known, then comptime-known fields must be validated as runtime values.
+ // But this was already handled for every field store by the machinery in `checkComptimeKnownStore`.
+
var root_msg: ?*Zcu.ErrorMsg = null;
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
- const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
- if (block.isComptime() and
- (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
- {
- try struct_ty.resolveLayout(pt);
- // In this case the only thing we need to do is evaluate the implicit
- // store instructions for default field values, and report any missing fields.
- // Avoid the cost of the extra machinery for detecting a comptime struct init value.
- for (found_fields, 0..) |field_ptr, i_usize| {
- const i: u32 = @intCast(i_usize);
- if (field_ptr != .none) continue;
-
- try struct_ty.resolveStructFieldInits(pt);
- const default_val = struct_ty.structFieldDefaultValue(i, zcu);
- if (default_val.toIntern() == .unreachable_value) {
- const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {
- const template = "missing tuple field with index {d}";
- if (root_msg) |msg| {
- try sema.errNote(init_src, msg, template, .{i});
- } else {
- root_msg = try sema.errMsg(init_src, template, .{i});
- }
- continue;
- };
- const template = "missing struct field: {f}";
- const args = .{field_name.fmt(ip)};
- if (root_msg) |msg| {
- try sema.errNote(init_src, msg, template, args);
- } else {
- root_msg = try sema.errMsg(init_src, template, args);
- }
- continue;
- }
-
- const field_src = init_src; // TODO better source location
- const default_field_ptr = if (struct_ty.isTuple(zcu))
- try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true)
- else
- try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);
- const init = Air.internedToRef(default_val.toIntern());
- try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
- }
-
- if (root_msg) |msg| {
- try sema.addDeclaredHereNote(msg, struct_ty);
- root_msg = null;
- return sema.failWithOwnedErrorMsg(block, msg);
- }
-
- return;
- }
-
- var fields_allow_runtime = true;
-
- var struct_is_comptime = true;
- var first_block_index = block.instructions.items.len;
-
- const require_comptime = try struct_ty.comptimeOnlySema(pt);
- const air_tags = sema.air_instructions.items(.tag);
- const air_datas = sema.air_instructions.items(.data);
-
- try struct_ty.resolveStructFieldInits(pt);
-
- // We collect the comptime field values in case the struct initialization
- // ends up being comptime-known.
- const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(zcu));
-
- field: for (found_fields, 0..) |opt_field_ptr, i_usize| {
+ for (found_fields, 0..) |explicit, i_usize| {
+ if (explicit) continue;
const i: u32 = @intCast(i_usize);
- if (opt_field_ptr.unwrap()) |field_ptr| {
- // Determine whether the value stored to this pointer is comptime-known.
- const field_ty = struct_ty.fieldType(i, zcu);
- if (try sema.typeHasOnePossibleValue(field_ty)) |opv| {
- field_values[i] = opv.toIntern();
- continue;
- }
-
- const field_ptr_ref = sema.inst_map.get(field_ptr).?;
-
- //std.debug.print("validateStructInit (field_ptr_ref=%{d}):\n", .{field_ptr_ref});
- //for (block.instructions.items) |item| {
- // std.debug.print(" %{d} = {s}\n", .{item, @tagName(air_tags[@intFromEnum(item)])});
- //}
-
- // We expect to see something like this in the current block AIR:
- // %a = field_ptr(...)
- // store(%a, %b)
- // With an optional bitcast between the store and the field_ptr.
- // If %b is a comptime operand, this field is comptime.
- //
- // However, in the case of a comptime-known pointer to a struct, the
- // the field_ptr instruction is missing, so we have to pattern-match
- // based only on the store instructions.
- // `first_block_index` needs to point to the `field_ptr` if it exists;
- // the `store` otherwise.
-
- // Possible performance enhancement: save the `block_index` between iterations
- // of the for loop.
- var block_index = block.instructions.items.len;
- while (block_index > 0) {
- block_index -= 1;
- const store_inst = block.instructions.items[block_index];
- if (store_inst.toRef() == field_ptr_ref) {
- struct_is_comptime = false;
- continue :field;
- }
- switch (air_tags[@intFromEnum(store_inst)]) {
- .store, .store_safe => {},
- else => continue,
- }
- const bin_op = air_datas[@intFromEnum(store_inst)].bin_op;
- var ptr_ref = bin_op.lhs;
- if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
- ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
- };
- if (ptr_ref != field_ptr_ref) continue;
- first_block_index = @min(if (field_ptr_ref.toIndex()) |field_ptr_inst|
- std.mem.lastIndexOfScalar(
- Air.Inst.Index,
- block.instructions.items[0..block_index],
- field_ptr_inst,
- ).?
- else
- block_index, first_block_index);
- if (!sema.checkRuntimeValue(bin_op.rhs)) fields_allow_runtime = false;
- if (try sema.resolveValue(bin_op.rhs)) |val| {
- field_values[i] = val.toIntern();
- } else if (require_comptime) {
- const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
- const src = block.nodeOffset(field_ptr_data.src_node);
- return sema.failWithNeededComptime(block, src, .{ .comptime_only = .{
- .ty = struct_ty,
- .msg = .struct_init,
- } });
- } else {
- struct_is_comptime = false;
- }
- continue :field;
- }
- struct_is_comptime = false;
- continue :field;
- }
+ try struct_ty.resolveStructFieldInits(pt);
const default_val = struct_ty.structFieldDefaultValue(i, zcu);
if (default_val.toIntern() == .unreachable_value) {
const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {
@@ -5214,70 +4970,6 @@ fn validateStructInit(
}
continue;
}
- field_values[i] = default_val.toIntern();
- }
-
- if (!struct_is_comptime and !fields_allow_runtime and root_msg == null) {
- root_msg = try sema.errMsg(init_src, "runtime value contains reference to comptime var", .{});
- try sema.errNote(init_src, root_msg.?, "comptime var pointers are not available at runtime", .{});
- }
-
- if (root_msg) |msg| {
- try sema.addDeclaredHereNote(msg, struct_ty);
- root_msg = null;
- return sema.failWithOwnedErrorMsg(block, msg);
- }
-
- if (struct_is_comptime) {
- // Our task is to delete all the `field_ptr` and `store` instructions, and insert
- // instead a single `store` to the struct_ptr with a comptime struct value.
- var init_index: usize = 0;
- var field_ptr_ref = Air.Inst.Ref.none;
- var block_index = first_block_index;
- for (block.instructions.items[first_block_index..]) |cur_inst| {
- while (field_ptr_ref == .none and init_index < instrs.len) : (init_index += 1) {
- const field_ty = struct_ty.fieldType(field_indices[init_index], zcu);
- if (try field_ty.onePossibleValue(pt)) |_| continue;
- field_ptr_ref = sema.inst_map.get(instrs[init_index]).?;
- }
- switch (air_tags[@intFromEnum(cur_inst)]) {
- .struct_field_ptr,
- .struct_field_ptr_index_0,
- .struct_field_ptr_index_1,
- .struct_field_ptr_index_2,
- .struct_field_ptr_index_3,
- => if (cur_inst.toRef() == field_ptr_ref) continue,
- .bitcast => if (air_datas[@intFromEnum(cur_inst)].ty_op.operand == field_ptr_ref) continue,
- .store, .store_safe => {
- var ptr_ref = air_datas[@intFromEnum(cur_inst)].bin_op.lhs;
- if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
- ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
- };
- if (ptr_ref == field_ptr_ref) {
- field_ptr_ref = .none;
- continue;
- }
- },
- else => {},
- }
- block.instructions.items[block_index] = cur_inst;
- block_index += 1;
- }
- block.instructions.shrinkRetainingCapacity(block_index);
-
- const struct_val = try pt.intern(.{ .aggregate = .{
- .ty = struct_ty.toIntern(),
- .storage = .{ .elems = field_values },
- } });
- const struct_init = Air.internedToRef(struct_val);
- try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
- return;
- }
- try struct_ty.resolveLayout(pt);
-
- // Our task is to insert `store` instructions for all the default field values.
- for (found_fields, 0..) |field_ptr, i| {
- if (field_ptr != .none) continue;
const field_src = init_src; // TODO better source location
const default_field_ptr = if (struct_ty.isTuple(zcu))
@@ -5285,8 +4977,13 @@ fn validateStructInit(
else
try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);
try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr);
- const init = Air.internedToRef(field_values[i]);
- try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
+ try sema.storePtr2(block, init_src, default_field_ptr, init_src, .fromValue(default_val), field_src, .store);
+ }
+
+ if (root_msg) |msg| {
+ try sema.addDeclaredHereNote(msg, struct_ty);
+ root_msg = null;
+ return sema.failWithOwnedErrorMsg(block, msg);
}
}
@@ -5307,15 +5004,14 @@ fn zirValidatePtrArrayInit(
const array_ty = sema.typeOf(array_ptr).childType(zcu).optEuBaseType(zcu);
const array_len = array_ty.arrayLen(zcu);
- // Collect the comptime element values in case the array literal ends up
- // being comptime-known.
- const element_vals = try sema.arena.alloc(
- InternPool.Index,
- try sema.usizeCast(block, init_src, array_len),
- );
+ // Analagously to `validateStructInit`, our job is to handle default fields; either emitting AIR
+ // to initialize them, or emitting a compile error if an unspecified field has no default. For
+ // tuples, there are literally default field values, although they're guaranteed to be comptime
+ // fields so we don't need to initialize them. For arrays, we may have a sentinel, which is never
+ // specified so we always need to initialize here. For vectors, there's no such thing.
- if (instrs.len != array_len) switch (array_ty.zigTypeTag(zcu)) {
- .@"struct" => {
+ switch (array_ty.zigTypeTag(zcu)) {
+ .@"struct" => if (instrs.len != array_len) {
var root_msg: ?*Zcu.ErrorMsg = null;
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
@@ -5332,8 +5028,6 @@ fn zirValidatePtrArrayInit(
}
continue;
}
-
- element_vals[i] = default_val;
}
if (root_msg) |msg| {
@@ -5341,162 +5035,25 @@ fn zirValidatePtrArrayInit(
return sema.failWithOwnedErrorMsg(block, msg);
}
},
- .array => {
+
+ .array => if (instrs.len != array_len) {
return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
array_len, instrs.len,
});
+ } else if (array_ty.sentinel(zcu)) |sentinel| {
+ const array_len_ref = try pt.intRef(.usize, array_len);
+ const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true);
+ try sema.checkKnownAllocPtr(block, array_ptr, sentinel_ptr);
+ try sema.storePtr2(block, init_src, sentinel_ptr, init_src, .fromValue(sentinel), init_src, .store);
},
- .vector => {
+
+ .vector => if (instrs.len != array_len) {
return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{
array_len, instrs.len,
});
},
+
else => unreachable,
- };
-
- if (block.isComptime() and
- (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null)
- {
- // In this case the comptime machinery will have evaluated the store instructions
- // at comptime so we have almost nothing to do here. However, in case of a
- // sentinel-terminated array, the sentinel will not have been populated by
- // any ZIR instructions at comptime; we need to do that here.
- if (array_ty.sentinel(zcu)) |sentinel_val| {
- const array_len_ref = try pt.intRef(.usize, array_len);
- const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true);
- const sentinel = Air.internedToRef(sentinel_val.toIntern());
- try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);
- }
- return;
- }
-
- // If the array has one possible value, the value is always comptime-known.
- if (try sema.typeHasOnePossibleValue(array_ty)) |array_opv| {
- const array_init = Air.internedToRef(array_opv.toIntern());
- try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
- return;
- }
-
- var array_is_comptime = true;
- var first_block_index = block.instructions.items.len;
-
- const air_tags = sema.air_instructions.items(.tag);
- const air_datas = sema.air_instructions.items(.data);
-
- outer: for (instrs, 0..) |elem_ptr, i| {
- // Determine whether the value stored to this pointer is comptime-known.
-
- if (array_ty.isTuple(zcu)) {
- if (array_ty.structFieldIsComptime(i, zcu))
- try array_ty.resolveStructFieldInits(pt);
- if (try array_ty.structFieldValueComptime(pt, i)) |opv| {
- element_vals[i] = opv.toIntern();
- continue;
- }
- }
-
- const elem_ptr_ref = sema.inst_map.get(elem_ptr).?;
-
- // We expect to see something like this in the current block AIR:
- // %a = elem_ptr(...)
- // store(%a, %b)
- // With an optional bitcast between the store and the elem_ptr.
- // If %b is a comptime operand, this element is comptime.
- //
- // However, in the case of a comptime-known pointer to an array, the
- // the elem_ptr instruction is missing, so we have to pattern-match
- // based only on the store instructions.
- // `first_block_index` needs to point to the `elem_ptr` if it exists;
- // the `store` otherwise.
- //
- // This is nearly identical to similar logic in `validateStructInit`.
-
- // Possible performance enhancement: save the `block_index` between iterations
- // of the for loop.
- var block_index = block.instructions.items.len;
- while (block_index > 0) {
- block_index -= 1;
- const store_inst = block.instructions.items[block_index];
- if (store_inst.toRef() == elem_ptr_ref) {
- array_is_comptime = false;
- continue :outer;
- }
- switch (air_tags[@intFromEnum(store_inst)]) {
- .store, .store_safe => {},
- else => continue,
- }
- const bin_op = air_datas[@intFromEnum(store_inst)].bin_op;
- var ptr_ref = bin_op.lhs;
- if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
- ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
- };
- if (ptr_ref != elem_ptr_ref) continue;
- first_block_index = @min(if (elem_ptr_ref.toIndex()) |elem_ptr_inst|
- std.mem.lastIndexOfScalar(
- Air.Inst.Index,
- block.instructions.items[0..block_index],
- elem_ptr_inst,
- ).?
- else
- block_index, first_block_index);
- if (try sema.resolveValue(bin_op.rhs)) |val| {
- element_vals[i] = val.toIntern();
- } else {
- array_is_comptime = false;
- }
- continue :outer;
- }
- array_is_comptime = false;
- continue :outer;
- }
-
- if (array_is_comptime) {
- if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {
- switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
- .ptr => |ptr| switch (ptr.base_addr) {
- .comptime_field => return, // This store was validated by the individual elem ptrs.
- else => {},
- },
- else => {},
- }
- }
-
- // Our task is to delete all the `elem_ptr` and `store` instructions, and insert
- // instead a single `store` to the array_ptr with a comptime struct value.
- var elem_index: usize = 0;
- var elem_ptr_ref = Air.Inst.Ref.none;
- var block_index = first_block_index;
- for (block.instructions.items[first_block_index..]) |cur_inst| {
- while (elem_ptr_ref == .none and elem_index < instrs.len) : (elem_index += 1) {
- if (array_ty.isTuple(zcu) and array_ty.structFieldIsComptime(elem_index, zcu)) continue;
- elem_ptr_ref = sema.inst_map.get(instrs[elem_index]).?;
- }
- switch (air_tags[@intFromEnum(cur_inst)]) {
- .ptr_elem_ptr => if (cur_inst.toRef() == elem_ptr_ref) continue,
- .bitcast => if (air_datas[@intFromEnum(cur_inst)].ty_op.operand == elem_ptr_ref) continue,
- .store, .store_safe => {
- var ptr_ref = air_datas[@intFromEnum(cur_inst)].bin_op.lhs;
- if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
- ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
- };
- if (ptr_ref == elem_ptr_ref) {
- elem_ptr_ref = .none;
- continue;
- }
- },
- else => {},
- }
- block.instructions.items[block_index] = cur_inst;
- block_index += 1;
- }
- block.instructions.shrinkRetainingCapacity(block_index);
-
- const array_val = try pt.intern(.{ .aggregate = .{
- .ty = array_ty.toIntern(),
- .storage = .{ .elems = element_vals },
- } });
- const array_init = Air.internedToRef(array_val);
- try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
}
}
@@ -5774,8 +5331,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
const tracy = trace(@src());
defer tracy.end();
- const pt = sema.pt;
- const zcu = pt.zcu;
const zir_tags = sema.code.instructions.items(.tag);
const zir_datas = sema.code.instructions.items(.data);
const inst_data = zir_datas[@intFromEnum(inst)].pl_node;
@@ -5789,16 +5344,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
else
false;
- // Check for the possibility of this pattern:
- // %a = ret_ptr
- // %b = store(%a, %c)
- // Where %c is an error union or error set. In such case we need to add
- // to the current function's inferred error set, if any.
- if (is_ret and sema.fn_ret_ty_ies != null) switch (sema.typeOf(operand).zigTypeTag(zcu)) {
- .error_union, .error_set => try sema.addToInferredErrorSet(operand),
- else => {},
- };
-
const ptr_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
const operand_src = block.src(.{ .node_offset_store_operand = inst_data.src_node });
const air_tag: Air.Inst.Tag = if (is_ret)
@@ -14136,7 +13681,7 @@ fn zirShl(
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
const bit_count = scalar_ty.intInfo(zcu).bits;
- if (!std.math.isPowerOfTwo(bit_count)) {
+ if (air_tag != .shl_sat and !std.math.isPowerOfTwo(bit_count)) {
const bit_count_val = try pt.intValue(scalar_rhs_ty, bit_count);
const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {
const bit_count_inst = Air.internedToRef((try sema.splat(rhs_ty, bit_count_val)).toIntern());
@@ -18634,8 +18179,12 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
const pt = sema.pt;
const zcu = pt.zcu;
if (err_union_ty.zigTypeTag(zcu) != .error_union) {
- return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{
- err_union_ty.fmt(pt),
+ return sema.failWithOwnedErrorMsg(parent_block, msg: {
+ const msg = try sema.errMsg(operand_src, "expected error union type, found '{f}'", .{err_union_ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, err_union_ty);
+ try sema.errNote(operand_src, msg, "consider omitting 'try'", .{});
+ break :msg msg;
});
}
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
@@ -18694,8 +18243,12 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
const pt = sema.pt;
const zcu = pt.zcu;
if (err_union_ty.zigTypeTag(zcu) != .error_union) {
- return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{
- err_union_ty.fmt(pt),
+ return sema.failWithOwnedErrorMsg(parent_block, msg: {
+ const msg = try sema.errMsg(operand_src, "expected error union type, found '{f}'", .{err_union_ty.fmt(pt)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, err_union_ty);
+ try sema.errNote(operand_src, msg, "consider omitting 'try'", .{});
+ break :msg msg;
});
}
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
@@ -20019,7 +19572,7 @@ fn structInitAnon(
try sema.declareDependency(.{ .interned = struct_ty });
try sema.addTypeReferenceEntry(src, struct_ty);
- const runtime_index = opt_runtime_index orelse {
+ _ = opt_runtime_index orelse {
const struct_val = try pt.intern(.{ .aggregate = .{
.ty = struct_ty,
.storage = .{ .elems = values },
@@ -20027,11 +19580,6 @@ fn structInitAnon(
return sema.addConstantMaybeRef(struct_val, is_ref);
};
- try sema.requireRuntimeBlock(block, LazySrcLoc.unneeded, block.src(.{ .init_elem = .{
- .init_node_offset = src.offset.node_offset.x,
- .elem_index = @intCast(runtime_index),
- } }));
-
if (is_ref) {
const target = zcu.getTarget();
const alloc_ty = try pt.ptrTypeSema(.{
@@ -20160,7 +19708,7 @@ fn zirArrayInit(
if (!comptime_known) break @intCast(i);
} else null;
- const runtime_index = opt_runtime_index orelse {
+ _ = opt_runtime_index orelse {
const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len);
for (elem_vals, resolved_args) |*val, arg| {
// We checked that all args are comptime above.
@@ -20175,11 +19723,6 @@ fn zirArrayInit(
return sema.addConstantMaybeRef(result_val.toIntern(), is_ref);
};
- try sema.requireRuntimeBlock(block, LazySrcLoc.unneeded, block.src(.{ .init_elem = .{
- .init_node_offset = src.offset.node_offset.x,
- .elem_index = runtime_index,
- } }));
-
if (is_ref) {
const target = zcu.getTarget();
const alloc_ty = try pt.ptrTypeSema(.{
@@ -21089,6 +20632,16 @@ fn zirReify(
}
const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
+ const has_tag = tag_type_val.optionalValue(zcu) != null;
+
+ if (has_tag) {
+ switch (layout) {
+ .@"extern" => return sema.fail(block, src, "extern union does not support enum tag type", .{}),
+ .@"packed" => return sema.fail(block, src, "packed union does not support enum tag type", .{}),
+ .auto => {},
+ }
+ }
+
const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });
return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
@@ -22483,11 +22036,18 @@ fn ptrCastFull(
.slice => {},
.many, .c, .one => break :len null,
}
- // `null` means the operand is a runtime-known slice (so the length is runtime-known).
- const opt_src_len: ?u64 = switch (src_info.flags.size) {
- .one => 1,
- .slice => src_len: {
- const operand_val = try sema.resolveValue(operand) orelse break :src_len null;
+ // A `null` length means the operand is a runtime-known slice (so the length is runtime-known).
+ // `src_elem_type` is different from `src_info.child` if the latter is an array, to ensure we ignore sentinels.
+ const src_elem_ty: Type, const opt_src_len: ?u64 = switch (src_info.flags.size) {
+ .one => src: {
+ const true_child: Type = .fromInterned(src_info.child);
+ break :src switch (true_child.zigTypeTag(zcu)) {
+ .array => .{ true_child.childType(zcu), true_child.arrayLen(zcu) },
+ else => .{ true_child, 1 },
+ };
+ },
+ .slice => src: {
+ const operand_val = try sema.resolveValue(operand) orelse break :src .{ .fromInterned(src_info.child), null };
if (operand_val.isUndef(zcu)) break :len .undef;
const slice_val = switch (operand_ty.zigTypeTag(zcu)) {
.optional => operand_val.optionalValue(zcu) orelse break :len .undef,
@@ -22496,14 +22056,13 @@ fn ptrCastFull(
};
const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));
if (slice_len_resolved.isUndef(zcu)) break :len .undef;
- break :src_len slice_len_resolved.toUnsignedInt(zcu);
+ break :src .{ .fromInterned(src_info.child), slice_len_resolved.toUnsignedInt(zcu) };
},
.many, .c => {
return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});
},
};
const dest_elem_ty: Type = .fromInterned(dest_info.child);
- const src_elem_ty: Type = .fromInterned(src_info.child);
if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) {
break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice;
}
@@ -22519,7 +22078,7 @@ fn ptrCastFull(
const bytes = src_len * src_elem_size;
const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {
.slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}),
- .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}),
+ .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{Type.fromInterned(src_info.child).fmt(pt)}),
else => unreachable,
};
break :len .{ .constant = dest_len };
@@ -25052,6 +24611,7 @@ fn analyzeMinMax(
} else {
for (operands[1..], operand_srcs[1..]) |operand, operand_src| {
const operand_ty = sema.typeOf(operand);
+ try sema.checkNumericType(block, operand_src, operand_ty);
if (operand_ty.zigTypeTag(zcu) == .vector) {
return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(operand_srcs[0], "expected vector, found '{f}'", .{first_operand_ty.fmt(pt)});
@@ -28009,15 +27569,24 @@ fn unionFieldPtr(
return Air.internedToRef(field_ptr_val.toIntern());
}
- if (!initializing and union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and
- union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)
- {
- const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);
- const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
- // TODO would it be better if get_union_tag supported pointers to unions?
- const union_val = try block.addTyOp(.load, union_ty, union_ptr);
- const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_ty), union_val);
- try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag);
+ // If the union has a tag, we must either set or or safety check it depending on `initializing`.
+ tag: {
+ if (union_ty.containerLayout(zcu) != .auto) break :tag;
+ const tag_ty: Type = .fromInterned(union_obj.enum_tag_ty);
+ if (try sema.typeHasOnePossibleValue(tag_ty) != null) break :tag;
+ // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
+ // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
+ const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
+ if (initializing) {
+ const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));
+ try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
+ } else if (block.wantSafety() and union_obj.hasTag(ip)) {
+ // The tag exists at runtime (safety tag), so emit a safety check.
+ // TODO would it be better if get_union_tag supported pointers to unions?
+ const union_val = try block.addTyOp(.load, union_ty, union_ptr);
+ const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);
+ try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(want_tag));
+ }
}
if (field_ty.zigTypeTag(zcu) == .noreturn) {
_ = try block.addNoOp(.unreach);
@@ -29166,17 +28735,36 @@ fn coerceExtra(
break :int;
};
const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);
- // TODO implement this compile error
- //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty);
- //if (!int_again_val.eql(val, inst_ty, zcu)) {
- // return sema.fail(
- // block,
- // inst_src,
- // "type '{f}' cannot represent integer value '{f}'",
- // .{ dest_ty.fmt(pt), val },
- // );
- //}
- return Air.internedToRef(result_val.toIntern());
+ const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {
+ else => unreachable,
+ .undef => true,
+ .float => |float| fits: {
+ var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
+ const operand_big_int = val.toBigInt(&buffer, zcu);
+ switch (float.storage) {
+ inline else => |x| {
+ if (!std.math.isFinite(x)) break :fits false;
+ var result_big_int: std.math.big.int.Mutable = .{
+ .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
+ .len = undefined,
+ .positive = undefined,
+ };
+ switch (result_big_int.setFloat(x, .nearest_even)) {
+ .inexact => break :fits false,
+ .exact => {},
+ }
+ break :fits result_big_int.toConst().eql(operand_big_int);
+ },
+ }
+ },
+ };
+ if (!fits) return sema.fail(
+ block,
+ inst_src,
+ "type '{f}' cannot represent integer value '{f}'",
+ .{ dest_ty.fmt(pt), val.fmtValue(pt) },
+ );
+ return .fromValue(result_val);
},
else => {},
},
@@ -32309,6 +31897,38 @@ fn analyzeSlice(
break :e try sema.coerce(block, .usize, uncasted_end, end_src);
} else break :e try sema.coerce(block, .usize, uncasted_end_opt, end_src);
}
+
+ // when slicing a many-item pointer, if a sentinel `S` is provided as in `ptr[a.. :S]`, it
+ // must match the sentinel of `@TypeOf(ptr)`.
+ sentinel_check: {
+ if (sentinel_opt == .none) break :sentinel_check;
+ const provided = provided: {
+ const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src);
+ try checkSentinelType(sema, block, sentinel_src, elem_ty);
+ break :provided try sema.resolveConstDefinedValue(
+ block,
+ sentinel_src,
+ casted,
+ .{ .simple = .slice_sentinel },
+ );
+ };
+
+ if (ptr_sentinel) |current| {
+ if (provided.toIntern() == current.toIntern()) break :sentinel_check;
+ }
+
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(sentinel_src, "sentinel-terminated slicing of many-item pointer must match existing sentinel", .{});
+ errdefer msg.destroy(sema.gpa);
+ if (ptr_sentinel) |current| {
+ try sema.errNote(sentinel_src, msg, "expected sentinel '{f}', found '{f}'", .{ current.fmtValue(pt), provided.fmtValue(pt) });
+ } else {
+ try sema.errNote(ptr_src, msg, "type '{f}' does not have a sentinel", .{slice_ty.fmt(pt)});
+ }
+ try sema.errNote(src, msg, "use @ptrCast to cast pointer sentinel", .{});
+ break :msg msg;
+ });
+ }
return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
};
diff --git a/src/Zcu.zig b/src/Zcu.zig
index df35777231..c13f7aaac9 100644
--- a/src/Zcu.zig
+++ b/src/Zcu.zig
@@ -3859,7 +3859,12 @@ pub fn atomicPtrAlignment(
}
return .none;
}
- if (ty.isAbiInt(zcu)) {
+ if (switch (ty.zigTypeTag(zcu)) {
+ .int, .@"enum" => true,
+ .@"struct" => ty.containerLayout(zcu) == .@"packed",
+ else => false,
+ }) {
+ assert(ty.isAbiInt(zcu));
const bit_count = ty.intInfo(zcu).bits;
if (bit_count > max_atomic_bits) {
diags.* = .{
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 89a23d3514..ad2d1b580f 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1103,11 +1103,7 @@ const FormatAirData = struct {
inst: Air.Inst.Index,
};
fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {
- // not acceptable implementation because it ignores `w`:
- //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
- _ = data;
- _ = w;
- @panic("TODO: unimplemented");
+ data.self.air.writeInst(w, data.inst, data.self.pt, data.self.liveness);
}
fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {
return .{ .data = .{ .self = self, .inst = inst } };
@@ -168141,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.unused,
.unused,
},
- .dst_temps = .{ .{ .cc = .b }, .unused },
+ .dst_temps = .{ .{ .cc = .be }, .unused },
.clobbers = .{ .eflags = true },
.each = .{ .once = &.{
.{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
@@ -168165,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.unused,
.unused,
},
- .dst_temps = .{ .{ .cc = .b }, .unused },
+ .dst_temps = .{ .{ .cc = .be }, .unused },
.clobbers = .{ .eflags = true },
.each = .{ .once = &.{
.{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
@@ -168189,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.unused,
.unused,
},
- .dst_temps = .{ .{ .cc = .b }, .unused },
+ .dst_temps = .{ .{ .cc = .be }, .unused },
.clobbers = .{ .eflags = true },
.each = .{ .once = &.{
.{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
@@ -179300,10 +179296,13 @@ fn lowerSwitchBr(
} else undefined;
const table_start: u31 = @intCast(cg.mir_table.items.len);
{
- const condition_index_reg = if (condition_index.isRegister())
- condition_index.getReg().?
- else
- try cg.copyToTmpRegister(.usize, condition_index);
+ const condition_index_reg = condition_index_reg: {
+ if (condition_index.isRegister()) {
+ const condition_index_reg = condition_index.getReg().?;
+ if (condition_index_reg.isClass(.general_purpose)) break :condition_index_reg condition_index_reg;
+ }
+ break :condition_index_reg try cg.copyToTmpRegister(.usize, condition_index);
+ };
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);
@@ -191921,18 +191920,15 @@ const Select = struct {
error.InvalidInstruction => {
const fixes = @tagName(mir_tag[0]);
const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
- return s.cg.fail(
- "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'",
- .{
- fixes[0..fixes_blank],
- @tagName(mir_tag[1]),
- fixes[fixes_blank + 1 ..],
- @tagName(mir_ops[0]),
- @tagName(mir_ops[1]),
- @tagName(mir_ops[2]),
- @tagName(mir_ops[3]),
- },
- );
+ return s.cg.fail("invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", .{
+ fixes[0..fixes_blank],
+ @tagName(mir_tag[1]),
+ fixes[fixes_blank + 1 ..],
+ @tagName(mir_ops[0]),
+ @tagName(mir_ops[1]),
+ @tagName(mir_ops[2]),
+ @tagName(mir_ops[3]),
+ });
},
else => |e| return e,
};
@@ -194424,6 +194420,18 @@ fn select(
while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {
if (try src_pattern.convert(src_temp, cg)) break;
} else break;
+ var src_locks: [s_src_temps.len][2]?RegisterLock = @splat(@splat(null));
+ for (src_locks[0..src_temps.len], src_temps) |*locks, src_temp| {
+ const regs: [2]Register = switch (src_temp.tracking(cg).short) {
+ else => continue,
+ .register => |reg| .{ reg, .none },
+ .register_pair => |regs| regs,
+ };
+ for (regs, locks) |reg, *lock| {
+ if (reg == .none) continue;
+ lock.* = cg.register_manager.lockRegIndex(RegisterManager.indexOfRegIntoTracked(reg) orelse continue);
+ }
+ }
@memcpy(s_src_temps[0..src_temps.len], src_temps);
std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]);
@@ -194442,6 +194450,7 @@ fn select(
}
assert(s.top == 0);
+ for (src_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
caller_preserved: {
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index af7304709c..cab392a7cd 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void {
else if (emit.bin_file.cast(.macho)) |macho_file|
macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
- else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: {
- const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
- return emit.fail("{s} creating lazy symbol", .{@errorName(err)});
- break :sym_index coff_file.getAtom(atom).getSymbolIndex().?;
- } else if (emit.bin_file.cast(.plan9)) |p9_file|
+ else if (emit.bin_file.cast(.coff)) |coff_file|
+ if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom|
+ coff_file.getAtom(atom).getSymbolIndex().?
+ else |err|
+ return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
+ else if (emit.bin_file.cast(.plan9)) |p9_file|
p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
else
diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig
index f4b02a13c8..2904d36b7f 100644
--- a/src/codegen/aarch64.zig
+++ b/src/codegen/aarch64.zig
@@ -19,8 +19,12 @@ pub fn generate(
) !Mir {
const zcu = pt.zcu;
const gpa = zcu.gpa;
+ const ip = &zcu.intern_pool;
const func = zcu.funcInfo(func_index);
- const func_type = zcu.intern_pool.indexToKey(func.ty).func_type;
+ const func_zir = func.zir_body_inst.resolveFull(ip).?;
+ const file = zcu.fileByIndex(func_zir.file);
+ const named_params_len = file.zir.?.getParamBody(func_zir.inst).len;
+ const func_type = ip.indexToKey(func.ty).func_type;
assert(liveness.* == null);
const mod = zcu.navFileScope(func.owner_nav).mod.?;
@@ -47,6 +51,7 @@ pub fn generate(
.literals = .empty,
.nav_relocs = .empty,
.uav_relocs = .empty,
+ .lazy_relocs = .empty,
.global_relocs = .empty,
.literal_relocs = .empty,
@@ -60,23 +65,32 @@ pub fn generate(
.values = .empty,
};
defer isel.deinit();
+ const is_sysv = !isel.target.os.tag.isDarwin() and isel.target.os.tag != .windows;
+ const is_sysv_var_args = is_sysv and func_type.is_var_args;
const air_main_body = air.getMainBody();
var param_it: Select.CallAbiIterator = .init;
const air_args = for (air_main_body, 0..) |air_inst_index, body_index| {
if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index];
- const param_ty = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg.ty.toType();
- const param_vi = try param_it.param(&isel, param_ty);
+ const arg = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg;
+ const param_ty = arg.ty.toType();
+ const param_vi = param_vi: {
+ if (arg.zir_param_index >= named_params_len) {
+ assert(func_type.is_var_args);
+ if (!is_sysv) break :param_vi try param_it.nonSysvVarArg(&isel, param_ty);
+ }
+ break :param_vi try param_it.param(&isel, param_ty);
+ };
tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) });
try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?);
} else unreachable;
const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start;
- const saved_gra_end = if (func_type.is_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn;
+ const saved_gra_end = if (is_sysv_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn;
const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start);
const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start;
- const saved_vra_end = if (func_type.is_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn;
+ const saved_vra_end = if (is_sysv_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn;
const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start);
const frame_record = 2;
@@ -84,11 +98,16 @@ pub fn generate(
.base = .fp,
.offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2),
};
- isel.va_list = .{
- .__stack = named_stack_args.withOffset(param_it.nsaa),
- .__gr_top = named_stack_args,
- .__vr_top = .{ .base = .fp, .offset = 0 },
- };
+ const stack_var_args = named_stack_args.withOffset(param_it.nsaa);
+ const gr_top = named_stack_args;
+ const vr_top: Select.Value.Indirect = .{ .base = .fp, .offset = 0 };
+ isel.va_list = if (is_sysv) .{ .sysv = .{
+ .__stack = stack_var_args,
+ .__gr_top = gr_top,
+ .__vr_top = vr_top,
+ .__gr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.ngrn_end) - @intFromEnum(param_it.ngrn)) * -8,
+ .__vr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.nsrn_end) - @intFromEnum(param_it.nsrn)) * -16,
+ } } else .{ .other = stack_var_args };
// translate arg locations from caller-based to callee-based
for (air_args) |air_inst_index| {
@@ -101,15 +120,13 @@ pub fn generate(
};
switch (passed_vi.parent(&isel)) {
.unallocated => if (!mod.strip) {
- var part_it = arg_vi.parts(&isel);
- const first_passed_part_vi = part_it.next() orelse passed_vi;
+ var part_it = passed_vi.parts(&isel);
+ const first_passed_part_vi = part_it.next().?;
const hint_ra = first_passed_part_vi.hint(&isel).?;
passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())
- isel.va_list.__vr_top.withOffset(@as(i8, -16) *
- (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
+ vr_top.withOffset(@as(i8, -16) * (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
else
- isel.va_list.__gr_top.withOffset(@as(i8, -8) *
- (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
+ gr_top.withOffset(@as(i8, -8) * (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
},
.stack_slot => |stack_slot| {
assert(stack_slot.base == .sp);
@@ -151,13 +168,7 @@ pub fn generate(
isel.verify(true);
const prologue = isel.instructions.items.len;
- const epilogue = try isel.layout(
- param_it,
- func_type.is_var_args,
- saved_gra_len,
- saved_vra_len,
- mod,
- );
+ const epilogue = try isel.layout(param_it, is_sysv_var_args, saved_gra_len, saved_vra_len, mod);
const instructions = try isel.instructions.toOwnedSlice(gpa);
var mir: Mir = .{
@@ -167,6 +178,7 @@ pub fn generate(
.literals = &.{},
.nav_relocs = &.{},
.uav_relocs = &.{},
+ .lazy_relocs = &.{},
.global_relocs = &.{},
.literal_relocs = &.{},
};
@@ -174,6 +186,7 @@ pub fn generate(
mir.literals = try isel.literals.toOwnedSlice(gpa);
mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);
mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);
+ mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa);
mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);
mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);
return mir;
diff --git a/src/codegen/aarch64/Assemble.zig b/src/codegen/aarch64/Assemble.zig
index 080df667d7..494e012d80 100644
--- a/src/codegen/aarch64/Assemble.zig
+++ b/src/codegen/aarch64/Assemble.zig
@@ -6,14 +6,19 @@ pub const Operand = union(enum) {
};
pub fn nextInstruction(as: *Assemble) !?Instruction {
- @setEvalBranchQuota(37_000);
+ @setEvalBranchQuota(42_000);
comptime var ct_token_buf: [token_buf_len]u8 = undefined;
var token_buf: [token_buf_len]u8 = undefined;
const original_source = while (true) {
const original_source = as.source;
const source_token = try as.nextToken(&token_buf, .{});
- if (source_token.len == 0) return null;
- if (source_token[0] != '\n') break original_source;
+ switch (source_token.len) {
+ 0 => return null,
+ else => switch (source_token[0]) {
+ else => break original_source,
+ '\n', ';' => {},
+ },
+ }
};
log.debug(
\\.
@@ -52,7 +57,13 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
std.zig.fmtString(source_token),
});
if (pattern_token.len == 0) {
- if (source_token.len > 0 and source_token[0] != '\n') break :next_pattern;
+ switch (source_token.len) {
+ 0 => {},
+ else => switch (source_token[0]) {
+ else => break :next_pattern,
+ '\n', ';' => {},
+ },
+ }
const encode = @field(Instruction, @tagName(instruction.encode[0]));
const Encode = @TypeOf(encode);
var args: std.meta.ArgsTuple(Encode) = undefined;
@@ -65,7 +76,7 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
const symbol = &@field(symbols, symbol_name);
symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;
log.debug("{s} = {any}", .{ symbol_name, symbol.* });
- } else if (!std.ascii.eqlIgnoreCase(pattern_token, source_token)) break :next_pattern;
+ } else if (!toUpperEqlAssertUpper(source_token, pattern_token)) break :next_pattern;
}
}
log.debug("'{s}' not matched...", .{instruction.pattern});
@@ -125,6 +136,15 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
}
}
+fn toUpperEqlAssertUpper(lhs: []const u8, rhs: []const u8) bool {
+ if (lhs.len != rhs.len) return false;
+ for (lhs, rhs) |l, r| {
+ assert(!std.ascii.isLower(r));
+ if (std.ascii.toUpper(l) != r) return false;
+ }
+ return true;
+}
+
const token_buf_len = "v31.b[15]".len;
fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
operands: bool = false,
@@ -134,7 +154,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
while (true) c: switch (as.source[0]) {
0 => return as.source[0..0],
'\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..],
- '\n', '!', '#', ',', '[', ']' => {
+ '\n', '!', '#', ',', ';', '[', ']' => {
defer as.source = as.source[1..];
return as.source[0..1];
},
diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig
index 1446238888..b6598b7ea7 100644
--- a/src/codegen/aarch64/Mir.zig
+++ b/src/codegen/aarch64/Mir.zig
@@ -4,6 +4,7 @@ epilogue: []const Instruction,
literals: []const u32,
nav_relocs: []const Reloc.Nav,
uav_relocs: []const Reloc.Uav,
+lazy_relocs: []const Reloc.Lazy,
global_relocs: []const Reloc.Global,
literal_relocs: []const Reloc.Literal,
@@ -21,8 +22,13 @@ pub const Reloc = struct {
reloc: Reloc,
};
+ pub const Lazy = struct {
+ symbol: link.File.LazySymbol,
+ reloc: Reloc,
+ };
+
pub const Global = struct {
- global: [*:0]const u8,
+ name: [*:0]const u8,
reloc: Reloc,
};
@@ -38,6 +44,7 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
gpa.free(mir.literals);
gpa.free(mir.nav_relocs);
gpa.free(mir.uav_relocs);
+ gpa.free(mir.lazy_relocs);
gpa.free(mir.global_relocs);
gpa.free(mir.literal_relocs);
mir.* = undefined;
@@ -119,16 +126,37 @@ pub fn emit(
body_end - Instruction.size * (1 + uav_reloc.reloc.label),
uav_reloc.reloc.addend,
);
+ for (mir.lazy_relocs) |lazy_reloc| try emitReloc(
+ lf,
+ zcu,
+ func.owner_nav,
+ if (lf.cast(.elf)) |ef|
+ ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
+ return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
+ else if (lf.cast(.macho)) |mf|
+ mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
+ return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
+ else if (lf.cast(.coff)) |cf|
+ if (cf.getOrCreateAtomForLazySymbol(pt, lazy_reloc.symbol)) |atom|
+ cf.getAtom(atom).getSymbolIndex().?
+ else |err|
+ return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
+ else
+ return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
+ mir.body[lazy_reloc.reloc.label],
+ body_end - Instruction.size * (1 + lazy_reloc.reloc.label),
+ lazy_reloc.reloc.addend,
+ );
for (mir.global_relocs) |global_reloc| try emitReloc(
lf,
zcu,
func.owner_nav,
if (lf.cast(.elf)) |ef|
- try ef.getGlobalSymbol(std.mem.span(global_reloc.global), null)
+ try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)
else if (lf.cast(.macho)) |mf|
- try mf.getGlobalSymbol(std.mem.span(global_reloc.global), null)
+ try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)
else if (lf.cast(.coff)) |cf|
- try cf.getGlobalSymbol(std.mem.span(global_reloc.global), "compiler_rt")
+ try cf.getGlobalSymbol(std.mem.span(global_reloc.name), "compiler_rt")
else
return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
mir.body[global_reloc.reloc.label],
@@ -172,35 +200,6 @@ fn emitReloc(
const gpa = zcu.gpa;
switch (instruction.decode()) {
else => unreachable,
- .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
- const zo = ef.zigObjectPtr().?;
- const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
- const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
- .b => .JUMP26,
- .bl => .CALL26,
- };
- try atom.addReloc(gpa, .{
- .r_offset = offset,
- .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
- .r_addend = @bitCast(addend),
- }, zo);
- } else if (lf.cast(.macho)) |mf| {
- const zo = mf.getZigObject().?;
- const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
- try atom.addReloc(mf, .{
- .tag = .@"extern",
- .offset = offset,
- .target = sym_index,
- .addend = @bitCast(addend),
- .type = .branch,
- .meta = .{
- .pcrel = true,
- .has_subtractor = false,
- .length = 2,
- .symbolnum = @intCast(sym_index),
- },
- });
- },
.data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
const zo = ef.zigObjectPtr().?;
const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
@@ -259,6 +258,80 @@ fn emitReloc(
},
}
},
+ .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
+ const zo = ef.zigObjectPtr().?;
+ const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
+ const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
+ .b => .JUMP26,
+ .bl => .CALL26,
+ };
+ try atom.addReloc(gpa, .{
+ .r_offset = offset,
+ .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
+ .r_addend = @bitCast(addend),
+ }, zo);
+ } else if (lf.cast(.macho)) |mf| {
+ const zo = mf.getZigObject().?;
+ const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
+ try atom.addReloc(mf, .{
+ .tag = .@"extern",
+ .offset = offset,
+ .target = sym_index,
+ .addend = @bitCast(addend),
+ .type = .branch,
+ .meta = .{
+ .pcrel = true,
+ .has_subtractor = false,
+ .length = 2,
+ .symbolnum = @intCast(sym_index),
+ },
+ });
+ },
+ .load_store => |decoded| if (lf.cast(.elf)) |ef| {
+ const zo = ef.zigObjectPtr().?;
+ const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
+ const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
+ .integer => |integer| switch (integer.decode()) {
+ .unallocated, .prfm => unreachable,
+ .strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC,
+ .strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC,
+ .ldrsw => .LDST32_ABS_LO12_NC,
+ inline .str, .ldr => |encoded| switch (encoded.sf) {
+ .word => .LDST32_ABS_LO12_NC,
+ .doubleword => .LDST64_ABS_LO12_NC,
+ },
+ },
+ .vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) {
+ .byte => .LDST8_ABS_LO12_NC,
+ .half => .LDST16_ABS_LO12_NC,
+ .single => .LDST32_ABS_LO12_NC,
+ .double => .LDST64_ABS_LO12_NC,
+ .quad => .LDST128_ABS_LO12_NC,
+ .scalable, .predicate => unreachable,
+ },
+ };
+ try atom.addReloc(gpa, .{
+ .r_offset = offset,
+ .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
+ .r_addend = @bitCast(addend),
+ }, zo);
+ } else if (lf.cast(.macho)) |mf| {
+ const zo = mf.getZigObject().?;
+ const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
+ try atom.addReloc(mf, .{
+ .tag = .@"extern",
+ .offset = offset,
+ .target = sym_index,
+ .addend = @bitCast(addend),
+ .type = .pageoff,
+ .meta = .{
+ .pcrel = false,
+ .has_subtractor = false,
+ .length = 2,
+ .symbolnum = @intCast(sym_index),
+ },
+ });
+ },
}
}
diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig
index f7da48d847..13c001a200 100644
--- a/src/codegen/aarch64/Select.zig
+++ b/src/codegen/aarch64/Select.zig
@@ -22,15 +22,21 @@ instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction),
literals: std.ArrayListUnmanaged(u32),
nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav),
uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav),
+lazy_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Lazy),
global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global),
literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal),
// Stack Frame
returns: bool,
-va_list: struct {
- __stack: Value.Indirect,
- __gr_top: Value.Indirect,
- __vr_top: Value.Indirect,
+va_list: union(enum) {
+ other: Value.Indirect,
+ sysv: struct {
+ __stack: Value.Indirect,
+ __gr_top: Value.Indirect,
+ __vr_top: Value.Indirect,
+ __gr_offs: i32,
+ __vr_offs: i32,
+ },
},
stack_size: u24,
stack_align: InternPool.Alignment,
@@ -50,11 +56,11 @@ pub const Block = struct {
std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),
);
- fn branch(block: *const Block, isel: *Select) !void {
- if (isel.instructions.items.len > block.target_label) {
- try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - block.target_label) << 2)));
+ fn branch(target_block: *const Block, isel: *Select) !void {
+ if (isel.instructions.items.len > target_block.target_label) {
+ try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - target_block.target_label) << 2)));
}
- try isel.merge(&block.live_registers, .{});
+ try isel.merge(&target_block.live_registers, .{});
}
};
@@ -84,12 +90,12 @@ pub const Loop = struct {
pub const empty_list: u32 = std.math.maxInt(u32);
- fn branch(loop: *Loop, isel: *Select) !void {
+ fn branch(target_loop: *Loop, isel: *Select) !void {
try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1);
- const repeat_list_tail = loop.repeat_list;
- loop.repeat_list = @intCast(isel.instructions.items.len);
+ const repeat_list_tail = target_loop.repeat_list;
+ target_loop.repeat_list = @intCast(isel.instructions.items.len);
isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail));
- try isel.merge(&loop.live_registers, .{});
+ try isel.merge(&target_loop.live_registers, .{});
}
};
@@ -108,6 +114,7 @@ pub fn deinit(isel: *Select) void {
isel.literals.deinit(gpa);
isel.nav_relocs.deinit(gpa);
isel.uav_relocs.deinit(gpa);
+ isel.lazy_relocs.deinit(gpa);
isel.global_relocs.deinit(gpa);
isel.literal_relocs.deinit(gpa);
@@ -406,13 +413,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
air_body_index += 1;
},
- .breakpoint,
- .dbg_stmt,
- .dbg_empty_stmt,
- .dbg_var_ptr,
- .dbg_var_val,
- .dbg_arg_inline,
- => {
+ .breakpoint, .dbg_stmt, .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, .c_va_end => {
air_body_index += 1;
air_inst_index = air_body[air_body_index];
continue :air_tag air_tags[@intFromEnum(air_inst_index)];
@@ -426,23 +427,43 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
const extra = isel.air.extraData(Air.Call, pl_op.payload);
const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
isel.saved_registers.insert(.lr);
+ const callee_ty = isel.air.typeOf(pl_op.operand, ip);
+ const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
+ else => unreachable,
+ .func_type => |func_type| func_type,
+ .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,
+ };
try isel.analyzeUse(pl_op.operand);
var param_it: CallAbiIterator = .init;
- for (args) |arg| {
+ for (args, 0..) |arg, arg_index| {
const restore_values_len = isel.values.items.len;
defer isel.values.shrinkRetainingCapacity(restore_values_len);
- const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;
- const param_parent = param_vi.parent(isel);
- switch (switch (param_parent) {
- .unallocated, .stack_slot => param_parent,
+ const param_vi = param_vi: {
+ const param_ty = isel.air.typeOf(arg, ip);
+ if (arg_index >= func_info.param_types.len) {
+ assert(func_info.is_var_args);
+ switch (isel.va_list) {
+ .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty),
+ .sysv => {},
+ }
+ }
+ break :param_vi try param_it.param(isel, param_ty);
+ } orelse continue;
+ defer param_vi.deref(isel);
+ const passed_vi = switch (param_vi.parent(isel)) {
+ .unallocated, .stack_slot => param_vi,
.value, .constant => unreachable,
- .address => |address_vi| address_vi.parent(isel),
- }) {
+ .address => |address_vi| address_vi,
+ };
+ switch (passed_vi.parent(isel)) {
.unallocated => {},
.stack_slot => |stack_slot| {
assert(stack_slot.base == .sp);
- isel.stack_size = @max(isel.stack_size, stack_slot.offset);
+ isel.stack_size = @max(
+ isel.stack_size,
+ stack_slot.offset + @as(u24, @intCast(passed_vi.size(isel))),
+ );
},
.value, .constant, .address => unreachable,
}
@@ -582,7 +603,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
air_body_index += 1;
},
- .@"try", .try_cold, .try_ptr, .try_ptr_cold => {
+ .@"try", .try_cold => {
const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
const extra = isel.air.extraData(Air.Try, pl_op.payload);
@@ -594,6 +615,18 @@ 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)];
},
+ .try_ptr, .try_ptr_cold => {
+ const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
+ const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);
+
+ try isel.analyzeUse(extra.data.ptr);
+ try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
+ try isel.def_order.putNoClobber(gpa, air_inst_index, {});
+
+ air_body_index += 1;
+ air_inst_index = air_body[air_body_index];
+ continue :air_tag air_tags[@intFromEnum(air_inst_index)];
+ },
.ret, .ret_safe, .ret_load => {
const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
isel.returns = true;
@@ -788,7 +821,7 @@ 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)];
},
- .set_err_return_trace, .c_va_end => {
+ .set_err_return_trace => {
const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
try isel.analyzeUse(un_op);
@@ -864,7 +897,7 @@ pub fn finishAnalysis(isel: *Select) !void {
}
}
-pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
+pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void {
const zcu = isel.pt.zcu;
const ip = &zcu.intern_pool;
const gpa = zcu.gpa;
@@ -946,7 +979,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
- .add, .add_optimized, .add_wrap, .sub, .sub_optimized, .sub_wrap => |air_tag| {
+ .add, .add_safe, .add_optimized, .add_wrap, .sub, .sub_safe, .sub_optimized, .sub_wrap => |air_tag| {
if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
defer res_vi.value.deref(isel);
@@ -954,13 +987,16 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
const ty = isel.air.typeOf(bin_op.lhs, ip);
if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) {
else => unreachable,
- .add, .add_wrap => .add,
- .sub, .sub_wrap => .sub,
- }, try isel.use(bin_op.rhs), .{ .wrap = switch (air_tag) {
- else => unreachable,
- .add, .sub => false,
- .add_wrap, .sub_wrap => true,
- } }) else switch (ty.floatBits(isel.target)) {
+ .add, .add_safe, .add_wrap => .add,
+ .sub, .sub_safe, .sub_wrap => .sub,
+ }, try isel.use(bin_op.rhs), .{
+ .overflow = switch (air_tag) {
+ else => unreachable,
+ .add, .sub => .@"unreachable",
+ .add_safe, .sub_safe => .{ .panic = .integer_overflow },
+ .add_wrap, .sub_wrap => .wrap,
+ },
+ }) else switch (ty.floatBits(isel.target)) {
else => unreachable,
16, 32, 64 => |bits| {
const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
@@ -1021,7 +1057,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (air_tag) {
+ .name = switch (air_tag) {
else => unreachable,
.add, .add_optimized => switch (bits) {
else => unreachable,
@@ -1336,7 +1372,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__mulhf3",
32 => "__mulsf3",
@@ -1379,6 +1415,143 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .mul_safe => |air_tag| {
+ if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
+ defer res_vi.value.deref(isel);
+
+ const bin_op = air.data(air.inst_index).bin_op;
+ const ty = isel.air.typeOf(bin_op.lhs, ip);
+ if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
+ const int_info = ty.intInfo(zcu);
+ switch (int_info.signedness) {
+ .signed => switch (int_info.bits) {
+ 0 => unreachable,
+ 1 => {
+ const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
+ const lhs_vi = try isel.use(bin_op.lhs);
+ const rhs_vi = try isel.use(bin_op.rhs);
+ const lhs_mat = try lhs_vi.matReg(isel);
+ const rhs_mat = try rhs_vi.matReg(isel);
+ try isel.emit(.orr(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(.integer_overflow);
+ try isel.emit(.@"b."(
+ .invert(.ne),
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.ands(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
+ try rhs_mat.finish(isel);
+ try lhs_mat.finish(isel);
+ },
+ else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
+ },
+ .unsigned => switch (int_info.bits) {
+ 0 => unreachable,
+ 1 => {
+ const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
+ const lhs_vi = try isel.use(bin_op.lhs);
+ const rhs_vi = try isel.use(bin_op.rhs);
+ const lhs_mat = try lhs_vi.matReg(isel);
+ const rhs_mat = try rhs_vi.matReg(isel);
+ try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
+ try rhs_mat.finish(isel);
+ try lhs_mat.finish(isel);
+ },
+ 2...16 => |bits| {
+ const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
+ const lhs_vi = try isel.use(bin_op.lhs);
+ const rhs_vi = try isel.use(bin_op.rhs);
+ const lhs_mat = try lhs_vi.matReg(isel);
+ const rhs_mat = try rhs_vi.matReg(isel);
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(.integer_overflow);
+ try isel.emit(.@"b."(
+ .eq,
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.ands(.wzr, res_ra.w(), .{ .immediate = .{
+ .N = .word,
+ .immr = @intCast(32 - bits),
+ .imms = @intCast(32 - bits - 1),
+ } }));
+ try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr));
+ try rhs_mat.finish(isel);
+ try lhs_mat.finish(isel);
+ },
+ 17...32 => |bits| {
+ const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
+ const lhs_vi = try isel.use(bin_op.lhs);
+ const rhs_vi = try isel.use(bin_op.rhs);
+ const lhs_mat = try lhs_vi.matReg(isel);
+ const rhs_mat = try rhs_vi.matReg(isel);
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(.integer_overflow);
+ try isel.emit(.@"b."(
+ .eq,
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.ands(.xzr, res_ra.x(), .{ .immediate = .{
+ .N = .doubleword,
+ .immr = @intCast(64 - bits),
+ .imms = @intCast(64 - bits - 1),
+ } }));
+ try isel.emit(.umaddl(res_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr));
+ try rhs_mat.finish(isel);
+ try lhs_mat.finish(isel);
+ },
+ 33...63 => |bits| {
+ const lo64_ra = try res_vi.value.defReg(isel) orelse break :unused;
+ const lhs_vi = try isel.use(bin_op.lhs);
+ const rhs_vi = try isel.use(bin_op.rhs);
+ const lhs_mat = try lhs_vi.matReg(isel);
+ const rhs_mat = try rhs_vi.matReg(isel);
+ const hi64_ra = hi64_ra: {
+ const lo64_lock = isel.tryLockReg(lo64_ra);
+ defer lo64_lock.unlock(isel);
+ break :hi64_ra try isel.allocIntReg();
+ };
+ defer isel.freeReg(hi64_ra);
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(.integer_overflow);
+ try isel.emit(.cbz(
+ hi64_ra.x(),
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.orr(hi64_ra.x(), hi64_ra.x(), .{ .shifted_register = .{
+ .register = lo64_ra.x(),
+ .shift = .{ .lsr = @intCast(bits) },
+ } }));
+ try isel.emit(.madd(lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
+ try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
+ try rhs_mat.finish(isel);
+ try lhs_mat.finish(isel);
+ },
+ 64 => {
+ const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
+ const lhs_vi = try isel.use(bin_op.lhs);
+ const rhs_vi = try isel.use(bin_op.rhs);
+ const lhs_mat = try lhs_vi.matReg(isel);
+ const rhs_mat = try rhs_vi.matReg(isel);
+ try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
+ const hi64_ra = try isel.allocIntReg();
+ defer isel.freeReg(hi64_ra);
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(.integer_overflow);
+ try isel.emit(.cbz(
+ hi64_ra.x(),
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
+ try rhs_mat.finish(isel);
+ try lhs_mat.finish(isel);
+ },
+ 65...128 => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
+ else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
+ },
+ }
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.mul_sat => |air_tag| {
if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
defer res_vi.value.deref(isel);
@@ -1674,7 +1847,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__divhf3",
32 => "__divsf3",
@@ -1746,8 +1919,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
switch (bits) {
else => unreachable,
1...32 => {
- try isel.emit(.sub(res_ra.w(), div_ra.w(), .{ .register = rem_ra.w() }));
- try isel.emit(.csinc(rem_ra.w(), .wzr, .wzr, .ge));
+ try isel.emit(.csel(res_ra.w(), div_ra.w(), rem_ra.w(), .pl));
+ try isel.emit(.sub(rem_ra.w(), div_ra.w(), .{ .immediate = 1 }));
try isel.emit(.ccmp(
rem_ra.w(),
.{ .immediate = 0 },
@@ -1759,8 +1932,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
},
33...64 => {
- try isel.emit(.sub(res_ra.x(), div_ra.x(), .{ .register = rem_ra.x() }));
- try isel.emit(.csinc(rem_ra.x(), .xzr, .xzr, .ge));
+ try isel.emit(.csel(res_ra.x(), div_ra.x(), rem_ra.x(), .pl));
+ try isel.emit(.sub(rem_ra.x(), div_ra.x(), .{ .immediate = 1 }));
try isel.emit(.ccmp(
rem_ra.x(),
.{ .immediate = 0 },
@@ -1813,7 +1986,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (int_info.signedness) {
+ .name = switch (int_info.signedness) {
.signed => "__divti3",
.unsigned => "__udivti3",
},
@@ -1917,7 +2090,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
else => unreachable,
.div_trunc, .div_trunc_optimized => {
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__trunch",
32 => "truncf",
@@ -1931,7 +2104,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
},
.div_floor, .div_floor_optimized => {
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__floorh",
32 => "floorf",
@@ -1946,7 +2119,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
.div_exact, .div_exact_optimized => {},
}
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__divhf3",
32 => "__divsf3",
@@ -1989,7 +2162,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
- .rem => |air_tag| {
+ .rem, .rem_optimized, .mod, .mod_optimized => |air_tag| {
if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
defer res_vi.value.deref(isel);
@@ -2007,17 +2180,57 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
const rhs_mat = try rhs_vi.matReg(isel);
const div_ra = try isel.allocIntReg();
defer isel.freeReg(div_ra);
+ const rem_ra = rem_ra: switch (air_tag) {
+ else => unreachable,
+ .rem => res_ra,
+ .mod => switch (int_info.signedness) {
+ .signed => {
+ const rem_ra = try isel.allocIntReg();
+ errdefer isel.freeReg(rem_ra);
+ switch (int_info.bits) {
+ else => unreachable,
+ 1...32 => {
+ try isel.emit(.csel(res_ra.w(), rem_ra.w(), div_ra.w(), .pl));
+ try isel.emit(.add(div_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() }));
+ try isel.emit(.ccmp(
+ div_ra.w(),
+ .{ .immediate = 0 },
+ .{ .n = false, .z = false, .c = false, .v = false },
+ .ne,
+ ));
+ try isel.emit(.eor(div_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() }));
+ try isel.emit(.subs(.wzr, rem_ra.w(), .{ .immediate = 0 }));
+ },
+ 33...64 => {
+ try isel.emit(.csel(res_ra.x(), rem_ra.x(), div_ra.x(), .pl));
+ try isel.emit(.add(div_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() }));
+ try isel.emit(.ccmp(
+ div_ra.x(),
+ .{ .immediate = 0 },
+ .{ .n = false, .z = false, .c = false, .v = false },
+ .ne,
+ ));
+ try isel.emit(.eor(div_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() }));
+ try isel.emit(.subs(.xzr, rem_ra.x(), .{ .immediate = 0 }));
+ },
+ }
+ break :rem_ra rem_ra;
+ },
+ .unsigned => res_ra,
+ },
+ };
+ defer if (rem_ra != res_ra) isel.freeReg(rem_ra);
switch (int_info.bits) {
else => unreachable,
1...32 => {
- try isel.emit(.msub(res_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
+ try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
try isel.emit(switch (int_info.signedness) {
.signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
.unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
});
},
33...64 => {
- try isel.emit(.msub(res_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));
+ try isel.emit(.msub(rem_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));
try isel.emit(switch (int_info.signedness) {
.signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
.unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
@@ -2028,25 +2241,188 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try lhs_mat.finish(isel);
} else {
const bits = ty.floatBits(isel.target);
-
- try call.prepareReturn(isel);
- switch (bits) {
+ switch (air_tag) {
else => unreachable,
- 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
- 80 => {
- var res_hi16_it = res_vi.value.field(ty, 8, 8);
- const res_hi16_vi = try res_hi16_it.only(isel);
- try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
- var res_lo64_it = res_vi.value.field(ty, 0, 8);
- const res_lo64_vi = try res_lo64_it.only(isel);
- try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
+ .rem, .rem_optimized => {
+ if (!res_vi.value.isUsed(isel)) break :unused;
+ try call.prepareReturn(isel);
+ switch (bits) {
+ else => unreachable,
+ 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
+ 80 => {
+ var res_hi16_it = res_vi.value.field(ty, 8, 8);
+ const res_hi16_vi = try res_hi16_it.only(isel);
+ try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
+ var res_lo64_it = res_vi.value.field(ty, 0, 8);
+ const res_lo64_vi = try res_lo64_it.only(isel);
+ try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
+ },
+ }
+ try call.finishReturn(isel);
+ },
+ .mod, .mod_optimized => switch (bits) {
+ else => unreachable,
+ 16, 32, 64 => {
+ const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
+ try call.prepareReturn(isel);
+ const rem_ra: Register.Alias = .v0;
+ const temp1_ra: Register.Alias = .v1;
+ const temp2_ra: Register.Alias = switch (res_ra) {
+ rem_ra, temp1_ra => .v2,
+ else => res_ra,
+ };
+ const need_fcvt = switch (bits) {
+ else => unreachable,
+ 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
+ 32, 64 => false,
+ };
+ if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
+ try isel.emit(switch (res_ra) {
+ rem_ra => .bif(res_ra.@"8b"(), temp2_ra.@"8b"(), temp1_ra.@"8b"()),
+ temp1_ra => .bsl(res_ra.@"8b"(), rem_ra.@"8b"(), temp2_ra.@"8b"()),
+ else => .bit(res_ra.@"8b"(), rem_ra.@"8b"(), temp1_ra.@"8b"()),
+ });
+ const rhs_vi = try isel.use(bin_op.rhs);
+ const rhs_mat = try rhs_vi.matReg(isel);
+ try isel.emit(bits: switch (bits) {
+ else => unreachable,
+ 16 => if (need_fcvt)
+ continue :bits 32
+ else
+ .fadd(temp2_ra.h(), rem_ra.h(), rhs_mat.ra.h()),
+ 32 => .fadd(temp2_ra.s(), rem_ra.s(), rhs_mat.ra.s()),
+ 64 => .fadd(temp2_ra.d(), rem_ra.d(), rhs_mat.ra.d()),
+ });
+ if (need_fcvt) {
+ try isel.emit(.fcvt(rhs_mat.ra.s(), rhs_mat.ra.h()));
+ try isel.emit(.fcvt(rem_ra.s(), rem_ra.h()));
+ }
+ try isel.emit(.orr(temp1_ra.@"8b"(), temp1_ra.@"8b"(), .{
+ .register = temp2_ra.@"8b"(),
+ }));
+ try isel.emit(switch (bits) {
+ else => unreachable,
+ 16 => .cmge(temp1_ra.@"4h"(), temp1_ra.@"4h"(), .zero),
+ 32 => .cmge(temp1_ra.@"2s"(), temp1_ra.@"2s"(), .zero),
+ 64 => .cmge(temp1_ra.d(), temp1_ra.d(), .zero),
+ });
+ try isel.emit(switch (bits) {
+ else => unreachable,
+ 16 => .fcmeq(temp2_ra.h(), rem_ra.h(), .zero),
+ 32 => .fcmeq(temp2_ra.s(), rem_ra.s(), .zero),
+ 64 => .fcmeq(temp2_ra.d(), rem_ra.d(), .zero),
+ });
+ try isel.emit(.eor(temp1_ra.@"8b"(), rem_ra.@"8b"(), .{
+ .register = rhs_mat.ra.@"8b"(),
+ }));
+ try rhs_mat.finish(isel);
+ try call.finishReturn(isel);
+ },
+ 80, 128 => {
+ if (!res_vi.value.isUsed(isel)) break :unused;
+ try call.prepareReturn(isel);
+ switch (bits) {
+ else => unreachable,
+ 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
+ 80 => {
+ var res_hi16_it = res_vi.value.field(ty, 8, 8);
+ const res_hi16_vi = try res_hi16_it.only(isel);
+ try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
+ var res_lo64_it = res_vi.value.field(ty, 0, 8);
+ const res_lo64_vi = try res_lo64_it.only(isel);
+ try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
+ },
+ }
+ const skip_label = isel.instructions.items.len;
+ try isel.global_relocs.append(gpa, .{
+ .name = switch (bits) {
+ else => unreachable,
+ 16 => "__addhf3",
+ 32 => "__addsf3",
+ 64 => "__adddf3",
+ 80 => "__addxf3",
+ 128 => "__addtf3",
+ },
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.bl(0));
+ const rhs_vi = try isel.use(bin_op.rhs);
+ switch (bits) {
+ else => unreachable,
+ 80 => {
+ const lhs_lo64_ra: Register.Alias = .r0;
+ const lhs_hi16_ra: Register.Alias = .r1;
+ const rhs_lo64_ra: Register.Alias = .r2;
+ const rhs_hi16_ra: Register.Alias = .r3;
+ const temp_ra: Register.Alias = .r4;
+ var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
+ const rhs_hi16_vi = try rhs_hi16_it.only(isel);
+ try call.paramLiveOut(isel, rhs_hi16_vi.?, rhs_hi16_ra);
+ var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
+ const rhs_lo64_vi = try rhs_lo64_it.only(isel);
+ try call.paramLiveOut(isel, rhs_lo64_vi.?, rhs_lo64_ra);
+ try isel.emit(.cbz(
+ temp_ra.x(),
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.orr(temp_ra.x(), lhs_lo64_ra.x(), .{ .shifted_register = .{
+ .register = lhs_hi16_ra.x(),
+ .shift = .{ .lsl = 64 - 15 },
+ } }));
+ try isel.emit(.tbz(
+ temp_ra.w(),
+ 15,
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.eor(temp_ra.w(), lhs_hi16_ra.w(), .{
+ .register = rhs_hi16_ra.w(),
+ }));
+ },
+ 128 => {
+ const lhs_ra: Register.Alias = .v0;
+ const rhs_ra: Register.Alias = .v1;
+ const temp1_ra: Register.Alias = .r0;
+ const temp2_ra: Register.Alias = .r1;
+ try call.paramLiveOut(isel, rhs_vi, rhs_ra);
+ try isel.emit(.@"b."(
+ .pl,
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.cbz(
+ temp1_ra.x(),
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.orr(temp1_ra.x(), temp1_ra.x(), .{ .shifted_register = .{
+ .register = temp2_ra.x(),
+ .shift = .{ .lsl = 1 },
+ } }));
+ try isel.emit(.fmov(temp1_ra.x(), .{
+ .register = rhs_ra.d(),
+ }));
+ try isel.emit(.tbz(
+ temp1_ra.x(),
+ 63,
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ try isel.emit(.eor(temp1_ra.x(), temp1_ra.x(), .{
+ .register = temp2_ra.x(),
+ }));
+ try isel.emit(.fmov(temp2_ra.x(), .{
+ .register = rhs_ra.@"d[]"(1),
+ }));
+ try isel.emit(.fmov(temp1_ra.x(), .{
+ .register = lhs_ra.@"d[]"(1),
+ }));
+ },
+ }
+ try call.finishReturn(isel);
+ },
},
}
- try call.finishReturn(isel);
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__fmodh",
32 => "fmodf",
@@ -2212,7 +2588,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (air_tag) {
+ .name = switch (air_tag) {
else => unreachable,
.max => switch (bits) {
else => unreachable,
@@ -2284,7 +2660,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
else => unreachable,
.add_with_overflow => .add,
.sub_with_overflow => .sub,
- }, rhs_vi, .{ .wrap = true, .overflow_ra = try overflow_vi.?.defReg(isel) orelse .zr });
+ }, rhs_vi, .{
+ .overflow = if (try overflow_vi.?.defReg(isel)) |overflow_ra| .{ .ra = overflow_ra } else .wrap,
+ });
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
@@ -2318,6 +2696,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .inferred_alloc, .inferred_alloc_comptime => unreachable,
.assembly => {
const ty_pl = air.data(air.inst_index).ty_pl;
const extra = isel.air.extraData(Air.Asm, ty_pl.payload);
@@ -3085,14 +3464,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
assert(dst_int_info.bits == src_child_int_info.bits * src_len);
const src_child_size = src_ty.childType(zcu).abiSize(zcu);
if (8 * src_child_size == src_child_int_info.bits) {
- try dst_vi.value.defAddr(isel, dst_ty, dst_int_info, comptime &.initFill(.free)) orelse break :unused;
+ try dst_vi.value.defAddr(isel, dst_ty, .{ .wrap = dst_int_info }) orelse break :unused;
try call.prepareReturn(isel);
try call.finishReturn(isel);
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = "memcpy",
+ .name = "memcpy",
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.bl(0));
@@ -3112,14 +3491,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
assert(dst_child_int_info.bits * dst_len == src_int_info.bits);
const dst_child_size = dst_ty.childType(zcu).abiSize(zcu);
if (8 * dst_child_size == dst_child_int_info.bits) {
- try dst_vi.value.defAddr(isel, dst_ty, null, comptime &.initFill(.free)) orelse break :unused;
+ try dst_vi.value.defAddr(isel, dst_ty, .{}) orelse break :unused;
try call.prepareReturn(isel);
try call.finishReturn(isel);
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = "memcpy",
+ .name = "memcpy",
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.bl(0));
@@ -3139,19 +3518,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
.block => {
const ty_pl = air.data(air.inst_index).ty_pl;
const extra = isel.air.extraData(Air.Block, ty_pl.payload);
-
- if (ty_pl.ty != .noreturn_type) {
- isel.blocks.putAssumeCapacityNoClobber(air.inst_index, .{
- .live_registers = isel.live_registers,
- .target_label = @intCast(isel.instructions.items.len),
- });
- }
- try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
- if (ty_pl.ty != .noreturn_type) {
- const block_entry = isel.blocks.pop().?;
- assert(block_entry.key == air.inst_index);
- if (isel.live_values.fetchRemove(air.inst_index)) |result_vi| result_vi.value.deref(isel);
- }
+ try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
+ isel.air.extra.items[extra.end..][0..extra.data.body_len],
+ ));
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
.loop => {
@@ -3175,11 +3544,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
// IT'S DOM TIME!!!
- for (isel.blocks.values(), 0..) |*block, dom_index| {
+ for (isel.blocks.values(), 0..) |*dom_block, dom_index| {
if (@as(u1, @truncate(isel.dom.items[
loop.dom + dom_index / @bitSizeOf(DomInt)
] >> @truncate(dom_index))) == 0) continue;
- var live_reg_it = block.live_registers.iterator();
+ var live_reg_it = dom_block.live_registers.iterator();
while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
_ => |live_vi| try live_vi.mat(isel),
.allocating => unreachable,
@@ -3211,8 +3580,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
},
.br => {
const br = air.data(air.inst_index).br;
- const block = isel.blocks.getPtr(br.block_inst).?;
- try block.branch(isel);
+ try isel.blocks.getPtr(br.block_inst).?.branch(isel);
if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand);
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
@@ -3224,10 +3592,32 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try isel.emit(.brk(0xf000));
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .ret_addr => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: {
+ defer addr_vi.value.deref(isel);
+ const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused;
+ try isel.emit(.ldr(addr_ra.x(), .{ .unsigned_offset = .{ .base = .fp, .offset = 8 } }));
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .frame_addr => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: {
+ defer addr_vi.value.deref(isel);
+ const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused;
+ try isel.emit(.orr(addr_ra.x(), .xzr, .{ .register = .fp }));
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.call => {
const pl_op = air.data(air.inst_index).pl_op;
const extra = isel.air.extraData(Air.Call, pl_op.payload);
const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
+ const callee_ty = isel.air.typeOf(pl_op.operand, ip);
+ const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
+ else => unreachable,
+ .func_type => |func_type| func_type,
+ .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,
+ };
try call.prepareReturn(isel);
const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index);
@@ -3251,12 +3641,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
.value, .constant => unreachable,
.address => |address_vi| {
maybe_ret_addr_vi = address_vi;
- _ = try def_ret_vi.value.defAddr(
- isel,
- isel.air.typeOfIndex(air.inst_index, ip),
- null,
- &call.caller_saved_regs,
- );
+ _ = try def_ret_vi.value.defAddr(isel, isel.air.typeOfIndex(air.inst_index, ip), .{
+ .expected_live_registers = &call.caller_saved_regs,
+ });
},
}
}
@@ -3294,41 +3681,50 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
ret_addr_vi.hint(isel).?,
);
var param_it: CallAbiIterator = .init;
- for (args) |arg| {
- const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;
+ for (args, 0..) |arg, arg_index| {
+ const param_ty = isel.air.typeOf(arg, ip);
+ const param_vi = param_vi: {
+ if (arg_index >= func_info.param_types.len) {
+ assert(func_info.is_var_args);
+ switch (isel.va_list) {
+ .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty),
+ .sysv => {},
+ }
+ }
+ break :param_vi try param_it.param(isel, param_ty);
+ } orelse continue;
defer param_vi.deref(isel);
const arg_vi = try isel.use(arg);
- const passed_vi = switch (param_vi.parent(isel)) {
- .unallocated, .stack_slot => param_vi,
- .value, .constant => unreachable,
- .address => |address_vi| {
- try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?);
- continue;
+ switch (param_vi.parent(isel)) {
+ .unallocated => if (param_vi.hint(isel)) |param_ra| {
+ try call.paramLiveOut(isel, arg_vi, param_ra);
+ } else {
+ var param_part_it = param_vi.parts(isel);
+ var arg_part_it = arg_vi.parts(isel);
+ if (arg_part_it.only()) |_| {
+ try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining);
+ arg_vi.setParts(isel, param_part_it.remaining);
+ while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart(
+ isel,
+ param_part_vi.get(isel).offset_from_parent,
+ param_part_vi.size(isel),
+ );
+ param_part_it = param_vi.parts(isel);
+ arg_part_it = arg_vi.parts(isel);
+ }
+ while (param_part_it.next()) |param_part_vi| {
+ const arg_part_vi = arg_part_it.next().?;
+ assert(arg_part_vi.get(isel).offset_from_parent ==
+ param_part_vi.get(isel).offset_from_parent);
+ assert(arg_part_vi.size(isel) == param_part_vi.size(isel));
+ try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?);
+ }
},
- };
- if (passed_vi.hint(isel)) |param_ra| {
- try call.paramLiveOut(isel, arg_vi, param_ra);
- } else {
- var param_part_it = passed_vi.parts(isel);
- var arg_part_it = arg_vi.parts(isel);
- if (arg_part_it.only()) |_| {
- try isel.values.ensureUnusedCapacity(isel.pt.zcu.gpa, param_part_it.remaining);
- arg_vi.setParts(isel, param_part_it.remaining);
- while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart(
- isel,
- param_part_vi.get(isel).offset_from_parent,
- param_part_vi.size(isel),
- );
- param_part_it = passed_vi.parts(isel);
- arg_part_it = arg_vi.parts(isel);
- }
- while (param_part_it.next()) |param_part_vi| {
- const arg_part_vi = arg_part_it.next().?;
- assert(arg_part_vi.get(isel).offset_from_parent ==
- param_part_vi.get(isel).offset_from_parent);
- assert(arg_part_vi.size(isel) == param_part_vi.size(isel));
- try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?);
- }
+ .stack_slot => |stack_slot| try arg_vi.store(isel, param_ty, stack_slot.base, .{
+ .offset = @intCast(stack_slot.offset),
+ }),
+ .value, .constant => unreachable,
+ .address => |address_vi| try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?),
}
}
try call.finishParams(isel);
@@ -3659,7 +4055,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (air_tag) {
+ .name = switch (air_tag) {
else => unreachable,
.sqrt => switch (bits) {
else => unreachable,
@@ -3751,7 +4147,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (air_tag) {
+ .name = switch (air_tag) {
else => unreachable,
.sin => switch (bits) {
else => unreachable,
@@ -4239,7 +4635,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__cmphf2",
32 => "__cmpsf2",
@@ -4328,7 +4724,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
};
var cond_mat: ?Value.Materialize = null;
var cond_reg: Register = undefined;
- var temp_reg: Register = undefined;
var cases_it = switch_br.iterateCases();
while (cases_it.next()) |case| {
const next_label = isel.instructions.items.len;
@@ -4342,11 +4737,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
if (cond_mat == null) {
var cond_vi = try isel.use(switch_br.operand);
cond_mat = try cond_vi.matReg(isel);
- const temp_ra = try isel.allocIntReg();
- cond_reg, temp_reg = switch (cond_int_info.bits) {
+ cond_reg = switch (cond_int_info.bits) {
else => unreachable,
- 1...32 => .{ cond_mat.?.ra.w(), temp_ra.w() },
- 33...64 => .{ cond_mat.?.ra.x(), temp_ra.x() },
+ 1...32 => cond_mat.?.ra.w(),
+ 33...64 => cond_mat.?.ra.x(),
};
}
if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned(
@@ -4387,17 +4781,45 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
) else high_bigint.toInt(i64) catch
return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)});
+ const adjusted_ra = switch (low_int) {
+ 0 => cond_mat.?.ra,
+ else => try isel.allocIntReg(),
+ };
+ defer if (adjusted_ra != cond_mat.?.ra) isel.freeReg(adjusted_ra);
+ const adjusted_reg = switch (cond_int_info.bits) {
+ else => unreachable,
+ 1...32 => adjusted_ra.w(),
+ 33...64 => adjusted_ra.x(),
+ };
const delta_int = high_int -% low_int;
- if (case_range_index > 0) {
- return isel.fail("case range", .{});
- } else if (case.items.len > 0) {
- return isel.fail("case range", .{});
+ if (case_range_index | case.items.len > 0) {
+ if (std.math.cast(u5, delta_int)) |pos_imm| try isel.emit(.ccmp(
+ adjusted_reg,
+ .{ .immediate = pos_imm },
+ .{ .n = false, .z = true, .c = false, .v = false },
+ if (case_range_index > 0) .hi else .ne,
+ )) else if (std.math.cast(u5, -delta_int)) |neg_imm| try isel.emit(.ccmn(
+ adjusted_reg,
+ .{ .immediate = neg_imm },
+ .{ .n = false, .z = true, .c = false, .v = false },
+ if (case_range_index > 0) .hi else .ne,
+ )) else {
+ const imm_ra = try isel.allocIntReg();
+ defer isel.freeReg(imm_ra);
+ const imm_reg = switch (cond_int_info.bits) {
+ else => unreachable,
+ 1...32 => imm_ra.w(),
+ 33...64 => imm_ra.x(),
+ };
+ try isel.emit(.ccmp(
+ cond_reg,
+ .{ .register = imm_reg },
+ .{ .n = false, .z = true, .c = false, .v = false },
+ if (case_range_index > 0) .hi else .ne,
+ ));
+ try isel.movImmediate(imm_reg, @bitCast(delta_int));
+ }
} else {
- const adjusted_reg = switch (low_int) {
- 0 => cond_reg,
- else => temp_reg,
- };
-
if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs(
zero_reg,
adjusted_reg,
@@ -4421,41 +4843,55 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
adjusted_reg,
.{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
)) else {
- try isel.movImmediate(temp_reg, @bitCast(delta_int));
- try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = temp_reg }));
+ const imm_ra = try isel.allocIntReg();
+ defer isel.freeReg(imm_ra);
+ const imm_reg = switch (cond_int_info.bits) {
+ else => unreachable,
+ 1...32 => imm_ra.w(),
+ 33...64 => imm_ra.x(),
+ };
+ try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = imm_reg }));
+ try isel.movImmediate(imm_reg, @bitCast(delta_int));
}
+ }
- switch (low_int) {
- 0 => {},
- else => {
- if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
- adjusted_reg,
- cond_reg,
- .{ .immediate = pos_imm },
- )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
- adjusted_reg,
- cond_reg,
- .{ .immediate = neg_imm },
- )) else if (if (@as(i12, @truncate(low_int)) == 0)
- std.math.cast(u12, low_int >> 12)
- else
- null) |pos_imm_lsr_12| try isel.emit(.sub(
- adjusted_reg,
- cond_reg,
- .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
- )) else if (if (@as(i12, @truncate(-low_int)) == 0)
- std.math.cast(u12, -low_int >> 12)
- else
- null) |neg_imm_lsr_12| try isel.emit(.add(
- adjusted_reg,
- cond_reg,
- .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
- )) else {
- try isel.movImmediate(temp_reg, @bitCast(low_int));
- try isel.emit(.subs(adjusted_reg, cond_reg, .{ .register = temp_reg }));
- }
- },
- }
+ switch (low_int) {
+ 0 => {},
+ else => {
+ if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
+ adjusted_reg,
+ cond_reg,
+ .{ .immediate = pos_imm },
+ )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
+ adjusted_reg,
+ cond_reg,
+ .{ .immediate = neg_imm },
+ )) else if (if (@as(i12, @truncate(low_int)) == 0)
+ std.math.cast(u12, low_int >> 12)
+ else
+ null) |pos_imm_lsr_12| try isel.emit(.sub(
+ adjusted_reg,
+ cond_reg,
+ .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
+ )) else if (if (@as(i12, @truncate(-low_int)) == 0)
+ std.math.cast(u12, -low_int >> 12)
+ else
+ null) |neg_imm_lsr_12| try isel.emit(.add(
+ adjusted_reg,
+ cond_reg,
+ .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
+ )) else {
+ const imm_ra = try isel.allocIntReg();
+ defer isel.freeReg(imm_ra);
+ const imm_reg = switch (cond_int_info.bits) {
+ else => unreachable,
+ 1...32 => imm_ra.w(),
+ 33...64 => imm_ra.x(),
+ };
+ try isel.emit(.sub(adjusted_reg, cond_reg, .{ .register = imm_reg }));
+ try isel.movImmediate(imm_reg, @bitCast(low_int));
+ }
+ },
}
}
var case_item_index = case.items.len;
@@ -4483,13 +4919,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
.{ .n = false, .z = true, .c = false, .v = false },
.ne,
)) else {
- try isel.movImmediate(temp_reg, @bitCast(item_int));
+ const imm_ra = try isel.allocIntReg();
+ defer isel.freeReg(imm_ra);
+ const imm_reg = switch (cond_int_info.bits) {
+ else => unreachable,
+ 1...32 => imm_ra.w(),
+ 33...64 => imm_ra.x(),
+ };
try isel.emit(.ccmp(
cond_reg,
- .{ .register = temp_reg },
+ .{ .register = imm_reg },
.{ .n = false, .z = true, .c = false, .v = false },
.ne,
));
+ try isel.movImmediate(imm_reg, @bitCast(item_int));
}
} else {
if (std.math.cast(u12, item_int)) |pos_imm| try isel.emit(.subs(
@@ -4515,16 +4958,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
cond_reg,
.{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
)) else {
- try isel.movImmediate(temp_reg, @bitCast(item_int));
- try isel.emit(.subs(zero_reg, cond_reg, .{ .register = temp_reg }));
+ const imm_ra = try isel.allocIntReg();
+ defer isel.freeReg(imm_ra);
+ const imm_reg = switch (cond_int_info.bits) {
+ else => unreachable,
+ 1...32 => imm_ra.w(),
+ 33...64 => imm_ra.x(),
+ };
+ try isel.emit(.subs(zero_reg, cond_reg, .{ .register = imm_reg }));
+ try isel.movImmediate(imm_reg, @bitCast(item_int));
}
}
}
}
- if (cond_mat) |mat| {
- try mat.finish(isel);
- isel.freeReg(temp_reg.alias);
- }
+ if (cond_mat) |mat| try mat.finish(isel);
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
.@"try", .try_cold => {
@@ -4560,24 +5007,75 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
const error_set_part_vi = try error_set_part_it.only(isel);
const error_set_part_mat = try error_set_part_vi.?.matReg(isel);
try isel.emit(.cbz(
- switch (error_set_part_vi.?.size(isel)) {
- else => unreachable,
- 1...4 => error_set_part_mat.ra.w(),
- 5...8 => error_set_part_mat.ra.x(),
- },
+ error_set_part_mat.ra.w(),
@intCast((isel.instructions.items.len + 1 - cont_label) << 2),
));
try error_set_part_mat.finish(isel);
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
- .dbg_stmt => {
+ .try_ptr, .try_ptr_cold => {
+ const ty_pl = air.data(air.inst_index).ty_pl;
+ const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);
+ const error_union_ty = isel.air.typeOf(extra.data.ptr, ip).childType(zcu);
+ const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
+ const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
+
+ const error_union_ptr_vi = try isel.use(extra.data.ptr);
+ const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
+ if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
+ defer payload_ptr_vi.value.deref(isel);
+ switch (codegen.errUnionPayloadOffset(ty_pl.ty.toType().childType(zcu), zcu)) {
+ 0 => try payload_ptr_vi.value.move(isel, extra.data.ptr),
+ else => |payload_offset| {
+ const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
+ const lo12: u12 = @truncate(payload_offset >> 0);
+ const hi12: u12 = @intCast(payload_offset >> 12);
+ if (hi12 > 0) try isel.emit(.add(
+ payload_ptr_ra.x(),
+ if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
+ .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
+ ));
+ if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
+ },
+ }
+ }
+
+ const cont_label = isel.instructions.items.len;
+ const cont_live_registers = isel.live_registers;
+ try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
+ try isel.merge(&cont_live_registers, .{});
+
+ const error_set_ra = try isel.allocIntReg();
+ defer isel.freeReg(error_set_ra);
+ try isel.loadReg(
+ error_set_ra,
+ ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu),
+ .unsigned,
+ error_union_ptr_mat.ra,
+ codegen.errUnionErrorOffset(payload_ty, zcu),
+ );
+ try error_union_ptr_mat.finish(isel);
+ try isel.emit(.cbz(
+ error_set_ra.w(),
+ @intCast((isel.instructions.items.len + 1 - cont_label) << 2),
+ ));
+
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .dbg_stmt => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
.dbg_empty_stmt => {
try isel.emit(.nop());
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .dbg_inline_block => {
+ const ty_pl = air.data(air.inst_index).ty_pl;
+ const extra = isel.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
+ try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
+ isel.air.extra.items[extra.end..][0..extra.data.body_len],
+ ));
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
@@ -4655,37 +5153,34 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef());
if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
defer dst_vi.value.deref(isel);
- switch (dst_vi.value.size(isel)) {
- 0 => unreachable,
- 1...Value.max_parts => {
- const ptr_vi = try isel.use(ty_op.operand);
- const ptr_mat = try ptr_vi.matReg(isel);
- _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{
- .@"volatile" = ptr_info.flags.is_volatile,
- });
- try ptr_mat.finish(isel);
- },
- else => |size| {
- try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), null, comptime &.initFill(.free)) orelse break :unused;
+ const size = dst_vi.value.size(isel);
+ if (size <= Value.max_parts and ip.zigTypeTag(ptr_info.child) != .@"union") {
+ const ptr_vi = try isel.use(ty_op.operand);
+ const ptr_mat = try ptr_vi.matReg(isel);
+ _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{
+ .@"volatile" = ptr_info.flags.is_volatile,
+ });
+ try ptr_mat.finish(isel);
+ } else {
+ try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), .{}) orelse break :unused;
- try call.prepareReturn(isel);
- try call.finishReturn(isel);
+ try call.prepareReturn(isel);
+ try call.finishReturn(isel);
- try call.prepareCallee(isel);
- try isel.global_relocs.append(gpa, .{
- .global = "memcpy",
- .reloc = .{ .label = @intCast(isel.instructions.items.len) },
- });
- try isel.emit(.bl(0));
- try call.finishCallee(isel);
+ try call.prepareCallee(isel);
+ try isel.global_relocs.append(gpa, .{
+ .name = "memcpy",
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.bl(0));
+ try call.finishCallee(isel);
- try call.prepareParams(isel);
- const ptr_vi = try isel.use(ty_op.operand);
- try isel.movImmediate(.x2, size);
- try call.paramLiveOut(isel, ptr_vi, .r1);
- try call.paramAddress(isel, dst_vi.value, .r0);
- try call.finishParams(isel);
- },
+ try call.prepareParams(isel);
+ const ptr_vi = try isel.use(ty_op.operand);
+ try isel.movImmediate(.x2, size);
+ try call.paramLiveOut(isel, ptr_vi, .r1);
+ try call.paramAddress(isel, dst_vi.value, .r0);
+ try call.finishParams(isel);
}
}
@@ -4765,10 +5260,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
const ptr_info = ptr_ty.ptrInfo(zcu);
if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{});
- if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val)) {
- if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
- break :air_tag;
- };
+ if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val))
+ break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
const src_vi = try isel.use(bin_op.rhs);
const size = src_vi.size(isel);
@@ -4782,8 +5275,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
});
try ptr_mat.finish(isel);
- if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
- break :air_tag;
+ break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
else => {},
};
@@ -4792,7 +5284,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = "memcpy",
+ .name = "memcpy",
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.bl(0));
@@ -4855,7 +5347,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (dst_bits) {
+ .name = switch (dst_bits) {
else => unreachable,
16 => switch (src_bits) {
else => unreachable,
@@ -5009,6 +5501,108 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .intcast_safe => |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;
+ const dst_ty = ty_op.ty.toType();
+ const dst_int_info = dst_ty.intInfo(zcu);
+ const src_ty = isel.air.typeOf(ty_op.operand, ip);
+ const src_int_info = src_ty.intInfo(zcu);
+ const can_be_negative = dst_int_info.signedness == .signed and
+ src_int_info.signedness == .signed;
+ const panic_id: Zcu.SimplePanicId = panic_id: switch (dst_ty.zigTypeTag(zcu)) {
+ else => unreachable,
+ .int => .integer_out_of_bounds,
+ .@"enum" => {
+ if (!dst_ty.isNonexhaustiveEnum(zcu)) {
+ return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
+ }
+ break :panic_id .invalid_enum_value;
+ },
+ };
+ if (dst_ty.toIntern() == src_ty.toIntern()) {
+ try dst_vi.value.move(isel, ty_op.operand);
+ } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 64) {
+ const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
+ const src_vi = try isel.use(ty_op.operand);
+ const dst_active_bits = dst_int_info.bits - @intFromBool(dst_int_info.signedness == .signed);
+ const src_active_bits = src_int_info.bits - @intFromBool(src_int_info.signedness == .signed);
+ if ((dst_int_info.signedness != .unsigned or src_int_info.signedness != .signed) and dst_active_bits >= src_active_bits) {
+ const src_mat = try src_vi.matReg(isel);
+ try isel.emit(if (can_be_negative and dst_active_bits > 32 and src_active_bits <= 32)
+ .sbfm(dst_ra.x(), src_mat.ra.x(), .{
+ .N = .doubleword,
+ .immr = 0,
+ .imms = @intCast(src_int_info.bits - 1),
+ })
+ else switch (src_int_info.bits) {
+ else => unreachable,
+ 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }),
+ 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }),
+ });
+ try src_mat.finish(isel);
+ } else {
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(panic_id);
+ try isel.emit(.@"b."(
+ .eq,
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ if (can_be_negative) {
+ const src_mat = src_mat: {
+ const dst_lock = isel.lockReg(dst_ra);
+ defer dst_lock.unlock(isel);
+ break :src_mat try src_vi.matReg(isel);
+ };
+ try isel.emit(switch (src_int_info.bits) {
+ else => unreachable,
+ 1...32 => .subs(.wzr, dst_ra.w(), .{ .register = src_mat.ra.w() }),
+ 33...64 => .subs(.xzr, dst_ra.x(), .{ .register = src_mat.ra.x() }),
+ });
+ try isel.emit(switch (@max(dst_int_info.bits, src_int_info.bits)) {
+ else => unreachable,
+ 1...32 => .sbfm(dst_ra.w(), src_mat.ra.w(), .{
+ .N = .word,
+ .immr = 0,
+ .imms = @intCast(dst_int_info.bits - 1),
+ }),
+ 33...64 => .sbfm(dst_ra.x(), src_mat.ra.x(), .{
+ .N = .doubleword,
+ .immr = 0,
+ .imms = @intCast(dst_int_info.bits - 1),
+ }),
+ });
+ try src_mat.finish(isel);
+ } else {
+ const src_mat = try src_vi.matReg(isel);
+ try isel.emit(switch (@min(dst_int_info.bits, src_int_info.bits)) {
+ else => unreachable,
+ 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }),
+ 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }),
+ });
+ const active_bits = @min(dst_active_bits, src_active_bits);
+ try isel.emit(switch (src_int_info.bits) {
+ else => unreachable,
+ 1...32 => .ands(.wzr, src_mat.ra.w(), .{ .immediate = .{
+ .N = .word,
+ .immr = @intCast(32 - active_bits),
+ .imms = @intCast(32 - active_bits - 1),
+ } }),
+ 33...64 => .ands(.xzr, src_mat.ra.x(), .{ .immediate = .{
+ .N = .doubleword,
+ .immr = @intCast(64 - active_bits),
+ .imms = @intCast(64 - active_bits - 1),
+ } }),
+ });
+ try src_mat.finish(isel);
+ }
+ }
+ } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.trunc => |air_tag| {
if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
defer dst_vi.value.deref(isel);
@@ -5096,14 +5690,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
- .optional_payload_ptr => {
- if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
- defer dst_vi.value.deref(isel);
- const ty_op = air.data(air.inst_index).ty_op;
- try dst_vi.value.move(isel, ty_op.operand);
- }
- if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
- },
.optional_payload => {
if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: {
defer payload_vi.value.deref(isel);
@@ -5122,6 +5708,37 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .optional_payload_ptr => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| {
+ defer payload_ptr_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ try payload_ptr_vi.value.move(isel, ty_op.operand);
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .optional_payload_ptr_set => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| {
+ defer payload_ptr_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ const opt_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu);
+ if (!opt_ty.optionalReprIsPayload(zcu)) {
+ const opt_ptr_vi = try isel.use(ty_op.operand);
+ const opt_ptr_mat = try opt_ptr_vi.matReg(isel);
+ const has_value_ra = try isel.allocIntReg();
+ defer isel.freeReg(has_value_ra);
+ try isel.storeReg(
+ has_value_ra,
+ 1,
+ opt_ptr_mat.ra,
+ opt_ty.optionalChild(zcu).abiSize(zcu),
+ );
+ try opt_ptr_mat.finish(isel);
+ try isel.emit(.movz(has_value_ra.w(), 1, .{ .lsl = .@"0" }));
+ }
+ try payload_ptr_vi.value.move(isel, ty_op.operand);
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.wrap_optional => {
if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: {
defer opt_vi.value.deref(isel);
@@ -5179,6 +5796,93 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .unwrap_errunion_payload_ptr => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
+ defer payload_ptr_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ switch (codegen.errUnionPayloadOffset(ty_op.ty.toType().childType(zcu), zcu)) {
+ 0 => try payload_ptr_vi.value.move(isel, ty_op.operand),
+ else => |payload_offset| {
+ const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
+ const error_union_ptr_vi = try isel.use(ty_op.operand);
+ const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
+ const lo12: u12 = @truncate(payload_offset >> 0);
+ const hi12: u12 = @intCast(payload_offset >> 12);
+ if (hi12 > 0) try isel.emit(.add(
+ payload_ptr_ra.x(),
+ if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
+ .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
+ ));
+ if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
+ try error_union_ptr_mat.finish(isel);
+ },
+ }
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .unwrap_errunion_err_ptr => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |error_ptr_vi| unused: {
+ defer error_ptr_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ switch (codegen.errUnionErrorOffset(
+ isel.air.typeOf(ty_op.operand, ip).childType(zcu).errorUnionPayload(zcu),
+ zcu,
+ )) {
+ 0 => try error_ptr_vi.value.move(isel, ty_op.operand),
+ else => |error_offset| {
+ const error_ptr_ra = try error_ptr_vi.value.defReg(isel) orelse break :unused;
+ const error_union_ptr_vi = try isel.use(ty_op.operand);
+ const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
+ const lo12: u12 = @truncate(error_offset >> 0);
+ const hi12: u12 = @intCast(error_offset >> 12);
+ if (hi12 > 0) try isel.emit(.add(
+ error_ptr_ra.x(),
+ if (lo12 > 0) error_ptr_ra.x() else error_union_ptr_mat.ra.x(),
+ .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
+ ));
+ if (lo12 > 0) try isel.emit(.add(error_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
+ try error_union_ptr_mat.finish(isel);
+ },
+ }
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .errunion_payload_ptr_set => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
+ defer payload_ptr_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ const payload_ty = ty_op.ty.toType().childType(zcu);
+ const error_union_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu);
+ const error_set_size = error_union_ty.errorUnionSet(zcu).abiSize(zcu);
+ const error_union_ptr_vi = try isel.use(ty_op.operand);
+ const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
+ if (error_set_size > 0) try isel.storeReg(
+ .zr,
+ error_set_size,
+ error_union_ptr_mat.ra,
+ codegen.errUnionErrorOffset(payload_ty, zcu),
+ );
+ switch (codegen.errUnionPayloadOffset(payload_ty, zcu)) {
+ 0 => {
+ try error_union_ptr_mat.finish(isel);
+ try payload_ptr_vi.value.move(isel, ty_op.operand);
+ },
+ else => |payload_offset| {
+ const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
+ const lo12: u12 = @truncate(payload_offset >> 0);
+ const hi12: u12 = @intCast(payload_offset >> 12);
+ if (hi12 > 0) try isel.emit(.add(
+ payload_ptr_ra.x(),
+ if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
+ .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
+ ));
+ if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
+ try error_union_ptr_mat.finish(isel);
+ },
+ }
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.wrap_errunion_payload => {
if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {
defer error_union_vi.value.deref(isel);
@@ -5220,26 +5924,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
const error_set_size = error_set_ty.abiSize(zcu);
const payload_size = payload_ty.abiSize(zcu);
- if (payload_size > 0) {
- var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
- const payload_part_vi = try payload_part_it.only(isel);
- if (try payload_part_vi.?.defReg(isel)) |payload_part_ra| try isel.emit(switch (payload_size) {
- else => unreachable,
- 1...4 => .orr(payload_part_ra.w(), .wzr, .{ .immediate = .{
- .N = .word,
- .immr = 0b000001,
- .imms = 0b111100,
- } }),
- 5...8 => .orr(payload_part_ra.x(), .xzr, .{ .immediate = .{
- .N = .word,
- .immr = 0b000001,
- .imms = 0b111100,
- } }),
- });
- }
var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size);
const error_set_part_vi = try error_set_part_it.only(isel);
try error_set_part_vi.?.move(isel, ty_op.operand);
+ if (payload_size > 0) {
+ var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
+ const payload_part_vi = try payload_part_it.only(isel);
+ try payload_part_vi.?.defUndef(isel, payload_ty, .{});
+ }
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
@@ -5313,7 +6005,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
.struct_field_val => {
- if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| {
+ if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| unused: {
defer field_vi.value.deref(isel);
const ty_pl = air.data(air.inst_index).ty_pl;
@@ -5340,31 +6032,85 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
});
const agg_vi = try isel.use(extra.struct_operand);
- var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8));
- while (try agg_part_it.next(isel)) |agg_part| {
- var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));
- const field_part_vi = try field_part_it.only(isel);
- if (field_part_vi.? == agg_part.vi) continue;
- var field_subpart_it = field_part_vi.?.parts(isel);
- const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|
- field_subpart_vi.get(isel).offset_from_parent
- else
- 0;
- while (field_subpart_it.next()) |field_subpart_vi| {
- const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;
- const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);
- var agg_subpart_it = agg_part.vi.field(
- field_ty,
- agg_part.offset + field_subpart_offset - field_part_offset,
- field_subpart_size,
- );
- const agg_subpart_vi = try agg_subpart_it.only(isel);
- try agg_subpart_vi.?.liveOut(isel, field_subpart_ra);
- }
+ switch (agg_ty.zigTypeTag(zcu)) {
+ else => unreachable,
+ .@"struct" => {
+ var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8));
+ while (try agg_part_it.next(isel)) |agg_part| {
+ var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));
+ const field_part_vi = try field_part_it.only(isel);
+ if (field_part_vi.? == agg_part.vi) continue;
+ var field_subpart_it = field_part_vi.?.parts(isel);
+ const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|
+ field_subpart_vi.get(isel).offset_from_parent
+ else
+ 0;
+ while (field_subpart_it.next()) |field_subpart_vi| {
+ const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;
+ const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);
+ var agg_subpart_it = agg_part.vi.field(
+ field_ty,
+ agg_part.offset + field_subpart_offset - field_part_offset,
+ field_subpart_size,
+ );
+ const agg_subpart_vi = try agg_subpart_it.only(isel);
+ try agg_subpart_vi.?.liveOut(isel, field_subpart_ra);
+ }
+ }
+ },
+ .@"union" => {
+ try field_vi.value.defAddr(isel, field_ty, .{}) orelse break :unused;
+
+ try call.prepareReturn(isel);
+ try call.finishReturn(isel);
+
+ try call.prepareCallee(isel);
+ try isel.global_relocs.append(gpa, .{
+ .name = "memcpy",
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.bl(0));
+ try call.finishCallee(isel);
+
+ try call.prepareParams(isel);
+ const union_layout = agg_ty.unionGetLayout(zcu);
+ var payload_it = agg_vi.field(agg_ty, union_layout.payloadOffset(), union_layout.payload_size);
+ const payload_vi = try payload_it.only(isel);
+ try isel.movImmediate(.x2, field_vi.value.size(isel));
+ try call.paramAddress(isel, payload_vi.?, .r1);
+ try call.paramAddress(isel, field_vi.value, .r0);
+ try call.finishParams(isel);
+ },
}
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .set_union_tag => {
+ const bin_op = air.data(air.inst_index).bin_op;
+ const union_ty = isel.air.typeOf(bin_op.lhs, ip).childType(zcu);
+ const union_layout = union_ty.unionGetLayout(zcu);
+ const tag_vi = try isel.use(bin_op.rhs);
+ const union_ptr_vi = try isel.use(bin_op.lhs);
+ const union_ptr_mat = try union_ptr_vi.matReg(isel);
+ try tag_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), union_ptr_mat.ra, .{
+ .offset = union_layout.tagOffset(),
+ });
+ try union_ptr_mat.finish(isel);
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .get_union_tag => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |tag_vi| {
+ defer tag_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ const union_ty = isel.air.typeOf(ty_op.operand, ip);
+ const union_layout = union_ty.unionGetLayout(zcu);
+ const union_vi = try isel.use(ty_op.operand);
+ var tag_part_it = union_vi.field(union_ty, union_layout.tagOffset(), union_layout.tag_size);
+ const tag_part_vi = try tag_part_it.only(isel);
+ try tag_vi.value.copy(isel, ty_op.ty.toType(), tag_part_vi.?);
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.slice => {
if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {
defer slice_vi.value.deref(isel);
@@ -5781,7 +6527,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (dst_int_info.bits) {
+ .name = switch (dst_int_info.bits) {
else => unreachable,
1...32 => switch (dst_int_info.signedness) {
.signed => switch (src_bits) {
@@ -5921,7 +6667,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (src_int_info.bits) {
+ .name = switch (src_int_info.bits) {
else => unreachable,
1...32 => switch (src_int_info.signedness) {
.signed => switch (dst_bits) {
@@ -6004,14 +6750,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
- .memset => |air_tag| {
+ .memset, .memset_safe => |air_tag| {
const bin_op = air.data(air.inst_index).bin_op;
const dst_ty = isel.air.typeOf(bin_op.lhs, ip);
const dst_info = dst_ty.ptrInfo(zcu);
const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: {
- if (bin_op.rhs.toInterned()) |fill_val|
+ if (bin_op.rhs.toInterned()) |fill_val| {
+ if (ip.isUndef(fill_val)) switch (air_tag) {
+ else => unreachable,
+ .memset => break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
+ .memset_safe => break :fill_byte .{ .constant = 0xaa },
+ };
if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
break :fill_byte .{ .constant = fill_byte };
+ }
switch (dst_ty.elemType2(zcu).abiSize(zcu)) {
0 => unreachable,
1 => break :fill_byte .{ .value = bin_op.rhs },
@@ -6070,8 +6822,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
.c => unreachable,
}
- if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
- break :air_tag;
+ break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }),
}
@@ -6082,7 +6833,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = "memset",
+ .name = "memset",
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.bl(0));
@@ -6128,7 +6879,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = @tagName(air_tag),
+ .name = @tagName(air_tag),
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.bl(0));
@@ -6217,6 +6968,72 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .error_name => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |name_vi| unused: {
+ defer name_vi.value.deref(isel);
+ var ptr_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 0, 8);
+ const ptr_part_vi = try ptr_part_it.only(isel);
+ const ptr_part_ra = try ptr_part_vi.?.defReg(isel);
+ var len_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 8, 8);
+ const len_part_vi = try len_part_it.only(isel);
+ const len_part_ra = try len_part_vi.?.defReg(isel);
+ if (ptr_part_ra == null and len_part_ra == null) break :unused;
+
+ const un_op = air.data(air.inst_index).un_op;
+ const error_vi = try isel.use(un_op);
+ const error_mat = try error_vi.matReg(isel);
+ const ptr_ra = try isel.allocIntReg();
+ defer isel.freeReg(ptr_ra);
+ const start_ra, const end_ra = range_ras: {
+ const name_lock: RegLock = if (len_part_ra != null) if (ptr_part_ra) |name_ptr_ra|
+ isel.tryLockReg(name_ptr_ra)
+ else
+ .empty else .empty;
+ defer name_lock.unlock(isel);
+ break :range_ras .{ try isel.allocIntReg(), try isel.allocIntReg() };
+ };
+ defer {
+ isel.freeReg(start_ra);
+ isel.freeReg(end_ra);
+ }
+ if (len_part_ra) |name_len_ra| try isel.emit(.sub(
+ name_len_ra.w(),
+ end_ra.w(),
+ .{ .register = start_ra.w() },
+ ));
+ if (ptr_part_ra) |name_ptr_ra| try isel.emit(.add(
+ name_ptr_ra.x(),
+ ptr_ra.x(),
+ .{ .extended_register = .{
+ .register = start_ra.w(),
+ .extend = .{ .uxtw = 0 },
+ } },
+ ));
+ if (len_part_ra) |_| try isel.emit(.sub(end_ra.w(), end_ra.w(), .{ .immediate = 1 }));
+ try isel.emit(.ldp(start_ra.w(), end_ra.w(), .{ .base = start_ra.x() }));
+ try isel.emit(.add(start_ra.x(), ptr_ra.x(), .{ .extended_register = .{
+ .register = error_mat.ra.w(),
+ .extend = switch (zcu.errorSetBits()) {
+ else => unreachable,
+ 1...8 => .{ .uxtb = 2 },
+ 9...16 => .{ .uxth = 2 },
+ 17...32 => .{ .uxtw = 2 },
+ },
+ } }));
+ try isel.lazy_relocs.append(gpa, .{
+ .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
+ try isel.lazy_relocs.append(gpa, .{
+ .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.adrp(ptr_ra.x(), 0));
+ try error_mat.finish(isel);
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.aggregate_init => {
if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| {
defer agg_vi.value.deref(isel);
@@ -6295,23 +7112,52 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
- .union_init => {
- if (isel.live_values.fetchRemove(air.inst_index)) |un_vi| unused: {
- defer un_vi.value.deref(isel);
+ .union_init => |air_tag| {
+ if (isel.live_values.fetchRemove(air.inst_index)) |union_vi| unused: {
+ defer union_vi.value.deref(isel);
const ty_pl = air.data(air.inst_index).ty_pl;
const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;
- const un_ty = ty_pl.ty.toType();
- if (un_ty.containerLayout(zcu) != .@"extern") return isel.fail("bad union init {f}", .{isel.fmtType(un_ty)});
+ const union_ty = ty_pl.ty.toType();
+ const loaded_union = ip.loadUnionType(union_ty.toIntern());
+ const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
- try un_vi.value.defAddr(isel, un_ty, null, comptime &.initFill(.free)) orelse break :unused;
+ if (union_layout.tag_size > 0) unused_tag: {
+ const loaded_tag = loaded_union.loadTagType(ip);
+ var tag_it = union_vi.value.field(union_ty, union_layout.tagOffset(), union_layout.tag_size);
+ const tag_vi = try tag_it.only(isel);
+ const tag_ra = try tag_vi.?.defReg(isel) orelse break :unused_tag;
+ switch (union_layout.tag_size) {
+ 0 => unreachable,
+ 1...4 => try isel.movImmediate(tag_ra.w(), @as(u32, switch (loaded_tag.values.len) {
+ 0 => extra.field_index,
+ else => switch (ip.indexToKey(loaded_tag.values.get(ip)[extra.field_index]).int.storage) {
+ .u64 => |imm| @intCast(imm),
+ .i64 => |imm| @bitCast(@as(i32, @intCast(imm))),
+ else => unreachable,
+ },
+ })),
+ 5...8 => try isel.movImmediate(tag_ra.x(), switch (loaded_tag.values.len) {
+ 0 => extra.field_index,
+ else => switch (ip.indexToKey(loaded_tag.values.get(ip)[extra.field_index]).int.storage) {
+ .u64 => |imm| imm,
+ .i64 => |imm| @bitCast(imm),
+ else => unreachable,
+ },
+ }),
+ else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(union_ty) }),
+ }
+ }
+ var payload_it = union_vi.value.field(union_ty, union_layout.payloadOffset(), union_layout.payload_size);
+ const payload_vi = try payload_it.only(isel);
+ try payload_vi.?.defAddr(isel, union_ty, .{ .root_vi = union_vi.value }) orelse break :unused;
try call.prepareReturn(isel);
try call.finishReturn(isel);
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = "memcpy",
+ .name = "memcpy",
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.bl(0));
@@ -6321,7 +7167,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
const init_vi = try isel.use(extra.init);
try isel.movImmediate(.x2, init_vi.size(isel));
try call.paramAddress(isel, init_vi, .r1);
- try call.paramAddress(isel, un_vi.value, .r0);
+ try call.paramAddress(isel, payload_vi.?, .r0);
try call.finishParams(isel);
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
@@ -6427,7 +7273,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
try call.prepareCallee(isel);
try isel.global_relocs.append(gpa, .{
- .global = switch (bits) {
+ .name = switch (bits) {
else => unreachable,
16 => "__fmah",
32 => "fmaf",
@@ -6508,6 +7354,33 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
+ .wasm_memory_size, .wasm_memory_grow => unreachable,
+ .cmp_lt_errors_len => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: {
+ defer is_vi.value.deref(isel);
+ const is_ra = try is_vi.value.defReg(isel) orelse break :unused;
+ try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(.ls)));
+
+ const un_op = air.data(air.inst_index).un_op;
+ const error_vi = try isel.use(un_op);
+ const error_mat = try error_vi.matReg(isel);
+ const ptr_ra = try isel.allocIntReg();
+ defer isel.freeReg(ptr_ra);
+ try isel.emit(.subs(.wzr, error_mat.ra.w(), .{ .register = ptr_ra.w() }));
+ try isel.lazy_relocs.append(gpa, .{
+ .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.ldr(ptr_ra.w(), .{ .base = ptr_ra.x() }));
+ try isel.lazy_relocs.append(gpa, .{
+ .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.adrp(ptr_ra.x(), 0));
+ try error_mat.finish(isel);
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
.runtime_nav_ptr => {
if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
defer ptr_vi.value.deref(isel);
@@ -6516,19 +7389,19 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
const ty_nav = air.data(air.inst_index).ty_nav;
if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
false => {
- try isel.nav_relocs.append(zcu.gpa, .{
+ try isel.nav_relocs.append(gpa, .{
.nav = ty_nav.nav,
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.adr(ptr_ra.x(), 0));
},
true => {
- try isel.nav_relocs.append(zcu.gpa, .{
+ try isel.nav_relocs.append(gpa, .{
.nav = ty_nav.nav,
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
- try isel.nav_relocs.append(zcu.gpa, .{
+ try isel.nav_relocs.append(gpa, .{
.nav = ty_nav.nav,
.reloc = .{ .label = @intCast(isel.instructions.items.len) },
});
@@ -6538,19 +7411,266 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
}
if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
},
- .add_safe,
- .sub_safe,
- .mul_safe,
- .inferred_alloc,
- .inferred_alloc_comptime,
- .int_from_float_safe,
- .int_from_float_optimized_safe,
- .wasm_memory_size,
- .wasm_memory_grow,
- .work_item_id,
- .work_group_size,
- .work_group_id,
- => unreachable,
+ .c_va_arg => {
+ const maybe_arg_vi = isel.live_values.fetchRemove(air.inst_index);
+ defer if (maybe_arg_vi) |arg_vi| arg_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ const ty = ty_op.ty.toType();
+ var param_it: CallAbiIterator = .init;
+ const param_vi = try param_it.param(isel, ty);
+ defer param_vi.?.deref(isel);
+ const passed_vi = switch (param_vi.?.parent(isel)) {
+ .unallocated => param_vi.?,
+ .stack_slot, .value, .constant => unreachable,
+ .address => |address_vi| address_vi,
+ };
+ const passed_size: u5 = @intCast(passed_vi.alignment(isel).forward(passed_vi.size(isel)));
+ const passed_is_vector = passed_vi.isVector(isel);
+
+ const va_list_ptr_vi = try isel.use(ty_op.operand);
+ const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel);
+ const offs_ra = try isel.allocIntReg();
+ defer isel.freeReg(offs_ra);
+ const stack_ra = try isel.allocIntReg();
+ defer isel.freeReg(stack_ra);
+
+ var part_vis: [2]Value.Index = undefined;
+ var arg_part_ras: [2]?Register.Alias = @splat(null);
+ const parts_len = parts_len: {
+ var parts_len: u2 = 0;
+ var part_it = passed_vi.parts(isel);
+ while (part_it.next()) |part_vi| : (parts_len += 1) {
+ part_vis[parts_len] = part_vi;
+ const arg_vi = maybe_arg_vi orelse continue;
+ const part_offset, const part_size = part_vi.position(isel);
+ var arg_part_it = arg_vi.value.field(ty, part_offset, part_size);
+ const arg_part_vi = try arg_part_it.only(isel);
+ arg_part_ras[parts_len] = try arg_part_vi.?.defReg(isel);
+ }
+ break :parts_len parts_len;
+ };
+
+ const done_label = isel.instructions.items.len;
+ try isel.emit(.str(stack_ra.x(), .{ .unsigned_offset = .{
+ .base = va_list_ptr_mat.ra.x(),
+ .offset = 0,
+ } }));
+ try isel.emit(switch (parts_len) {
+ else => unreachable,
+ 1 => if (arg_part_ras[0]) |arg_part_ra| switch (part_vis[0].size(isel)) {
+ else => unreachable,
+ 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }) else switch (part_vis[0].signedness(isel)) {
+ .signed => .ldrsb(arg_part_ra.w(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }),
+ .unsigned => .ldrb(arg_part_ra.w(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }),
+ },
+ 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }) else switch (part_vis[0].signedness(isel)) {
+ .signed => .ldrsh(arg_part_ra.w(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }),
+ .unsigned => .ldrh(arg_part_ra.w(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }),
+ },
+ 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }),
+ 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }),
+ 16 => .ldr(arg_part_ra.q(), .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } }),
+ } else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }),
+ 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) .ldp(
+ @as(Register.Alias, arg_part_ras[0] orelse .zr).x(),
+ @as(Register.Alias, arg_part_ras[1] orelse .zr).x(),
+ .{ .post_index = .{
+ .base = stack_ra.x(),
+ .index = passed_size,
+ } },
+ ) else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }),
+ });
+ try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{
+ .base = va_list_ptr_mat.ra.x(),
+ .offset = 0,
+ } }));
+ switch (isel.va_list) {
+ .other => {},
+ .sysv => {
+ const stack_label = isel.instructions.items.len;
+ try isel.emit(.b(
+ @intCast((isel.instructions.items.len + 1 - done_label) << 2),
+ ));
+ switch (parts_len) {
+ else => unreachable,
+ 1 => if (arg_part_ras[0]) |arg_part_ra| try isel.emit(switch (part_vis[0].size(isel)) {
+ else => unreachable,
+ 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }) else switch (part_vis[0].signedness(isel)) {
+ .signed => .ldrsb(arg_part_ra.w(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }),
+ .unsigned => .ldrb(arg_part_ra.w(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }),
+ },
+ 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }) else switch (part_vis[0].signedness(isel)) {
+ .signed => .ldrsh(arg_part_ra.w(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }),
+ .unsigned => .ldrh(arg_part_ra.w(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }),
+ },
+ 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }),
+ 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }),
+ 16 => .ldr(arg_part_ra.q(), .{ .extended_register = .{
+ .base = stack_ra.x(),
+ .index = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }),
+ }),
+ 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) {
+ try isel.emit(.ldp(
+ @as(Register.Alias, arg_part_ras[0] orelse .zr).x(),
+ @as(Register.Alias, arg_part_ras[1] orelse .zr).x(),
+ .{ .base = stack_ra.x() },
+ ));
+ try isel.emit(.add(stack_ra.x(), stack_ra.x(), .{ .extended_register = .{
+ .register = offs_ra.w(),
+ .extend = .{ .sxtw = 0 },
+ } }));
+ },
+ }
+ try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{
+ .base = va_list_ptr_mat.ra.x(),
+ .offset = if (passed_is_vector) 16 else 8,
+ } }));
+ try isel.emit(.@"b."(
+ .gt,
+ @intCast((isel.instructions.items.len + 1 - stack_label) << 2),
+ ));
+ try isel.emit(.str(stack_ra.w(), .{ .unsigned_offset = .{
+ .base = va_list_ptr_mat.ra.x(),
+ .offset = if (passed_is_vector) 28 else 24,
+ } }));
+ try isel.emit(.adds(stack_ra.w(), offs_ra.w(), .{ .immediate = passed_size }));
+ try isel.emit(.tbz(
+ offs_ra.w(),
+ 31,
+ @intCast((isel.instructions.items.len + 1 - stack_label) << 2),
+ ));
+ try isel.emit(.ldr(offs_ra.w(), .{ .unsigned_offset = .{
+ .base = va_list_ptr_mat.ra.x(),
+ .offset = if (passed_is_vector) 28 else 24,
+ } }));
+ },
+ }
+ try va_list_ptr_mat.finish(isel);
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .c_va_copy => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| {
+ defer va_list_vi.value.deref(isel);
+ const ty_op = air.data(air.inst_index).ty_op;
+ const va_list_ptr_vi = try isel.use(ty_op.operand);
+ const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel);
+ _ = try va_list_vi.value.load(isel, ty_op.ty.toType(), va_list_ptr_mat.ra, .{});
+ try va_list_ptr_mat.finish(isel);
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .c_va_end => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
+ .c_va_start => {
+ if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| {
+ defer va_list_vi.value.deref(isel);
+ const ty = air.data(air.inst_index).ty;
+ switch (isel.va_list) {
+ .other => |va_list| if (try va_list_vi.value.defReg(isel)) |va_list_ra| try isel.emit(.add(
+ va_list_ra.x(),
+ va_list.base.x(),
+ .{ .immediate = @intCast(va_list.offset) },
+ )),
+ .sysv => |va_list| {
+ var vr_offs_it = va_list_vi.value.field(ty, 28, 4);
+ const vr_offs_vi = try vr_offs_it.only(isel);
+ if (try vr_offs_vi.?.defReg(isel)) |vr_offs_ra| try isel.movImmediate(
+ vr_offs_ra.w(),
+ @as(u32, @bitCast(va_list.__vr_offs)),
+ );
+ var gr_offs_it = va_list_vi.value.field(ty, 24, 4);
+ const gr_offs_vi = try gr_offs_it.only(isel);
+ if (try gr_offs_vi.?.defReg(isel)) |gr_offs_ra| try isel.movImmediate(
+ gr_offs_ra.w(),
+ @as(u32, @bitCast(va_list.__gr_offs)),
+ );
+ var vr_top_it = va_list_vi.value.field(ty, 16, 8);
+ const vr_top_vi = try vr_top_it.only(isel);
+ if (try vr_top_vi.?.defReg(isel)) |vr_top_ra| try isel.emit(.add(
+ vr_top_ra.x(),
+ va_list.__vr_top.base.x(),
+ .{ .immediate = @intCast(va_list.__vr_top.offset) },
+ ));
+ var gr_top_it = va_list_vi.value.field(ty, 8, 8);
+ const gr_top_vi = try gr_top_it.only(isel);
+ if (try gr_top_vi.?.defReg(isel)) |gr_top_ra| try isel.emit(.add(
+ gr_top_ra.x(),
+ va_list.__gr_top.base.x(),
+ .{ .immediate = @intCast(va_list.__gr_top.offset) },
+ ));
+ var stack_it = va_list_vi.value.field(ty, 0, 8);
+ const stack_vi = try stack_it.only(isel);
+ if (try stack_vi.?.defReg(isel)) |stack_ra| try isel.emit(.add(
+ stack_ra.x(),
+ va_list.__stack.base.x(),
+ .{ .immediate = @intCast(va_list.__stack.offset) },
+ ));
+ },
+ }
+ }
+ if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
+ },
+ .work_item_id, .work_group_size, .work_group_id => unreachable,
}
assert(air.body_index == 0);
}
@@ -6631,7 +7751,7 @@ pub fn verify(isel: *Select, check_values: bool) void {
pub fn layout(
isel: *Select,
incoming: CallAbiIterator,
- have_va: bool,
+ is_sysv_var_args: bool,
saved_gra_len: u7,
saved_vra_len: u7,
mod: *const Package.Module,
@@ -6642,8 +7762,6 @@ pub fn layout(
wip_mir_log.debug("{f}:\n", .{nav.fqn.fmt(ip)});
const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size));
- const stack_size_low: u12 = @truncate(stack_size >> 0);
- const stack_size_high: u12 = @truncate(stack_size >> 12);
var saves_buf: [10 + 8 + 8 + 2 + 8]struct {
class: enum { integer, vector },
@@ -6721,7 +7839,7 @@ pub fn layout(
// incoming vr arguments
save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start;
- while (save_ra != if (have_va) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
+ while (save_ra != if (is_sysv_var_args) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
saves_size = std.mem.alignForward(u10, saves_size, 16);
saves_buf[saves_len] = .{
.class = .vector,
@@ -6771,9 +7889,12 @@ pub fn layout(
saves_len += 1;
saves_size += 8;
deferred_gr = null;
+ } else switch (@as(u1, @truncate(saved_gra_len))) {
+ 0 => {},
+ 1 => saves_size += 8,
}
save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start;
- while (save_ra != if (have_va) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
+ while (save_ra != if (is_sysv_var_args) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
saves_size = std.mem.alignForward(u10, saves_size, 8);
saves_buf[saves_len] = .{
.class = .integer,
@@ -6793,65 +7914,92 @@ pub fn layout(
{
wip_mir_log.debug("{f}:", .{nav.fqn.fmt(ip)});
var save_index: usize = 0;
- while (save_index < saves.len) {
- if (save_index + 2 <= saves.len and saves[save_index + 0].class == saves[save_index + 1].class and
- saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
- {
- try isel.emit(.stp(
- saves[save_index + 0].register,
- saves[save_index + 1].register,
- switch (saves[save_index + 0].offset) {
- 0 => .{ .pre_index = .{
- .base = .sp,
- .index = @intCast(-@as(i11, saves_size)),
- } },
- else => |offset| .{ .signed_offset = .{
- .base = .sp,
- .offset = @intCast(offset),
- } },
- },
- ));
- save_index += 2;
- } else {
- try isel.emit(.str(
- saves[save_index].register,
- switch (saves[save_index].offset) {
- 0 => .{ .pre_index = .{
- .base = .sp,
- .index = @intCast(-@as(i11, saves_size)),
- } },
- else => |offset| .{ .unsigned_offset = .{
- .base = .sp,
- .offset = @intCast(offset),
- } },
- },
- ));
- save_index += 1;
- }
- }
+ while (save_index < saves.len) if (save_index + 2 <= saves.len and
+ saves[save_index + 0].class == saves[save_index + 1].class and
+ saves[save_index + 0].size == saves[save_index + 1].size and
+ saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
+ {
+ try isel.emit(.stp(
+ saves[save_index + 0].register,
+ saves[save_index + 1].register,
+ switch (saves[save_index + 0].offset) {
+ 0 => .{ .pre_index = .{
+ .base = .sp,
+ .index = @intCast(-@as(i11, saves_size)),
+ } },
+ else => |offset| .{ .signed_offset = .{
+ .base = .sp,
+ .offset = @intCast(offset),
+ } },
+ },
+ ));
+ save_index += 2;
+ } else {
+ try isel.emit(.str(
+ saves[save_index].register,
+ switch (saves[save_index].offset) {
+ 0 => .{ .pre_index = .{
+ .base = .sp,
+ .index = @intCast(-@as(i11, saves_size)),
+ } },
+ else => |offset| .{ .unsigned_offset = .{
+ .base = .sp,
+ .offset = @intCast(offset),
+ } },
+ },
+ ));
+ save_index += 1;
+ };
+ try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset }));
const scratch_reg: Register = if (isel.stack_align == .@"16")
.sp
- else if (stack_size == 0)
+ else if (stack_size == 0 and frame_record_offset == 0)
.fp
else
- .x9;
- try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset }));
- if (stack_size_high > 0) try isel.emit(.sub(scratch_reg, .sp, .{
- .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },
- }));
- if (stack_size_low > 0) try isel.emit(.sub(
- scratch_reg,
- if (stack_size_high > 0) scratch_reg else .sp,
- .{ .immediate = stack_size_low },
- ));
- if (isel.stack_align != .@"16") {
- try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{
- .N = .doubleword,
- .immr = -%isel.stack_align.toLog2Units(),
- .imms = ~isel.stack_align.toLog2Units(),
- } }));
+ .ip0;
+ const stack_size_lo: u12 = @truncate(stack_size >> 0);
+ const stack_size_hi: u12 = @truncate(stack_size >> 12);
+ if (mod.stack_check) {
+ if (stack_size_hi > 2) {
+ try isel.movImmediate(.ip1, stack_size_hi);
+ const loop_label = isel.instructions.items.len;
+ try isel.emit(.sub(.sp, .sp, .{
+ .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" },
+ }));
+ try isel.emit(.sub(.ip1, .ip1, .{ .immediate = 1 }));
+ try isel.emit(.ldr(.xzr, .{ .base = .sp }));
+ try isel.emit(.cbnz(.ip1, -@as(i21, @intCast(
+ (isel.instructions.items.len - loop_label) << 2,
+ ))));
+ } else for (0..stack_size_hi) |_| {
+ try isel.emit(.sub(.sp, .sp, .{
+ .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" },
+ }));
+ try isel.emit(.ldr(.xzr, .{ .base = .sp }));
+ }
+ if (stack_size_lo > 0) try isel.emit(.sub(
+ scratch_reg,
+ .sp,
+ .{ .immediate = stack_size_lo },
+ )) else if (scratch_reg.alias == Register.Alias.ip0)
+ try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 }));
+ } else {
+ if (stack_size_hi > 0) try isel.emit(.sub(scratch_reg, .sp, .{
+ .shifted_immediate = .{ .immediate = stack_size_hi, .lsl = .@"12" },
+ }));
+ if (stack_size_lo > 0) try isel.emit(.sub(
+ scratch_reg,
+ if (stack_size_hi > 0) scratch_reg else .sp,
+ .{ .immediate = stack_size_lo },
+ )) else if (scratch_reg.alias == Register.Alias.ip0 and stack_size_hi == 0)
+ try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 }));
}
+ if (isel.stack_align != .@"16") try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{
+ .N = .doubleword,
+ .immr = -%isel.stack_align.toLog2Units(),
+ .imms = ~isel.stack_align.toLog2Units(),
+ } }));
wip_mir_log.debug("", .{});
}
@@ -6859,6 +8007,7 @@ pub fn layout(
if (isel.returns) {
try isel.emit(.ret(.lr));
var save_index: usize = 0;
+ var first_offset: ?u10 = null;
while (save_index < saves.len) {
if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and
saves[save_index + 0].class == saves[save_index + 1].class and
@@ -6867,46 +8016,51 @@ pub fn layout(
try isel.emit(.ldp(
saves[save_index + 0].register,
saves[save_index + 1].register,
- switch (saves[save_index + 0].offset) {
- 0 => .{ .post_index = .{
+ if (first_offset) |offset| .{ .signed_offset = .{
+ .base = .sp,
+ .offset = @intCast(saves[save_index + 0].offset - offset),
+ } } else form: {
+ first_offset = @intCast(saves[save_index + 0].offset);
+ break :form .{ .post_index = .{
.base = .sp,
- .index = @intCast(saves_size),
- } },
- else => |offset| .{ .signed_offset = .{
- .base = .sp,
- .offset = @intCast(offset),
- } },
+ .index = @intCast(saves_size - first_offset.?),
+ } };
},
));
save_index += 2;
} else if (saves[save_index].needs_restore) {
try isel.emit(.ldr(
saves[save_index].register,
- switch (saves[save_index].offset) {
- 0 => .{ .post_index = .{
+ if (first_offset) |offset| .{ .unsigned_offset = .{
+ .base = .sp,
+ .offset = saves[save_index + 0].offset - offset,
+ } } else form: {
+ const offset = saves[save_index + 0].offset;
+ first_offset = offset;
+ break :form .{ .post_index = .{
.base = .sp,
- .index = @intCast(saves_size),
- } },
- else => |offset| .{ .unsigned_offset = .{
- .base = .sp,
- .offset = @intCast(offset),
- } },
+ .index = @intCast(saves_size - offset),
+ } };
},
));
save_index += 1;
} else save_index += 1;
}
- if (isel.stack_align != .@"16" or (stack_size_low > 0 and stack_size_high > 0)) {
- try isel.emit(switch (frame_record_offset) {
- 0 => .add(.sp, .fp, .{ .immediate = 0 }),
- else => |offset| .sub(.sp, .fp, .{ .immediate = offset }),
- });
+ const offset = stack_size + first_offset.?;
+ const offset_lo: u12 = @truncate(offset >> 0);
+ const offset_hi: u12 = @truncate(offset >> 12);
+ if (isel.stack_align != .@"16" or (offset_lo > 0 and offset_hi > 0)) {
+ const fp_offset = @as(i11, first_offset.?) - frame_record_offset;
+ try isel.emit(if (fp_offset >= 0)
+ .add(.sp, .fp, .{ .immediate = @intCast(fp_offset) })
+ else
+ .sub(.sp, .fp, .{ .immediate = @intCast(-fp_offset) }));
} else {
- if (stack_size_high > 0) try isel.emit(.add(.sp, .sp, .{
- .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },
+ if (offset_hi > 0) try isel.emit(.add(.sp, .sp, .{
+ .shifted_immediate = .{ .immediate = offset_hi, .lsl = .@"12" },
}));
- if (stack_size_low > 0) try isel.emit(.add(.sp, .sp, .{
- .immediate = stack_size_low,
+ if (offset_lo > 0) try isel.emit(.add(.sp, .sp, .{
+ .immediate = offset_lo,
}));
}
wip_mir_log.debug("{f}:\n", .{nav.fqn.fmt(ip)});
@@ -6977,11 +8131,43 @@ fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmt
return constant.fmtValue(isel.pt);
}
+fn block(
+ isel: *Select,
+ air_inst_index: Air.Inst.Index,
+ res_ty: ZigType,
+ air_body: []const Air.Inst.Index,
+) !void {
+ if (res_ty.toIntern() != .noreturn_type) {
+ isel.blocks.putAssumeCapacityNoClobber(air_inst_index, .{
+ .live_registers = isel.live_registers,
+ .target_label = @intCast(isel.instructions.items.len),
+ });
+ }
+ try isel.body(air_body);
+ if (res_ty.toIntern() != .noreturn_type) {
+ const block_entry = isel.blocks.pop().?;
+ assert(block_entry.key == air_inst_index);
+ if (isel.live_values.fetchRemove(air_inst_index)) |result_vi| result_vi.value.deref(isel);
+ }
+}
+
fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void {
wip_mir_log.debug(" | {f}", .{instruction});
try isel.instructions.append(isel.pt.zcu.gpa, instruction);
}
+fn emitPanic(isel: *Select, panic_id: Zcu.SimplePanicId) !void {
+ const zcu = isel.pt.zcu;
+ try isel.nav_relocs.append(zcu.gpa, .{
+ .nav = switch (zcu.intern_pool.indexToKey(zcu.builtin_decl_values.get(panic_id.toBuiltin()))) {
+ else => unreachable,
+ inline .@"extern", .func => |func| func.owner_nav,
+ },
+ .reloc = .{ .label = @intCast(isel.instructions.items.len) },
+ });
+ try isel.emit(.bl(0));
+}
+
fn emitLiteral(isel: *Select, bytes: []const u8) !void {
const words: []align(1) const u32 = @ptrCast(bytes);
const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len);
@@ -8000,9 +9186,18 @@ pub const Value = struct {
var dst_part_it = dst_vi.parts(isel);
if (dst_part_it.only()) |dst_part_vi| {
var src_part_it = src_vi.parts(isel);
- if (src_part_it.only()) |src_part_vi| {
- try src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return);
- } else while (src_part_it.next()) |src_part_vi| {
+ if (src_part_it.only()) |src_part_vi| only: {
+ const src_part_size = src_part_vi.size(isel);
+ if (src_part_size > @as(@TypeOf(src_part_size), if (src_part_vi.isVector(isel)) 16 else 8)) {
+ var subpart_it = root.src_vi.field(root.ty, root.src_offset, src_part_size - 1);
+ _ = try subpart_it.next(isel);
+ src_part_it = src_vi.parts(isel);
+ assert(src_part_it.only() == null);
+ break :only;
+ }
+ return src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return);
+ }
+ while (src_part_it.next()) |src_part_vi| {
const src_part_offset, const src_part_size = src_part_vi.position(isel);
var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size);
const dst_field_vi = try dst_field_it.only(isel);
@@ -8028,6 +9223,32 @@ pub const Value = struct {
}
}
+ const AddOrSubtractOptions = struct {
+ overflow: Overflow,
+
+ const Overflow = union(enum) {
+ @"unreachable",
+ panic: Zcu.SimplePanicId,
+ wrap,
+ ra: Register.Alias,
+
+ fn defCond(overflow: Overflow, isel: *Select, cond: codegen.aarch64.encoding.ConditionCode) !void {
+ switch (overflow) {
+ .@"unreachable" => unreachable,
+ .panic => |panic_id| {
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(panic_id);
+ try isel.emit(.@"b."(
+ cond.invert(),
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ },
+ .wrap => {},
+ .ra => |overflow_ra| try isel.emit(.csinc(overflow_ra.w(), .wzr, .wzr, cond.invert())),
+ }
+ }
+ };
+ };
fn addOrSubtract(
res_vi: Value.Index,
isel: *Select,
@@ -8035,19 +9256,21 @@ pub const Value = struct {
lhs_vi: Value.Index,
op: codegen.aarch64.encoding.Instruction.AddSubtractOp,
rhs_vi: Value.Index,
- opts: struct {
- wrap: bool,
- overflow_ra: Register.Alias = .zr,
- },
+ opts: AddOrSubtractOptions,
) !void {
- assert(opts.wrap or opts.overflow_ra == .zr);
const zcu = isel.pt.zcu;
if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
const int_info = ty.intInfo(zcu);
if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
var part_offset = res_vi.size(isel);
- var need_wrap = opts.wrap;
- var need_carry = opts.overflow_ra != .zr;
+ var need_wrap = switch (opts.overflow) {
+ .@"unreachable" => false,
+ .panic, .wrap, .ra => true,
+ };
+ var need_carry = switch (opts.overflow) {
+ .@"unreachable", .wrap => false,
+ .panic, .ra => true,
+ };
while (part_offset > 0) : (need_wrap = false) {
const part_size = @min(part_offset, 8);
part_offset -= part_size;
@@ -8057,48 +9280,87 @@ pub const Value = struct {
const unwrapped_res_part_ra = unwrapped_res_part_ra: {
if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra;
if (int_info.bits % 32 == 0) {
- if (opts.overflow_ra != .zr) try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(switch (int_info.signedness) {
+ try opts.overflow.defCond(isel, switch (int_info.signedness) {
.signed => .vs,
.unsigned => switch (op) {
.add => .cs,
.sub => .cc,
},
- })));
+ });
break :unwrapped_res_part_ra wrapped_res_part_ra;
}
- const wrapped_part_ra, const unwrapped_part_ra = if (opts.overflow_ra != .zr) part_ra: {
- switch (op) {
- .add => {},
- .sub => switch (int_info.signedness) {
- .signed => {},
- .unsigned => {
- try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.cc)));
- break :part_ra .{ wrapped_res_part_ra, wrapped_res_part_ra };
- },
+ need_carry = false;
+ const wrapped_part_ra, const unwrapped_part_ra = part_ra: switch (opts.overflow) {
+ .@"unreachable" => unreachable,
+ .panic, .ra => switch (int_info.signedness) {
+ .signed => {
+ try opts.overflow.defCond(isel, .ne);
+ const wrapped_part_ra = switch (wrapped_res_part_ra) {
+ else => |res_part_ra| res_part_ra,
+ .zr => try isel.allocIntReg(),
+ };
+ errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
+ const unwrapped_part_ra = unwrapped_part_ra: {
+ const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
+ else => |res_part_ra| isel.lockReg(res_part_ra),
+ .zr => .empty,
+ };
+ defer wrapped_res_part_lock.unlock(isel);
+ break :unwrapped_part_ra try isel.allocIntReg();
+ };
+ errdefer isel.freeReg(unwrapped_part_ra);
+ switch (part_size) {
+ else => unreachable,
+ 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })),
+ 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })),
+ }
+ break :part_ra .{ wrapped_part_ra, unwrapped_part_ra };
},
- }
- try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.ne)));
- const wrapped_part_ra = switch (wrapped_res_part_ra) {
- else => |res_part_ra| res_part_ra,
- .zr => try isel.allocIntReg(),
- };
- errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
- const unwrapped_part_ra = unwrapped_part_ra: {
- const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
- else => |res_part_ra| isel.lockReg(res_part_ra),
- .zr => .empty,
- };
- defer wrapped_res_part_lock.unlock(isel);
- break :unwrapped_part_ra try isel.allocIntReg();
- };
- errdefer isel.freeReg(unwrapped_part_ra);
- switch (part_size) {
- else => unreachable,
- 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })),
- 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })),
- }
- break :part_ra .{ wrapped_part_ra, unwrapped_part_ra };
- } else .{ wrapped_res_part_ra, wrapped_res_part_ra };
+ .unsigned => {
+ const unwrapped_part_ra = unwrapped_part_ra: {
+ const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
+ else => |res_part_ra| isel.lockReg(res_part_ra),
+ .zr => .empty,
+ };
+ defer wrapped_res_part_lock.unlock(isel);
+ break :unwrapped_part_ra try isel.allocIntReg();
+ };
+ errdefer isel.freeReg(unwrapped_part_ra);
+ const bit: u6 = @truncate(int_info.bits);
+ switch (opts.overflow) {
+ .@"unreachable", .wrap => unreachable,
+ .panic => |panic_id| {
+ const skip_label = isel.instructions.items.len;
+ try isel.emitPanic(panic_id);
+ try isel.emit(.tbz(
+ switch (bit) {
+ 0, 32 => unreachable,
+ 1...31 => unwrapped_part_ra.w(),
+ 33...63 => unwrapped_part_ra.x(),
+ },
+ bit,
+ @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
+ ));
+ },
+ .ra => |overflow_ra| try isel.emit(switch (bit) {
+ 0, 32 => unreachable,
+ 1...31 => .ubfm(overflow_ra.w(), unwrapped_part_ra.w(), .{
+ .N = .word,
+ .immr = bit,
+ .imms = bit,
+ }),
+ 33...63 => .ubfm(overflow_ra.x(), unwrapped_part_ra.x(), .{
+ .N = .doubleword,
+ .immr = bit,
+ .imms = bit,
+ }),
+ }),
+ }
+ break :part_ra .{ wrapped_res_part_ra, unwrapped_part_ra };
+ },
+ },
+ .wrap => .{ wrapped_res_part_ra, wrapped_res_part_ra },
+ };
defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra);
if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) {
@@ -8409,9 +9671,12 @@ pub const Value = struct {
fn defAddr(
def_vi: Value.Index,
isel: *Select,
- def_ty: ZigType,
- wrap: ?std.builtin.Type.Int,
- expected_live_registers: *const LiveRegisters,
+ root_ty: ZigType,
+ opts: struct {
+ root_vi: Value.Index = .free,
+ wrap: ?std.builtin.Type.Int = null,
+ expected_live_registers: *const LiveRegisters = &.initFill(.free),
+ },
) !?void {
if (!def_vi.isUsed(isel)) return null;
const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel);
@@ -8420,11 +9685,12 @@ pub const Value = struct {
.stack_slot => |stack_slot| .{ stack_slot, false },
else => unreachable,
};
- _ = try def_vi.load(isel, def_ty, stack_slot.base, .{
+ _ = try def_vi.load(isel, root_ty, stack_slot.base, .{
+ .root_vi = opts.root_vi,
.offset = @intCast(stack_slot.offset + offset_from_parent),
.split = false,
- .wrap = wrap,
- .expected_live_registers = expected_live_registers,
+ .wrap = opts.wrap,
+ .expected_live_registers = opts.expected_live_registers,
});
if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot });
}
@@ -8454,12 +9720,12 @@ pub const Value = struct {
const part_mat = try part_vi.matReg(isel);
try isel.emit(if (part_vi.isVector(isel)) emit: {
assert(part_offset == 0 and part_size == vi_size);
- break :emit size: switch (vi_size) {
+ break :emit switch (vi_size) {
else => unreachable,
2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
.fmov(ra.h(), .{ .register = part_mat.ra.h() })
else
- continue :size 4,
+ .dup(ra.h(), part_mat.ra.@"h[]"(0)),
4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }),
8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }),
16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }),
@@ -8503,6 +9769,53 @@ pub const Value = struct {
}
}
+ pub fn defUndef(def_vi: Value.Index, isel: *Select, root_ty: ZigType, opts: struct {
+ root_vi: Value.Index = .free,
+ offset: u64 = 0,
+ split: bool = true,
+ }) !void {
+ const root_vi = switch (opts.root_vi) {
+ _ => |root_vi| root_vi,
+ .allocating => unreachable,
+ .free => def_vi,
+ };
+ var part_it = def_vi.parts(isel);
+ if (part_it.only()) |part_vi| only: {
+ const part_size = part_vi.size(isel);
+ const part_is_vector = part_vi.isVector(isel);
+ if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) {
+ if (!opts.split) return;
+ var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1);
+ _ = try subpart_it.next(isel);
+ part_it = def_vi.parts(isel);
+ assert(part_it.only() == null);
+ break :only;
+ }
+ return if (try part_vi.defReg(isel)) |part_ra| try isel.emit(if (part_is_vector)
+ .movi(switch (part_size) {
+ else => unreachable,
+ 1...8 => part_ra.@"8b"(),
+ 9...16 => part_ra.@"16b"(),
+ }, 0xaa, .{ .lsl = 0 })
+ else switch (part_size) {
+ else => unreachable,
+ 1...4 => .orr(part_ra.w(), .wzr, .{ .immediate = .{
+ .N = .word,
+ .immr = 0b000001,
+ .imms = 0b111100,
+ } }),
+ 5...8 => .orr(part_ra.x(), .xzr, .{ .immediate = .{
+ .N = .word,
+ .immr = 0b000001,
+ .imms = 0b111100,
+ } }),
+ });
+ }
+ while (part_it.next()) |part_vi| try part_vi.defUndef(isel, root_ty, .{
+ .root_vi = root_vi,
+ });
+ }
+
pub fn liveIn(
vi: Value.Index,
isel: *Select,
@@ -8532,21 +9845,30 @@ pub const Value = struct {
},
true => switch (vi.size(isel)) {
else => unreachable,
- 2 => .fmov(dst_ra.w(), .{ .register = src_ra.h() }),
+ 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
+ .fmov(dst_ra.w(), .{ .register = src_ra.h() })
+ else
+ .umov(dst_ra.w(), src_ra.@"h[]"(0)),
4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }),
8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }),
},
},
true => switch (src_ra.isVector()) {
- false => switch (vi.size(isel)) {
+ false => size: switch (vi.size(isel)) {
else => unreachable,
- 2 => .fmov(dst_ra.h(), .{ .register = src_ra.w() }),
+ 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
+ .fmov(dst_ra.h(), .{ .register = src_ra.w() })
+ else
+ continue :size 4,
4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }),
8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }),
},
true => switch (vi.size(isel)) {
else => unreachable,
- 2 => .fmov(dst_ra.h(), .{ .register = src_ra.h() }),
+ 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
+ .fmov(dst_ra.h(), .{ .register = src_ra.h() })
+ else
+ .dup(dst_ra.h(), src_ra.@"h[]"(0)),
4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }),
8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }),
16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }),
@@ -8574,41 +9896,15 @@ pub const Value = struct {
expected_live_registers: *const LiveRegisters,
) !void {
try vi.liveIn(isel, src_ra, expected_live_registers);
- const offset_from_parent: i65, const parent_vi = vi.valueParent(isel);
+ const offset_from_parent, const parent_vi = vi.valueParent(isel);
switch (parent_vi.parent(isel)) {
.unallocated => {},
- .stack_slot => |stack_slot| {
- const offset = stack_slot.offset + offset_from_parent;
- try isel.emit(switch (vi.size(isel)) {
- else => unreachable,
- 1 => if (src_ra.isVector()) .str(src_ra.b(), .{ .unsigned_offset = .{
- .base = stack_slot.base.x(),
- .offset = @intCast(offset),
- } }) else .strb(src_ra.w(), .{ .unsigned_offset = .{
- .base = stack_slot.base.x(),
- .offset = @intCast(offset),
- } }),
- 2 => if (src_ra.isVector()) .str(src_ra.h(), .{ .unsigned_offset = .{
- .base = stack_slot.base.x(),
- .offset = @intCast(offset),
- } }) else .strh(src_ra.w(), .{ .unsigned_offset = .{
- .base = stack_slot.base.x(),
- .offset = @intCast(offset),
- } }),
- 4 => .str(if (src_ra.isVector()) src_ra.s() else src_ra.w(), .{ .unsigned_offset = .{
- .base = stack_slot.base.x(),
- .offset = @intCast(offset),
- } }),
- 8 => .str(if (src_ra.isVector()) src_ra.d() else src_ra.x(), .{ .unsigned_offset = .{
- .base = stack_slot.base.x(),
- .offset = @intCast(offset),
- } }),
- 16 => .str(src_ra.q(), .{ .unsigned_offset = .{
- .base = stack_slot.base.x(),
- .offset = @intCast(offset),
- } }),
- });
- },
+ .stack_slot => |stack_slot| if (stack_slot.base != Register.Alias.fp) try isel.storeReg(
+ src_ra,
+ vi.size(isel),
+ stack_slot.base,
+ @as(i65, stack_slot.offset) + offset_from_parent,
+ ),
else => unreachable,
}
try vi.spillReg(isel, src_ra, 0, expected_live_registers);
@@ -8629,9 +9925,12 @@ pub const Value = struct {
const part_size = part_vi.size(isel);
const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra;
defer if (part_ra != dst_ra) isel.freeReg(part_ra);
- if (part_ra != dst_ra) try isel.emit(switch (part_size) {
+ if (part_ra != dst_ra) try isel.emit(part_size: switch (part_size) {
else => unreachable,
- 2 => .fmov(dst_ra.h(), .{ .register = part_ra.w() }),
+ 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
+ .fmov(dst_ra.h(), .{ .register = part_ra.w() })
+ else
+ continue :part_size 4,
4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }),
8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }),
});
@@ -8798,6 +10097,11 @@ pub const Value = struct {
return it.vi;
}
+ pub fn peek(it: PartIterator) ?Value.Index {
+ var it_mut = it;
+ return it_mut.next();
+ }
+
pub fn only(it: PartIterator) ?Value.Index {
return if (it.remaining == 1) it.vi else null;
}
@@ -8856,24 +10160,31 @@ pub const Value = struct {
_ = vi.addPart(isel, 8, 8);
} else unreachable,
},
- .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu))
- continue :type_key ip.indexToKey(child_type)
- else switch (ZigType.fromInterned(child_type).abiSize(zcu)) {
- 0...8, 16 => |child_size| if (offset == 0 and size == ty_size) {
- vi.setParts(isel, 2);
- _ = vi.addPart(isel, 0, child_size);
- _ = vi.addPart(isel, child_size, 1);
- } else unreachable,
- 9...15 => |child_size| if (offset == 0 and size == ty_size) {
- vi.setParts(isel, 2);
- _ = vi.addPart(isel, 0, 8);
- _ = vi.addPart(isel, 8, ty_size - 8);
- } else if (offset == 8 and size == ty_size - 8) {
- vi.setParts(isel, 2);
- _ = vi.addPart(isel, 0, child_size - 8);
- _ = vi.addPart(isel, child_size - 8, 1);
- } else unreachable,
- else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
+ .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu)) continue :type_key ip.indexToKey(child_type) else {
+ const child_ty: ZigType = .fromInterned(child_type);
+ const child_size = child_ty.abiSize(zcu);
+ if (offset == 0 and size == child_size) {
+ ty = child_ty;
+ ty_size = child_size;
+ continue :type_key ip.indexToKey(child_type);
+ }
+ switch (child_size) {
+ 0...8, 16 => if (offset == 0 and size == ty_size) {
+ vi.setParts(isel, 2);
+ _ = vi.addPart(isel, 0, child_size);
+ _ = vi.addPart(isel, child_size, 1);
+ } else unreachable,
+ 9...15 => if (offset == 0 and size == ty_size) {
+ vi.setParts(isel, 2);
+ _ = vi.addPart(isel, 0, 8);
+ _ = vi.addPart(isel, 8, ty_size - 8);
+ } else if (offset == 8 and size == ty_size - 8) {
+ vi.setParts(isel, 2);
+ _ = vi.addPart(isel, 0, child_size - 8);
+ _ = vi.addPart(isel, child_size - 8, 1);
+ } else unreachable,
+ else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
+ }
},
.array_type => |array_type| {
const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
@@ -9027,8 +10338,14 @@ pub const Value = struct {
} },
},
.struct_type => {
- const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
const loaded_struct = ip.loadStructType(ty.toIntern());
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {},
+ .@"packed" => continue :type_key .{
+ .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
+ },
+ }
+ const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
if (loaded_struct.field_types.len > Value.max_parts and
(std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
@@ -9136,6 +10453,77 @@ pub const Value = struct {
if (part.is_vector) subpart_vi.setIsVector(isel);
}
},
+ .union_type => {
+ const loaded_union = ip.loadUnionType(ty.toIntern());
+ switch (loaded_union.flagsUnordered(ip).layout) {
+ .auto, .@"extern" => {},
+ .@"packed" => continue :type_key .{ .int_type = .{
+ .signedness = .unsigned,
+ .bits = @intCast(ty.bitSize(zcu)),
+ } },
+ }
+ const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
+ if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
+ return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
+ const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
+ const alignment = vi.alignment(isel);
+ const tag_offset = union_layout.tagOffset();
+ const payload_offset = union_layout.payloadOffset();
+ const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness };
+ var parts: [2]Part = undefined;
+ var parts_len: Value.PartsLen = 0;
+ var field_end: u64 = 0;
+ for (0..2) |field_index| {
+ const field: enum { tag, payload } = switch (field_index) {
+ 0 => if (tag_offset < payload_offset) .tag else .payload,
+ 1 => if (tag_offset < payload_offset) .payload else .tag,
+ else => unreachable,
+ };
+ const field_size, const field_begin = switch (field) {
+ .tag => .{ union_layout.tag_size, tag_offset },
+ .payload => .{ union_layout.payload_size, payload_offset },
+ };
+ if (field_begin >= offset + size) break;
+ if (field_size == 0) continue;
+ field_end = field_begin + field_size;
+ if (field_end <= offset) continue;
+ const field_signedness = field_signedness: switch (field) {
+ .tag => {
+ if (offset >= field_begin and offset + size <= field_begin + field_size) {
+ ty = .fromInterned(loaded_union.enum_tag_ty);
+ ty_size = field_size;
+ offset -= field_begin;
+ continue :type_key ip.indexToKey(loaded_union.enum_tag_ty);
+ }
+ break :field_signedness ip.indexToKey(loaded_union.loadTagType(ip).tag_ty).int_type.signedness;
+ },
+ .payload => null,
+ };
+ if (parts_len > 0) combine: {
+ const prev_part = &parts[parts_len - 1];
+ const combined_size = field_end - prev_part.offset;
+ if (combined_size > @as(u64, 1) << @min(
+ min_part_log2_stride,
+ alignment.toLog2Units(),
+ @ctz(prev_part.offset),
+ )) break :combine;
+ prev_part.size = combined_size;
+ prev_part.signedness = null;
+ continue;
+ }
+ parts[parts_len] = .{
+ .offset = field_begin,
+ .size = field_size,
+ .signedness = field_signedness,
+ };
+ parts_len += 1;
+ }
+ vi.setParts(isel, parts_len);
+ for (parts[0..parts_len]) |part| {
+ const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
+ if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
+ }
+ },
.opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
.enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
.error_set_type,
@@ -9187,7 +10575,10 @@ pub const Value = struct {
if (vi.register(isel)) |ra| {
if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) {
else => unreachable,
- 2 => .fmov(mat.ra.h(), .{ .register = ra.h() }),
+ 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
+ .fmov(mat.ra.h(), .{ .register = ra.h() })
+ else
+ .dup(mat.ra.h(), ra.@"h[]"(0)),
4 => .fmov(mat.ra.s(), .{ .register = ra.s() }),
8 => .fmov(mat.ra.d(), .{ .register = ra.d() }),
16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }),
@@ -9347,11 +10738,12 @@ pub const Value = struct {
} },
.error_union => |error_union| {
const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
+ const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
- if (!ip.isNoReturn(error_union_type.error_set_type) and
- offset == codegen.errUnionErrorOffset(payload_ty, zcu))
- {
- offset = 0;
+ const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
+ const error_set_size = error_set_ty.abiSize(zcu);
+ if (offset >= error_set_offset and offset + size <= error_set_offset + error_set_size) {
+ offset -= error_set_offset;
continue :constant_key switch (error_union.val) {
.err_name => |err_name| .{ .err = .{
.ty = error_union_type.error_set_type,
@@ -9363,15 +10755,18 @@ pub const Value = struct {
} },
};
}
- assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
- offset -= @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));
- switch (error_union.val) {
- .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
- .payload => |payload| {
- constant = payload;
- constant_key = ip.indexToKey(payload);
- continue :constant_key constant_key;
- },
+ const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
+ const payload_size = payload_ty.abiSize(zcu);
+ if (offset >= payload_offset and offset + size <= payload_offset + payload_size) {
+ offset -= payload_offset;
+ switch (error_union.val) {
+ .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
+ .payload => |payload| {
+ constant = payload;
+ constant_key = ip.indexToKey(payload);
+ continue :constant_key constant_key;
+ },
+ }
}
},
.enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },
@@ -9555,21 +10950,29 @@ pub const Value = struct {
var base_ptr = ip.indexToKey(base).ptr;
const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child;
const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type;
- base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu);
+ base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu) + ptr.byte_offset;
+ continue :constant_key .{ .ptr = base_ptr };
+ },
+ .opt_payload => |base| {
+ var base_ptr = ip.indexToKey(base).ptr;
+ base_ptr.byte_offset += ptr.byte_offset;
continue :constant_key .{ .ptr = base_ptr };
},
- .opt_payload => |base| continue :constant_key .{ .ptr = ip.indexToKey(base).ptr },
.field => |field| {
var base_ptr = ip.indexToKey(field.base).ptr;
const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
- base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu);
+ base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset;
continue :constant_key .{ .ptr = base_ptr };
},
.comptime_alloc, .comptime_field, .arr_elem => unreachable,
};
},
.slice => |slice| switch (offset) {
- 0 => continue :constant_key .{ .ptr = ip.indexToKey(slice.ptr).ptr },
+ 0 => continue :constant_key switch (ip.indexToKey(slice.ptr)) {
+ else => unreachable,
+ .undef => |undef| .{ .undef = undef },
+ .ptr => |ptr| .{ .ptr = ptr },
+ },
else => {
assert(offset == @divExact(isel.target.ptrBitWidth(), 8));
offset = 0;
@@ -9900,7 +11303,17 @@ fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8
fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {
const zcu = isel.pt.zcu;
const ip = &zcu.intern_pool;
- switch (ip.indexToKey(constant.toIntern())) {
+ if (try isel.writeKeyToMemory(ip.indexToKey(constant.toIntern()), buffer)) return true;
+ constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
+ error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
+ };
+ return true;
+}
+fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) error{OutOfMemory}!bool {
+ const zcu = isel.pt.zcu;
+ const ip = &zcu.intern_pool;
+ switch (constant_key) {
.int_type,
.ptr_type,
.array_type,
@@ -9922,6 +11335,37 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
.empty_enum_value,
.memoized_call,
=> unreachable, // not a runtime value
+ .err => |err| {
+ const error_int = ip.getErrorValueIfExists(err.name).?;
+ switch (buffer.len) {
+ else => unreachable,
+ inline 1...4 => |size| std.mem.writeInt(
+ @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * size } }),
+ buffer[0..size],
+ @intCast(error_int),
+ isel.target.cpu.arch.endian(),
+ ),
+ }
+ },
+ .error_union => |error_union| {
+ const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
+ const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
+ const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
+ const error_set = buffer[@intCast(codegen.errUnionErrorOffset(payload_ty, zcu))..][0..@intCast(error_set_ty.abiSize(zcu))];
+ switch (error_union.val) {
+ .err_name => |err_name| if (!try isel.writeKeyToMemory(.{ .err = .{
+ .ty = error_set_ty.toIntern(),
+ .name = err_name,
+ } }, error_set)) return false,
+ .payload => |payload| {
+ if (!try isel.writeToMemory(
+ .fromInterned(payload),
+ buffer[@intCast(codegen.errUnionPayloadOffset(payload_ty, zcu))..][0..@intCast(payload_ty.abiSize(zcu))],
+ )) return false;
+ @memset(error_set, 0);
+ },
+ }
+ },
.opt => |opt| {
const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));
switch (opt.val) {
@@ -9933,7 +11377,6 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);
},
}
- return true;
},
.aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
else => unreachable,
@@ -9952,9 +11395,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
elem_offset += elem_size;
},
}
- return true;
},
- .vector_type => {},
+ .vector_type => return false,
.struct_type => {
const loaded_struct = ip.loadStructType(aggregate.ty);
switch (loaded_struct.layout) {
@@ -9977,9 +11419,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
}), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
field_offset += field_size;
}
- return true;
},
- .@"extern", .@"packed" => {},
+ .@"extern", .@"packed" => return false,
}
},
.tuple_type => |tuple_type| {
@@ -9996,15 +11437,10 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
}), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
field_offset += field_size;
}
- return true;
},
},
- else => {},
+ else => return false,
}
- constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
- error.OutOfMemory => return error.OutOfMemory,
- error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
- };
return true;
}
@@ -10622,16 +12058,14 @@ pub const CallAbiIterator = struct {
{
const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
const offset = codegen.errUnionErrorOffset(payload_ty, zcu);
- const size = error_set_ty.abiSize(zcu);
- const end = offset % 8 + size;
+ const end = offset % 8 + error_set_ty.abiSize(zcu);
const part_index: usize = @intCast(offset / 8);
sizes[part_index] = @max(sizes[part_index], @min(end, 8));
if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
}
{
const offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
- const size = payload_ty.abiSize(zcu);
- const end = offset % 8 + size;
+ const end = offset % 8 + payload_ty.abiSize(zcu);
const part_index: usize = @intCast(offset / 8);
sizes[part_index] = @max(sizes[part_index], @min(end, 8));
if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
@@ -10675,8 +12109,14 @@ pub const CallAbiIterator = struct {
=> unreachable,
},
.struct_type => {
- const size = wip_vi.size(isel);
const loaded_struct = ip.loadStructType(ty.toIntern());
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {},
+ .@"packed" => continue :type_key .{
+ .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
+ },
+ }
+ const size = wip_vi.size(isel);
if (size <= 16 * 4) homogeneous_aggregate: {
const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate;
const parts_len = @shrExact(size, fdt.log2Size());
@@ -10761,6 +12201,40 @@ pub const CallAbiIterator = struct {
else => it.indirect(isel, wip_vi),
}
},
+ .union_type => {
+ const loaded_union = ip.loadUnionType(ty.toIntern());
+ switch (loaded_union.flagsUnordered(ip).layout) {
+ .auto, .@"extern" => {},
+ .@"packed" => continue :type_key .{ .int_type = .{
+ .signedness = .unsigned,
+ .bits = @intCast(ty.bitSize(zcu)),
+ } },
+ }
+ switch (wip_vi.size(isel)) {
+ 0 => unreachable,
+ 1...8 => it.integer(isel, wip_vi),
+ 9...16 => {
+ const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
+ var sizes: [2]u64 = @splat(0);
+ {
+ const offset = union_layout.tagOffset();
+ const end = offset % 8 + union_layout.tag_size;
+ const part_index: usize = @intCast(offset / 8);
+ sizes[part_index] = @max(sizes[part_index], @min(end, 8));
+ if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
+ }
+ {
+ const offset = union_layout.payloadOffset();
+ const end = offset % 8 + union_layout.payload_size;
+ const part_index: usize = @intCast(offset / 8);
+ sizes[part_index] = @max(sizes[part_index], @min(end, 8));
+ if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
+ }
+ it.integers(isel, wip_vi, sizes);
+ },
+ else => it.indirect(isel, wip_vi),
+ }
+ },
.opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
.enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
.error_set_type,
@@ -10789,6 +12263,16 @@ pub const CallAbiIterator = struct {
return wip_vi.ref(isel);
}
+ pub fn nonSysvVarArg(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
+ const ngrn = it.ngrn;
+ defer it.ngrn = ngrn;
+ it.ngrn = ngrn_end;
+ const nsrn = it.nsrn;
+ defer it.nsrn = nsrn;
+ it.nsrn = nsrn_end;
+ return it.param(isel, ty);
+ }
+
pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
const wip_vi = try it.param(isel, ty) orelse return null;
switch (wip_vi.parent(isel)) {
diff --git a/src/codegen/aarch64/encoding.zig b/src/codegen/aarch64/encoding.zig
index 1697b2957b..42d38d2ea4 100644
--- a/src/codegen/aarch64/encoding.zig
+++ b/src/codegen/aarch64/encoding.zig
@@ -81,6 +81,14 @@ pub const Register = struct {
.@"16b", .@"8b" => .byte,
};
}
+
+ pub fn elemSz(arrangement: Arrangement) Instruction.DataProcessingVector.Sz {
+ return switch (arrangement) {
+ else => unreachable,
+ .@"2d", .@"1d" => .double,
+ .@"4s", .@"2s" => .single,
+ };
+ }
};
pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } };
@@ -151,6 +159,7 @@ pub const Register = struct {
pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } };
pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } };
+ pub const ip = x16;
pub const ip0 = x16;
pub const ip1 = x17;
pub const fp = x29;
@@ -774,6 +783,7 @@ pub const Register = struct {
ffr,
+ pub const ip: Alias = .r16;
pub const ip0: Alias = .r16;
pub const ip1: Alias = .r17;
pub const fp: Alias = .r29;
@@ -6815,7 +6825,7 @@ pub const Instruction = packed union {
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b01,
- U: bool = false,
+ U: std.builtin.Signedness = .signed,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
@@ -6829,7 +6839,7 @@ pub const Instruction = packed union {
o0: AddSubtractOp = .sub,
Rm: Register.Encoded,
op21: u2 = 0b01,
- U: bool = false,
+ U: std.builtin.Signedness = .signed,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
@@ -6843,7 +6853,7 @@ pub const Instruction = packed union {
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b10,
- U: bool = false,
+ U: std.builtin.Signedness = .signed,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
@@ -6857,7 +6867,7 @@ pub const Instruction = packed union {
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b01,
- U: bool = true,
+ U: std.builtin.Signedness = .unsigned,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
@@ -6871,7 +6881,7 @@ pub const Instruction = packed union {
o0: AddSubtractOp = .sub,
Rm: Register.Encoded,
op21: u2 = 0b01,
- U: bool = true,
+ U: std.builtin.Signedness = .unsigned,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
@@ -6885,7 +6895,7 @@ pub const Instruction = packed union {
o0: AddSubtractOp = .add,
Rm: Register.Encoded,
op21: u2 = 0b10,
- U: bool = true,
+ U: std.builtin.Signedness = .unsigned,
decoded24: u5 = 0b11011,
op54: u2 = 0b00,
sf: Register.IntegerSize = .doubleword,
@@ -7007,8 +7017,12 @@ pub const Instruction = packed union {
/// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD
pub const DataProcessingVector = packed union {
group: @This().Group,
+ simd_scalar_copy: SimdScalarCopy,
+ simd_scalar_two_register_miscellaneous_fp16: SimdScalarTwoRegisterMiscellaneousFp16,
+ simd_scalar_two_register_miscellaneous: SimdScalarTwoRegisterMiscellaneous,
simd_scalar_pairwise: SimdScalarPairwise,
simd_copy: SimdCopy,
+ simd_two_register_miscellaneous_fp16: SimdTwoRegisterMiscellaneousFp16,
simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous,
simd_across_lanes: SimdAcrossLanes,
simd_three_same: SimdThreeSame,
@@ -7018,6 +7032,7 @@ pub const Instruction = packed union {
float_compare: FloatCompare,
float_immediate: FloatImmediate,
float_data_processing_two_source: FloatDataProcessingTwoSource,
+ float_conditional_select: FloatConditionalSelect,
float_data_processing_three_source: FloatDataProcessingThreeSource,
/// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group
@@ -7030,6 +7045,876 @@ pub const Instruction = packed union {
op0: u4,
};
+ /// Advanced SIMD scalar copy
+ pub const SimdScalarCopy = packed union {
+ group: @This().Group,
+ dup: Dup,
+
+ pub const Group = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ imm4: u4,
+ decoded15: u1 = 0b0,
+ imm5: u5,
+ decoded21: u8 = 0b11110000,
+ op: u1,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.39 DUP (element)
+ pub const Dup = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ imm4: u4 = 0b0000,
+ decoded15: u1 = 0b0,
+ imm5: u5,
+ decoded21: u8 = 0b11110000,
+ op: u1 = 0b0,
+ decoded30: u2 = 0b01,
+ };
+
+ pub const Decoded = union(enum) {
+ unallocated,
+ dup: Dup,
+ };
+ pub fn decode(inst: @This()) @This().Decoded {
+ return switch (inst.group.op) {
+ 0b0 => switch (inst.group.imm4) {
+ else => .unallocated,
+ 0b0000 => .{ .dup = inst.dup },
+ },
+ 0b1 => .unallocated,
+ };
+ }
+ };
+
+ /// Advanced SIMD scalar two-register miscellaneous FP16
+ pub const SimdScalarTwoRegisterMiscellaneousFp16 = packed union {
+ group: @This().Group,
+ fcvtns: Fcvtns,
+ fcvtms: Fcvtms,
+ fcvtas: Fcvtas,
+ scvtf: Scvtf,
+ fcmgt: Fcmgt,
+ fcmeq: Fcmeq,
+ fcmlt: Fcmlt,
+ fcvtps: Fcvtps,
+ fcvtzs: Fcvtzs,
+ frecpe: Frecpe,
+ frecpx: Frecpx,
+ fcvtnu: Fcvtnu,
+ fcvtmu: Fcvtmu,
+ fcvtau: Fcvtau,
+ ucvtf: Ucvtf,
+ fcmge: Fcmge,
+ fcmle: Fcmle,
+ fcvtpu: Fcvtpu,
+ fcvtzu: Fcvtzu,
+ frsqrte: Frsqrte,
+
+ pub const Group = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5,
+ decoded17: u6 = 0b111100,
+ a: u1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.80 FCVTNS (vector)
+ pub const Fcvtns = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.75 FCVTMS (vector)
+ pub const Fcvtms = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.70 FCVTAS (vector)
+ pub const Fcvtas = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.234 SCVTF (vector, integer)
+ pub const Scvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.61 FCMGT (zero)
+ pub const Fcmgt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.57 FCMEQ (zero)
+ pub const Fcmeq = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.65 FCMLT (zero)
+ pub const Fcmlt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01110,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.84 FCVTPS (vector)
+ pub const Fcvtps = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.90 FCVTZS (vector, integer)
+ pub const Fcvtzs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.144 FRECPE
+ pub const Frecpe = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.146 FRECPX
+ pub const Frecpx = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11111,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.82 FCVTNU (vector)
+ pub const Fcvtnu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.77 FCVTMU (vector)
+ pub const Fcvtmu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.72 FCVTAU (vector)
+ pub const Fcvtau = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.353 UCVTF (vector, integer)
+ pub const Ucvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.59 FCMGE (zero)
+ pub const Fcmge = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.64 FCMLE (zero)
+ pub const Fcmle = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.86 FCVTPU (vector)
+ pub const Fcvtpu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.94 FCVTZU (vector, integer)
+ pub const Fcvtzu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.169 FRSQRTE
+ pub const Frsqrte = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+ };
+
+ /// Advanced SIMD scalar two-register miscellaneous
+ pub const SimdScalarTwoRegisterMiscellaneous = packed union {
+ group: @This().Group,
+ suqadd: Suqadd,
+ sqabs: Sqabs,
+ cmgt: Cmgt,
+ cmeq: Cmeq,
+ cmlt: Cmlt,
+ abs: Abs,
+ sqxtn: Sqxtn,
+ fcvtns: Fcvtns,
+ fcvtms: Fcvtms,
+ fcvtas: Fcvtas,
+ scvtf: Scvtf,
+ fcmgt: Fcmgt,
+ fcmeq: Fcmeq,
+ fcmlt: Fcmlt,
+ fcvtps: Fcvtps,
+ fcvtzs: Fcvtzs,
+ frecpe: Frecpe,
+ frecpx: Frecpx,
+ usqadd: Usqadd,
+ sqneg: Sqneg,
+ cmge: Cmge,
+ cmle: Cmle,
+ neg: Neg,
+ sqxtun: Sqxtun,
+ uqxtn: Uqxtn,
+ fcvtxn: Fcvtxn,
+ fcvtnu: Fcvtnu,
+ fcvtmu: Fcvtmu,
+ fcvtau: Fcvtau,
+ ucvtf: Ucvtf,
+ fcmge: Fcmge,
+ fcmle: Fcmle,
+ fcvtpu: Fcvtpu,
+ fcvtzu: Fcvtzu,
+ frsqrte: Frsqrte,
+
+ pub const Group = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.337 SUQADD
+ pub const Suqadd = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.282 SQABS
+ pub const Sqabs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00111,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.32 CMGT (zero)
+ pub const Cmgt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01000,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.28 CMEQ (zero)
+ pub const Cmeq = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01001,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.36 CMLT (zero)
+ pub const Cmlt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01010,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.1 ABS
+ pub const Abs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.308 SQXTN
+ pub const Sqxtn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10100,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.80 FCVTNS (vector)
+ pub const Fcvtns = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.75 FCVTMS (vector)
+ pub const Fcvtms = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.70 FCVTAS (vector)
+ pub const Fcvtas = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.234 SCVTF (vector, integer)
+ pub const Scvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.61 FCMGT (zero)
+ pub const Fcmgt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.57 FCMEQ (zero)
+ pub const Fcmeq = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.65 FCMLT (zero)
+ pub const Fcmlt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01110,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.84 FCVTPS (vector)
+ pub const Fcvtps = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.90 FCVTZS (vector, integer)
+ pub const Fcvtzs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.144 FRECPE
+ pub const Frecpe = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.146 FRECPX
+ pub const Frecpx = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11111,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .signed,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.394 USQADD
+ pub const Usqadd = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.292 SQNEG
+ pub const Sqneg = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00111,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.30 CMGE (zero)
+ pub const Cmge = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01000,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.35 CMLE (zero)
+ pub const Cmle = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01001,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.209 NEG (vector)
+ pub const Neg = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.309 SQXTUN
+ pub const Sqxtun = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10010,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.381 UQXTN
+ pub const Uqxtn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10100,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.88 FCVTXN
+ pub const Fcvtxn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10110,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.82 FCVTNU (vector)
+ pub const Fcvtnu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.77 FCVTMU (vector)
+ pub const Fcvtmu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.72 FCVTAU (vector)
+ pub const Fcvtau = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.353 UCVTF (vector, integer)
+ pub const Ucvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.59 FCMGE (zero)
+ pub const Fcmge = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.64 FCMLE (zero)
+ pub const Fcmle = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.86 FCVTPU (vector)
+ pub const Fcvtpu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.94 FCVTZU (vector, integer)
+ pub const Fcvtzu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+
+ /// C7.2.169 FRSQRTE
+ pub const Frsqrte = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b11110,
+ U: std.builtin.Signedness = .unsigned,
+ decoded30: u2 = 0b01,
+ };
+ };
+
/// Advanced SIMD scalar pairwise
pub const SimdScalarPairwise = packed union {
group: @This().Group,
@@ -7043,7 +7928,7 @@ pub const Instruction = packed union {
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b11110,
- U: u1,
+ U: std.builtin.Signedness,
decoded30: u2 = 0b01,
};
@@ -7056,7 +7941,7 @@ pub const Instruction = packed union {
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b11110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
decoded30: u2 = 0b01,
};
};
@@ -7064,8 +7949,10 @@ pub const Instruction = packed union {
/// Advanced SIMD copy
pub const SimdCopy = packed union {
group: @This().Group,
+ dup: Dup,
smov: Smov,
umov: Umov,
+ ins: Ins,
pub const Group = packed struct {
Rd: Register.Encoded,
@@ -7076,22 +7963,41 @@ pub const Instruction = packed union {
imm5: u5,
decoded21: u8 = 0b01110000,
op: u1,
- Q: Register.IntegerSize,
+ Q: u1,
decoded31: u1 = 0b0,
};
+ /// C7.2.39 DUP (element)
+ /// C7.2.40 DUP (general)
+ pub const Dup = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ imm4: Imm4,
+ decoded15: u1 = 0b0,
+ imm5: u5,
+ decoded21: u8 = 0b01110000,
+ op: u1 = 0b0,
+ Q: Q,
+ decoded31: u1 = 0b0,
+
+ pub const Imm4 = enum(u4) {
+ element = 0b0000,
+ general = 0b0001,
+ _,
+ };
+ };
+
/// C7.2.279 SMOV
pub const Smov = packed struct {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
- decoded11: u1 = 0b1,
- decoded12: u1 = 0b0,
- decoded13: u2 = 0b01,
+ imm4: u4 = 0b0101,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b01110000,
- decoded29: u1 = 0b0,
+ op: u1 = 0b0,
Q: Register.IntegerSize,
decoded31: u1 = 0b0,
};
@@ -7101,22 +8007,587 @@ pub const Instruction = packed union {
Rd: Register.Encoded,
Rn: Register.Encoded,
decoded10: u1 = 0b1,
- decoded11: u1 = 0b1,
- decoded12: u1 = 0b1,
- decoded13: u2 = 0b01,
+ imm4: u4 = 0b0111,
decoded15: u1 = 0b0,
imm5: u5,
decoded21: u8 = 0b01110000,
- decoded29: u1 = 0b0,
+ op: u1 = 0b0,
Q: Register.IntegerSize,
decoded31: u1 = 0b0,
};
+
+ /// C7.2.175 INS (element)
+ /// C7.2.176 INS (general)
+ pub const Ins = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ imm4: Imm4,
+ decoded15: u1 = 0b0,
+ imm5: u5,
+ decoded21: u8 = 0b01110000,
+ op: Op,
+ Q: u1 = 0b1,
+ decoded31: u1 = 0b0,
+
+ pub const Imm4 = packed union {
+ general: General,
+ element: u4,
+
+ pub const General = enum(u4) {
+ general = 0b0011,
+ _,
+ };
+ };
+
+ pub const Op = enum(u1) {
+ general = 0b0,
+ element = 0b1,
+ };
+ };
+
+ pub const Decoded = union(enum) {
+ unallocated,
+ dup: Dup,
+ smov: Smov,
+ umov: Umov,
+ ins: Ins,
+ };
+ pub fn decode(inst: @This()) @This().Decoded {
+ return switch (inst.group.op) {
+ 0b0 => switch (inst.group.imm4) {
+ 0b0000, 0b0001 => .{ .dup = inst.dup },
+ else => .unallocated,
+ 0b0101 => switch (@ctz(inst.group.imm5)) {
+ 0, 1 => .{ .smov = inst.smov },
+ 2 => switch (inst.group.Q) {
+ 0b1 => .{ .smov = inst.smov },
+ 0b0 => .unallocated,
+ },
+ else => .unallocated,
+ },
+ 0b0111 => switch (@ctz(inst.group.imm5)) {
+ 0, 1, 2 => switch (inst.group.Q) {
+ 0b0 => .{ .umov = inst.umov },
+ 0b1 => .unallocated,
+ },
+ 3 => switch (inst.group.Q) {
+ 0b1 => .{ .umov = inst.umov },
+ 0b0 => .unallocated,
+ },
+ else => .unallocated,
+ },
+ },
+ 0b1 => switch (inst.group.Q) {
+ 0b0 => .unallocated,
+ 0b1 => .{ .ins = inst.ins },
+ },
+ };
+ }
+ };
+
+ /// Advanced SIMD two-register miscellaneous (FP16)
+ pub const SimdTwoRegisterMiscellaneousFp16 = packed union {
+ group: @This().Group,
+ frintn: Frintn,
+ frintm: Frintm,
+ fcvtns: Fcvtns,
+ fcvtms: Fcvtms,
+ fcvtas: Fcvtas,
+ scvtf: Scvtf,
+ fcmgt: Fcmgt,
+ fcmeq: Fcmeq,
+ fcmlt: Fcmlt,
+ fabs: Fabs,
+ frintp: Frintp,
+ frintz: Frintz,
+ fcvtps: Fcvtps,
+ fcvtzs: Fcvtzs,
+ frecpe: Frecpe,
+ frinta: Frinta,
+ frintx: Frintx,
+ fcvtnu: Fcvtnu,
+ fcvtmu: Fcvtmu,
+ fcvtau: Fcvtau,
+ ucvtf: Ucvtf,
+ fcmge: Fcmge,
+ fcmle: Fcmle,
+ fneg: Fneg,
+ frinti: Frinti,
+ fcvtpu: Fcvtpu,
+ fcvtzu: Fcvtzu,
+ frsqrte: Frsqrte,
+ fsqrt: Fsqrt,
+
+ pub const Group = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5,
+ decoded17: u6 = 0b111100,
+ a: u1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.161 FRINTN (vector)
+ pub const Frintn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11000,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.159 FRINTM (vector)
+ pub const Frintm = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.80 FCVTNS (vector)
+ pub const Fcvtns = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.75 FCVTMS (vector)
+ pub const Fcvtms = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.70 FCVTAS (vector)
+ pub const Fcvtas = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.234 SCVTF (vector, integer)
+ pub const Scvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.61 FCMGT (zero)
+ pub const Fcmgt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.57 FCMEQ (zero)
+ pub const Fcmeq = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.65 FCMLT (zero)
+ pub const Fcmlt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01110,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.45 FABS (vector)
+ pub const Fabs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01111,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.163 FRINTP (vector)
+ pub const Frintp = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11000,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.167 FRINTZ (vector)
+ pub const Frintz = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.84 FCVTPS (vector)
+ pub const Fcvtps = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.90 FCVTZS (vector, integer)
+ pub const Fcvtzs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.144 FRECPE
+ pub const Frecpe = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.155 FRINTA (vector)
+ pub const Frinta = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11000,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.159 FRINTX (vector)
+ pub const Frintx = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.82 FCVTNU (vector)
+ pub const Fcvtnu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.77 FCVTMU (vector)
+ pub const Fcvtmu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.72 FCVTAU (vector)
+ pub const Fcvtau = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.353 UCVTF (vector, integer)
+ pub const Ucvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.59 FCMGE (zero)
+ pub const Fcmge = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.64 FCMLE (zero)
+ pub const Fcmle = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.139 FNEG (vector)
+ pub const Fneg = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01111,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.157 FRINTI (vector)
+ pub const Frinti = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.86 FCVTPU (vector)
+ pub const Fcvtpu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.94 FCVTZU (vector, integer)
+ pub const Fcvtzu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.169 FRSQRTE
+ pub const Frsqrte = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.171 FSQRT
+ pub const Fsqrt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11111,
+ decoded17: u6 = 0b111100,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
};
/// Advanced SIMD two-register miscellaneous
pub const SimdTwoRegisterMiscellaneous = packed union {
group: @This().Group,
+ suqadd: Suqadd,
cnt: Cnt,
+ sqabs: Sqabs,
+ cmgt: Cmgt,
+ cmeq: Cmeq,
+ cmlt: Cmlt,
+ abs: Abs,
+ sqxtn: Sqxtn,
+ frintn: Frintn,
+ frintm: Frintm,
+ fcvtns: Fcvtns,
+ fcvtms: Fcvtms,
+ fcvtas: Fcvtas,
+ scvtf: Scvtf,
+ fcmgt: Fcmgt,
+ fcmeq: Fcmeq,
+ fcmlt: Fcmlt,
+ fabs: Fabs,
+ frintp: Frintp,
+ frintz: Frintz,
+ fcvtps: Fcvtps,
+ fcvtzs: Fcvtzs,
+ frecpe: Frecpe,
+ usqadd: Usqadd,
+ sqneg: Sqneg,
+ cmge: Cmge,
+ cmle: Cmle,
+ neg: Neg,
+ sqxtun: Sqxtun,
+ uqxtn: Uqxtn,
+ fcvtxn: Fcvtxn,
+ frinta: Frinta,
+ frintx: Frintx,
+ fcvtnu: Fcvtnu,
+ fcvtmu: Fcvtmu,
+ fcvtau: Fcvtau,
+ ucvtf: Ucvtf,
+ not: Not,
+ fcmge: Fcmge,
+ fcmle: Fcmle,
+ fneg: Fneg,
+ frinti: Frinti,
+ fcvtpu: Fcvtpu,
+ fcvtzu: Fcvtzu,
+ frsqrte: Frsqrte,
+ fsqrt: Fsqrt,
pub const Group = packed struct {
Rd: Register.Encoded,
@@ -7126,7 +8597,21 @@ pub const Instruction = packed union {
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
- U: u1,
+ U: std.builtin.Signedness,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.337 SUQADD
+ pub const Suqadd = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7140,7 +8625,653 @@ pub const Instruction = packed union {
decoded17: u5 = 0b10000,
size: Size,
decoded24: u5 = 0b01110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.282 SQABS
+ pub const Sqabs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00111,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.32 CMGT (zero)
+ pub const Cmgt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01000,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.28 CMEQ (zero)
+ pub const Cmeq = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01001,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.36 CMLT (zero)
+ pub const Cmlt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01010,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.1 ABS
+ pub const Abs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.308 SQXTN
+ pub const Sqxtn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10100,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.161 FRINTN (vector)
+ pub const Frintn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11000,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.159 FRINTM (vector)
+ pub const Frintm = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.80 FCVTNS (vector)
+ pub const Fcvtns = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.75 FCVTMS (vector)
+ pub const Fcvtms = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.70 FCVTAS (vector)
+ pub const Fcvtas = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.234 SCVTF (vector, integer)
+ pub const Scvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.61 FCMGT (zero)
+ pub const Fcmgt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.57 FCMEQ (zero)
+ pub const Fcmeq = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.65 FCMLT (zero)
+ pub const Fcmlt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01110,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.45 FABS (vector)
+ pub const Fabs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01111,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.163 FRINTP (vector)
+ pub const Frintp = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11000,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.167 FRINTZ (vector)
+ pub const Frintz = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.84 FCVTPS (vector)
+ pub const Fcvtps = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.90 FCVTZS (vector, integer)
+ pub const Fcvtzs = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.144 FRECPE
+ pub const Frecpe = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .signed,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.394 USQADD
+ pub const Usqadd = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.292 SQNEG
+ pub const Sqneg = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00111,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.30 CMGE (zero)
+ pub const Cmge = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01000,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.35 CMLE (zero)
+ pub const Cmle = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01001,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.209 NEG (vector)
+ pub const Neg = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01011,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.309 SQXTUN
+ pub const Sqxtun = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10010,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.381 UQXTN
+ pub const Uqxtn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10100,
+ decoded17: u5 = 0b10000,
+ size: Size,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.88 FCVTXN
+ pub const Fcvtxn = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b10110,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.155 FRINTA (vector)
+ pub const Frinta = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11000,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.165 FRINTX (vector)
+ pub const Frintx = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.82 FCVTNU (vector)
+ pub const Fcvtnu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.77 FCVTMU (vector)
+ pub const Fcvtmu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.72 FCVTAU (vector)
+ pub const Fcvtau = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.353 UCVTF (vector, integer)
+ pub const Ucvtf = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b0,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.210 NOT
+ pub const Not = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b00101,
+ decoded17: u5 = 0b10000,
+ size: Size = .byte,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.59 FCMGE (zero)
+ pub const Fcmge = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01100,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.64 FCMLE (zero)
+ pub const Fcmle = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.139 FNEG (vector)
+ pub const Fneg = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b01111,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.157 FRINTI (vector)
+ pub const Frinti = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11001,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.86 FCVTPU (vector)
+ pub const Fcvtpu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11010,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.94 FCVTZU (vector, integer)
+ pub const Fcvtzu = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11011,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.169 FRSQRTE
+ pub const Frsqrte = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11101,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.171 FSQRT (vector)
+ pub const Fsqrt = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b10,
+ opcode: u5 = 0b11111,
+ decoded17: u5 = 0b10000,
+ sz: Sz,
+ o2: u1 = 0b1,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7159,7 +9290,7 @@ pub const Instruction = packed union {
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b01110,
- U: u1,
+ U: std.builtin.Signedness,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7173,7 +9304,7 @@ pub const Instruction = packed union {
decoded17: u5 = 0b11000,
size: Size,
decoded24: u5 = 0b01110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7188,6 +9319,9 @@ pub const Instruction = packed union {
orr: Orr,
orn: Orn,
eor: Eor,
+ bsl: Bsl,
+ bit: Bit,
+ bif: Bif,
pub const Group = packed struct {
Rd: Register.Encoded,
@@ -7198,7 +9332,7 @@ pub const Instruction = packed union {
decoded21: u1 = 0b1,
size: Size,
decoded24: u5 = 0b01110,
- U: u1,
+ U: std.builtin.Signedness,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7213,7 +9347,7 @@ pub const Instruction = packed union {
decoded21: u1 = 0b1,
size: Size,
decoded24: u5 = 0b01110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7228,7 +9362,7 @@ pub const Instruction = packed union {
decoded21: u1 = 0b1,
size: Size = .byte,
decoded24: u5 = 0b01110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7243,7 +9377,7 @@ pub const Instruction = packed union {
decoded21: u1 = 0b1,
size: Size = .half,
decoded24: u5 = 0b01110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7258,7 +9392,7 @@ pub const Instruction = packed union {
decoded21: u1 = 0b1,
size: Size = .single,
decoded24: u5 = 0b01110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7273,7 +9407,7 @@ pub const Instruction = packed union {
decoded21: u1 = 0b1,
size: Size = .double,
decoded24: u5 = 0b01110,
- U: u1 = 0b0,
+ U: std.builtin.Signedness = .signed,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -7288,7 +9422,52 @@ pub const Instruction = packed union {
decoded21: u1 = 0b1,
size: Size = .byte,
decoded24: u5 = 0b01110,
- U: u1 = 0b1,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.24 BSL
+ pub const Bsl = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ opcode: u5 = 0b00011,
+ Rm: Register.Encoded,
+ decoded21: u1 = 0b1,
+ size: Size = .half,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.23 BIT
+ pub const Bit = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ opcode: u5 = 0b00011,
+ Rm: Register.Encoded,
+ decoded21: u1 = 0b1,
+ size: Size = .single,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
+ Q: Q,
+ decoded31: u1 = 0b0,
+ };
+
+ /// C7.2.22 BIF
+ pub const Bif = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u1 = 0b1,
+ opcode: u5 = 0b00011,
+ Rm: Register.Encoded,
+ decoded21: u1 = 0b1,
+ size: Size = .double,
+ decoded24: u5 = 0b01110,
+ U: std.builtin.Signedness = .unsigned,
Q: Q,
decoded31: u1 = 0b0,
};
@@ -8152,6 +10331,58 @@ pub const Instruction = packed union {
};
};
+ /// Floating-point conditional select
+ pub const FloatConditionalSelect = packed union {
+ group: @This().Group,
+ fcsel: Fcsel,
+
+ pub const Group = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b11,
+ cond: ConditionCode,
+ Rm: Register.Encoded,
+ decoded21: u1 = 0b1,
+ ptype: Ftype,
+ decoded24: u5 = 0b11110,
+ S: bool,
+ decoded30: u1 = 0b0,
+ M: u1,
+ };
+
+ /// C7.2.68 FCSEL
+ pub const Fcsel = packed struct {
+ Rd: Register.Encoded,
+ Rn: Register.Encoded,
+ decoded10: u2 = 0b11,
+ cond: ConditionCode,
+ Rm: Register.Encoded,
+ decoded21: u1 = 0b1,
+ ftype: Ftype,
+ decoded24: u5 = 0b11110,
+ S: bool = false,
+ decoded30: u1 = 0b0,
+ M: u1 = 0b0,
+ };
+
+ pub const Decoded = union(enum) {
+ unallocated,
+ fcsel: Fcsel,
+ };
+ pub fn decode(inst: @This()) @This().Decoded {
+ return switch (inst.group.ptype) {
+ .quad => .unallocated,
+ .single, .double, .half => switch (inst.group.S) {
+ true => .unallocated,
+ false => switch (inst.group.M) {
+ 0b0 => .{ .fcsel = inst.fcsel },
+ 0b1 => .unallocated,
+ },
+ },
+ };
+ }
+ };
+
/// Floating-point data-processing (3 source)
pub const FloatDataProcessingThreeSource = packed union {
group: @This().Group,
@@ -8240,11 +10471,6 @@ pub const Instruction = packed union {
};
};
- pub const Q = enum(u1) {
- double = 0b0,
- quad = 0b1,
- };
-
pub const Size = enum(u2) {
byte = 0b00,
half = 0b01,
@@ -8262,6 +10488,7 @@ pub const Instruction = packed union {
pub fn fromVectorSize(vs: Register.VectorSize) Size {
return switch (vs) {
+ else => unreachable,
.byte => .byte,
.half => .half,
.single => .single,
@@ -8270,11 +10497,54 @@ pub const Instruction = packed union {
}
};
+ pub const Sz = enum(u1) {
+ single = 0b0,
+ double = 0b1,
+
+ pub fn toVectorSize(sz: Sz) Register.VectorSize {
+ return switch (sz) {
+ .single => .single,
+ .double => .double,
+ };
+ }
+
+ pub fn fromVectorSize(vs: Register.VectorSize) Sz {
+ return switch (vs) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ };
+ }
+ };
+
+ pub const Q = enum(u1) {
+ double = 0b0,
+ quad = 0b1,
+ };
+
pub const Ftype = enum(u2) {
single = 0b00,
double = 0b01,
quad = 0b10,
half = 0b11,
+
+ pub fn toVectorSize(ftype: Ftype) Register.VectorSize {
+ return switch (ftype) {
+ _ => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ };
+ }
+
+ pub fn fromVectorSize(vs: Register.VectorSize) Ftype {
+ return switch (vs) {
+ else => unreachable,
+ .single => .single,
+ .double => .double,
+ .half => .half,
+ };
+ }
};
};
@@ -8318,6 +10588,33 @@ pub const Instruction = packed union {
};
}
+ /// C7.2.1 ABS (zero)
+ pub fn abs(d: Register, n: Register) Instruction {
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == .double and elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .abs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .abs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ }
+ }
/// C6.2.1 ADC
pub fn adc(d: Register, n: Register, m: Register) Instruction {
const sf = d.format.integer;
@@ -8865,6 +11162,45 @@ pub const Instruction = packed union {
} },
}
}
+ /// C7.2.22 BIF
+ pub fn bif(d: Register, n: Register, m: Register) Instruction {
+ const arrangement = d.format.vector;
+ assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_three_same = .{
+ .bif = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Rm = m.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } };
+ }
+ /// C7.2.23 BIT
+ pub fn bit(d: Register, n: Register, m: Register) Instruction {
+ const arrangement = d.format.vector;
+ assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_three_same = .{
+ .bit = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Rm = m.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } };
+ }
+ /// C7.2.24 BSL
+ pub fn bsl(d: Register, n: Register, m: Register) Instruction {
+ const arrangement = d.format.vector;
+ assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_three_same = .{
+ .bsl = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Rm = m.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } };
+ }
/// C6.2.34 BL
pub fn bl(label: i28) Instruction {
return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
@@ -8997,6 +11333,151 @@ pub const Instruction = packed union {
},
} } };
}
+ /// C7.2.28 CMEQ (zero)
+ pub fn cmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == .double and elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .cmeq = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .cmeq = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ },
+ }
+ }
+ /// C7.2.30 CMGE (zero)
+ pub fn cmge(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == .double and elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .cmge = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .cmge = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ },
+ }
+ }
+ /// C7.2.32 CMGT (zero)
+ pub fn cmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == .double and elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .cmgt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .cmgt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ },
+ }
+ }
+ /// C7.2.35 CMLE (zero)
+ pub fn cmle(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == .double and elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .cmle = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .cmle = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ },
+ }
+ }
+ /// C7.2.36 CMLT (zero)
+ pub fn cmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == .double and elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .cmlt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .cmlt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ },
+ }
+ }
/// C7.2.38 CNT
pub fn cnt(d: Register, n: Register) Instruction {
const arrangement = d.format.vector;
@@ -9092,6 +11573,57 @@ pub const Instruction = packed union {
},
} } };
}
+ /// C7.2.39 DUP (element)
+ /// C7.2.40 DUP (general)
+ pub fn dup(d: Register, n: Register) Instruction {
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(@intFromEnum(elem_size) <= @intFromEnum(Register.VectorSize.double) and elem_size == n.format.element.size);
+ return .{ .data_processing_vector = .{ .simd_scalar_copy = .{
+ .dup = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .imm5 = @shlExact(@as(u5, n.format.element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d");
+ const elem_size = arrangement.elemSize();
+ switch (n.format) {
+ else => unreachable,
+ .element => |element| {
+ assert(elem_size.toVectorSize() == element.size);
+ return .{ .data_processing_vector = .{ .simd_copy = .{
+ .dup = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .imm4 = .element,
+ .imm5 = @shlExact(@as(u5, element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ .integer => |sf| {
+ assert(sf == @as(Register.IntegerSize, switch (elem_size) {
+ .byte, .half, .single => .word,
+ .double => .doubleword,
+ }));
+ return .{ .data_processing_vector = .{ .simd_copy = .{
+ .dup = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{}),
+ .imm4 = .general,
+ .imm5 = @shlExact(@as(u5, 0b1), @intFromEnum(elem_size)),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ }
+ },
+ }
+ }
/// C6.2.118 EON (shifted register)
pub fn eon(d: Register, n: Register, form: union(enum) {
register: Register,
@@ -9210,22 +11742,43 @@ pub const Instruction = packed union {
},
} } };
}
+ /// C7.2.45 FABS (vector)
/// C7.2.46 FABS (scalar)
pub fn fabs(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .fabs = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fabs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fabs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .fabs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
/// C7.2.50 FADD (scalar)
pub fn fadd(d: Register, n: Register, m: Register) Instruction {
@@ -9236,15 +11789,265 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
+ /// C7.2.57 FCMEQ (zero)
+ pub fn fcmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |ftype| switch (n.format) {
+ else => unreachable,
+ .scalar => |n_scalar| {
+ assert(n_scalar == ftype);
+ switch (ftype) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcmeq = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcmeq = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(ftype),
+ },
+ } } },
+ }
+ },
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcmeq = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcmeq = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ },
+ }
+ }
+ /// C7.2.59 FCMGE (zero)
+ pub fn fcmge(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |ftype| switch (n.format) {
+ else => unreachable,
+ .scalar => |n_scalar| {
+ assert(n_scalar == ftype);
+ switch (ftype) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcmge = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcmge = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(ftype),
+ },
+ } } },
+ }
+ },
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcmge = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcmge = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ },
+ }
+ }
+ /// C7.2.61 FCMGT (zero)
+ pub fn fcmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |ftype| switch (n.format) {
+ else => unreachable,
+ .scalar => |n_scalar| {
+ assert(n_scalar == ftype);
+ switch (ftype) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcmgt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcmgt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(ftype),
+ },
+ } } },
+ }
+ },
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcmgt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcmgt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ },
+ }
+ }
+ /// C7.2.64 FCMLE (zero)
+ pub fn fcmle(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |ftype| switch (n.format) {
+ else => unreachable,
+ .scalar => |n_scalar| {
+ assert(n_scalar == ftype);
+ switch (ftype) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcmle = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcmle = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(ftype),
+ },
+ } } },
+ }
+ },
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcmle = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcmle = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ },
+ }
+ }
+ /// C7.2.65 FCMLT (zero)
+ pub fn fcmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
+ switch (form) {
+ .zero => switch (d.format) {
+ else => unreachable,
+ .scalar => |ftype| switch (n.format) {
+ else => unreachable,
+ .scalar => |n_scalar| {
+ assert(n_scalar == ftype);
+ switch (ftype) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcmlt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcmlt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(ftype),
+ },
+ } } },
+ }
+ },
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcmlt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcmlt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ },
+ }
+ }
/// C7.2.66 FCMP
pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction {
const ftype = n.format.scalar;
@@ -9256,12 +12059,7 @@ pub const Instruction = packed union {
.opc0 = .register,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
},
@@ -9270,12 +12068,7 @@ pub const Instruction = packed union {
.opc0 = .register,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = @enumFromInt(0b00000),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } },
}
@@ -9291,12 +12084,7 @@ pub const Instruction = packed union {
.opc0 = .zero,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
},
@@ -9305,16 +12093,25 @@ pub const Instruction = packed union {
.opc0 = .zero,
.Rn = n.alias.encode(.{ .V = true }),
.Rm = @enumFromInt(0b00000),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } },
}
}
+ /// C7.2.68 FCSEL
+ pub fn fcsel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
+ const ftype = d.format.scalar;
+ assert(n.format.scalar == ftype and m.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_conditional_select = .{
+ .fcsel = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .cond = cond,
+ .Rm = m.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ }
/// C7.2.69 FCVT
pub fn fcvt(d: Register, n: Register) Instruction {
assert(d.format.scalar != n.format.scalar);
@@ -9328,174 +12125,589 @@ pub const Instruction = packed union {
.double => .double,
.half => .half,
},
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(n.format.scalar),
},
} } };
}
+ /// C7.2.70 FCVTAS (vector)
/// C7.2.71 FCVTAS (scalar)
pub fn fcvtas(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtas = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtas = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtas = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtas = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtas = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtas = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.72 FCVTAU (vector)
/// C7.2.73 FCVTAU (scalar)
pub fn fcvtau(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtau = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtau = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtau = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtau = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtau = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtau = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.75 FCVTMS (vector)
/// C7.2.76 FCVTMS (scalar)
pub fn fcvtms(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtms = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtms = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtms = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtms = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtms = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtms = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.77 FCVTMU (vector)
/// C7.2.78 FCVTMU (scalar)
pub fn fcvtmu(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtmu = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtmu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtmu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtmu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtmu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtmu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.80 FCVTNS (vector)
/// C7.2.81 FCVTNS (scalar)
pub fn fcvtns(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtns = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtns = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtns = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtns = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtns = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtns = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.82 FCVTNU (vector)
/// C7.2.83 FCVTNU (scalar)
pub fn fcvtnu(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtnu = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtnu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtnu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtnu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtnu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtnu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.84 FCVTPS (vector)
/// C7.2.85 FCVTPS (scalar)
pub fn fcvtps(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtps = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtps = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtps = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtps = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtps = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtps = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.86 FCVTPU (vector)
/// C7.2.87 FCVTPU (scalar)
pub fn fcvtpu(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtpu = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtpu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtpu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtpu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtpu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtpu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.90 FCVTZS (vector, integer)
/// C7.2.92 FCVTZS (scalar, integer)
pub fn fcvtzs(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtzs = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtzs = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtzs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtzs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtzs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtzs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
+ /// C7.2.94 FCVTZU (vector, integer)
/// C7.2.96 FCVTZU (scalar, integer)
pub fn fcvtzu(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .fcvtzu = .{
- .Rd = d.alias.encode(.{}),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (n.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .fcvtzu = .{
+ .Rd = d.alias.encode(.{}),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(n.format.scalar),
+ .sf = sf,
+ },
+ } } },
+ .scalar => |elem_size| switch (n.format) {
+ else => unreachable,
+ .scalar => |ftype| {
+ assert(ftype == elem_size);
+ switch (elem_size) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .fcvtzu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .fcvtzu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(elem_size),
+ },
+ } } },
+ }
},
- .sf = d.format.integer,
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fcvtzu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fcvtzu = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
/// C7.2.98 FDIV (scalar)
pub fn fdiv(d: Register, n: Register, m: Register) Instruction {
@@ -9506,12 +12718,7 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9536,12 +12743,7 @@ pub const Instruction = packed union {
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9554,12 +12756,7 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9572,12 +12769,7 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9590,12 +12782,7 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9608,12 +12795,7 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9640,12 +12822,7 @@ pub const Instruction = packed union {
.fmov = .{
.Rd = d.alias.encode(.{ .V = true }),
.imm8 = imm,
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } },
.vector => |arrangement| {
@@ -9678,12 +12855,7 @@ pub const Instruction = packed union {
.Rn = n.alias.encode(.{ .V = true }),
.opcode = .float_to_integer,
.rmode = .@"0",
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
.sf = sf,
},
} } };
@@ -9721,12 +12893,7 @@ pub const Instruction = packed union {
.Rn = n.alias.encode(.{}),
.opcode = .integer_to_float,
.rmode = .@"0",
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
.sf = sf,
},
} } };
@@ -9737,12 +12904,7 @@ pub const Instruction = packed union {
.fmov = .{
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
},
@@ -9779,12 +12941,7 @@ pub const Instruction = packed union {
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9797,31 +12954,47 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
+ /// C7.2.139 FNEG (vector)
/// C7.2.140 FNEG (scalar)
pub fn fneg(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .fneg = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fneg = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fneg = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .fneg = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
/// C7.2.141 FNMADD
pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
@@ -9833,12 +13006,7 @@ pub const Instruction = packed union {
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9852,12 +13020,7 @@ pub const Instruction = packed union {
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
.Ra = a.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -9870,150 +13033,313 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
+ /// C7.2.155 FRINTA (vector)
/// C7.2.156 FRINTA (scalar)
pub fn frinta(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .frinta = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .frinta = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .frinta = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .frinta = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
+ /// C7.2.157 FRINTI (vector)
/// C7.2.158 FRINTI (scalar)
pub fn frinti(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .frinti = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .frinti = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .frinti = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .frinti = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
+ /// C7.2.159 FRINTM (vector)
/// C7.2.160 FRINTM (scalar)
pub fn frintm(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .frintm = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .frintm = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .frintm = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .frintm = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
+ /// C7.2.161 FRINTN (vector)
/// C7.2.162 FRINTN (scalar)
pub fn frintn(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .frintn = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .frintn = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .frintn = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .frintn = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
+ /// C7.2.163 FRINTP (vector)
/// C7.2.164 FRINTP (scalar)
pub fn frintp(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .frintp = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .frintp = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .frintp = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .frintp = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
+ /// C7.2.165 FRINTX (vector)
/// C7.2.166 FRINTX (scalar)
pub fn frintx(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .frintx = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .frintx = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .frintx = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .frintx = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
+ /// C7.2.167 FRINTZ (vector)
/// C7.2.168 FRINTZ (scalar)
pub fn frintz(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .frintz = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .frintz = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .frintz = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .frintz = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
+ /// C7.2.171 FSQRT (vector)
/// C7.2.172 FSQRT (scalar)
pub fn fsqrt(d: Register, n: Register) Instruction {
- const ftype = d.format.scalar;
- assert(n.format.scalar == ftype);
- return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
- .fsqrt = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
+ switch (d.format) {
+ else => unreachable,
+ .vector => |arrangement| {
+ assert(n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .fsqrt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .fsqrt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
},
- } } };
+ .scalar => |ftype| {
+ assert(n.format.scalar == ftype);
+ return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
+ .fsqrt = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .ftype = .fromVectorSize(ftype),
+ },
+ } } };
+ },
+ }
}
/// C7.2.174 FSUB (scalar)
pub fn fsub(d: Register, n: Register, m: Register) Instruction {
@@ -10024,12 +13350,7 @@ pub const Instruction = packed union {
.Rd = d.alias.encode(.{ .V = true }),
.Rn = n.alias.encode(.{ .V = true }),
.Rm = m.alias.encode(.{ .V = true }),
- .ftype = switch (ftype) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
- },
+ .ftype = .fromVectorSize(ftype),
},
} } };
}
@@ -10087,18 +13408,6 @@ pub const Instruction = packed union {
},
} } } };
},
- .signed_offset => |signed_offset| {
- assert(signed_offset.base.format.integer == .doubleword);
- return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
- .ldp = .{
- .Rt = t1.alias.encode(.{}),
- .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
- .Rt2 = t2.alias.encode(.{}),
- .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
- .sf = sf,
- },
- } } } };
- },
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
@@ -10111,6 +13420,18 @@ pub const Instruction = packed union {
},
} } } };
},
+ .signed_offset => |signed_offset| {
+ assert(signed_offset.base.format.integer == .doubleword);
+ return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
+ .ldp = .{
+ .Rt = t1.alias.encode(.{}),
+ .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
+ .Rt2 = t2.alias.encode(.{}),
+ .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
+ .sf = sf,
+ },
+ } } } };
+ },
.base => |base| continue :form .{ .signed_offset = .{ .base = base } },
}
},
@@ -11019,12 +14340,52 @@ pub const Instruction = packed union {
},
} } };
}
+ /// C7.2.209 NEG (vector)
+ pub fn neg(d: Register, n: Register) Instruction {
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == .double and elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .neg = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .neg = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ }
+ }
/// C6.2.238 NOP
pub fn nop() Instruction {
return .{ .branch_exception_generating_system = .{ .hints = .{
.nop = .{},
} } };
}
+ /// C7.2.210 NOT
+ pub fn not(d: Register, n: Register) Instruction {
+ const arrangement = d.format.vector;
+ assert(arrangement.elemSize() == .byte and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .not = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ }
/// C6.2.239 ORN (shifted register)
/// C7.2.211 ORN (vector)
pub fn orn(d: Register, n: Register, form: union(enum) {
@@ -11341,21 +14702,63 @@ pub const Instruction = packed union {
},
} } };
}
+ /// C7.2.234 SCVTF (vector, integer)
/// C7.2.236 SCVTF (scalar, integer)
pub fn scvtf(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .scvtf = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{}),
- .ftype = switch (d.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |ftype| switch (n.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(ftype == elem_size);
+ switch (ftype) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .scvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .scvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(ftype),
+ },
+ } } },
+ }
},
- .sf = n.format.integer,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .scvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{}),
+ .ftype = .fromVectorSize(ftype),
+ .sf = sf,
+ },
+ } } },
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .scvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .scvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
/// C6.2.270 SDIV
pub fn sdiv(d: Register, n: Register, m: Register) Instruction {
@@ -11446,6 +14849,60 @@ pub const Instruction = packed union {
},
} } };
}
+ /// C7.2.282 SQABS
+ pub fn sqabs(d: Register, n: Register) Instruction {
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .sqabs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .sqabs = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ }
+ }
+ /// C7.2.308 SQXTN
+ pub fn sqxtn(d: Register, n: Register) Instruction {
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .sqxtn = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .sqxtn = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ }
+ }
/// C6.2.321 STP
/// C7.2.330 STP (SIMD&FP)
pub fn stp(t1: Register, t2: Register, form: union(enum) {
@@ -11471,18 +14928,6 @@ pub const Instruction = packed union {
},
} } } };
},
- .signed_offset => |signed_offset| {
- assert(signed_offset.base.format.integer == .doubleword);
- return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
- .stp = .{
- .Rt = t1.alias.encode(.{}),
- .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
- .Rt2 = t2.alias.encode(.{}),
- .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
- .sf = sf,
- },
- } } } };
- },
.pre_index => |pre_index| {
assert(pre_index.base.format.integer == .doubleword);
return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
@@ -11495,6 +14940,18 @@ pub const Instruction = packed union {
},
} } } };
},
+ .signed_offset => |signed_offset| {
+ assert(signed_offset.base.format.integer == .doubleword);
+ return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
+ .stp = .{
+ .Rt = t1.alias.encode(.{}),
+ .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
+ .Rt2 = t2.alias.encode(.{}),
+ .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
+ .sf = sf,
+ },
+ } } } };
+ },
.base => |base| continue :form .{ .signed_offset = .{ .base = base } },
}
},
@@ -11940,6 +15397,33 @@ pub const Instruction = packed union {
} },
}
}
+ /// C7.2.337 SUQADD
+ pub fn suqadd(d: Register, n: Register) Instruction {
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(elem_size == n.format.scalar);
+ return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .suqadd = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = .fromVectorSize(elem_size),
+ },
+ } } };
+ },
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .suqadd = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .size = arrangement.elemSize(),
+ .Q = arrangement.size(),
+ },
+ } } };
+ },
+ }
+ }
/// C6.2.365 SVC
pub fn svc(imm: u16) Instruction {
return .{ .branch_exception_generating_system = .{ .exception_generating = .{
@@ -12019,21 +15503,63 @@ pub const Instruction = packed union {
},
} } };
}
+ /// C7.2.353 UCVTF (vector, integer)
/// C7.2.355 UCVTF (scalar, integer)
pub fn ucvtf(d: Register, n: Register) Instruction {
- return .{ .data_processing_vector = .{ .convert_float_integer = .{
- .ucvtf = .{
- .Rd = d.alias.encode(.{ .V = true }),
- .Rn = n.alias.encode(.{}),
- .ftype = switch (d.format.scalar) {
- else => unreachable,
- .single => .single,
- .double => .double,
- .half => .half,
+ switch (d.format) {
+ else => unreachable,
+ .scalar => |ftype| switch (n.format) {
+ else => unreachable,
+ .scalar => |elem_size| {
+ assert(ftype == elem_size);
+ switch (ftype) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
+ .ucvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
+ .ucvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = .fromVectorSize(ftype),
+ },
+ } } },
+ }
},
- .sf = n.format.integer,
+ .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
+ .ucvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{}),
+ .ftype = .fromVectorSize(ftype),
+ .sf = sf,
+ },
+ } } },
},
- } } };
+ .vector => |arrangement| {
+ assert(arrangement != .@"1d" and n.format.vector == arrangement);
+ switch (arrangement.elemSize()) {
+ else => unreachable,
+ .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
+ .ucvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .Q = arrangement.size(),
+ },
+ } } },
+ .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
+ .ucvtf = .{
+ .Rd = d.alias.encode(.{ .V = true }),
+ .Rn = n.alias.encode(.{ .V = true }),
+ .sz = arrangement.elemSz(),
+ .Q = arrangement.size(),
+ },
+ } } },
+ }
+ },
+ }
}
/// C6.2.387 UDF
pub fn udf(imm: u16) Instruction {
@@ -12147,7 +15673,7 @@ pub const Instruction = packed union {
}
comptime {
- @setEvalBranchQuota(68_000);
+ @setEvalBranchQuota(110_000);
verify(@typeName(Instruction), Instruction);
}
fn verify(name: []const u8, Type: type) void {
diff --git a/src/codegen/aarch64/instructions.zon b/src/codegen/aarch64/instructions.zon
index 85de196050..48b8eaa21f 100644
--- a/src/codegen/aarch64/instructions.zon
+++ b/src/codegen/aarch64/instructions.zon
@@ -213,6 +213,63 @@
},
.encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
},
+ // C6.2.16 ASR (register)
+ .{
+ .pattern = "ASR , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .asrv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "ASR , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .asrv, .Xd, .Xn, .Xm },
+ },
+ // C6.2.17 ASR (immediate)
+ .{
+ .pattern = "ASR , , #",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
+ },
+ .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .shift, .imms = 31 } },
+ },
+ .{
+ .pattern = "ASR , , #",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
+ },
+ .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .shift, .imms = 63 } },
+ },
+ // C6.2.18 ASRV
+ .{
+ .pattern = "ASRV , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .asrv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "ASRV , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .asrv, .Xd, .Xn, .Xm },
+ },
// C6.2.35 BLR
.{
.pattern = "BLR ",
@@ -681,6 +738,82 @@
},
.encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
},
+ // C6.2.212 LSL (register)
+ .{
+ .pattern = "LSL , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .lslv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "LSL , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .lslv, .Xd, .Xn, .Xm },
+ },
+ // C6.2.214 LSLV
+ .{
+ .pattern = "LSLV , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .lslv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "LSLV , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .lslv, .Xd, .Xn, .Xm },
+ },
+ // C6.2.215 LSR (register)
+ .{
+ .pattern = "LSR , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .lsrv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "LSR , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .lsrv, .Xd, .Xn, .Xm },
+ },
+ // C6.2.217 LSRV
+ .{
+ .pattern = "LSRV , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .lsrv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "LSRV , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .lsrv, .Xd, .Xn, .Xm },
+ },
// C6.2.220 MOV (to/from SP)
.{
.pattern = "MOV WSP, ",
@@ -964,6 +1097,63 @@
},
.encode = .{ .ret, .Xn },
},
+ // C6.2.261 ROR (immediate)
+ .{
+ .pattern = "ROR , , #",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Ws = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
+ },
+ .encode = .{ .extr, .Wd, .Ws, .Ws, .shift },
+ },
+ .{
+ .pattern = "ROR , , #",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xs = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
+ },
+ .encode = .{ .extr, .Xd, .Xs, .Xs, .shift },
+ },
+ // C6.2.262 ROR (register)
+ .{
+ .pattern = "ROR , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .rorv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "ROR , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .rorv, .Xd, .Xn, .Xm },
+ },
+ // C6.2.263 RORV
+ .{
+ .pattern = "RORV , , ",
+ .symbols = .{
+ .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
+ .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
+ },
+ .encode = .{ .rorv, .Wd, .Wn, .Wm },
+ },
+ .{
+ .pattern = "RORV , , ",
+ .symbols = .{
+ .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
+ },
+ .encode = .{ .rorv, .Xd, .Xn, .Xm },
+ },
// C6.2.268 SBFM
.{
.pattern = "SBFM , , #, #",
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 111fc6ec14..5e522c3d73 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -4339,9 +4339,11 @@ pub const Object = struct {
/// types to work around a LLVM deficiency when targeting ARM/AArch64.
fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {
const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
const int_ty = switch (ty.zigTypeTag(zcu)) {
.int => ty,
.@"enum" => ty.intTagType(zcu),
+ .@"struct" => Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),
.float => {
if (!is_rmw_xchg) return .none;
return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));
@@ -11424,7 +11426,7 @@ pub const FuncGen = struct {
if (workaround_disable_truncate) {
// see https://github.com/llvm/llvm-project/issues/64222
- // disable the truncation codepath for larger that 32bits value - with this heuristic, the backend passes the test suite.
+ // disable the truncation codepath for larger than 32bits value - with this heuristic, the backend passes the test suite.
return try fg.wip.load(access_kind, payload_llvm_ty, payload_ptr, payload_alignment, "");
}
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
index 509aa1d4bb..9233237c3a 100644
--- a/src/link/Dwarf.zig
+++ b/src/link/Dwarf.zig
@@ -142,8 +142,8 @@ const DebugInfo = struct {
&abbrev_code_buf,
debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
) != abbrev_code_buf.len) return error.InputOutput;
- var abbrev_code_br: std.io.Reader = .fixed(&abbrev_code_buf);
- return @enumFromInt(abbrev_code_br.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable);
+ var abbrev_code_reader: std.Io.Reader = .fixed(&abbrev_code_buf);
+ return @enumFromInt(abbrev_code_reader.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable);
}
const trailer_bytes = 1 + 1;
@@ -2094,7 +2094,7 @@ pub const WipNav = struct {
.generic_decl_const,
.generic_decl_func,
=> true,
- else => unreachable,
+ else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
};
if (parent_type.getCaptures(zcu).len == 0) {
if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);
@@ -6104,33 +6104,16 @@ fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
}
fn uleb128Bytes(value: anytype) u32 {
- return leb128Bytes(switch (@typeInfo(@TypeOf(value))) {
- .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value),
- .int => |value_info| switch (value_info.signedness) {
- .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)),
- .unsigned => value,
- },
- else => comptime unreachable,
- });
+ var trash_buffer: [64]u8 = undefined;
+ var d: std.Io.Writer.Discarding = .init(&trash_buffer);
+ d.writer.writeUleb128(value) catch unreachable;
+ return @intCast(d.count + d.writer.end);
}
fn sleb128Bytes(value: anytype) u32 {
- return leb128Bytes(switch (@typeInfo(@TypeOf(value))) {
- .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value),
- .int => |value_info| switch (value_info.signedness) {
- .signed => value,
- .unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value),
- },
- else => comptime unreachable,
- });
-}
-fn leb128Bytes(value: anytype) u32 {
- const value_info = @typeInfo(@TypeOf(value)).int;
- var buffer: [
- std.math.divCeil(u16, @intFromBool(value_info.signedness == .signed) + value_info.bits, 7) catch unreachable
- ]u8 = undefined;
- var bw: Writer = .fixed(&buffer);
- bw.writeLeb128(value) catch unreachable;
- return @intCast(bw.end);
+ var trash_buffer: [64]u8 = undefined;
+ var d: std.Io.Writer.Discarding = .init(&trash_buffer);
+ d.writer.writeSleb128(value) catch unreachable;
+ return @intCast(d.count + d.writer.end);
}
/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig
index 8422ac0ef5..4c90509900 100644
--- a/src/link/Elf/Object.zig
+++ b/src/link/Elf/Object.zig
@@ -1198,11 +1198,14 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index
const chdr = (try r.takeStruct(elf.Elf64_Chdr)).*;
switch (chdr.ch_type) {
.ZLIB => {
- var bw: Writer = .fixed(try gpa.alloc(u8, std.math.cast(usize, chdr.ch_size) orelse return error.Overflow));
- errdefer gpa.free(bw.buffer);
- try std.compress.zlib.decompress(&r, &bw);
- if (bw.end != bw.buffer.len) return error.InputOutput;
- return bw.buffer;
+ var stream: std.Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);
+ var zlib_stream: std.compress.flate.Decompress = .init(&stream, .zlib, &.{});
+ const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow;
+ var aw: std.Io.Writer.Allocating = .init(gpa);
+ try aw.ensureUnusedCapacity(size);
+ defer aw.deinit();
+ _ = try zlib_stream.reader.streamRemaining(&aw.writer);
+ return aw.toOwnedSlice();
},
else => @panic("TODO unhandled compression scheme"),
}
diff --git a/src/main.zig b/src/main.zig
index a0a40ae093..9349899a56 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -361,7 +361,12 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
dev.check(.env_command);
verifyLibcxxCorrectlyLinked();
var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
- try @import("print_env.zig").cmdEnv(arena, &stdout_writer.interface);
+ try @import("print_env.zig").cmdEnv(
+ arena,
+ &stdout_writer.interface,
+ args,
+ if (native_os == .wasi) wasi_preopens,
+ );
return stdout_writer.interface.flush();
} else if (mem.eql(u8, cmd, "reduce")) {
return jitCmd(gpa, arena, cmd_args, .{
@@ -4639,7 +4644,7 @@ const usage_init =
\\ directory.
\\
\\Options:
- \\ -s, --strip Generate files without comments
+ \\ -m, --minimal Use minimal init template
\\ -h, --help Print this help and exit
\\
\\
diff --git a/src/print_env.zig b/src/print_env.zig
index d1251c0d62..e1b2b1eb83 100644
--- a/src/print_env.zig
+++ b/src/print_env.zig
@@ -1,21 +1,43 @@
const std = @import("std");
+const builtin = @import("builtin");
const build_options = @import("build_options");
-const introspect = @import("introspect.zig");
+const Compilation = @import("Compilation.zig");
const Allocator = std.mem.Allocator;
+const EnvVar = std.zig.EnvVar;
const fatal = std.process.fatal;
-pub fn cmdEnv(arena: Allocator, out: *std.Io.Writer) !void {
- const cwd_path = try introspect.getResolvedCwd(arena);
- const self_exe_path = try std.fs.selfExePathAlloc(arena);
+pub fn cmdEnv(
+ arena: Allocator,
+ out: *std.Io.Writer,
+ args: []const []const u8,
+ wasi_preopens: switch (builtin.target.os.tag) {
+ .wasi => std.fs.wasi.Preopens,
+ else => void,
+ },
+) !void {
+ const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
+ const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
- var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, cwd_path, self_exe_path) catch |err| {
- fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});
+ const self_exe_path = switch (builtin.target.os.tag) {
+ .wasi => args[0],
+ else => std.fs.selfExePathAlloc(arena) catch |err| {
+ fatal("unable to find zig self exe path: {s}", .{@errorName(err)});
+ },
};
- defer zig_lib_directory.handle.close();
- const zig_std_dir = try std.fs.path.join(arena, &[_][]const u8{ zig_lib_directory.path.?, "std" });
+ var dirs: Compilation.Directories = .init(
+ arena,
+ override_lib_dir,
+ override_global_cache_dir,
+ .global,
+ if (builtin.target.os.tag == .wasi) wasi_preopens,
+ if (builtin.target.os.tag != .wasi) self_exe_path,
+ );
+ defer dirs.deinit();
- const global_cache_dir = try introspect.resolveGlobalCacheDir(arena);
+ const zig_lib_dir = dirs.zig_lib.path orelse "";
+ const zig_std_dir = try dirs.zig_lib.join(arena, &.{"std"});
+ const global_cache_dir = dirs.global_cache.path orelse "";
const host = try std.zig.system.resolveTargetQuery(.{});
const triple = try host.zigTriple(arena);
@@ -24,7 +46,7 @@ pub fn cmdEnv(arena: Allocator, out: *std.Io.Writer) !void {
var root = try serializer.beginStruct(.{});
try root.field("zig_exe", self_exe_path, .{});
- try root.field("lib_dir", zig_lib_directory.path.?, .{});
+ try root.field("lib_dir", zig_lib_dir, .{});
try root.field("std_dir", zig_std_dir, .{});
try root.field("global_cache_dir", global_cache_dir, .{});
try root.field("version", build_options.version, .{});
diff --git a/src/target.zig b/src/target.zig
index e59c3eda05..ba7cca6391 100644
--- a/src/target.zig
+++ b/src/target.zig
@@ -236,7 +236,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
if (target.cpu.arch.isSpirV()) return true;
if (target.cpu.arch == .x86_64 and target.ptrBitWidth() == 64) {
- if (target.os.tag == .netbsd) {
+ if (target.os.tag == .netbsd or target.os.tag == .openbsd) {
// Self-hosted linker needs work: https://github.com/ziglang/zig/issues/24341
return false;
}
@@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
return false;
}
-pub fn supportsStackProbing(target: *const std.Target) bool {
- return target.os.tag != .windows and target.os.tag != .uefi and
- (target.cpu.arch == .x86 or target.cpu.arch == .x86_64);
+pub fn supportsStackProbing(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
+ return switch (backend) {
+ .stage2_aarch64, .stage2_x86_64 => true,
+ .stage2_llvm => target.os.tag != .windows and target.os.tag != .uefi and
+ (target.cpu.arch == .x86 or target.cpu.arch == .x86_64),
+ else => false,
+ };
}
pub fn supportsStackProtector(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
@@ -347,7 +351,7 @@ pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.builtin.Opti
}
}
-pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool {
+pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool {
switch (target.os.tag) {
.plan9 => return false,
else => {},
@@ -369,7 +373,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime
};
}
-pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool {
+pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool {
switch (target.cpu.arch) {
.spirv32, .spirv64 => return false,
// Remove this once https://github.com/ziglang/zig/issues/23715 is fixed
@@ -378,6 +382,7 @@ pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime ha
}
return switch (zigBackend(target, use_llvm)) {
.stage2_llvm => true,
+ .stage2_wasm => false,
.stage2_x86_64 => switch (target.ofmt) {
.elf, .macho => true,
else => have_llvm,
@@ -856,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile
pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {
return switch (feature) {
.panic_fn => switch (backend) {
+ .stage2_aarch64,
.stage2_c,
.stage2_llvm,
.stage2_x86_64,
diff --git a/test/behavior/array.zig b/test/behavior/array.zig
index 76dcc8075d..07eb632b1e 100644
--- a/test/behavior/array.zig
+++ b/test/behavior/array.zig
@@ -395,7 +395,6 @@ test "array literal as argument to function" {
}
test "double nested array to const slice cast in array literal" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
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
@@ -541,7 +540,6 @@ test "sentinel element count towards the ABI size calculation" {
}
test "zero-sized array with recursive type definition" {
- 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;
@@ -650,7 +648,6 @@ test "runtime initialized sentinel-terminated array literal" {
}
test "array of array agregate init" {
- 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
@@ -1100,3 +1097,16 @@ test "initialize pointer to anyopaque with reference to empty array initializer"
// We can't check the value, but it's zero-bit, so the type matching is good enough.
comptime assert(@TypeOf(loaded) == @TypeOf(.{}));
}
+
+test "sentinel of runtime-known array initialization is populated" {
+ if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
+
+ var rt: u32 = undefined;
+ rt = 42;
+
+ const arr: [1:123]u32 = .{rt};
+ const elems: [*]const u32 = &arr;
+
+ try expect(elems[0] == 42);
+ try expect(elems[1] == 123);
+}
diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig
index cda8b5f033..15d4b99ba4 100644
--- a/test/behavior/atomics.zig
+++ b/test/behavior/atomics.zig
@@ -1,7 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
const expect = std.testing.expect;
-const expectEqual = std.testing.expectEqual;
const supports_128_bit_atomics = switch (builtin.cpu.arch) {
// TODO: Ideally this could be sync'd with the logic in Sema.
@@ -364,25 +363,32 @@ 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);
try testAtomicsWithType(u1, 0, 1);
- try testAtomicsWithType(i4, 0, 1);
- try testAtomicsWithType(u5, 0, 1);
- try testAtomicsWithType(i15, 0, 1);
- try testAtomicsWithType(u24, 0, 1);
+ try testAtomicsWithType(i4, 2, 1);
+ try testAtomicsWithType(u5, 2, 1);
+ try testAtomicsWithType(i15, 2, 1);
+ try testAtomicsWithType(u24, 2, 1);
try testAtomicsWithType(u0, 0, 0);
try testAtomicsWithType(i0, 0, 0);
try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);
+ try testAtomicsWithType(enum(u19) { x = 1234, y = 5678 }, .x, .y);
try testAtomicsWithPackedStruct(
packed struct { x: u7, y: u24, z: bool },
.{ .x = 1, .y = 2, .z = true },
.{ .x = 3, .y = 4, .z = false },
);
+ try testAtomicsWithPackedStruct(
+ packed struct { x: u19, y: bool },
+ .{ .x = 1, .y = true },
+ .{ .x = 3, .y = false },
+ );
}
fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
diff --git a/test/behavior/bit_shifting.zig b/test/behavior/bit_shifting.zig
index 05b4444708..8c426dc05e 100644
--- a/test/behavior/bit_shifting.zig
+++ b/test/behavior/bit_shifting.zig
@@ -170,8 +170,6 @@ test "Saturating Shift Left" {
const S = struct {
fn shlSat(x: anytype, y: std.math.Log2Int(@TypeOf(x))) @TypeOf(x) {
- // workaround https://github.com/ziglang/zig/issues/23033
- @setRuntimeSafety(false);
return x <<| y;
}
diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig
index 30cad924fe..0c4d01f501 100644
--- a/test/behavior/cast_int.zig
+++ b/test/behavior/cast_int.zig
@@ -217,6 +217,7 @@ test "load non byte-sized value in struct" {
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;
diff --git a/test/behavior/decl_literals.zig b/test/behavior/decl_literals.zig
index 169c705a6b..f96f461771 100644
--- a/test/behavior/decl_literals.zig
+++ b/test/behavior/decl_literals.zig
@@ -33,7 +33,6 @@ test "decl literal with pointer" {
}
test "call decl literal with optional" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
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;
@@ -74,7 +73,6 @@ test "call decl literal" {
}
test "call decl literal with error union" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
const S = struct {
diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig
index 72a8badc1d..05f74eff32 100644
--- a/test/behavior/defer.zig
+++ b/test/behavior/defer.zig
@@ -107,7 +107,6 @@ test "mixing normal and error defers" {
}
test "errdefer with payload" {
- 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;
@@ -129,7 +128,6 @@ test "errdefer with payload" {
}
test "reference to errdefer payload" {
- 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
diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig
index 2d9d41d7b2..d719a611e6 100644
--- a/test/behavior/enum.zig
+++ b/test/behavior/enum.zig
@@ -926,7 +926,6 @@ test "enum literal casting to tagged union" {
const Bar = enum { A, B, C, D };
test "enum literal casting to error union with payload enum" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var bar: error{B}!Bar = undefined;
diff --git a/test/behavior/error.zig b/test/behavior/error.zig
index eff2cf855f..4ce94bb43b 100644
--- a/test/behavior/error.zig
+++ b/test/behavior/error.zig
@@ -145,14 +145,11 @@ 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_aarch64) return error.SkipZigTest;
-
entry();
comptime entry();
}
test "fn returning empty error set can be passed as fn returning any error - pointer" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
entryPtr();
@@ -404,7 +401,6 @@ fn intLiteral(str: []const u8) !?i64 {
}
test "nested error union function call in optional unwrap" {
- 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
@@ -482,7 +478,6 @@ test "optional error set is the same size as error set" {
}
test "nested catch" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
const S = struct {
@@ -590,7 +585,6 @@ test "error union comptime caching" {
}
test "@errorName" {
- 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;
@@ -605,7 +599,6 @@ fn gimmeItBroke() anyerror {
}
test "@errorName sentinel length matches slice length" {
- 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;
@@ -700,7 +693,6 @@ test "coerce error set to the current inferred error set" {
}
test "error union payload is properly aligned" {
- 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;
@@ -759,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {
}
test "pointer to error union payload" {
- 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;
@@ -847,7 +838,6 @@ test "alignment of wrapping an error union payload" {
}
test "compare error union and error set" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
var a: anyerror = error.Foo;
@@ -883,7 +873,6 @@ test "catch within a function that calls no errorable functions" {
}
test "error from comptime string" {
- 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;
@@ -946,7 +935,6 @@ test "optional error set function parameter" {
}
test "returning an error union containing a type with no runtime bits" {
- 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;
@@ -1038,8 +1026,6 @@ test "errorCast to adhoc inferred error set" {
}
test "@errorCast from error set to error union" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-
const S = struct {
fn doTheTest(set: error{ A, B }) error{A}!i32 {
return @errorCast(set);
@@ -1050,8 +1036,6 @@ test "@errorCast from error set to error union" {
}
test "@errorCast from error union to error union" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-
const S = struct {
fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {
return @errorCast(set);
diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig
index 59742cf3f6..65050e3df0 100644
--- a/test/behavior/field_parent_ptr.zig
+++ b/test/behavior/field_parent_ptr.zig
@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;
const builtin = @import("builtin");
test "@fieldParentPtr struct" {
- 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;
@@ -587,11 +586,12 @@ test "@fieldParentPtr extern struct last zero-bit field" {
}
test "@fieldParentPtr unaligned packed struct" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
const C = packed struct {
a: bool = true,
@@ -726,11 +726,12 @@ test "@fieldParentPtr unaligned packed struct" {
}
test "@fieldParentPtr aligned packed struct" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
const C = packed struct {
a: f32 = 3.14,
@@ -868,6 +869,7 @@ test "@fieldParentPtr nested packed struct" {
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
{
const C = packed struct {
@@ -1342,7 +1344,6 @@ test "@fieldParentPtr packed struct last zero-bit field" {
}
test "@fieldParentPtr tagged union" {
- 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;
@@ -1479,7 +1480,6 @@ test "@fieldParentPtr tagged union" {
}
test "@fieldParentPtr untagged union" {
- 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;
@@ -1616,6 +1616,7 @@ test "@fieldParentPtr untagged union" {
}
test "@fieldParentPtr extern union" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
diff --git a/test/behavior/inline_switch.zig b/test/behavior/inline_switch.zig
index a6f664ded8..a1efe7ab02 100644
--- a/test/behavior/inline_switch.zig
+++ b/test/behavior/inline_switch.zig
@@ -43,7 +43,6 @@ test "inline switch enums" {
const U = union(E) { a: void, b: u2, c: u3, d: u4 };
test "inline switch unions" {
- 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
@@ -105,7 +104,6 @@ test "inline else enum" {
}
test "inline else int with gaps" {
- 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; // TODO
diff --git a/test/behavior/math.zig b/test/behavior/math.zig
index 0f6dc8459d..679c94a78e 100644
--- a/test/behavior/math.zig
+++ b/test/behavior/math.zig
@@ -168,7 +168,6 @@ fn testOneCtz(comptime T: type, x: T) u32 {
}
test "@ctz 128-bit integers" {
- 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;
@@ -463,7 +462,6 @@ test "binary not big int <= 128 bits" {
}
test "division" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -527,6 +525,8 @@ fn testIntDivision() !void {
try expect(rem(i32, 10, 12) == 10);
try expect(rem(i32, -14, 12) == -2);
try expect(rem(i32, -2, 12) == -2);
+ try expect(rem(i32, 118, -12) == 10);
+ try expect(rem(i32, -14, -12) == -2);
try expect(rem(i16, -118, 12) == -10);
try expect(divTrunc(i20, 20, -5) == -4);
@@ -1819,7 +1819,6 @@ test "runtime int comparison to inf is comptime-known" {
}
test "float divide by zero" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig
index 3a63dfb1ac..d8d26d6a0f 100644
--- a/test/behavior/optional.zig
+++ b/test/behavior/optional.zig
@@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" {
}
test "coerce an anon struct literal to optional struct" {
- 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;
@@ -391,7 +390,6 @@ test "0-bit child type coerced to optional" {
}
test "array of optional unaligned types" {
- 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;
@@ -447,7 +445,6 @@ test "optional pointer to zero bit optional payload" {
}
test "optional pointer to zero bit error union payload" {
- 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;
diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig
index c2a48757c8..8c1b9ecf97 100644
--- a/test/behavior/packed-struct.zig
+++ b/test/behavior/packed-struct.zig
@@ -1322,6 +1322,7 @@ test "packed struct equality ignores padding bits" {
}
test "packed struct with signed field" {
+ if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
var s: packed struct {
diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig
index 2a786ecdb6..fbc74c1718 100644
--- a/test/behavior/pointers.zig
+++ b/test/behavior/pointers.zig
@@ -246,7 +246,6 @@ test "implicit casting between C pointer and optional non-C pointer" {
}
test "implicit cast error unions with non-optional to optional 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_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig
index 678fd68cbb..7b6e6edbb8 100644
--- a/test/behavior/ptrcast.zig
+++ b/test/behavior/ptrcast.zig
@@ -552,3 +552,13 @@ test "@ptrCast single-item pointer to slice of bytes" {
try comptime S.doTheTest(void, &{});
try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
}
+
+test "@ptrCast array pointer removing sentinel" {
+ const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 };
+ const out: []const i8 = @ptrCast(in);
+ comptime assert(out.len == 4);
+ comptime assert(out[0] == 1);
+ comptime assert(out[1] == 2);
+ comptime assert(out[2] == 3);
+ comptime assert(out[3] == 4);
+}
diff --git a/test/behavior/return_address.zig b/test/behavior/return_address.zig
index ba342956b3..d7fb76d3b0 100644
--- a/test/behavior/return_address.zig
+++ b/test/behavior/return_address.zig
@@ -6,7 +6,6 @@ fn retAddr() usize {
}
test "return address" {
- 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;
diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig
index d58cf79276..22e4e06dfe 100644
--- a/test/behavior/slice.zig
+++ b/test/behavior/slice.zig
@@ -628,9 +628,6 @@ test "slice syntax resulting in pointer-to-array" {
comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8);
comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8);
comptime assert(@TypeOf(ptr[1..][0..2 :4]) == *[2:4]u8);
- comptime assert(@TypeOf(ptr[1.. :0][0..2]) == *[2]u8);
- comptime assert(@TypeOf(ptr[1.. :0][0..4]) == *[4]u8);
- comptime assert(@TypeOf(ptr[1.. :0][0..2 :4]) == *[2:4]u8);
var ptr_z: [*:0]u8 = &array;
comptime assert(@TypeOf(ptr_z[1..][0..2]) == *[2]u8);
@@ -710,7 +707,6 @@ test "slice pointer-to-array zero length" {
}
test "type coercion of pointer to anon struct literal to pointer to slice" {
- 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;
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index ba69ae0990..2c2432afd9 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -797,7 +797,6 @@ test "fn with C calling convention returns struct by value" {
}
test "non-packed struct with u128 entry in union" {
- 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;
@@ -956,7 +955,6 @@ test "tuple element initialized with fn call" {
}
test "struct with union field" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
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
@@ -1026,7 +1024,6 @@ test "packed struct with undefined initializers" {
}
test "for loop over pointers to struct, getting field from struct pointer" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
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
@@ -1093,7 +1090,6 @@ test "anon init through error unions and optionals" {
}
test "anon init through optional" {
- 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;
@@ -1113,7 +1109,6 @@ test "anon init through optional" {
}
test "anon init through error union" {
- 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;
@@ -1398,7 +1393,6 @@ test "struct has only one reference" {
}
test "no dependency loop on pointer to optional struct" {
- 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;
diff --git a/test/behavior/struct_contains_slice_of_itself.zig b/test/behavior/struct_contains_slice_of_itself.zig
index a54049d123..5cf8d8134a 100644
--- a/test/behavior/struct_contains_slice_of_itself.zig
+++ b/test/behavior/struct_contains_slice_of_itself.zig
@@ -12,7 +12,6 @@ const NodeAligned = struct {
};
test "struct contains slice of itself" {
- 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;
@@ -53,7 +52,6 @@ test "struct contains slice of itself" {
}
test "struct contains aligned slice of itself" {
- 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;
diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig
index 813530b361..afc38661c3 100644
--- a/test/behavior/switch.zig
+++ b/test/behavior/switch.zig
@@ -8,7 +8,6 @@ const minInt = std.math.minInt;
const maxInt = std.math.maxInt;
test "switch with numbers" {
- 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;
@@ -300,7 +299,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
}
test "switch on enum using pointer capture" {
- 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
@@ -361,7 +359,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
}
test "switch on union with some prongs capturing" {
- 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
@@ -469,7 +466,6 @@ test "switch on integer with else capturing expr" {
}
test "else prong of switch on error set excludes other cases" {
- 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;
@@ -505,7 +501,6 @@ test "else prong of switch on error set excludes other cases" {
}
test "switch prongs with error set cases make a new error set type for capture value" {
- 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;
@@ -736,7 +731,6 @@ test "switch on error set with single else" {
}
test "switch capture copies its payload" {
- 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;
@@ -931,7 +925,6 @@ test "nested break ignores switch conditions and breaks instead" {
}
test "peer type resolution on switch captures ignores unused payload bits" {
- 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;
@@ -976,8 +969,6 @@ test "switch prong captures range" {
}
test "prong with inline call to unreachable" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-
const U = union(enum) {
void: void,
bool: bool,
@@ -1072,3 +1063,13 @@ test "switch on a signed value smaller than the smallest prong value" {
else => {},
}
}
+
+test "switch on 8-bit mod result" {
+ var x: u8 = undefined;
+ x = 16;
+ switch (x % 4) {
+ 0 => {},
+ 1, 2, 3 => return error.TestFailed,
+ else => unreachable,
+ }
+}
diff --git a/test/behavior/switch_on_captured_error.zig b/test/behavior/switch_on_captured_error.zig
index 75a4280d62..9aae1c7fbe 100644
--- a/test/behavior/switch_on_captured_error.zig
+++ b/test/behavior/switch_on_captured_error.zig
@@ -6,7 +6,6 @@ const expectEqual = std.testing.expectEqual;
const builtin = @import("builtin");
test "switch on error union catch capture" {
- 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;
diff --git a/test/behavior/switch_prong_err_enum.zig b/test/behavior/switch_prong_err_enum.zig
index 6dbc76505c..a2eed86c0f 100644
--- a/test/behavior/switch_prong_err_enum.zig
+++ b/test/behavior/switch_prong_err_enum.zig
@@ -21,7 +21,6 @@ fn doThing(form_id: u64) anyerror!FormValue {
}
test "switch prong returns error enum" {
- 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_riscv64) return error.SkipZigTest;
diff --git a/test/behavior/try.zig b/test/behavior/try.zig
index b3014ef669..fd120fc86f 100644
--- a/test/behavior/try.zig
+++ b/test/behavior/try.zig
@@ -47,7 +47,6 @@ test "try then not executed with assignment" {
}
test "`try`ing an if/else expression" {
- 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_riscv64) return error.SkipZigTest;
diff --git a/test/behavior/union.zig b/test/behavior/union.zig
index bbace0f706..186ae56593 100644
--- a/test/behavior/union.zig
+++ b/test/behavior/union.zig
@@ -12,7 +12,6 @@ const FooWithFloats = union {
};
test "basic unions with floats" {
- 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_riscv64) return error.SkipZigTest;
@@ -29,7 +28,6 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {
}
test "init union with runtime value - floats" {
- 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_riscv64) return error.SkipZigTest;
@@ -41,7 +39,6 @@ test "init union with runtime value - floats" {
}
test "basic unions" {
- 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;
@@ -60,7 +57,6 @@ const Foo = union {
};
test "init union with runtime value" {
- 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_riscv64) return error.SkipZigTest;
@@ -101,7 +97,6 @@ const FooExtern = extern union {
};
test "basic extern unions" {
- 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;
@@ -160,7 +155,6 @@ test "unions embedded in aggregate types" {
}
test "constant tagged union with 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
@@ -263,7 +257,6 @@ fn testComparison() !void {
}
test "comparison between union and enum literal" {
- 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;
@@ -279,7 +272,6 @@ const TheUnion = union(TheTag) {
C: i32,
};
test "cast union to tag type of union" {
- 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
@@ -300,7 +292,6 @@ test "union field access gives the enum values" {
}
test "cast tag type of union to union" {
- 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
@@ -316,7 +307,6 @@ const Value2 = union(Letter2) {
};
test "implicit cast union to its tag type" {
- 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
@@ -337,7 +327,6 @@ pub const PackThis = union(enum) {
};
test "constant packed union" {
- 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;
@@ -483,7 +472,6 @@ pub const FooUnion = union(enum) {
var glbl_array: [2]FooUnion = undefined;
test "initialize global array of union" {
- 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;
@@ -495,7 +483,6 @@ test "initialize global array of union" {
}
test "update the tag value for zero-sized unions" {
- 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
@@ -734,7 +721,6 @@ 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_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
@@ -817,7 +803,6 @@ test "return union init with void payload" {
}
test "@unionInit stored to a const" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -848,7 +833,6 @@ test "@unionInit stored to a const" {
}
test "@unionInit can modify a union type" {
- 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
@@ -871,7 +855,6 @@ test "@unionInit can modify a union type" {
}
test "@unionInit can modify a pointer value" {
- 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
@@ -926,7 +909,6 @@ test "extern union doesn't trigger field check at comptime" {
}
test "anonymous union literal syntax" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -990,7 +972,6 @@ test "function call result coerces from tagged union to the tag" {
}
test "switching on non exhaustive union" {
- 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
@@ -1096,7 +1077,6 @@ test "union enum type gets a separate scope" {
}
test "global variable struct contains union initialized to non-most-aligned field" {
- 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;
@@ -1123,7 +1103,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel
}
test "union with no result loc initiated with a runtime value" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -1141,7 +1120,6 @@ test "union with no result loc initiated with a runtime value" {
}
test "union with a large struct field" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -1176,7 +1154,6 @@ test "comptime equality of extern unions with same tag" {
}
test "union tag is set when initiated as a temporary value at runtime" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -1216,7 +1193,6 @@ test "extern union most-aligned field is smaller" {
}
test "return an extern union from C calling convention" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -1248,7 +1224,6 @@ test "return an extern union from C calling convention" {
}
test "noreturn field in union" {
- 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
@@ -1299,7 +1274,6 @@ test "noreturn field in union" {
}
test "@unionInit uses tag value instead of field index" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
@@ -1408,7 +1382,6 @@ test "union int tag type is properly managed" {
}
test "no dependency loop when function pointer in union returns the union" {
- 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_riscv64) return error.SkipZigTest;
@@ -1430,7 +1403,6 @@ test "no dependency loop when function pointer in union returns the union" {
}
test "union reassignment can use previous value" {
- 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;
@@ -1481,8 +1453,6 @@ test "reinterpreting enum value inside packed union" {
}
test "access the tag of a global tagged union" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-
const U = union(enum) {
a,
b: u8,
@@ -1634,7 +1604,6 @@ test "union with 128 bit integer" {
}
test "memset extern union" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const U = extern union {
@@ -1956,7 +1925,6 @@ test "packed union initialized via reintepreted struct field initializer" {
}
test "store of comptime reinterpreted memory to extern 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 };
@@ -2063,7 +2031,6 @@ test "circular dependency through pointer field of a union" {
}
test "pass nested union with rls" {
- 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;
@@ -2085,7 +2052,6 @@ test "pass nested union with rls" {
}
test "runtime union init, most-aligned field != largest" {
- 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;
@@ -2111,7 +2077,6 @@ test "runtime union init, most-aligned field != largest" {
}
test "copied union field doesn't alias source" {
- 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;
@@ -2255,7 +2220,6 @@ test "matching captures causes union equivalence" {
}
test "signed enum tag with negative value" {
- 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_riscv64) return error.SkipZigTest;
@@ -2312,7 +2276,6 @@ test "extern union @FieldType" {
}
test "assign global tagged union" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
const U = union(enum) {
@@ -2334,8 +2297,6 @@ test "assign global tagged union" {
}
test "set mutable union by switching on same union" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-
const U = union(enum) {
foo,
bar: usize,
diff --git a/test/behavior/union_with_members.zig b/test/behavior/union_with_members.zig
index 288d47d9cb..9303ac14da 100644
--- a/test/behavior/union_with_members.zig
+++ b/test/behavior/union_with_members.zig
@@ -17,7 +17,6 @@ const ET = union(enum) {
};
test "enum with members" {
- 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;
diff --git a/test/behavior/var_args.zig b/test/behavior/var_args.zig
index b8cde21723..b42feb2a4d 100644
--- a/test/behavior/var_args.zig
+++ b/test/behavior/var_args.zig
@@ -92,7 +92,6 @@ fn doNothingWithFirstArg(args: anytype) void {
}
test "simple variadic function" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
@@ -154,7 +153,6 @@ test "simple variadic function" {
}
test "coerce reference to var arg" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
@@ -234,7 +232,6 @@ test "variadic functions" {
}
test "copy VaList" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
@@ -269,7 +266,6 @@ test "copy VaList" {
}
test "unused VaList arg" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
diff --git a/test/behavior/while.zig b/test/behavior/while.zig
index db3d299b55..7a177d5690 100644
--- a/test/behavior/while.zig
+++ b/test/behavior/while.zig
@@ -174,7 +174,6 @@ test "while with optional as condition with else" {
}
test "while with error union condition" {
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
@@ -306,7 +305,6 @@ test "while optional 2 break statements and an else" {
}
test "while error 2 break statements and an else" {
- 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
@@ -344,7 +342,6 @@ test "else continue outer while" {
}
test "try terminating an infinite 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_spirv) return error.SkipZigTest;
diff --git a/test/behavior/x86_64/binary.zig b/test/behavior/x86_64/binary.zig
index 99dd47155b..e90c4f1eb0 100644
--- a/test/behavior/x86_64/binary.zig
+++ b/test/behavior/x86_64/binary.zig
@@ -5473,8 +5473,6 @@ inline fn shlSaturate(comptime Type: type, lhs: Type, rhs: Type) Type {
// workaround https://github.com/ziglang/zig/issues/23139
return lhs <<| @min(@abs(rhs), splat(ChangeScalar(Type, u64), imax(u64)));
}
- // workaround https://github.com/ziglang/zig/issues/23033
- @setRuntimeSafety(false);
return lhs <<| @abs(rhs);
}
test shlSaturate {
diff --git a/test/cases/array_in_anon_struct.zig b/test/cases/array_in_anon_struct.zig
index 5961b3f723..8c4f5ea051 100644
--- a/test/cases/array_in_anon_struct.zig
+++ b/test/cases/array_in_anon_struct.zig
@@ -19,4 +19,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/compile_errors/atomics_with_invalid_type.zig b/test/cases/compile_errors/atomics_with_invalid_type.zig
index 321cda3655..4643dc7543 100644
--- a/test/cases/compile_errors/atomics_with_invalid_type.zig
+++ b/test/cases/compile_errors/atomics_with_invalid_type.zig
@@ -5,14 +5,27 @@ export fn float() void {
const NormalStruct = struct { x: u32 };
export fn normalStruct() void {
- var x: NormalStruct = 0;
+ var x: NormalStruct = .{ .x = 0 };
_ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);
}
+export fn anyError() void {
+ var x: anyerror = error.A;
+ _ = @cmpxchgWeak(anyerror, &x, error.A, error.B, .seq_cst, .seq_cst);
+}
+
+const ErrorSet = error{ A, B };
+export fn errorSet() void {
+ var x: ErrorSet = error.A;
+ _ = @cmpxchgWeak(ErrorSet, &x, error.A, error.B, .seq_cst, .seq_cst);
+}
+
// error
// backend=stage2
// target=native
//
// :3:22: error: expected bool, integer, enum, packed struct, or pointer type; found 'f32'
-// :8:27: error: expected type 'tmp.NormalStruct', found 'comptime_int'
+// :9:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'tmp.NormalStruct'
// :6:22: note: struct declared here
+// :14:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'anyerror'
+// :20:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'error{A,B}'
diff --git a/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig b/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig
index 8bbc3154a1..5f42b7d9af 100644
--- a/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig
+++ b/test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig
@@ -7,5 +7,5 @@ export fn entry3() callconv(.avr_interrupt) void {}
// target=aarch64-linux-none
//
// :1:30: error: calling convention 'x86_64_interrupt' only available on architectures 'x86_64'
-// :1:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'
-// :1:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'
+// :2:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'
+// :3:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'
diff --git a/test/cases/compile_errors/comptime_try_non_error.zig b/test/cases/compile_errors/comptime_try_non_error.zig
index 8d61df6e9a..44f7dbe614 100644
--- a/test/cases/compile_errors/comptime_try_non_error.zig
+++ b/test/cases/compile_errors/comptime_try_non_error.zig
@@ -13,4 +13,5 @@ pub fn bar() u8 {
// error
//
// :6:12: error: expected error union type, found 'u8'
+// :6:12: note: consider omitting 'try'
// :2:8: note: called at comptime here
diff --git a/test/cases/compile_errors/error_set_membership.zig b/test/cases/compile_errors/error_set_membership.zig
index 67826f4db9..a146bd39ba 100644
--- a/test/cases/compile_errors/error_set_membership.zig
+++ b/test/cases/compile_errors/error_set_membership.zig
@@ -25,7 +25,7 @@ pub fn main() Error!void {
// error
// backend=stage2
-// target=native
+// target=x86_64-linux
//
// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'
// :23:29: note: 'error.InvalidDirection' not a member of destination error set
diff --git a/test/cases/compile_errors/function_ptr_alignment.zig b/test/cases/compile_errors/function_ptr_alignment.zig
index cf97e61f40..fd8aec06d0 100644
--- a/test/cases/compile_errors/function_ptr_alignment.zig
+++ b/test/cases/compile_errors/function_ptr_alignment.zig
@@ -10,7 +10,7 @@ comptime {
// error
// backend=stage2
-// target=native
+// target=x86_64-linux
//
// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'
diff --git a/test/cases/compile_errors/int_to_float_coercion_loses_precision.zig b/test/cases/compile_errors/int_to_float_coercion_loses_precision.zig
new file mode 100644
index 0000000000..bc1d8e7dee
--- /dev/null
+++ b/test/cases/compile_errors/int_to_float_coercion_loses_precision.zig
@@ -0,0 +1,9 @@
+export fn foo() void {
+ const int: u16 = 65535;
+ const float: f16 = int;
+ _ = float;
+}
+
+// error
+//
+// :3:24: error: type 'f16' cannot represent integer value '65535'
diff --git a/test/cases/compile_errors/issue_15572_break_on_inline_while.zig b/test/cases/compile_errors/issue_15572_break_on_inline_while.zig
index f264e695c0..69d5c11eab 100644
--- a/test/cases/compile_errors/issue_15572_break_on_inline_while.zig
+++ b/test/cases/compile_errors/issue_15572_break_on_inline_while.zig
@@ -15,6 +15,6 @@ pub fn main() void {
// error
// backend=stage2
-// target=native
+// target=x86_64-linux
//
// :9:28: error: incompatible types: 'builtin.Type.EnumField' and 'void'
diff --git a/test/cases/compile_errors/minmax_nonnumeric_operand.zig b/test/cases/compile_errors/minmax_nonnumeric_operand.zig
new file mode 100644
index 0000000000..7100879b5b
--- /dev/null
+++ b/test/cases/compile_errors/minmax_nonnumeric_operand.zig
@@ -0,0 +1,41 @@
+// zig fmt: off
+comptime { _ = @min(0, u32); } // type
+comptime { _ = @max(0, {}); } // void
+comptime { _ = @min(0, false); } // boolean
+comptime { _ = @min(0, &@as(u8, 0)); } // pointer
+comptime { _ = @max(0, [0]u8{}); } // array
+comptime { _ = @min(0, Struct{}); } // struct
+comptime { _ = @max(0, null); } // null
+comptime { _ = @min(0, @as(?u8, 0)); } // nullable
+comptime { _ = @max(0, @as(error{}!u8, 0)); } // error union
+comptime { _ = @min(0, error.Foo); } // error set
+comptime { _ = @max(0, Enum.foo); } // enum
+comptime { _ = @min(0, Union{ .foo = {} }); } // union
+comptime { _ = @max(0, struct { fn func() u8 { return 42; }}.func); }
+comptime { _ = @max(0, .foo); } // enum literal
+
+const Struct = struct {};
+const Enum = enum { foo };
+const Union = union { foo: void };
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:24: error: expected number, found 'type'
+// :3:24: error: expected number, found 'void'
+// :4:24: error: expected number, found 'bool'
+// :5:24: error: expected number, found '*const u8'
+// :6:29: error: expected number, found '[0]u8'
+// :7:30: error: expected number, found 'tmp.Struct'
+// :17:16: note: struct declared here
+// :8:24: error: expected number, found '@TypeOf(null)'
+// :9:24: error: expected number, found '?u8'
+// :10:24: error: expected number, found 'error{}!u8'
+// :11:24: error: expected number, found 'error{Foo}'
+// :12:28: error: expected number, found 'tmp.Enum'
+// :18:14: note: enum declared here
+// :13:29: error: expected number, found 'tmp.Union'
+// :19:15: note: union declared here
+// :14:61: error: expected number, found 'fn () u8'
+// :15:25: error: expected number, found '@Type(.enum_literal)'
diff --git a/test/cases/compile_errors/redundant_try.zig b/test/cases/compile_errors/redundant_try.zig
index 5472701ce0..73beca2c2d 100644
--- a/test/cases/compile_errors/redundant_try.zig
+++ b/test/cases/compile_errors/redundant_try.zig
@@ -43,10 +43,16 @@ comptime {
// error
//
// :5:23: error: expected error union type, found 'comptime_int'
+// :5:23: note: consider omitting 'try'
// :10:23: error: expected error union type, found '@TypeOf(.{})'
+// :10:23: note: consider omitting 'try'
// :15:23: error: expected error union type, found 'tmp.S'
// :1:11: note: struct declared here
+// :15:23: note: consider omitting 'try'
// :20:27: error: expected error union type, found 'tmp.S'
// :1:11: note: struct declared here
+// :20:27: note: consider omitting 'try'
// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
+// :25:23: note: consider omitting 'try'
// :31:13: error: expected error union type, found 'u32'
+// :31:13: note: consider omitting 'try'
diff --git a/test/cases/compile_errors/reify_type_for_tagged_extern_union.zig b/test/cases/compile_errors/reify_type_for_tagged_extern_union.zig
new file mode 100644
index 0000000000..24169e2ff3
--- /dev/null
+++ b/test/cases/compile_errors/reify_type_for_tagged_extern_union.zig
@@ -0,0 +1,34 @@
+const Tag = @Type(.{
+ .@"enum" = .{
+ .tag_type = u2,
+ .fields = &.{
+ .{ .name = "signed", .value = 0 },
+ .{ .name = "unsigned", .value = 1 },
+ },
+ .decls = &.{},
+ .is_exhaustive = true,
+ },
+});
+
+const Extern = @Type(.{
+ .@"union" = .{
+ .layout = .@"extern",
+ .tag_type = Tag,
+ .fields = &.{
+ .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },
+ .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },
+ },
+ .decls = &.{},
+ },
+});
+
+export fn entry() void {
+ const tagged: Extern = .{ .signed = -1 };
+ _ = tagged;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :13:16: error: extern union does not support enum tag type
diff --git a/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig b/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig
new file mode 100644
index 0000000000..ee085b07b3
--- /dev/null
+++ b/test/cases/compile_errors/reify_type_for_tagged_packed_union.zig
@@ -0,0 +1,34 @@
+const Tag = @Type(.{
+ .@"enum" = .{
+ .tag_type = u2,
+ .fields = &.{
+ .{ .name = "signed", .value = 0 },
+ .{ .name = "unsigned", .value = 1 },
+ },
+ .decls = &.{},
+ .is_exhaustive = true,
+ },
+});
+
+const Packed = @Type(.{
+ .@"union" = .{
+ .layout = .@"packed",
+ .tag_type = Tag,
+ .fields = &.{
+ .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },
+ .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },
+ },
+ .decls = &.{},
+ },
+});
+
+export fn entry() void {
+ const tagged: Packed = .{ .signed = -1 };
+ _ = tagged;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :13:16: error: packed union does not support enum tag type
diff --git a/test/cases/compile_errors/runtime_value_in_comptime_array.zig b/test/cases/compile_errors/runtime_value_in_comptime_array.zig
new file mode 100644
index 0000000000..804cd258fb
--- /dev/null
+++ b/test/cases/compile_errors/runtime_value_in_comptime_array.zig
@@ -0,0 +1,14 @@
+fn comptimeArray(comptime _: []const u8) void {}
+fn bar() u8 {
+ return 123;
+}
+export fn entry() void {
+ const y = bar();
+ comptimeArray(&.{y});
+}
+
+// error
+//
+// :7:19: error: unable to resolve comptime value
+// :7:19: note: argument to comptime parameter must be comptime-known
+// :1:18: note: parameter declared comptime here
diff --git a/test/cases/compile_errors/runtime_value_in_comptime_struct.zig b/test/cases/compile_errors/runtime_value_in_comptime_struct.zig
new file mode 100644
index 0000000000..acaef3c543
--- /dev/null
+++ b/test/cases/compile_errors/runtime_value_in_comptime_struct.zig
@@ -0,0 +1,14 @@
+fn comptimeStruct(comptime _: anytype) void {}
+fn bar() u8 {
+ return 123;
+}
+export fn entry() void {
+ const y = bar();
+ comptimeStruct(.{ .foo = y });
+}
+
+// error
+//
+// :7:21: error: unable to resolve comptime value
+// :7:21: note: argument to comptime parameter must be comptime-known
+// :1:19: note: parameter declared comptime here
diff --git a/test/cases/compile_errors/slice_of_many-item_pointer_preserves_sentinel.zig b/test/cases/compile_errors/slice_of_many-item_pointer_preserves_sentinel.zig
new file mode 100644
index 0000000000..02fbb5289d
--- /dev/null
+++ b/test/cases/compile_errors/slice_of_many-item_pointer_preserves_sentinel.zig
@@ -0,0 +1,18 @@
+comptime {
+ var ptr: [*]const u8 = undefined;
+ _ = ptr[0.. :0];
+}
+
+comptime {
+ var ptrz: [*:0]const u8 = undefined;
+ _ = ptrz[0.. :1];
+}
+
+// error
+//
+// :3:18: error: sentinel-terminated slicing of many-item pointer must match existing sentinel
+// :3:9: note: type '[*]const u8' does not have a sentinel
+// :3:12: note: use @ptrCast to cast pointer sentinel
+// :8:19: error: sentinel-terminated slicing of many-item pointer must match existing sentinel
+// :8:19: note: expected sentinel '0', found '1'
+// :8:13: note: use @ptrCast to cast pointer sentinel
diff --git a/test/cases/compile_errors/switch_on_non_err_union.zig b/test/cases/compile_errors/switch_on_non_err_union.zig
index 87624b21dc..e79a181e62 100644
--- a/test/cases/compile_errors/switch_on_non_err_union.zig
+++ b/test/cases/compile_errors/switch_on_non_err_union.zig
@@ -6,6 +6,6 @@ pub fn main() void {
// error
// backend=stage2
-// target=native
+// target=x86_64-linux
//
// :2:23: error: expected error union type, found 'bool'
diff --git a/test/cases/pic_freestanding.zig b/test/cases/pic_freestanding.zig
index 86e37662e2..eda1399887 100644
--- a/test/cases/pic_freestanding.zig
+++ b/test/cases/pic_freestanding.zig
@@ -1,7 +1,7 @@
const builtin = @import("builtin");
const std = @import("std");
-fn _start() callconv(.naked) void {}
+pub fn _start() callconv(.naked) void {}
comptime {
@export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" });
diff --git a/test/cases/safety/@alignCast misaligned.zig b/test/cases/safety/@alignCast misaligned.zig
index e523a9d120..017c46a98d 100644
--- a/test/cases/safety/@alignCast misaligned.zig
+++ b/test/cases/safety/@alignCast misaligned.zig
@@ -22,4 +22,4 @@ fn foo(bytes: []u8) u32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@enumFromInt - no matching tag value.zig b/test/cases/safety/@enumFromInt - no matching tag value.zig
index 0021a4d397..7953b93358 100644
--- a/test/cases/safety/@enumFromInt - no matching tag value.zig
+++ b/test/cases/safety/@enumFromInt - no matching tag value.zig
@@ -23,4 +23,4 @@ fn baz(_: Foo) void {}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig
index 92065c4892..ace1e08d11 100644
--- a/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig
+++ b/test/cases/safety/@enumFromInt truncated bits - exhaustive.zig
@@ -20,4 +20,4 @@ pub fn main() u8 {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig
index 25959c9ffd..8f20081610 100644
--- a/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig
+++ b/test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig
@@ -20,4 +20,4 @@ pub fn main() u8 {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@errorCast error not present in destination.zig b/test/cases/safety/@errorCast error not present in destination.zig
index 74e81f2a60..a121d3e6e8 100644
--- a/test/cases/safety/@errorCast error not present in destination.zig
+++ b/test/cases/safety/@errorCast error not present in destination.zig
@@ -18,4 +18,4 @@ fn foo(set1: Set1) Set2 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@errorCast error union casted to disjoint set.zig b/test/cases/safety/@errorCast error union casted to disjoint set.zig
index 2696a037c7..a84f61d8e5 100644
--- a/test/cases/safety/@errorCast error union casted to disjoint set.zig
+++ b/test/cases/safety/@errorCast error union casted to disjoint set.zig
@@ -17,4 +17,4 @@ fn foo() anyerror!i32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intCast to u0.zig b/test/cases/safety/@intCast to u0.zig
index 4394f63f54..219f42f213 100644
--- a/test/cases/safety/@intCast to u0.zig
+++ b/test/cases/safety/@intCast to u0.zig
@@ -19,4 +19,4 @@ fn bar(one: u1, not_zero: i32) void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig
index 38ec595b45..70f0cebb93 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig
index 97a651855b..bc35aa6e23 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig
index cc19ee84ff..56e87423a1 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig
index abc95e396a..61704a8733 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig
index f488d0291f..361a528498 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig
index 8d459e1a5c..5706d192d5 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig
index 95122abc8c..842aaaa1de 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig
index fbc7cf18ac..c1e8af2f5e 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig
index 35b4c91509..96e1c5594e 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig
index 94ad509772..cf17014d3f 100644
--- a/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig
index 80edbdfd3c..23d9f87ac1 100644
--- a/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - negative out of range.zig
@@ -17,4 +17,4 @@ fn bar(a: f32) i8 {
fn baz(_: i8) void {}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig
index ee0c040273..9d28ee0aaa 100644
--- a/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig
@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {
fn baz(_: u8) void {}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig
index c526a70047..2e76a9b253 100644
--- a/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig
+++ b/test/cases/safety/@intFromFloat cannot fit - positive out of range.zig
@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {
fn baz(_: u8) void {}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig
index 4944a239e2..eb45f357dd 100644
--- a/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig
+++ b/test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig
index a217de3073..308f97ad12 100644
--- a/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig
+++ b/test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@ptrFromInt with misaligned address.zig b/test/cases/safety/@ptrFromInt with misaligned address.zig
index b95c1b320f..1383a4c3c3 100644
--- a/test/cases/safety/@ptrFromInt with misaligned address.zig
+++ b/test/cases/safety/@ptrFromInt with misaligned address.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/@tagName on corrupted enum value.zig b/test/cases/safety/@tagName on corrupted enum value.zig
index df6a3f45e0..450d0ee2e0 100644
--- a/test/cases/safety/@tagName on corrupted enum value.zig
+++ b/test/cases/safety/@tagName on corrupted enum value.zig
@@ -23,4 +23,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/@tagName on corrupted union value.zig b/test/cases/safety/@tagName on corrupted union value.zig
index 7b856e57b9..b61a72420e 100644
--- a/test/cases/safety/@tagName on corrupted union value.zig
+++ b/test/cases/safety/@tagName on corrupted union value.zig
@@ -24,4 +24,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/array slice sentinel mismatch vector.zig b/test/cases/safety/array slice sentinel mismatch vector.zig
index 55ff4b3e39..f374f1b9d5 100644
--- a/test/cases/safety/array slice sentinel mismatch vector.zig
+++ b/test/cases/safety/array slice sentinel mismatch vector.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/array slice sentinel mismatch.zig b/test/cases/safety/array slice sentinel mismatch.zig
index ab7a513b39..deb43250ec 100644
--- a/test/cases/safety/array slice sentinel mismatch.zig
+++ b/test/cases/safety/array slice sentinel mismatch.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/bad union field access.zig b/test/cases/safety/bad union field access.zig
index 14ebb1f344..a2778237c4 100644
--- a/test/cases/safety/bad union field access.zig
+++ b/test/cases/safety/bad union field access.zig
@@ -24,4 +24,4 @@ fn bar(f: *Foo) void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/calling panic.zig b/test/cases/safety/calling panic.zig
index 7b8a478be3..7ac512eadc 100644
--- a/test/cases/safety/calling panic.zig
+++ b/test/cases/safety/calling panic.zig
@@ -13,4 +13,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig
index b6b8e89bf9..65dda78751 100644
--- a/test/cases/safety/cast []u8 to bigger slice of wrong size.zig
+++ b/test/cases/safety/cast []u8 to bigger slice of wrong size.zig
@@ -18,4 +18,4 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/cast integer to global error and no code matches.zig b/test/cases/safety/cast integer to global error and no code matches.zig
index fa0474a88c..2b9cadf811 100644
--- a/test/cases/safety/cast integer to global error and no code matches.zig
+++ b/test/cases/safety/cast integer to global error and no code matches.zig
@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/empty slice with sentinel out of bounds.zig b/test/cases/safety/empty slice with sentinel out of bounds.zig
index 51846f894f..2d9494826d 100644
--- a/test/cases/safety/empty slice with sentinel out of bounds.zig
+++ b/test/cases/safety/empty slice with sentinel out of bounds.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/exact division failure - vectors.zig b/test/cases/safety/exact division failure - vectors.zig
index 30d5dcf11a..398ae7a4cd 100644
--- a/test/cases/safety/exact division failure - vectors.zig
+++ b/test/cases/safety/exact division failure - vectors.zig
@@ -20,4 +20,4 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/exact division failure.zig b/test/cases/safety/exact division failure.zig
index be86853c77..0831bb4e09 100644
--- a/test/cases/safety/exact division failure.zig
+++ b/test/cases/safety/exact division failure.zig
@@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/for_len_mismatch.zig b/test/cases/safety/for_len_mismatch.zig
index 8841f11aa7..55bb7bf8b5 100644
--- a/test/cases/safety/for_len_mismatch.zig
+++ b/test/cases/safety/for_len_mismatch.zig
@@ -22,4 +22,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/for_len_mismatch_three.zig b/test/cases/safety/for_len_mismatch_three.zig
index 4efe18d3cd..b4256b0eee 100644
--- a/test/cases/safety/for_len_mismatch_three.zig
+++ b/test/cases/safety/for_len_mismatch_three.zig
@@ -21,4 +21,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/ignored expression integer overflow.zig b/test/cases/safety/ignored expression integer overflow.zig
index 1089010854..859c615e42 100644
--- a/test/cases/safety/ignored expression integer overflow.zig
+++ b/test/cases/safety/ignored expression integer overflow.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/integer addition overflow.zig b/test/cases/safety/integer addition overflow.zig
index 499e8b1015..119800c686 100644
--- a/test/cases/safety/integer addition overflow.zig
+++ b/test/cases/safety/integer addition overflow.zig
@@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/integer division by zero - vectors.zig b/test/cases/safety/integer division by zero - vectors.zig
index 63e77a0dd4..d3ddfa06c6 100644
--- a/test/cases/safety/integer division by zero - vectors.zig
+++ b/test/cases/safety/integer division by zero - vectors.zig
@@ -19,4 +19,4 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/integer division by zero.zig b/test/cases/safety/integer division by zero.zig
index e8eba5c4f0..dc12dde343 100644
--- a/test/cases/safety/integer division by zero.zig
+++ b/test/cases/safety/integer division by zero.zig
@@ -17,4 +17,4 @@ fn div0(a: i32, b: i32) i32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/integer multiplication overflow.zig b/test/cases/safety/integer multiplication overflow.zig
index f7f4148a15..4380ec6d51 100644
--- a/test/cases/safety/integer multiplication overflow.zig
+++ b/test/cases/safety/integer multiplication overflow.zig
@@ -18,4 +18,4 @@ fn mul(a: u16, b: u16) u16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/integer negation overflow.zig b/test/cases/safety/integer negation overflow.zig
index cfdfed0429..1c6610ae6f 100644
--- a/test/cases/safety/integer negation overflow.zig
+++ b/test/cases/safety/integer negation overflow.zig
@@ -18,4 +18,4 @@ fn neg(a: i16) i16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/integer subtraction overflow.zig b/test/cases/safety/integer subtraction overflow.zig
index 14e9131c3b..9211c877e4 100644
--- a/test/cases/safety/integer subtraction overflow.zig
+++ b/test/cases/safety/integer subtraction overflow.zig
@@ -18,4 +18,4 @@ fn sub(a: u16, b: u16) u16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/memcpy_alias.zig b/test/cases/safety/memcpy_alias.zig
index f7a1a16024..62c30ec459 100644
--- a/test/cases/safety/memcpy_alias.zig
+++ b/test/cases/safety/memcpy_alias.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/memcpy_len_mismatch.zig b/test/cases/safety/memcpy_len_mismatch.zig
index 0ef22b959c..aa9b3fd63f 100644
--- a/test/cases/safety/memcpy_len_mismatch.zig
+++ b/test/cases/safety/memcpy_len_mismatch.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/memmove_len_mismatch.zig b/test/cases/safety/memmove_len_mismatch.zig
index 881af9f336..fa22597122 100644
--- a/test/cases/safety/memmove_len_mismatch.zig
+++ b/test/cases/safety/memmove_len_mismatch.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/memset_array_undefined_bytes.zig b/test/cases/safety/memset_array_undefined_bytes.zig
index 20a65d65d6..47865a8def 100644
--- a/test/cases/safety/memset_array_undefined_bytes.zig
+++ b/test/cases/safety/memset_array_undefined_bytes.zig
@@ -15,4 +15,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/memset_array_undefined_large.zig b/test/cases/safety/memset_array_undefined_large.zig
index a52bfecbf0..10f57521cf 100644
--- a/test/cases/safety/memset_array_undefined_large.zig
+++ b/test/cases/safety/memset_array_undefined_large.zig
@@ -15,4 +15,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/memset_slice_undefined_bytes.zig b/test/cases/safety/memset_slice_undefined_bytes.zig
index fb67999306..4d76bbc414 100644
--- a/test/cases/safety/memset_slice_undefined_bytes.zig
+++ b/test/cases/safety/memset_slice_undefined_bytes.zig
@@ -17,4 +17,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/memset_slice_undefined_large.zig b/test/cases/safety/memset_slice_undefined_large.zig
index 166557240c..e404e35226 100644
--- a/test/cases/safety/memset_slice_undefined_large.zig
+++ b/test/cases/safety/memset_slice_undefined_large.zig
@@ -17,4 +17,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/modrem by zero.zig b/test/cases/safety/modrem by zero.zig
index 35b7e37e3a..fac10065ed 100644
--- a/test/cases/safety/modrem by zero.zig
+++ b/test/cases/safety/modrem by zero.zig
@@ -17,4 +17,4 @@ fn div0(a: u32, b: u32) u32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/modulus by zero.zig b/test/cases/safety/modulus by zero.zig
index cdeab00dbc..1c0c8ba3a9 100644
--- a/test/cases/safety/modulus by zero.zig
+++ b/test/cases/safety/modulus by zero.zig
@@ -17,4 +17,4 @@ fn mod0(a: i32, b: i32) i32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/noreturn returned.zig b/test/cases/safety/noreturn returned.zig
index c92fb08e62..b91a6def49 100644
--- a/test/cases/safety/noreturn returned.zig
+++ b/test/cases/safety/noreturn returned.zig
@@ -20,4 +20,4 @@ pub fn main() void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/optional unwrap operator on C pointer.zig b/test/cases/safety/optional unwrap operator on C pointer.zig
index 98135cfae4..4deb62bc25 100644
--- a/test/cases/safety/optional unwrap operator on C pointer.zig
+++ b/test/cases/safety/optional unwrap operator on C pointer.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/optional unwrap operator on null pointer.zig b/test/cases/safety/optional unwrap operator on null pointer.zig
index 6ac54e6bd0..97d07626f5 100644
--- a/test/cases/safety/optional unwrap operator on null pointer.zig
+++ b/test/cases/safety/optional unwrap operator on null pointer.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/optional_empty_error_set.zig b/test/cases/safety/optional_empty_error_set.zig
index dbe39d00c3..1ee1690d51 100644
--- a/test/cases/safety/optional_empty_error_set.zig
+++ b/test/cases/safety/optional_empty_error_set.zig
@@ -19,4 +19,4 @@ fn foo() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/out of bounds array slice by length.zig b/test/cases/safety/out of bounds array slice by length.zig
index 325749a5eb..df613b1d53 100644
--- a/test/cases/safety/out of bounds array slice by length.zig
+++ b/test/cases/safety/out of bounds array slice by length.zig
@@ -17,4 +17,4 @@ fn foo(a: u32) u32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/out of bounds slice access.zig b/test/cases/safety/out of bounds slice access.zig
index f4f34a203f..d5ebf6d531 100644
--- a/test/cases/safety/out of bounds slice access.zig
+++ b/test/cases/safety/out of bounds slice access.zig
@@ -18,4 +18,4 @@ fn bar(a: []const i32) i32 {
fn baz(_: i32) void {}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/pointer casting null to non-optional pointer.zig b/test/cases/safety/pointer casting null to non-optional pointer.zig
index 33da071e73..ef61f162b4 100644
--- a/test/cases/safety/pointer casting null to non-optional pointer.zig
+++ b/test/cases/safety/pointer casting null to non-optional pointer.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/pointer casting to null function pointer.zig b/test/cases/safety/pointer casting to null function pointer.zig
index a57e71cb8f..1ce1ebc266 100644
--- a/test/cases/safety/pointer casting to null function pointer.zig
+++ b/test/cases/safety/pointer casting to null function pointer.zig
@@ -20,4 +20,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/pointer slice sentinel mismatch.zig b/test/cases/safety/pointer slice sentinel mismatch.zig
index 519b04b916..a400c0bc35 100644
--- a/test/cases/safety/pointer slice sentinel mismatch.zig
+++ b/test/cases/safety/pointer slice sentinel mismatch.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/remainder division by zero.zig b/test/cases/safety/remainder division by zero.zig
index 2d938a2fd6..3749c3d5d7 100644
--- a/test/cases/safety/remainder division by zero.zig
+++ b/test/cases/safety/remainder division by zero.zig
@@ -17,4 +17,4 @@ fn rem0(a: i32, b: i32) i32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/shift left by huge amount.zig b/test/cases/safety/shift left by huge amount.zig
index 374b03d123..b6b88ba870 100644
--- a/test/cases/safety/shift left by huge amount.zig
+++ b/test/cases/safety/shift left by huge amount.zig
@@ -19,4 +19,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/shift right by huge amount.zig b/test/cases/safety/shift right by huge amount.zig
index 173e6fcd7e..664e2b5473 100644
--- a/test/cases/safety/shift right by huge amount.zig
+++ b/test/cases/safety/shift right by huge amount.zig
@@ -19,4 +19,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/signed integer division overflow - vectors.zig b/test/cases/safety/signed integer division overflow - vectors.zig
index 0de062094d..7a696c4b4d 100644
--- a/test/cases/safety/signed integer division overflow - vectors.zig
+++ b/test/cases/safety/signed integer division overflow - vectors.zig
@@ -20,4 +20,4 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/signed integer division overflow.zig b/test/cases/safety/signed integer division overflow.zig
index 0d67f72649..acbb3d4e16 100644
--- a/test/cases/safety/signed integer division overflow.zig
+++ b/test/cases/safety/signed integer division overflow.zig
@@ -18,4 +18,4 @@ fn div(a: i16, b: i16) i16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig
index fa0eec94c0..f47083d4df 100644
--- a/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig
+++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig
index 6ce662cdc7..881b3c1631 100644
--- a/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig
+++ b/test/cases/safety/signed integer not fitting in cast to unsigned integer.zig
@@ -17,4 +17,4 @@ fn unsigned_cast(x: i32) u32 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/signed shift left overflow.zig b/test/cases/safety/signed shift left overflow.zig
index 54a51e0ccd..0cab01ca02 100644
--- a/test/cases/safety/signed shift left overflow.zig
+++ b/test/cases/safety/signed shift left overflow.zig
@@ -18,4 +18,4 @@ fn shl(a: i16, b: u4) i16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/signed shift right overflow.zig b/test/cases/safety/signed shift right overflow.zig
index 1a0c5973c9..9fe3fe7873 100644
--- a/test/cases/safety/signed shift right overflow.zig
+++ b/test/cases/safety/signed shift right overflow.zig
@@ -18,4 +18,4 @@ fn shr(a: i16, b: u4) i16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/signed-unsigned vector cast.zig b/test/cases/safety/signed-unsigned vector cast.zig
index 919562b06c..22d4073694 100644
--- a/test/cases/safety/signed-unsigned vector cast.zig
+++ b/test/cases/safety/signed-unsigned vector cast.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/slice by length sentinel mismatch on lhs.zig b/test/cases/safety/slice by length sentinel mismatch on lhs.zig
index c66a968d4b..85785ce769 100644
--- a/test/cases/safety/slice by length sentinel mismatch on lhs.zig
+++ b/test/cases/safety/slice by length sentinel mismatch on lhs.zig
@@ -15,4 +15,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice by length sentinel mismatch on rhs.zig b/test/cases/safety/slice by length sentinel mismatch on rhs.zig
index a4a2189a9c..64fe818d1e 100644
--- a/test/cases/safety/slice by length sentinel mismatch on rhs.zig
+++ b/test/cases/safety/slice by length sentinel mismatch on rhs.zig
@@ -15,4 +15,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice sentinel mismatch - floats.zig b/test/cases/safety/slice sentinel mismatch - floats.zig
index be63272f0c..b31855ab42 100644
--- a/test/cases/safety/slice sentinel mismatch - floats.zig
+++ b/test/cases/safety/slice sentinel mismatch - floats.zig
@@ -17,4 +17,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/slice sentinel mismatch - optional pointers.zig b/test/cases/safety/slice sentinel mismatch - optional pointers.zig
index 38ab78b2c1..4337fe448d 100644
--- a/test/cases/safety/slice sentinel mismatch - optional pointers.zig
+++ b/test/cases/safety/slice sentinel mismatch - optional pointers.zig
@@ -17,4 +17,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice slice sentinel mismatch.zig b/test/cases/safety/slice slice sentinel mismatch.zig
index 51d4c16596..76224f966d 100644
--- a/test/cases/safety/slice slice sentinel mismatch.zig
+++ b/test/cases/safety/slice slice sentinel mismatch.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice start index greater than end index.zig b/test/cases/safety/slice start index greater than end index.zig
index a6dde3ac63..684020b8a7 100644
--- a/test/cases/safety/slice start index greater than end index.zig
+++ b/test/cases/safety/slice start index greater than end index.zig
@@ -21,4 +21,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig
index 7039f541e3..b9ef281144 100644
--- a/test/cases/safety/slice with sentinel out of bounds - runtime len.zig
+++ b/test/cases/safety/slice with sentinel out of bounds - runtime len.zig
@@ -20,4 +20,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice with sentinel out of bounds.zig b/test/cases/safety/slice with sentinel out of bounds.zig
index 8439e8c737..f07d393a0e 100644
--- a/test/cases/safety/slice with sentinel out of bounds.zig
+++ b/test/cases/safety/slice with sentinel out of bounds.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice_cast_change_len_0.zig b/test/cases/safety/slice_cast_change_len_0.zig
index d32bdfc920..96d94cfad5 100644
--- a/test/cases/safety/slice_cast_change_len_0.zig
+++ b/test/cases/safety/slice_cast_change_len_0.zig
@@ -24,4 +24,4 @@ const std = @import("std");
// run
// backend=stage2,llvm
-// target=x86_64-linux
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice_cast_change_len_1.zig b/test/cases/safety/slice_cast_change_len_1.zig
index 5d3728bcdc..21a1d69558 100644
--- a/test/cases/safety/slice_cast_change_len_1.zig
+++ b/test/cases/safety/slice_cast_change_len_1.zig
@@ -24,4 +24,4 @@ const std = @import("std");
// run
// backend=stage2,llvm
-// target=x86_64-linux
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slice_cast_change_len_2.zig b/test/cases/safety/slice_cast_change_len_2.zig
index 3a25d27504..5da254e903 100644
--- a/test/cases/safety/slice_cast_change_len_2.zig
+++ b/test/cases/safety/slice_cast_change_len_2.zig
@@ -24,4 +24,4 @@ const std = @import("std");
// run
// backend=stage2,llvm
-// target=x86_64-linux
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slicing null C pointer - runtime len.zig b/test/cases/safety/slicing null C pointer - runtime len.zig
index 763553b04a..831224edee 100644
--- a/test/cases/safety/slicing null C pointer - runtime len.zig
+++ b/test/cases/safety/slicing null C pointer - runtime len.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/slicing null C pointer.zig b/test/cases/safety/slicing null C pointer.zig
index a928fd585f..53da877c59 100644
--- a/test/cases/safety/slicing null C pointer.zig
+++ b/test/cases/safety/slicing null C pointer.zig
@@ -17,4 +17,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/switch else on corrupt enum value - one prong.zig b/test/cases/safety/switch else on corrupt enum value - one prong.zig
index 73f6ed9dc8..b2ef933080 100644
--- a/test/cases/safety/switch else on corrupt enum value - one prong.zig
+++ b/test/cases/safety/switch else on corrupt enum value - one prong.zig
@@ -21,4 +21,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/switch else on corrupt enum value - union.zig b/test/cases/safety/switch else on corrupt enum value - union.zig
index 77dacd86c6..933f7995a5 100644
--- a/test/cases/safety/switch else on corrupt enum value - union.zig
+++ b/test/cases/safety/switch else on corrupt enum value - union.zig
@@ -26,4 +26,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/switch else on corrupt enum value.zig b/test/cases/safety/switch else on corrupt enum value.zig
index 228e3c70ec..300de27e93 100644
--- a/test/cases/safety/switch else on corrupt enum value.zig
+++ b/test/cases/safety/switch else on corrupt enum value.zig
@@ -20,4 +20,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/switch on corrupted enum value.zig b/test/cases/safety/switch on corrupted enum value.zig
index 4d46d2e7a7..74ec3a4057 100644
--- a/test/cases/safety/switch on corrupted enum value.zig
+++ b/test/cases/safety/switch on corrupted enum value.zig
@@ -24,4 +24,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/switch on corrupted union value.zig b/test/cases/safety/switch on corrupted union value.zig
index 0f622dcbd8..cede4feb04 100644
--- a/test/cases/safety/switch on corrupted union value.zig
+++ b/test/cases/safety/switch on corrupted union value.zig
@@ -24,4 +24,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/truncating vector cast.zig b/test/cases/safety/truncating vector cast.zig
index 9b222e6918..f6271a094e 100644
--- a/test/cases/safety/truncating vector cast.zig
+++ b/test/cases/safety/truncating vector cast.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/unreachable.zig b/test/cases/safety/unreachable.zig
index fc1e886540..1094123cba 100644
--- a/test/cases/safety/unreachable.zig
+++ b/test/cases/safety/unreachable.zig
@@ -12,4 +12,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig
index 185cde9973..7f27c5fcd5 100644
--- a/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig
+++ b/test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig
@@ -16,4 +16,4 @@ pub fn main() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/unsigned shift left overflow.zig b/test/cases/safety/unsigned shift left overflow.zig
index e2f58f0f3b..1098a80c8e 100644
--- a/test/cases/safety/unsigned shift left overflow.zig
+++ b/test/cases/safety/unsigned shift left overflow.zig
@@ -18,4 +18,4 @@ fn shl(a: u16, b: u4) u16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/unsigned shift right overflow.zig b/test/cases/safety/unsigned shift right overflow.zig
index 6ded52098d..e9ad8571b6 100644
--- a/test/cases/safety/unsigned shift right overflow.zig
+++ b/test/cases/safety/unsigned shift right overflow.zig
@@ -18,4 +18,4 @@ fn shr(a: u16, b: u4) u16 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/unsigned-signed vector cast.zig b/test/cases/safety/unsigned-signed vector cast.zig
index 6501643b36..5b3b58d928 100644
--- a/test/cases/safety/unsigned-signed vector cast.zig
+++ b/test/cases/safety/unsigned-signed vector cast.zig
@@ -18,4 +18,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/unwrap error switch.zig b/test/cases/safety/unwrap error switch.zig
index b3194bd2e0..a1a148cfd9 100644
--- a/test/cases/safety/unwrap error switch.zig
+++ b/test/cases/safety/unwrap error switch.zig
@@ -18,4 +18,4 @@ fn bar() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/unwrap error.zig b/test/cases/safety/unwrap error.zig
index 9fe7d437bc..dd157c8721 100644
--- a/test/cases/safety/unwrap error.zig
+++ b/test/cases/safety/unwrap error.zig
@@ -16,4 +16,4 @@ fn bar() !void {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/value does not fit in shortening cast - u0.zig b/test/cases/safety/value does not fit in shortening cast - u0.zig
index f29df8d8af..9d77b3f1c8 100644
--- a/test/cases/safety/value does not fit in shortening cast - u0.zig
+++ b/test/cases/safety/value does not fit in shortening cast - u0.zig
@@ -18,4 +18,4 @@ fn shorten_cast(x: u8) u0 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/value does not fit in shortening cast.zig b/test/cases/safety/value does not fit in shortening cast.zig
index 415ac95dbb..9b6af39967 100644
--- a/test/cases/safety/value does not fit in shortening cast.zig
+++ b/test/cases/safety/value does not fit in shortening cast.zig
@@ -18,4 +18,4 @@ fn shorten_cast(x: i32) i8 {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/safety/vector integer addition overflow.zig b/test/cases/safety/vector integer addition overflow.zig
index db08d8b241..64f6e238e0 100644
--- a/test/cases/safety/vector integer addition overflow.zig
+++ b/test/cases/safety/vector integer addition overflow.zig
@@ -19,4 +19,4 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/vector integer multiplication overflow.zig b/test/cases/safety/vector integer multiplication overflow.zig
index 61176fd482..69d0dde16d 100644
--- a/test/cases/safety/vector integer multiplication overflow.zig
+++ b/test/cases/safety/vector integer multiplication overflow.zig
@@ -19,4 +19,4 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/vector integer negation overflow.zig b/test/cases/safety/vector integer negation overflow.zig
index f1f36ff294..72182cfdfc 100644
--- a/test/cases/safety/vector integer negation overflow.zig
+++ b/test/cases/safety/vector integer negation overflow.zig
@@ -19,4 +19,4 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/vector integer subtraction overflow.zig b/test/cases/safety/vector integer subtraction overflow.zig
index 9ba942469c..8ac2c6d756 100644
--- a/test/cases/safety/vector integer subtraction overflow.zig
+++ b/test/cases/safety/vector integer subtraction overflow.zig
@@ -19,4 +19,4 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/cases/safety/zero casted to error.zig b/test/cases/safety/zero casted to error.zig
index 1ffa995260..7a02ec2b71 100644
--- a/test/cases/safety/zero casted to error.zig
+++ b/test/cases/safety/zero casted to error.zig
@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
}
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux,aarch64-linux
diff --git a/test/cases/taking_pointer_of_global_tagged_union.zig b/test/cases/taking_pointer_of_global_tagged_union.zig
index accb22667d..adc71d81c0 100644
--- a/test/cases/taking_pointer_of_global_tagged_union.zig
+++ b/test/cases/taking_pointer_of_global_tagged_union.zig
@@ -23,4 +23,4 @@ pub fn main() !void {
// run
// backend=stage2,llvm
-// target=native
+// target=x86_64-linux
diff --git a/test/incremental/change_panic_handler b/test/incremental/change_panic_handler
index 699134100e..3e400b854e 100644
--- a/test/incremental/change_panic_handler
+++ b/test/incremental/change_panic_handler
@@ -1,4 +1,3 @@
-#target=x86_64-linux-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#update=initial version
diff --git a/test/incremental/change_panic_handler_explicit b/test/incremental/change_panic_handler_explicit
index 2d068d593e..9f7eb6c12f 100644
--- a/test/incremental/change_panic_handler_explicit
+++ b/test/incremental/change_panic_handler_explicit
@@ -1,4 +1,3 @@
-#target=x86_64-linux-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#update=initial version
diff --git a/test/incremental/type_becomes_comptime_only b/test/incremental/type_becomes_comptime_only
index 3bcae1cd21..5c5d332975 100644
--- a/test/incremental/type_becomes_comptime_only
+++ b/test/incremental/type_becomes_comptime_only
@@ -1,4 +1,3 @@
-#target=x86_64-linux-selfhosted
#target=x86_64-linux-cbe
#target=x86_64-windows-cbe
#target=wasm32-wasi-selfhosted
diff --git a/test/link/build.zig.zon b/test/link/build.zig.zon
index 16bba08c4e..ab44726091 100644
--- a/test/link/build.zig.zon
+++ b/test/link/build.zig.zon
@@ -1,5 +1,6 @@
.{
- .name = "link_test_cases",
+ .name = .link_test_cases,
+ .fingerprint = 0x404f657576fec9f2,
.version = "0.0.0",
.dependencies = .{
.bss = .{
diff --git a/test/link/elf.zig b/test/link/elf.zig
index f6dfbbea86..1d6de32f0d 100644
--- a/test/link/elf.zig
+++ b/test/link/elf.zig
@@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.addObject(obj);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
\\
,
});
- main_o.linkLibC();
+ main_o.root_module.link_libc = true;
const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });
addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});
@@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
const exe = addExecutable(b, opts, .{
.name = "test",
});
- exe.addObject(main_o);
- exe.linkSystemLibrary2("foo", .{ .needed = true });
- exe.addLibraryPath(libfoo.getEmittedBinDirectory());
- exe.addRPath(libfoo.getEmittedBinDirectory());
- exe.linkSystemLibrary2("bar", .{ .needed = true });
- exe.addLibraryPath(libbar.getEmittedBinDirectory());
- exe.addRPath(libbar.getEmittedBinDirectory());
- exe.linkSystemLibrary2("baz", .{ .needed = true });
- exe.addLibraryPath(libbaz.getEmittedBinDirectory());
- exe.addRPath(libbaz.getEmittedBinDirectory());
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkSystemLibrary("foo", .{ .needed = true });
+ exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
+ exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
+ exe.root_module.linkSystemLibrary("bar", .{ .needed = true });
+ exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
+ exe.root_module.addRPath(libbar.getEmittedBinDirectory());
+ exe.root_module.linkSystemLibrary("baz", .{ .needed = true });
+ exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
+ exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("42\n");
@@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
const exe = addExecutable(b, opts, .{
.name = "test",
});
- exe.addObject(main_o);
- exe.linkSystemLibrary2("foo", .{ .needed = false });
- exe.addLibraryPath(libfoo.getEmittedBinDirectory());
- exe.addRPath(libfoo.getEmittedBinDirectory());
- exe.linkSystemLibrary2("bar", .{ .needed = false });
- exe.addLibraryPath(libbar.getEmittedBinDirectory());
- exe.addRPath(libbar.getEmittedBinDirectory());
- exe.linkSystemLibrary2("baz", .{ .needed = false });
- exe.addLibraryPath(libbaz.getEmittedBinDirectory());
- exe.addRPath(libbaz.getEmittedBinDirectory());
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkSystemLibrary("foo", .{ .needed = false });
+ exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
+ exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
+ exe.root_module.linkSystemLibrary("bar", .{ .needed = false });
+ exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
+ exe.root_module.addRPath(libbar.getEmittedBinDirectory());
+ exe.root_module.linkSystemLibrary("baz", .{ .needed = false });
+ exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
+ exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("42\n");
@@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
,
.pic = false,
});
- main_o.linkLibC();
+ main_o.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{
.name = "main",
});
- exe.addObject(main_o);
- exe.addObject(b_o);
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
exe.pie = false;
const run = addRunArtifact(exe);
@@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
\\}
,
});
- a_o.linkLibCpp();
+ a_o.root_module.link_libcpp = true;
const main_o = addObject(b, opts, .{
.name = "main",
@@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
\\}
,
});
- main_o.linkLibCpp();
+ main_o.root_module.link_libcpp = true;
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(a_o);
- exe.addObject(main_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(main_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(
@@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
- exe.addObject(a_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(
@@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
{
const c_o = addObject(b, opts, .{ .name = "c" });
- c_o.addObject(main_o);
- c_o.addObject(a_o);
+ c_o.root_module.addObject(main_o);
+ c_o.root_module.addObject(a_o);
const exe = addExecutable(b, opts, .{ .name = "main3" });
- exe.addObject(c_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(c_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(
@@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
{
const d_o = addObject(b, opts, .{ .name = "d" });
- d_o.addObject(a_o);
- d_o.addObject(main_o);
+ d_o.root_module.addObject(a_o);
+ d_o.root_module.addObject(main_o);
const exe = addExecutable(b, opts, .{ .name = "main4" });
- exe.addObject(d_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(d_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(
@@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step {
\\ printf("%d %d %d\n", foo, bar, baz);
\\}
, &.{"-fcommon"});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("0 5 42\n");
@@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
,
.c_source_flags = &.{"-fcommon"},
});
- a_o.linkLibC();
+ a_o.root_module.link_libc = true;
const b_o = addObject(b, opts, .{
.name = "b",
@@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
});
const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
- lib.addObject(b_o);
- lib.addObject(c_o);
- lib.addObject(d_o);
+ lib.root_module.addObject(b_o);
+ lib.root_module.addObject(c_o);
+ lib.root_module.addObject(d_o);
const exe = addExecutable(b, opts, .{
.name = "test",
});
- exe.addObject(a_o);
- exe.linkLibrary(lib);
- exe.linkLibC();
+ exe.root_module.addObject(a_o);
+ exe.root_module.linkLibrary(lib);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("5 0 0 -1\n");
@@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
});
const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
- lib.addObject(b_o);
- lib.addObject(e_o);
+ lib.root_module.addObject(b_o);
+ lib.root_module.addObject(e_o);
const exe = addExecutable(b, opts, .{
.name = "test",
});
- exe.addObject(a_o);
- exe.linkLibrary(lib);
- exe.linkLibC();
+ exe.root_module.addObject(a_o);
+ exe.root_module.linkLibrary(lib);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("5 0 7 2\n");
@@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("3 5\n");
@@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step {
\\extern int bar;
\\int *get_bar() { return &bar; }
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
exe.pie = false;
const run = addRunArtifact(exe);
@@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
,
.pic = false,
});
- obj.linkLibC();
+ obj.root_module.link_libc = true;
const exp_stdout = "5\n";
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(obj);
- exe.linkLibrary(a_so);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.linkLibrary(a_so);
+ exe.root_module.link_libc = true;
exe.pie = false;
const run = addRunArtifact(exe);
@@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(obj);
- exe.linkLibrary(b_so);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.linkLibrary(b_so);
+ exe.root_module.link_libc = true;
exe.pie = false;
const run = addRunArtifact(exe);
@@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(obj);
- exe.linkLibrary(c_so);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.linkLibrary(c_so);
+ exe.root_module.link_libc = true;
exe.pie = false;
const run = addRunArtifact(exe);
@@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
\\ real_hello();
\\}
, &.{});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{ .name = "test" });
addCSourceBytes(exe,
@@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
\\ hello();
\\}
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello WORLD\n");
@@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
\\int bar = 5;
\\int baz() { return foo; }
, &.{});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const obj = addObject(b, opts, .{
.name = "obj",
@@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
});
const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
- lib.addObject(obj);
+ lib.root_module.addObject(obj);
const exe = addExecutable(b, opts, .{ .name = "test" });
- exe.linkLibrary(dso);
- exe.linkLibrary(lib);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.linkLibrary(lib);
addCSourceBytes(exe,
\\extern int bar;
\\int main() {
\\ return bar - 5;
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
\\ std.debug.print("foo={d}\n", .{foo()});
\\}
});
- a_o.linkLibC();
+ a_o.root_module.link_libc = true;
const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes =
\\#include
@@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
\\ fprintf(stderr, "bar=%d\n", bar);
\\}
});
- b_o.linkLibC();
+ b_o.root_module.link_libc = true;
const c_o = addObject(b, opts, .{ .name = "c" });
- c_o.addObject(a_o);
- c_o.addObject(b_o);
+ c_o.root_module.addObject(a_o);
+ c_o.root_module.addObject(b_o);
const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes =
\\const std = @import("std");
@@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
\\ printBar();
\\}
});
- exe.addObject(c_o);
- exe.linkLibC();
+ exe.root_module.addObject(c_o);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdErrEqual(
@@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {
});
const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
- lib.addObject(obj1);
- lib.addObject(obj2);
- lib.addObject(obj3);
+ lib.root_module.addObject(obj1);
+ lib.root_module.addObject(obj2);
+ lib.root_module.addObject(obj3);
const check = lib.checkObject();
check.checkInArchiveSymtab();
@@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
\\}
,
});
- lib.addObject(obj1);
+ lib.root_module.addObject(obj1);
const exe = addExecutable(b, opts, .{
.name = "test",
@@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.linkLibrary(lib);
+ exe.root_module.linkLibrary(lib);
const run = addRunArtifact(exe);
run.expectStdErrEqual("44");
@@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
const exe = addExecutable(b, opts, .{ .name = "test" });
addCSourceBytes(exe, "int main() { return 0; }", &.{});
addCSourceBytes(exe, "", &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(a_o);
- exe.addObject(b_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
exe.entry = .{ .symbol_name = "foo" };
const check = exe.checkObject();
@@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
// cause an artifact collision taking the cached executable from the above
// step instead of generating a new one.
const exe = addExecutable(b, opts, .{ .name = "other" });
- exe.addObject(a_o);
- exe.addObject(b_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
exe.entry = .{ .symbol_name = "bar" };
const check = exe.checkObject();
@@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step {
\\ return baz;
\\}
, &.{});
- exe.addObject(obj);
- exe.linkLibrary(dso);
+ exe.root_module.addObject(obj);
+ exe.root_module.linkLibrary(dso);
exe.rdynamic = true;
const check = exe.checkObject();
@@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {
\\ foo();
\\}
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInDynamicSymtab();
@@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step {
\\ assert(fn == ptr);
\\}
, &.{});
- exe.linkLibrary(dso);
+ exe.root_module.linkLibrary(dso);
exe.root_module.pic = false;
exe.pie = false;
@@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step {
});
obj.link_function_sections = true;
obj.link_data_sections = true;
- obj.linkLibC();
- obj.linkLibCpp();
+ obj.root_module.link_libc = true;
+ obj.root_module.link_libcpp = true;
{
const exe = addExecutable(b, opts, .{ .name = "test" });
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.link_gc_sections = false;
- exe.linkLibC();
- exe.linkLibCpp();
+ exe.root_module.link_libc = true;
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("1 2\n");
@@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "test" });
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.link_gc_sections = true;
- exe.linkLibC();
- exe.linkLibCpp();
+ exe.root_module.link_libc = true;
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("1 2\n");
@@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.link_gc_sections = false;
const run = addRunArtifact(exe);
@@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.link_gc_sections = true;
const run = addRunArtifact(exe);
@@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step {
\\}
, &.{});
exe.root_module.pic = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {
\\ assert(foo == p);
\\}
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
- exe.linkSystemLibrary2("dl", .{});
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
+ exe.root_module.linkSystemLibrary("dl", .{});
exe.root_module.pic = false;
exe.pie = false;
@@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
\\}
,
});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{
.name = "main",
@@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.linkLibrary(dso);
+ exe.root_module.linkLibrary(dso);
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello world\n");
@@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe, main_c, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
exe.link_z_lazy = true;
const run = addRunArtifact(exe);
@@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "other" });
addCSourceBytes(exe, main_c, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello world\n");
@@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step {
\\ return real_foobar;
\\}
, &.{});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const check = dso.checkObject();
check.checkInDynamicSymtab();
@@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {
\\}
, &.{});
exe.root_module.pic = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("3\n");
@@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step {
\\}
, &.{"-fno-plt"});
exe.root_module.pic = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello world\n");
@@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
exe.linkage = .static;
const run = addRunArtifact(exe);
@@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
exe.linkage = .static;
exe.root_module.pic = true;
exe.pie = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello world\n");
@@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
exe.image_base = 0x8000000;
const run = addRunArtifact(exe);
@@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
\\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }
,
});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const main = addExecutable(b, opts, .{
.name = "main",
@@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
.strip = true, // TODO temp hack
});
main.pie = true;
- main.linkLibrary(dso);
+ main.root_module.linkLibrary(dso);
const run = addRunArtifact(main);
run.expectStdErrEqual(
@@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
}, .{
.name = "a",
});
- lib.addObject(obj);
+ lib.root_module.addObject(obj);
const main = addExecutable(b, opts, .{
.name = "main",
@@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
,
.strip = true, // TODO temp hack
});
- main.linkLibrary(lib);
- main.linkLibC();
+ main.root_module.linkLibrary(lib);
+ main.root_module.link_libc = true;
const run = addRunArtifact(main);
run.expectStdErrEqual("42\n");
@@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
\\__attribute__((constructor(10000))) void init4() { printf("1"); }
,
});
- a_o.linkLibC();
+ a_o.root_module.link_libc = true;
const b_o = addObject(b, opts, .{
.name = "b",
@@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
\\__attribute__((constructor(1000))) void init3() { printf("2"); }
,
});
- b_o.linkLibC();
+ b_o.root_module.link_libc = true;
const c_o = addObject(b, opts, .{
.name = "c",
@@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
\\__attribute__((constructor)) void init1() { printf("3"); }
,
});
- c_o.linkLibC();
+ c_o.root_module.link_libc = true;
const d_o = addObject(b, opts, .{
.name = "d",
@@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
\\__attribute__((constructor)) void init2() { printf("4"); }
,
});
- d_o.linkLibC();
+ d_o.root_module.link_libc = true;
const e_o = addObject(b, opts, .{
.name = "e",
@@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
\\__attribute__((destructor(10000))) void fini4() { printf("5"); }
,
});
- e_o.linkLibC();
+ e_o.root_module.link_libc = true;
const f_o = addObject(b, opts, .{
.name = "f",
@@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
\\__attribute__((destructor(1000))) void fini3() { printf("6"); }
,
});
- f_o.linkLibC();
+ f_o.root_module.link_libc = true;
const g_o = addObject(b, opts, .{
.name = "g",
@@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
\\__attribute__((destructor)) void fini1() { printf("7"); }
,
});
- g_o.linkLibC();
+ g_o.root_module.link_libc = true;
const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes =
\\#include
\\__attribute__((destructor)) void fini2() { printf("8"); }
});
- h_o.linkLibC();
+ h_o.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe, "int main() { return 0; }", &.{});
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(c_o);
- exe.addObject(d_o);
- exe.addObject(e_o);
- exe.addObject(f_o);
- exe.addObject(g_o);
- exe.addObject(h_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(c_o);
+ exe.root_module.addObject(d_o);
+ exe.root_module.addObject(e_o);
+ exe.root_module.addObject(f_o);
+ exe.root_module.addObject(g_o);
+ exe.root_module.addObject(h_o);
if (opts.target.result.isGnuLibC()) {
// TODO I think we need to clarify our use of `-fPIC -fPIE` flags for different targets
@@ -1970,7 +1970,7 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
\\}
, &.{});
dso.link_function_sections = true;
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const check = dso.checkObject();
check.checkInSymtab();
@@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
\\void greet();
\\int main() { greet(); }
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello world");
@@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {
\\}
, &.{});
exe.link_function_sections = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInSymtab();
@@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step {
\\ return arr[2000];
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
// Disabled to work around the ELF linker crashing.
// Can be reproduced on a x86_64-linux host by commenting out the line below.
exe.root_module.sanitize_c = .off;
@@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
});
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(obj);
+ dso.root_module.addObject(obj);
const lib = addStaticLibrary(b, opts, .{ .name = "b" });
- lib.addObject(obj);
+ lib.root_module.addObject(obj);
const main_o = addObject(b, opts, .{
.name = "main",
@@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
// https://github.com/ziglang/zig/issues/17450
// {
// const exe = addExecutable(b, opts, .{ .name = "main1"});
- // exe.addObject(main_o);
- // exe.linkSystemLibrary2("a", .{});
- // exe.addLibraryPath(dso.getEmittedBinDirectory());
- // exe.addRPath(dso.getEmittedBinDirectory());
- // exe.linkSystemLibrary2("b", .{});
- // exe.addLibraryPath(lib.getEmittedBinDirectory());
- // exe.addRPath(lib.getEmittedBinDirectory());
- // exe.linkLibC();
+ // exe.root_module.addObject(main_o);
+ // exe.root_module.linkSystemLibrary("a", .{});
+ // exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
+ // exe.root_module.addRPath(dso.getEmittedBinDirectory());
+ // exe.root_module.linkSystemLibrary("b", .{});
+ // exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
+ // exe.root_module.addRPath(lib.getEmittedBinDirectory());
+ // exe.root_module.link_libc = true;
// const check = exe.checkObject();
// check.checkInDynamicSection();
@@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
- exe.linkSystemLibrary2("b", .{});
- exe.addLibraryPath(lib.getEmittedBinDirectory());
- exe.addRPath(lib.getEmittedBinDirectory());
- exe.linkSystemLibrary2("a", .{});
- exe.addLibraryPath(dso.getEmittedBinDirectory());
- exe.addRPath(dso.getEmittedBinDirectory());
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkSystemLibrary("b", .{});
+ exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
+ exe.root_module.addRPath(lib.getEmittedBinDirectory());
+ exe.root_module.linkSystemLibrary("a", .{});
+ exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
+ exe.root_module.addRPath(dso.getEmittedBinDirectory());
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInDynamicSection();
@@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step {
\\ return bar() - baz();
\\}
, &.{});
- exe.linkSystemLibrary2("a", .{});
- exe.addLibraryPath(scripts.getDirectory());
- exe.addLibraryPath(scripts2.getDirectory());
- exe.addLibraryPath(bar.getEmittedBinDirectory());
- exe.addLibraryPath(baz.getEmittedBinDirectory());
- exe.addRPath(bar.getEmittedBinDirectory());
- exe.addRPath(baz.getEmittedBinDirectory());
- exe.linkLibC();
+ exe.root_module.linkSystemLibrary("a", .{});
+ exe.root_module.addLibraryPath(scripts.getDirectory());
+ exe.root_module.addLibraryPath(scripts2.getDirectory());
+ exe.root_module.addLibraryPath(bar.getEmittedBinDirectory());
+ exe.root_module.addLibraryPath(baz.getEmittedBinDirectory());
+ exe.root_module.addRPath(bar.getEmittedBinDirectory());
+ exe.root_module.addRPath(baz.getEmittedBinDirectory());
+ exe.root_module.link_libc = true;
exe.allow_so_scripts = true;
const run = addRunArtifact(exe);
@@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe, "int main() { return 0; }", &.{});
- exe.linkSystemLibrary2("a", .{});
- exe.addLibraryPath(scripts.getDirectory());
- exe.linkLibC();
+ exe.root_module.linkSystemLibrary("a", .{});
+ exe.root_module.addLibraryPath(scripts.getDirectory());
+ exe.root_module.link_libc = true;
exe.allow_so_scripts = true;
// TODO: A future enhancement could make this error message also mention
@@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.linkLibrary(so);
- exe.linkLibC();
+ exe.root_module.linkLibrary(so);
+ exe.root_module.link_libc = true;
exe.allow_so_scripts = true;
const run = addRunArtifact(exe);
@@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {
\\ return foo;
\\}
, &.{});
- exe.addObject(obj);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.link_libc = true;
expectLinkErrors(exe, test_step, .{ .exact = &.{
"invalid ELF machine type: AARCH64",
@@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello World!\n");
@@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibC();
- exe.linkLibCpp();
+ exe.root_module.link_libc = true;
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello World!\n");
@@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
const run = addRunArtifact(exe);
run.expectStdErrEqual("84\n");
@@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
\\}
,
});
- lib.addObject(obj);
+ lib.root_module.addObject(obj);
const exe = addExecutable(b, opts, .{
.name = "testlib",
@@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.linkLibrary(lib);
+ exe.root_module.linkLibrary(lib);
const run = addRunArtifact(exe);
run.expectStdErrEqual("0\n");
@@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
\\char16_t *utf16_1 = u"foo";
\\char32_t *utf32_1 = U"foo";
, &.{"-O2"});
- obj1.linkLibC();
+ obj1.root_module.link_libc = true;
const obj2 = addObject(b, opts, .{ .name = "b.o" });
addCSourceBytes(obj2,
@@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
\\ assert((void*)wide1 != (void*)utf16_1);
\\}
, &.{"-O2"});
- obj2.linkLibC();
+ obj2.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(obj1);
- exe.addObject(obj2);
- exe.linkLibC();
+ exe.root_module.addObject(obj1);
+ exe.root_module.addObject(obj2);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(obj1);
- exe.addObject(obj2);
+ exe.root_module.addObject(obj1);
+ exe.root_module.addObject(obj2);
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
{
const obj3 = addObject(b, opts, .{ .name = "c" });
- obj3.addObject(obj1);
- obj3.addObject(obj2);
+ obj3.root_module.addObject(obj1);
+ obj3.root_module.addObject(obj2);
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(obj3);
+ exe.root_module.addObject(obj3);
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe, "int main() { return 0; }", &.{});
exe.link_eh_frame_hdr = false;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInHeaders();
@@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
exe.root_module.pic = true;
exe.pie = true;
@@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step {
\\ printf("Hello world\n");
\\}
, &.{});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe,
@@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step {
\\void foo() { ignore(hello); }
\\int main() { hello(); }
, &.{});
- exe.linkLibrary(dso);
+ exe.root_module.linkLibrary(dso);
exe.root_module.pic = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello world\n");
@@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
});
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
const check = exe.checkObject();
check.checkInDynamicSection();
@@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
\\__attribute__((section(".preinit_array")))
\\void *preinit[] = { preinit_fn };
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInDynamicSection();
@@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step {
});
const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
- lib.addObject(obj1);
- lib.addObject(obj2);
- lib.addObject(obj3);
+ lib.root_module.addObject(obj1);
+ lib.root_module.addObject(obj2);
+ lib.root_module.addObject(obj3);
const obj5 = addObject(b, opts, .{
.name = "obj5",
});
- obj5.addObject(obj4);
- obj5.linkLibrary(lib);
+ obj5.root_module.addObject(obj4);
+ obj5.root_module.linkLibrary(lib);
const check = obj5.checkObject();
check.checkInSymtab();
@@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
\\}
,
});
- obj1.linkLibCpp();
+ obj1.root_module.link_libcpp = true;
const obj2 = addObject(b, opts, .{
.name = "obj2",
.cpp_source_bytes =
@@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
\\}
,
});
- obj2.linkLibCpp();
+ obj2.root_module.link_libcpp = true;
const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes =
\\#include
\\#include
@@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
});
- obj3.linkLibCpp();
+ obj3.root_module.link_libcpp = true;
{
const obj = addObject(b, opts, .{ .name = "obj" });
- obj.addObject(obj1);
- obj.addObject(obj2);
- obj.linkLibCpp();
+ obj.root_module.addObject(obj1);
+ obj.root_module.addObject(obj2);
+ obj.root_module.link_libcpp = true;
const exe = addExecutable(b, opts, .{ .name = "test1" });
- exe.addObject(obj3);
- exe.addObject(obj);
- exe.linkLibCpp();
+ exe.root_module.addObject(obj3);
+ exe.root_module.addObject(obj);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("exception=Oh no!");
@@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
{
// Flipping the order should not influence the end result.
const obj = addObject(b, opts, .{ .name = "obj" });
- obj.addObject(obj2);
- obj.addObject(obj1);
- obj.linkLibCpp();
+ obj.root_module.addObject(obj2);
+ obj.root_module.addObject(obj1);
+ obj.root_module.link_libcpp = true;
const exe = addExecutable(b, opts, .{ .name = "test2" });
- exe.addObject(obj3);
- exe.addObject(obj);
- exe.linkLibCpp();
+ exe.root_module.addObject(obj3);
+ exe.root_module.addObject(obj);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("exception=Oh no!");
@@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
\\}
,
});
- obj1.linkLibCpp();
+ obj1.root_module.link_libcpp = true;
const obj2 = addObject(b, opts, .{
.name = "obj2",
.cpp_source_bytes =
@@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
\\}
,
});
- obj2.linkLibCpp();
+ obj2.root_module.link_libcpp = true;
const obj3 = addObject(b, opts, .{
.name = "obj3",
.cpp_source_bytes =
@@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
\\}
,
});
- obj3.linkLibCpp();
+ obj3.root_module.link_libcpp = true;
const obj = addObject(b, opts, .{ .name = "obj" });
- obj.addObject(obj1);
- obj.addObject(obj2);
- obj.addObject(obj3);
- obj.linkLibCpp();
+ obj.root_module.addObject(obj1);
+ obj.root_module.addObject(obj2);
+ obj.root_module.addObject(obj3);
+ obj.root_module.link_libcpp = true;
const exe = addExecutable(b, opts, .{ .name = "test2" });
- exe.addObject(obj);
- exe.linkLibCpp();
+ exe.root_module.addObject(obj);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("exception=Oh no!");
@@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {
});
const obj2 = addObject(b, opts, .{ .name = "b" });
- obj2.addObject(obj1);
+ obj2.root_module.addObject(obj1);
const check = obj2.checkObject();
check.dumpSection(".rodata.str1.1");
@@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
const obj2 = addObject(b, opts, .{
.name = "obj2",
});
- obj2.addObject(obj1);
+ obj2.root_module.addObject(obj1);
const check1 = obj1.checkObject();
check1.checkInHeaders();
@@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
,
.pic = true,
});
- obj.linkLibC();
+ obj.root_module.link_libc = true;
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(obj);
- exe.linkLibrary(dso);
+ exe.root_module.addObject(obj);
+ exe.root_module.linkLibrary(dso);
exe.pie = true;
const run = addRunArtifact(exe);
@@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
// https://github.com/ziglang/zig/issues/17430
// {
// const exe = addExecutable(b, opts, .{ .name = "main2"});
- // exe.addObject(obj);
- // exe.linkLibrary(dso);
+ // exe.root_module.addObject(obj);
+ // exe.root_module.linkLibrary(dso);
// exe.pie = false;
// const run = addRunArtifact(exe);
@@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step {
\\}
,
});
- obj.linkLibC();
+ obj.root_module.link_libc = true;
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.root_module.strip = false;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInHeaders();
@@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.root_module.strip = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInHeaders();
@@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
{
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(obj);
+ dso.root_module.addObject(obj);
// dso.link_relax = true;
const check = dso.checkObject();
@@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
// TODO add -Wl,--no-relax
// {
// const dso = addSharedLibrary(b, opts, .{ .name = "a"});
- // dso.addObject(obj);
+ // dso.root_module.addObject(obj);
// dso.link_relax = false;
// const check = dso.checkObject();
@@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("5 3 5 3 5 3\n");
@@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
,
.pic = true,
});
- main_o.linkLibC();
+ main_o.root_module.link_libc = true;
const a_o = addObject(b, opts, .{
.name = "a",
@@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
const exp_stdout = "1 2 3 4 5 6\n";
const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });
- dso1.addObject(a_o);
+ dso1.root_module.addObject(a_o);
const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });
- dso2.addObject(b_o);
+ dso2.root_module.addObject(b_o);
// dso2.link_relax = false; // TODO
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
- exe.linkLibrary(dso1);
- exe.linkLibrary(dso2);
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkLibrary(dso1);
+ exe.root_module.linkLibrary(dso2);
const run = addRunArtifact(exe);
run.expectStdOutEqual(exp_stdout);
@@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
+ exe.root_module.addObject(main_o);
// exe.link_relax = false; // TODO
- exe.linkLibrary(dso1);
- exe.linkLibrary(dso2);
+ exe.root_module.linkLibrary(dso1);
+ exe.root_module.linkLibrary(dso2);
const run = addRunArtifact(exe);
run.expectStdOutEqual(exp_stdout);
@@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
// https://github.com/ziglang/zig/issues/17430 ??
// {
// const exe = addExecutable(b, opts, .{ .name = "main3"});
- // exe.addObject(main_o);
- // exe.linkLibrary(dso1);
- // exe.linkLibrary(dso2);
+ // exe.root_module.addObject(main_o);
+ // exe.root_module.linkLibrary(dso1);
+ // exe.root_module.linkLibrary(dso2);
// exe.linkage = .static;
// const run = addRunArtifact(exe);
@@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
// {
// const exe = addExecutable(b, opts, .{ .name = "main4"});
- // exe.addObject(main_o);
+ // exe.root_module.addObject(main_o);
// // exe.link_relax = false; // TODO
- // exe.linkLibrary(dso1);
- // exe.linkLibrary(dso2);
+ // exe.root_module.linkLibrary(dso1);
+ // exe.root_module.linkLibrary(dso2);
// exe.linkage = .static;
// const run = addRunArtifact(exe);
@@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
.c_source_flags = &.{"-fno-plt"},
.pic = true,
});
- obj.linkLibC();
+ obj.root_module.link_libc = true;
const a_so = addSharedLibrary(b, opts, .{ .name = "a" });
addCSourceBytes(a_so,
@@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(obj);
- exe.linkLibrary(a_so);
- exe.linkLibrary(b_so);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.linkLibrary(a_so);
+ exe.root_module.linkLibrary(b_so);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("1 2 3 4 5 6\n");
@@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(obj);
- exe.linkLibrary(a_so);
- exe.linkLibrary(b_so);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.linkLibrary(a_so);
+ exe.root_module.linkLibrary(b_so);
+ exe.root_module.link_libc = true;
// exe.link_relax = false; // TODO
const run = addRunArtifact(exe);
@@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
,
.pic = true,
});
- a_o.linkLibC();
+ a_o.root_module.link_libc = true;
const b_o = addObject(b, opts, .{
.name = "b",
@@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
{
const dso = addSharedLibrary(b, opts, .{ .name = "a1" });
- dso.addObject(a_o);
+ dso.root_module.addObject(a_o);
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(b_o);
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.addObject(b_o);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("1 2 3\n");
@@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
{
const dso = addSharedLibrary(b, opts, .{ .name = "a2" });
- dso.addObject(a_o);
+ dso.root_module.addObject(a_o);
// dso.link_relax = false; // TODO
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(b_o);
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.addObject(b_o);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("1 2 3\n");
@@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
// {
// const dso = addSharedLibrary(b, opts, .{ .name = "a"});
- // dso.addObject(a_o);
+ // dso.root_module.addObject(a_o);
// dso.link_z_nodlopen = true;
// const exe = addExecutable(b, opts, .{ .name = "main"});
- // exe.addObject(b_o);
- // exe.linkLibrary(dso);
+ // exe.root_module.addObject(b_o);
+ // exe.root_module.linkLibrary(dso);
// const run = addRunArtifact(exe);
// run.expectStdOutEqual("1 2 3\n");
@@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
// {
// const dso = addSharedLibrary(b, opts, .{ .name = "a"});
- // dso.addObject(a_o);
+ // dso.root_module.addObject(a_o);
// dso.link_relax = false;
// dso.link_z_nodlopen = true;
// const exe = addExecutable(b, opts, .{ .name = "main"});
- // exe.addObject(b_o);
- // exe.linkLibrary(dso);
+ // exe.root_module.addObject(b_o);
+ // exe.root_module.linkLibrary(dso);
// const run = addRunArtifact(exe);
// run.expectStdOutEqual("1 2 3\n");
@@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
\\ printf("%d %d ", foo, bar);
\\}
, &.{});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const main_o = addObject(b, opts, .{
.name = "main",
@@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
\\}
,
});
- main_o.linkLibC();
+ main_o.root_module.link_libc = true;
const exp_stdout = "0 0 3 5 7\n";
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(exp_stdout);
@@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
// exe.link_relax = false; // TODO
const run = addRunArtifact(exe);
@@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
,
.pic = true,
});
- c_o.linkLibC();
+ c_o.root_module.link_libc = true;
{
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(a_o);
- dso.addObject(b_o);
+ dso.root_module.addObject(a_o);
+ dso.root_module.addObject(b_o);
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(c_o);
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.addObject(c_o);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("42 1 2 3\n");
@@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(c_o);
- exe.linkLibC();
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(c_o);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("42 1 2 3\n");
@@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step {
\\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
// Disabled to work around the ELF linker crashing.
// Can be reproduced on a x86_64-linux host by commenting out the line below.
exe.root_module.sanitize_c = .off;
@@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {
\\}
, &.{});
exe.root_module.pic = true;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("1 2 3 0 5\n");
@@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
.c_source_flags = &.{"-ftls-model=local-dynamic"},
.pic = true,
});
- main_o.linkLibC();
+ main_o.root_module.link_libc = true;
const a_o = addObject(b, opts, .{
.name = "a",
@@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
- exe.addObject(a_o);
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(exp_stdout);
@@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
- exe.addObject(a_o);
- exe.linkLibC();
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.link_libc = true;
// exe.link_relax = false; // TODO
const run = addRunArtifact(exe);
@@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("1 2\n");
@@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
.c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },
.pic = true,
});
- a_o.linkLibC();
+ a_o.root_module.link_libc = true;
const b_o = addObject(b, opts, .{
.name = "b",
@@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.linkLibC();
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("3 5 3 5\n");
@@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.linkLibC();
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.link_libc = true;
// exe.link_relax = false; // TODO
const run = addRunArtifact(exe);
@@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step {
\\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;
, &.{});
exe.root_module.pic = false;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("3 5 3 5\n");
@@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
\\ return NULL;
\\}
, &.{});
- dso.linkLibC();
+ dso.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe,
@@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
\\ pthread_join(thread, NULL);
\\}
, &.{});
- exe.addRPath(dso.getEmittedBinDirectory());
- exe.linkLibC();
+ exe.root_module.addRPath(dso.getEmittedBinDirectory());
+ exe.root_module.link_libc = true;
exe.root_module.pic = true;
const run = addRunArtifact(exe);
@@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step {
,
.pic = true,
});
- obj.linkLibC();
+ obj.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe,
\\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;
, &.{});
- exe.addObject(obj);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("3 5 3 5\n");
@@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
,
.pic = true,
});
- c_o.linkLibC();
+ c_o.root_module.link_libc = true;
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(c_o);
- exe.linkLibC();
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(c_o);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("42\n");
@@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
{
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(a_o);
- dso.addObject(b_o);
+ dso.root_module.addObject(a_o);
+ dso.root_module.addObject(b_o);
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(c_o);
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.addObject(c_o);
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("42\n");
@@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(
@@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {
\\ return foo;
\\}
, &.{});
- exe.linkLibrary(dylib);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dylib);
+ exe.root_module.link_libc = true;
expectLinkErrors(exe, test_step, .{
.contains = "error: failed to parse shared library: BadMagic",
@@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
,
.c_source_flags = &.{"-ffunction-sections"},
});
- obj1.linkLibC();
+ obj1.root_module.link_libc = true;
const obj2 = addObject(b, opts, .{
.name = "b",
@@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
,
.c_source_flags = &.{"-ffunction-sections"},
});
- obj2.linkLibC();
+ obj2.root_module.link_libc = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(obj1);
- exe.addObject(obj2);
- exe.linkLibC();
+ exe.root_module.addObject(obj1);
+ exe.root_module.addObject(obj2);
+ exe.root_module.link_libc = true;
expectLinkErrors(exe, test_step, .{ .exact = &.{
"error: undefined symbol: foo",
@@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
,
.pic = true,
});
- obj.linkLibC();
+ obj.root_module.link_libc = true;
{
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(obj);
- dso.linkLibC();
+ dso.root_module.addObject(obj);
+ dso.root_module.link_libc = true;
const check = dso.checkObject();
check.checkInDynamicSymtab();
@@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(obj);
- exe.linkLibC();
+ exe.root_module.addObject(obj);
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInDynamicSymtab();
@@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
\\int bar();
\\int main() { printf("bar=%d\n", bar()); }
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("bar=-1\n");
@@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
\\int bar();
\\int main() { printf("bar=%d\n", bar()); }
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("bar=5\n");
@@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
{
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(obj);
+ dso.root_module.addObject(obj);
const check = dso.checkObject();
check.checkInDynamicSection();
@@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
{
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(obj);
+ dso.root_module.addObject(obj);
dso.link_z_lazy = true;
const check = dso.checkObject();
@@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {
const exe = addExecutable(b, opts, .{ .name = "main" });
addCSourceBytes(exe, "int main() { return 0; }", &.{});
exe.stack_size = 0x800000;
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const check = exe.checkObject();
check.checkInHeaders();
@@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step {
});
const dso = addSharedLibrary(b, opts, .{ .name = "a" });
- dso.addObject(a_o);
- dso.addObject(b_o);
+ dso.root_module.addObject(a_o);
+ dso.root_module.addObject(b_o);
dso.link_z_notext = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
@@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step {
\\ printf("%d\n", fnn());
\\}
, &.{});
- exe.linkLibrary(dso);
- exe.linkLibC();
+ exe.root_module.linkLibrary(dso);
+ exe.root_module.link_libc = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual("3\n");
diff --git a/test/link/link.zig b/test/link/link.zig
index 5d1a02f23e..601247e877 100644
--- a/test/link/link.zig
+++ b/test/link/link.zig
@@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run {
pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
const b = comp.step.owner;
const file = WriteFile.create(b).add("a.c", bytes);
- comp.addCSourceFile(.{ .file = file, .flags = flags });
+ comp.root_module.addCSourceFile(.{ .file = file, .flags = flags });
}
pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
const b = comp.step.owner;
const file = WriteFile.create(b).add("a.cpp", bytes);
- comp.addCSourceFile(.{ .file = file, .flags = flags });
+ comp.root_module.addCSourceFile(.{ .file = file, .flags = flags });
}
pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {
const b = comp.step.owner;
const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");
const file = WriteFile.create(b).add("a.s", actual_bytes);
- comp.addAssemblyFile(file);
+ comp.root_module.addAssemblyFile(file);
}
pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void {
diff --git a/test/link/macho.zig b/test/link/macho.zig
index 80d861eea0..422fc89a56 100644
--- a/test/link/macho.zig
+++ b/test/link/macho.zig
@@ -127,7 +127,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.link_gc_sections = false;
const check = exe.checkObject();
@@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
exe.link_gc_sections = true;
const check = exe.checkObject();
@@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
\\ strong();
\\}
});
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
expectLinkErrors(exe, test_step, .{ .exact = &.{
"error: duplicate symbol definition: _strong",
@@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
+ exe.root_module.addObject(main_o);
exe.root_module.linkFramework("Cocoa", .{});
const check = exe.checkObject();
@@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
+ exe.root_module.addObject(main_o);
exe.root_module.linkFramework("Cocoa", .{});
exe.dead_strip_dylibs = true;
@@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
\\ printf("Hello world!");
\\}
});
- exe.addObject(empty);
+ exe.root_module.addObject(empty);
const run = addRunArtifact(exe);
run.expectStdOutEqual("Hello world!");
@@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
, &.{});
- exe.linkLibrary(dylib);
+ exe.root_module.linkLibrary(dylib);
exe.entry = .{ .symbol_name = "_bootstrap" };
exe.forceUndefinedSymbol("_my_main");
@@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
});
const lib = addSharedLibrary(b, opts, .{ .name = "a" });
- lib.addObject(obj1);
+ lib.root_module.addObject(obj1);
{
const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" });
- exe.addObject(obj1);
+ exe.root_module.addObject(obj1);
const check = exe.checkObject();
check.checkInHeaders();
@@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
}
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.linkLibrary(lib);
- exe.addObject(obj);
+ exe.root_module.linkLibrary(lib);
+ exe.root_module.addObject(obj);
const check = exe.checkObject();
check.checkInHeaders();
@@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
\\_main:
\\ ret
});
- exe.linkLibrary(lib);
+ exe.root_module.linkLibrary(lib);
const check = exe.checkObject();
check.checkInHeaders();
@@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
\\}
,
});
- lib.addObject(obj);
+ lib.root_module.addObject(obj);
const exe = addExecutable(b, opts, .{
.name = "testlib",
@@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
\\}
,
});
- exe.linkLibrary(lib);
+ exe.root_module.linkLibrary(lib);
const run = addRunArtifact(exe);
run.expectStdErrEqual("0\n");
@@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(main_o);
runWithChecks(test_step, exe);
}
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(b_o);
- exe.addObject(a_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(main_o);
runWithChecks(test_step, exe);
}
{
const c_o = addObject(b, opts, .{ .name = "c" });
- c_o.addObject(a_o);
- c_o.addObject(b_o);
- c_o.addObject(main_o);
+ c_o.root_module.addObject(a_o);
+ c_o.root_module.addObject(b_o);
+ c_o.root_module.addObject(main_o);
const exe = addExecutable(b, opts, .{ .name = "main3" });
- exe.addObject(c_o);
+ exe.root_module.addObject(c_o);
runWithChecks(test_step, exe);
}
@@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(main_o);
runWithChecks(test_step, exe);
}
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(b_o);
- exe.addObject(a_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(main_o);
runWithChecks(test_step, exe);
}
{
const c_o = addObject(b, opts, .{ .name = "c" });
- c_o.addObject(a_o);
- c_o.addObject(b_o);
- c_o.addObject(main_o);
+ c_o.root_module.addObject(a_o);
+ c_o.root_module.addObject(b_o);
+ c_o.root_module.addObject(main_o);
const exe = addExecutable(b, opts, .{ .name = "main3" });
- exe.addObject(c_o);
+ exe.root_module.addObject(c_o);
runWithChecks(test_step, exe);
}
@@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {
});
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(main_o);
const check = exe.checkObject();
check.dumpSection("__TEXT,__const");
@@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(main_o);
runWithChecks(test_step, exe);
}
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(b_o);
- exe.addObject(a_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(main_o);
runWithChecks(test_step, exe);
}
@@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
- exe.addObject(a_o);
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(a_o);
exe.root_module.linkFramework("Foundation", .{});
runWithChecks(test_step, exe);
}
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(a_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(main_o);
exe.root_module.linkFramework("Foundation", .{});
runWithChecks(test_step, exe);
}
{
const b_o = addObject(b, opts, .{ .name = "b" });
- b_o.addObject(a_o);
- b_o.addObject(main_o);
+ b_o.root_module.addObject(a_o);
+ b_o.root_module.addObject(main_o);
const exe = addExecutable(b, opts, .{ .name = "main3" });
- exe.addObject(b_o);
+ exe.root_module.addObject(b_o);
exe.root_module.linkFramework("Foundation", .{});
runWithChecks(test_step, exe);
}
@@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
\\@end
});
foo_o.root_module.addIncludePath(foo_h.dirname());
- foo_o.linkLibCpp();
+ foo_o.root_module.link_libcpp = true;
const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes =
\\#import "Foo.h"
@@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
\\}
});
exe.root_module.addIncludePath(foo_h.dirname());
- exe.addObject(foo_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(foo_o);
+ exe.root_module.link_libcpp = true;
exe.root_module.linkFramework("Foundation", .{});
const run = addRunArtifact(exe);
@@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step {
\\ return bar() - foo();
\\}
});
- exe.linkLibrary(lib);
+ exe.root_module.linkLibrary(lib);
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
\\ throw std::runtime_error("Oh no!");
\\}
});
- a_o.linkLibCpp();
+ a_o.root_module.link_libcpp = true;
const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes =
\\extern int try_me();
@@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
});
- main_o.linkLibCpp();
+ main_o.root_module.link_libcpp = true;
const exp_stdout = "exception=Oh no!";
{
const c_o = addObject(b, opts, .{ .name = "c" });
- c_o.addObject(a_o);
- c_o.addObject(b_o);
+ c_o.root_module.addObject(a_o);
+ c_o.root_module.addObject(b_o);
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
- exe.addObject(c_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(c_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(exp_stdout);
@@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
{
const d_o = addObject(b, opts, .{ .name = "d" });
- d_o.addObject(a_o);
- d_o.addObject(b_o);
- d_o.addObject(main_o);
+ d_o.root_module.addObject(a_o);
+ d_o.root_module.addObject(b_o);
+ d_o.root_module.addObject(main_o);
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(d_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(d_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(exp_stdout);
@@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {
});
const c_o = addObject(b, opts, .{ .name = "c" });
- c_o.addObject(a_o);
- c_o.addObject(b_o);
- c_o.addObject(main_o);
+ c_o.root_module.addObject(a_o);
+ c_o.root_module.addObject(b_o);
+ c_o.root_module.addObject(main_o);
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(c_o);
+ exe.root_module.addObject(c_o);
const run = addRunArtifact(exe);
run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
@@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
});
const liba = addStaticLibrary(b, opts, .{ .name = "a" });
- liba.addObject(obj);
+ liba.root_module.addObject(obj);
const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
- dylib.addObject(obj);
+ dylib.root_module.addObject(obj);
const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes =
\\#include
@@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(main_o);
+ exe.root_module.addObject(main_o);
exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });
exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
@@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(main_o);
+ exe.root_module.addObject(main_o);
exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });
exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
@@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
});
const exe = addExecutable(b, opts, .{ .name = "test" });
- exe.addObject(obj1);
- exe.addObject(obj2);
- exe.addObject(main_o);
+ exe.root_module.addObject(obj1);
+ exe.root_module.addObject(obj2);
+ exe.root_module.addObject(main_o);
const run = b.addRunArtifact(exe);
run.skip_foreign_checks = true;
@@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
});
const exe = addExecutable(b, opts, .{ .name = "test" });
- exe.addObject(obj1);
- exe.addObject(obj3);
- exe.addObject(main_o);
+ exe.root_module.addObject(obj1);
+ exe.root_module.addObject(obj3);
+ exe.root_module.addObject(main_o);
const run = b.addRunArtifact(exe);
run.skip_foreign_checks = true;
@@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
});
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(obj1);
- exe.addObject(obj2);
- exe.addObject(main_o);
+ exe.root_module.addObject(obj1);
+ exe.root_module.addObject(obj2);
+ exe.root_module.addObject(main_o);
const run = addRunArtifact(exe);
run.expectStdOutEqual("All your codebase are belong to us.\n");
@@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
});
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(obj1);
- exe.addObject(obj2);
- exe.addObject(main_o);
+ exe.root_module.addObject(obj1);
+ exe.root_module.addObject(obj2);
+ exe.root_module.addObject(main_o);
const check = exe.checkObject();
check.checkInHeaders();
@@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step {
});
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(a_o);
- exe.addObject(b_o);
- exe.addObject(main_o);
+ exe.root_module.addObject(a_o);
+ exe.root_module.addObject(b_o);
+ exe.root_module.addObject(main_o);
const run = addRunArtifact(exe);
run.expectStdOutEqual("foo=42,bar=24");
@@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
\\}
});
bar_o.root_module.addIncludePath(foo_h.dirname());
- bar_o.linkLibCpp();
+ bar_o.root_module.link_libcpp = true;
const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes =
\\#include "foo.h"
@@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
\\}
});
baz_o.root_module.addIncludePath(foo_h.dirname());
- baz_o.linkLibCpp();
+ baz_o.root_module.link_libcpp = true;
const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes =
\\extern int bar();
@@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
\\}
});
main_o.root_module.addIncludePath(foo_h.dirname());
- main_o.linkLibCpp();
+ main_o.root_module.link_libcpp = true;
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(bar_o);
- exe.addObject(baz_o);
- exe.addObject(main_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(bar_o);
+ exe.root_module.addObject(baz_o);
+ exe.root_module.addObject(main_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
+ exe.root_module.addObject(main_o);
exe.root_module.linkSystemLibrary("a", .{});
exe.root_module.linkSystemLibrary("b", .{});
exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
@@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
+ exe.root_module.addObject(main_o);
exe.root_module.linkSystemLibrary("b", .{});
exe.root_module.linkSystemLibrary("a", .{});
exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
@@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" });
const lib = addStaticLibrary(b, opts, .{ .name = "a" });
- lib.addObject(obj);
+ lib.root_module.addObject(obj);
const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
{
const exe = addExecutable(b, opts, .{ .name = "main3" });
- exe.addObject(main_o);
- exe.addObject(obj);
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(obj);
exe.discard_local_symbols = true;
const run = addRunArtifact(exe);
@@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main4" });
- exe.addObject(main_o);
- exe.linkLibrary(lib);
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkLibrary(lib);
exe.discard_local_symbols = true;
const run = addRunArtifact(exe);
@@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });
const lib = addStaticLibrary(b, opts, .{ .name = "a" });
- lib.addObject(obj);
+ lib.root_module.addObject(obj);
const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
{
const exe = addExecutable(b, opts, .{ .name = "main1" });
- exe.addObject(main_o);
- exe.linkLibrary(lib);
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkLibrary(lib);
exe.forceUndefinedSymbol("_foo");
const run = addRunArtifact(exe);
@@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main2" });
- exe.addObject(main_o);
- exe.linkLibrary(lib);
+ exe.root_module.addObject(main_o);
+ exe.root_module.linkLibrary(lib);
exe.forceUndefinedSymbol("_foo");
exe.link_gc_sections = true;
@@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main3" });
- exe.addObject(main_o);
- exe.addObject(obj);
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(obj);
const run = addRunArtifact(exe);
run.expectExitCode(0);
@@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
{
const exe = addExecutable(b, opts, .{ .name = "main4" });
- exe.addObject(main_o);
- exe.addObject(obj);
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(obj);
exe.link_gc_sections = true;
const run = addRunArtifact(exe);
@@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
\\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()});
\\}
});
- exe.addObject(obj);
+ exe.root_module.addObject(obj);
// TODO order should match across backends if possible
if (opts.use_llvm) {
@@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
\\}
});
main_o.root_module.addIncludePath(all_h.dirname());
- main_o.linkLibCpp();
+ main_o.root_module.link_libcpp = true;
const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes =
\\#include "all.h"
@@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
\\}
});
simple_string_o.root_module.addIncludePath(all_h.dirname());
- simple_string_o.linkLibCpp();
+ simple_string_o.root_module.link_libcpp = true;
const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes =
\\#include "all.h"
@@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
\\}
});
simple_string_owner_o.root_module.addIncludePath(all_h.dirname());
- simple_string_owner_o.linkLibCpp();
+ simple_string_owner_o.root_module.link_libcpp = true;
const exp_stdout =
\\Constructed: a
@@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
;
const exe = addExecutable(b, opts, .{ .name = "main" });
- exe.addObject(main_o);
- exe.addObject(simple_string_o);
- exe.addObject(simple_string_owner_o);
- exe.linkLibCpp();
+ exe.root_module.addObject(main_o);
+ exe.root_module.addObject(simple_string_o);
+ exe.root_module.addObject(simple_string_owner_o);
+ exe.root_module.link_libcpp = true;
const run = addRunArtifact(exe);
run.expectStdOutEqual(exp_stdout);
@@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
});
- exe.addObject(a_o);
+ exe.root_module.addObject(a_o);
const run = addRunArtifact(exe);
run.expectStdOutEqual("4\n");
@@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {
\\ return 0;
\\}
});
- exe.addObject(a_o);
+ exe.root_module.addObject(a_o);
const run = addRunArtifact(exe);
run.expectStdOutEqual("4\n");
@@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step {
\\ .quad 0
\\ .quad _weak_internal_tlv$tlv$init
});
- exe.linkLibrary(lib);
+ exe.root_module.linkLibrary(lib);
{
const check = exe.checkObject();
diff --git a/test/link/wasm/extern/build.zig b/test/link/wasm/extern/build.zig
index 4976c97b31..74036d486d 100644
--- a/test/link/wasm/extern/build.zig
+++ b/test/link/wasm/extern/build.zig
@@ -16,7 +16,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),
}),
});
- exe.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
+ exe.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
exe.use_llvm = false;
exe.use_lld = false;
diff --git a/test/src/Cases.zig b/test/src/Cases.zig
index 9f6a7fe189..e6c851bd81 100644
--- a/test/src/Cases.zig
+++ b/test/src/Cases.zig
@@ -436,7 +436,7 @@ fn addFromDirInner(
const target = &resolved_target.result;
for (backends) |backend| {
if (backend == .stage2 and
- target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64)
+ target.cpu.arch != .aarch64 and target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64)
{
// Other backends don't support new liveness format
continue;
@@ -447,10 +447,6 @@ fn addFromDirInner(
// Rosetta has issues with ZLD
continue;
}
- if (backend == .stage2 and target.ofmt == .coff) {
- // COFF linker has bitrotted
- continue;
- }
const next = ctx.cases.items.len;
try ctx.cases.append(.{
@@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps(
.root_module = translate_c.createModule(),
});
run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
- run_exe.linkLibC();
+ run_exe.root_module.link_libc = true;
const run = b.addRunArtifact(run_exe);
run.step.name = b.fmt("{s} run", .{annotated_case_name});
run.expectStdOutEqual(output);
diff --git a/test/src/RunTranslatedC.zig b/test/src/RunTranslatedC.zig
index 528df69c4b..537c49dcd5 100644
--- a/test/src/RunTranslatedC.zig
+++ b/test/src/RunTranslatedC.zig
@@ -89,7 +89,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
.root_module = translate_c.createModule(),
});
exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
- exe.linkLibC();
+ exe.root_module.link_libc = true;
const run = b.addRunArtifact(exe);
run.step.name = b.fmt("{s} run", .{annotated_case_name});
if (!case.allow_warnings) {
diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon
index 8cf899477f..bdd059ab37 100644
--- a/test/standalone/build.zig.zon
+++ b/test/standalone/build.zig.zon
@@ -1,6 +1,6 @@
.{
.name = .standalone_test_cases,
- .fingerprint = 0xc0dbdf9c818957be,
+ .fingerprint = 0xc0dbdf9c3b92810b,
.version = "0.0.0",
.dependencies = .{
.simple = .{
@@ -181,6 +181,9 @@
.install_headers = .{
.path = "install_headers",
},
+ .dependency_options = .{
+ .path = "dependency_options",
+ },
.dependencyFromBuildZig = .{
.path = "dependencyFromBuildZig",
},
diff --git a/test/standalone/c_embed_path/build.zig b/test/standalone/c_embed_path/build.zig
index a314847ba6..246e18b3f0 100644
--- a/test/standalone/c_embed_path/build.zig
+++ b/test/standalone/c_embed_path/build.zig
@@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
}),
});
- exe.addCSourceFile(.{
+ exe.root_module.addCSourceFile(.{
.file = b.path("test.c"),
.flags = &.{"-std=c23"},
});
- exe.linkLibC();
- exe.addEmbedPath(b.path("data"));
+ exe.root_module.link_libc = true;
+ exe.root_module.addEmbedPath(b.path("data"));
const run_c_cmd = b.addRunArtifact(exe);
run_c_cmd.expectExitCode(0);
diff --git a/test/standalone/dependencyFromBuildZig/build.zig.zon b/test/standalone/dependencyFromBuildZig/build.zig.zon
index 085ae2c80b..fda6a098d8 100644
--- a/test/standalone/dependencyFromBuildZig/build.zig.zon
+++ b/test/standalone/dependencyFromBuildZig/build.zig.zon
@@ -1,5 +1,6 @@
.{
- .name = "dependencyFromBuildZig",
+ .name = .dependencyFromBuildZig,
+ .fingerprint = 0xfd939a1eb8169080,
.version = "0.0.0",
.dependencies = .{
.other = .{
diff --git a/test/standalone/dependencyFromBuildZig/other/build.zig.zon b/test/standalone/dependencyFromBuildZig/other/build.zig.zon
index 204abdbbba..bb8fcb6fb4 100644
--- a/test/standalone/dependencyFromBuildZig/other/build.zig.zon
+++ b/test/standalone/dependencyFromBuildZig/other/build.zig.zon
@@ -1,5 +1,6 @@
.{
- .name = "other",
+ .name = .other,
+ .fingerprint = 0xd9583520a2405f6c,
.version = "0.0.0",
.dependencies = .{},
.paths = .{""},
diff --git a/test/standalone/dependency_options/build.zig b/test/standalone/dependency_options/build.zig
new file mode 100644
index 0000000000..95cde3c891
--- /dev/null
+++ b/test/standalone/dependency_options/build.zig
@@ -0,0 +1,148 @@
+const std = @import("std");
+
+pub const Enum = enum { alfa, bravo, charlie };
+
+pub fn build(b: *std.Build) !void {
+ const test_step = b.step("test", "Test passing options to a dependency");
+ b.default_step = test_step;
+
+ const none_specified = b.dependency("other", .{});
+
+ const none_specified_mod = none_specified.module("dummy");
+ if (!none_specified_mod.resolved_target.?.query.eql(b.graph.host.query)) return error.TestFailed;
+ const expected_optimize: std.builtin.OptimizeMode = switch (b.release_mode) {
+ .off => .Debug,
+ .any => unreachable,
+ .fast => .ReleaseFast,
+ .safe => .ReleaseSafe,
+ .small => .ReleaseSmall,
+ };
+ if (none_specified_mod.optimize.? != expected_optimize) return error.TestFailed;
+
+ // Passing null is the same as not specifying the option,
+ // so this should resolve to the same cached dependency instance.
+ const null_specified = b.dependency("other", .{
+ // Null literals
+ .target = null,
+ .optimize = null,
+ .bool = null,
+
+ // Optionals
+ .int = @as(?i64, null),
+ .float = @as(?f64, null),
+
+ // Optionals of the wrong type
+ .string = @as(?usize, null),
+ .@"enum" = @as(?bool, null),
+
+ // Non-defined option names
+ .this_option_does_not_exist = null,
+ .neither_does_this_one = @as(?[]const u8, null),
+ });
+
+ if (null_specified != none_specified) return error.TestFailed;
+
+ const all_specified = b.dependency("other", .{
+ .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
+ .optimize = @as(std.builtin.OptimizeMode, .ReleaseSafe),
+ .bool = @as(bool, true),
+ .int = @as(i64, 123),
+ .float = @as(f64, 0.5),
+ .string = @as([]const u8, "abc"),
+ .string_list = @as([]const []const u8, &.{ "a", "b", "c" }),
+ .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
+ .lazy_path_list = @as([]const std.Build.LazyPath, &.{
+ .{ .cwd_relative = "a.txt" },
+ .{ .cwd_relative = "b.txt" },
+ .{ .cwd_relative = "c.txt" },
+ }),
+ .@"enum" = @as(Enum, .alfa),
+ .enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }),
+ .build_id = @as(std.zig.BuildId, .uuid),
+ .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"),
+ });
+
+ const all_specified_mod = all_specified.module("dummy");
+ if (all_specified_mod.resolved_target.?.result.cpu.arch != .x86_64) return error.TestFailed;
+ if (all_specified_mod.resolved_target.?.result.os.tag != .windows) return error.TestFailed;
+ if (all_specified_mod.resolved_target.?.result.abi != .gnu) return error.TestFailed;
+ if (all_specified_mod.optimize.? != .ReleaseSafe) return error.TestFailed;
+
+ const all_specified_optional = b.dependency("other", .{
+ .target = @as(?std.Build.ResolvedTarget, b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu })),
+ .optimize = @as(?std.builtin.OptimizeMode, .ReleaseSafe),
+ .bool = @as(?bool, true),
+ .int = @as(?i64, 123),
+ .float = @as(?f64, 0.5),
+ .string = @as(?[]const u8, "abc"),
+ .string_list = @as(?[]const []const u8, &.{ "a", "b", "c" }),
+ .lazy_path = @as(?std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
+ .lazy_path_list = @as(?[]const std.Build.LazyPath, &.{
+ .{ .cwd_relative = "a.txt" },
+ .{ .cwd_relative = "b.txt" },
+ .{ .cwd_relative = "c.txt" },
+ }),
+ .@"enum" = @as(?Enum, .alfa),
+ .enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }),
+ .build_id = @as(?std.zig.BuildId, .uuid),
+ .hex_build_id = @as(?std.zig.BuildId, .initHexString("\x12\x34\xcd\xef")),
+ });
+
+ if (all_specified_optional != all_specified) return error.TestFailed;
+
+ const all_specified_literal = b.dependency("other", .{
+ .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
+ .optimize = .ReleaseSafe,
+ .bool = true,
+ .int = 123,
+ .float = 0.5,
+ .string = "abc",
+ .string_list = &[_][]const u8{ "a", "b", "c" },
+ .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
+ .lazy_path_list = &[_]std.Build.LazyPath{
+ .{ .cwd_relative = "a.txt" },
+ .{ .cwd_relative = "b.txt" },
+ .{ .cwd_relative = "c.txt" },
+ },
+ .@"enum" = .alfa,
+ .enum_list = &[_]Enum{ .alfa, .bravo, .charlie },
+ .build_id = .uuid,
+ .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"),
+ });
+
+ if (all_specified_literal != all_specified) return error.TestFailed;
+
+ var mut_string_buf = "abc".*;
+ const mut_string: []u8 = &mut_string_buf;
+ var mut_string_list_buf = [_][]const u8{ "a", "b", "c" };
+ const mut_string_list: [][]const u8 = &mut_string_list_buf;
+ var mut_lazy_path_list_buf = [_]std.Build.LazyPath{
+ .{ .cwd_relative = "a.txt" },
+ .{ .cwd_relative = "b.txt" },
+ .{ .cwd_relative = "c.txt" },
+ };
+ const mut_lazy_path_list: []std.Build.LazyPath = &mut_lazy_path_list_buf;
+ var mut_enum_list_buf = [_]Enum{ .alfa, .bravo, .charlie };
+ const mut_enum_list: []Enum = &mut_enum_list_buf;
+
+ // Most supported option types are serialized to a string representation,
+ // so alternative representations of the same option value should resolve
+ // to the same cached dependency instance.
+ const all_specified_alt = b.dependency("other", .{
+ .target = @as(std.Target.Query, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
+ .optimize = "ReleaseSafe",
+ .bool = .true,
+ .int = "123",
+ .float = @as(f16, 0.5),
+ .string = mut_string,
+ .string_list = mut_string_list,
+ .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
+ .lazy_path_list = mut_lazy_path_list,
+ .@"enum" = "alfa",
+ .enum_list = mut_enum_list,
+ .build_id = "uuid",
+ .hex_build_id = "0x1234cdef",
+ });
+
+ if (all_specified_alt != all_specified) return error.TestFailed;
+}
diff --git a/test/standalone/dependency_options/build.zig.zon b/test/standalone/dependency_options/build.zig.zon
new file mode 100644
index 0000000000..6788640a80
--- /dev/null
+++ b/test/standalone/dependency_options/build.zig.zon
@@ -0,0 +1,11 @@
+.{
+ .name = .dependency_options,
+ .fingerprint = 0x3e3ce1c1f92ba47e,
+ .version = "0.0.0",
+ .dependencies = .{
+ .other = .{
+ .path = "other",
+ },
+ },
+ .paths = .{""},
+}
diff --git a/test/standalone/dependency_options/other/build.zig b/test/standalone/dependency_options/other/build.zig
new file mode 100644
index 0000000000..c18f92f14d
--- /dev/null
+++ b/test/standalone/dependency_options/other/build.zig
@@ -0,0 +1,59 @@
+const std = @import("std");
+
+pub const Enum = enum { alfa, bravo, charlie };
+
+pub fn build(b: *std.Build) !void {
+ const target = b.standardTargetOptions(.{});
+ const optimize = b.standardOptimizeOption(.{});
+
+ const expected_bool: bool = true;
+ const expected_int: i64 = 123;
+ const expected_float: f64 = 0.5;
+ const expected_string: []const u8 = "abc";
+ const expected_string_list: []const []const u8 = &.{ "a", "b", "c" };
+ const expected_lazy_path: std.Build.LazyPath = .{ .cwd_relative = "abc.txt" };
+ const expected_lazy_path_list: []const std.Build.LazyPath = &.{
+ .{ .cwd_relative = "a.txt" },
+ .{ .cwd_relative = "b.txt" },
+ .{ .cwd_relative = "c.txt" },
+ };
+ const expected_enum: Enum = .alfa;
+ const expected_enum_list: []const Enum = &.{ .alfa, .bravo, .charlie };
+ const expected_build_id: std.zig.BuildId = .uuid;
+ const expected_hex_build_id: std.zig.BuildId = .initHexString("\x12\x34\xcd\xef");
+
+ const @"bool" = b.option(bool, "bool", "bool") orelse expected_bool;
+ const int = b.option(i64, "int", "int") orelse expected_int;
+ const float = b.option(f64, "float", "float") orelse expected_float;
+ const string = b.option([]const u8, "string", "string") orelse expected_string;
+ const string_list = b.option([]const []const u8, "string_list", "string_list") orelse expected_string_list;
+ const lazy_path = b.option(std.Build.LazyPath, "lazy_path", "lazy_path") orelse expected_lazy_path;
+ const lazy_path_list = b.option([]const std.Build.LazyPath, "lazy_path_list", "lazy_path_list") orelse expected_lazy_path_list;
+ const @"enum" = b.option(Enum, "enum", "enum") orelse expected_enum;
+ const enum_list = b.option([]const Enum, "enum_list", "enum_list") orelse expected_enum_list;
+ const build_id = b.option(std.zig.BuildId, "build_id", "build_id") orelse expected_build_id;
+ const hex_build_id = b.option(std.zig.BuildId, "hex_build_id", "hex_build_id") orelse expected_hex_build_id;
+
+ if (@"bool" != expected_bool) return error.TestFailed;
+ if (int != expected_int) return error.TestFailed;
+ if (float != expected_float) return error.TestFailed;
+ if (!std.mem.eql(u8, string, expected_string)) return error.TestFailed;
+ if (string_list.len != expected_string_list.len) return error.TestFailed;
+ for (string_list, expected_string_list) |x, y| {
+ if (!std.mem.eql(u8, x, y)) return error.TestFailed;
+ }
+ if (!std.mem.eql(u8, lazy_path.cwd_relative, expected_lazy_path.cwd_relative)) return error.TestFailed;
+ for (lazy_path_list, expected_lazy_path_list) |x, y| {
+ if (!std.mem.eql(u8, x.cwd_relative, y.cwd_relative)) return error.TestFailed;
+ }
+ if (@"enum" != expected_enum) return error.TestFailed;
+ if (!std.mem.eql(Enum, enum_list, expected_enum_list)) return error.TestFailed;
+ if (!std.meta.eql(build_id, expected_build_id)) return error.TestFailed;
+ if (!hex_build_id.eql(expected_hex_build_id)) return error.TestFailed;
+
+ _ = b.addModule("dummy", .{
+ .root_source_file = b.path("build.zig"),
+ .target = target,
+ .optimize = optimize,
+ });
+}
diff --git a/test/standalone/dependency_options/other/build.zig.zon b/test/standalone/dependency_options/other/build.zig.zon
new file mode 100644
index 0000000000..d49a2cdcf8
--- /dev/null
+++ b/test/standalone/dependency_options/other/build.zig.zon
@@ -0,0 +1,7 @@
+.{
+ .name = .other,
+ .fingerprint = 0xd95835207bc8b630,
+ .version = "0.0.0",
+ .dependencies = .{},
+ .paths = .{""},
+}
diff --git a/test/standalone/extern/build.zig b/test/standalone/extern/build.zig
index 3c22f77f2a..178fa76d41 100644
--- a/test/standalone/extern/build.zig
+++ b/test/standalone/extern/build.zig
@@ -31,8 +31,8 @@ pub fn build(b: *std.Build) void {
.target = b.graph.host,
.optimize = optimize,
}) });
- test_exe.addObject(obj);
- test_exe.linkLibrary(shared);
+ test_exe.root_module.addObject(obj);
+ test_exe.root_module.linkLibrary(shared);
test_step.dependOn(&b.addRunArtifact(test_exe).step);
}
diff --git a/test/standalone/issue_794/build.zig b/test/standalone/issue_794/build.zig
index 4b0c089f97..0f3f0a16f7 100644
--- a/test/standalone/issue_794/build.zig
+++ b/test/standalone/issue_794/build.zig
@@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {
.root_source_file = b.path("main.zig"),
.target = b.graph.host,
}) });
- test_artifact.addIncludePath(b.path("a_directory"));
+ test_artifact.root_module.addIncludePath(b.path("a_directory"));
// TODO: actually check the output
_ = test_artifact.getEmittedBin();
diff --git a/test/standalone/stack_iterator/build.zig b/test/standalone/stack_iterator/build.zig
index 878859312b..8d2c448215 100644
--- a/test/standalone/stack_iterator/build.zig
+++ b/test/standalone/stack_iterator/build.zig
@@ -109,7 +109,7 @@ pub fn build(b: *std.Build) void {
// .use_llvm = true,
// });
- // exe.linkLibrary(c_shared_lib);
+ // exe.root_module.linkLibrary(c_shared_lib);
// const run_cmd = b.addRunArtifact(exe);
// test_step.dependOn(&run_cmd.step);
diff --git a/test/tests.zig b/test/tests.zig
index caec19d556..a12312d278 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -2371,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
} else "";
const use_pic = if (test_target.pic == true) "-pic" else "";
- for (options.include_paths) |include_path| these_tests.addIncludePath(b.path(include_path));
+ for (options.include_paths) |include_path| these_tests.root_module.addIncludePath(b.path(include_path));
if (target.os.tag == .windows) {
- for (options.windows_libs) |lib| these_tests.linkSystemLibrary(lib);
+ for (options.windows_libs) |lib| these_tests.root_module.linkSystemLibrary(lib, .{});
}
const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{