authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:27:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:27:45-07:00
log08efe0d598b43951321a9e651c0ff62825db6ee6
tree20d867086cfa0bd5179107f17efd979a25bf8306
parent45a35d448e85351756fe18e901748c4446a1b56a
parentd91744401fd83fe2d603b5020fc141285aa017a1

Merge remote-tracking branch 'origin/flate' into wrangle-writer-buffering


294 files changed, 11080 insertions(+), 6828 deletions(-)

doc/langref.html.in+28-37
...@@ -3215,7 +3215,7 @@ fn createFoo(param: i32) !Foo {...@@ -3215,7 +3215,7 @@ fn createFoo(param: i32) !Foo {
3215 to increase their development pace.3215 to increase their development pace.
3216 </p>3216 </p>
3217 <p>3217 <p>
3218 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.3218 Error Return Traces are enabled by default in {#link|Debug#} builds and disabled by default in {#link|ReleaseFast#}, {#link|ReleaseSafe#} and {#link|ReleaseSmall#} builds.
3219 </p>3219 </p>
3220 <p>3220 <p>
3221 There are a few ways to activate this error return tracing feature:3221 There are a few ways to activate this error return tracing feature:
...@@ -4319,7 +4319,7 @@ comptime {...@@ -4319,7 +4319,7 @@ comptime {
4319 </p>4319 </p>
4320 <p>4320 <p>
4321 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4321 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4322 an integer or an enum.4322 an integer, an enum, or a packed struct.
4323 </p>4323 </p>
4324 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4324 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4325 {#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}4325 {#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}
...@@ -4333,7 +4333,7 @@ comptime {...@@ -4333,7 +4333,7 @@ comptime {
4333 </p>4333 </p>
4334 <p>4334 <p>
4335 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4335 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4336 an integer or an enum.4336 an integer, an enum, or a packed struct.
4337 </p>4337 </p>
4338 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4338 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4339 <p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>4339 <p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>
...@@ -4347,7 +4347,7 @@ comptime {...@@ -4347,7 +4347,7 @@ comptime {
4347 </p>4347 </p>
4348 <p>4348 <p>
4349 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4349 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4350 an integer or an enum.4350 an integer, an enum, or a packed struct.
4351 </p>4351 </p>
4352 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4352 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4353 {#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}4353 {#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
...@@ -4576,8 +4576,8 @@ comptime {...@@ -4576,8 +4576,8 @@ comptime {
4576 more efficiently in machine instructions.4576 more efficiently in machine instructions.
4577 </p>4577 </p>
4578 <p>4578 <p>
4579 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4579 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
4580 an integer or an enum.4580 an integer, an enum, or a packed struct.
4581 </p>4581 </p>
4582 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>4582 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
4583 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4583 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
...@@ -4608,8 +4608,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4608,8 +4608,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4608 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.4608 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
4609 </p>4609 </p>
4610 <p>4610 <p>
4611 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4611 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
4612 an integer or an enum.4612 an integer, an enum, or a packed struct.
4613 </p>4613 </p>
4614 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>4614 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
4615 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4615 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
...@@ -4840,7 +4840,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4840,7 +4840,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4840 <p>4840 <p>
4841 This builtin can be called from a {#link|comptime#} block to conditionally export symbols.4841 This builtin can be called from a {#link|comptime#} block to conditionally export symbols.
4842 When <code>ptr</code> points to a function with the C calling convention and4842 When <code>ptr</code> points to a function with the C calling convention and
4843 {#syntax#}options.linkage{#endsyntax#} is {#syntax#}.Strong{#endsyntax#}, this is equivalent to4843 {#syntax#}options.linkage{#endsyntax#} is {#syntax#}.strong{#endsyntax#}, this is equivalent to
4844 the {#syntax#}export{#endsyntax#} keyword used on a function:4844 the {#syntax#}export{#endsyntax#} keyword used on a function:
4845 </p>4845 </p>
4846 {#code|export_builtin.zig#}4846 {#code|export_builtin.zig#}
...@@ -4952,34 +4952,25 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4952,34 +4952,25 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4952 {#header_close#}4952 {#header_close#}
49534953
4954 {#header_open|@import#}4954 {#header_open|@import#}
4955 <pre>{#syntax#}@import(comptime path: []const u8) type{#endsyntax#}</pre>4955 <pre>{#syntax#}@import(comptime target: []const u8) anytype{#endsyntax#}</pre>
4956 <p>4956 <p>Imports the file at {#syntax#}target{#endsyntax#}, adding it to the compilation if it is not already
4957 This function finds a zig file corresponding to {#syntax#}path{#endsyntax#} and adds it to the build,4957 added. {#syntax#}target{#endsyntax#} is either a relative path to another file from the file containing
4958 if it is not already added.4958 the {#syntax#}@import{#endsyntax#} call, or it is the name of a {#link|module|Compilation Model#}, with
4959 </p>4959 the import referring to the root source file of that module. Either way, the file path must end in
4960 <p>4960 either <code>.zig</code> (for a Zig source file) or <code>.zon</code> (for a ZON data file).</p>
4961 Zig source files are implicitly structs, with a name equal to the file's basename with the extension4961 <p>If {#syntax#}target{#endsyntax#} refers to a Zig source file, then {#syntax#}@import{#endsyntax#} returns
4962 truncated. {#syntax#}@import{#endsyntax#} returns the struct type corresponding to the file.4962 that file's {#link|corresponding struct type|Source File Structs#}, essentially as if the builtin call was
4963 </p>4963 replaced by {#syntax#}struct { FILE_CONTENTS }{#endsyntax#}. The return type is {#syntax#}type{#endsyntax#}.</p>
4964 <p>4964 <p>If {#syntax#}target{#endsyntax#} refers to a ZON file, then {#syntax#}@import{#endsyntax#} returns the value
4965 Declarations which have the {#syntax#}pub{#endsyntax#} keyword may be referenced from a different4965 of the literal in the file. If there is an inferred {#link|result type|Result Types#}, then the return type
4966 source file than the one they are declared in.4966 is that type, and the ZON literal is interpreted as that type ({#link|Result Types#} are propagated through
4967 </p>4967 the ZON expression). Otherwise, the return type is the type of the equivalent Zig expression, essentially as
4968 <p>4968 if the builtin call was replaced by the ZON file contents.</p>
4969 {#syntax#}path{#endsyntax#} can be a relative path or it can be the name of a package.4969 <p>The following modules are always available for import:</p>
4970 If it is a relative path, it is relative to the file that contains the {#syntax#}@import{#endsyntax#}
4971 function call.
4972 </p>
4973 <p>
4974 The following packages are always available:
4975 </p>
4976 <ul>4970 <ul>
4977 <li>{#syntax#}@import("std"){#endsyntax#} - Zig Standard Library</li>4971 <li>{#syntax#}@import("std"){#endsyntax#} - Zig Standard Library</li>
4978 <li>{#syntax#}@import("builtin"){#endsyntax#} - Target-specific information4972 <li>{#syntax#}@import("builtin"){#endsyntax#} - Target-specific information. The command <code>zig build-exe --show-builtin</code> outputs the source to stdout for reference.</li>
4979 The command <code>zig build-exe --show-builtin</code> outputs the source to stdout for reference.4973 <li>{#syntax#}@import("root"){#endsyntax#} - Alias for the root module. In typical project structures, this means it refers back to <code>src/main.zig</code>.
4980 </li>
4981 <li>{#syntax#}@import("root"){#endsyntax#} - Root source file
4982 This is usually <code>src/main.zig</code> but depends on what file is built.
4983 </li>4974 </li>
4984 </ul>4975 </ul>
4985 {#see_also|Compile Variables|@embedFile#}4976 {#see_also|Compile Variables|@embedFile#}
...@@ -5179,7 +5170,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5179,7 +5170,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5179 <pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>5170 <pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>
5180 <p>5171 <p>
5181 Modulus division. For unsigned integers this is the same as5172 Modulus division. For unsigned integers this is the same as
5182 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the5173 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
5183 operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.5174 operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
5184 </p>5175 </p>
5185 <ul>5176 <ul>
...@@ -5284,7 +5275,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5284,7 +5275,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5284 <pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>5275 <pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
5285 <p>5276 <p>
5286 Remainder division. For unsigned integers this is the same as5277 Remainder division. For unsigned integers this is the same as
5287 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the5278 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
5288 operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.5279 operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
5289 </p>5280 </p>
5290 <ul>5281 <ul>
doc/langref/build.zig+4-2
...@@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void {...@@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
5 const exe = b.addExecutable(.{5 const exe = b.addExecutable(.{
6 .name = "example",6 .name = "example",
7 .root_source_file = b.path("example.zig"),7 .root_module = b.createModule(.{
8 .optimize = optimize,8 .root_source_file = b.path("example.zig"),
9 .optimize = optimize,
10 }),
9 });11 });
10 b.default_step.dependOn(&exe.step);12 b.default_step.dependOn(&exe.step);
11}13}
doc/langref/build_c.zig+8-4
...@@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void {...@@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void {
4 const lib = b.addLibrary(.{4 const lib = b.addLibrary(.{
5 .linkage = .dynamic,5 .linkage = .dynamic,
6 .name = "mathtest",6 .name = "mathtest",
7 .root_source_file = b.path("mathtest.zig"),7 .root_module = b.createModule(.{
8 .root_source_file = b.path("mathtest.zig"),
9 }),
8 .version = .{ .major = 1, .minor = 0, .patch = 0 },10 .version = .{ .major = 1, .minor = 0, .patch = 0 },
9 });11 });
10 const exe = b.addExecutable(.{12 const exe = b.addExecutable(.{
11 .name = "test",13 .name = "test",
14 .root_module = b.createModule(.{
15 .link_libc = true,
16 }),
12 });17 });
13 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });18 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
14 exe.linkLibrary(lib);19 exe.root_module.linkLibrary(lib);
15 exe.linkSystemLibrary("c");
1620
17 b.default_step.dependOn(&exe.step);21 b.default_step.dependOn(&exe.step);
1822
doc/langref/build_object.zig+8-4
...@@ -3,15 +3,19 @@ const std = @import("std");...@@ -3,15 +3,19 @@ const std = @import("std");
3pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
4 const obj = b.addObject(.{4 const obj = b.addObject(.{
5 .name = "base64",5 .name = "base64",
6 .root_source_file = b.path("base64.zig"),6 .root_module = b.createModule(.{
7 .root_source_file = b.path("base64.zig"),
8 }),
7 });9 });
810
9 const exe = b.addExecutable(.{11 const exe = b.addExecutable(.{
10 .name = "test",12 .name = "test",
13 .root_module = b.createModule(.{
14 .link_libc = true,
15 }),
11 });16 });
12 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });17 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
13 exe.addObject(obj);18 exe.root_module.addObject(obj);
14 exe.linkSystemLibrary("c");
15 b.installArtifact(exe);19 b.installArtifact(exe);
16}20}
1721
doc/langref/test_coerce_slices_arrays_and_pointers.zig+7
...@@ -67,4 +67,11 @@ test "*T to *[1]T" {...@@ -67,4 +67,11 @@ test "*T to *[1]T" {
67 try expect(z[0] == 1234);67 try expect(z[0] == 1234);
68}68}
6969
70// Sentinel-terminated slices can be coerced into sentinel-terminated pointers
71test "[:x]T to [*:x]T" {
72 const buf: [:0]const u8 = "hello";
73 const buf2: [*:0]const u8 = buf;
74 try expect(buf2[4] == 'o');
75}
76
70// test77// test
lib/compiler/build_runner.zig+6-2
...@@ -696,8 +696,11 @@ fn runStepNames(...@@ -696,8 +696,11 @@ fn runStepNames(
696 .failures, .none => true,696 .failures, .none => true,
697 else => false,697 else => false,
698 };698 };
699 if (failure_count == 0 and failures_only) {699 if (failure_count == 0) {
700 return run.cleanExit();700 std.Progress.setStatus(.success);
701 if (failures_only) return run.cleanExit();
702 } else {
703 std.Progress.setStatus(.failure);
701 }704 }
702705
703 const ttyconf = run.ttyconf;706 const ttyconf = run.ttyconf;
...@@ -1149,6 +1152,7 @@ fn workerMakeOneStep(...@@ -1149,6 +1152,7 @@ fn workerMakeOneStep(
1149 } else |err| switch (err) {1152 } else |err| switch (err) {
1150 error.MakeFailed => {1153 error.MakeFailed => {
1151 @atomicStore(Step.State, &s.state, .failure, .seq_cst);1154 @atomicStore(Step.State, &s.state, .failure, .seq_cst);
1155 std.Progress.setStatus(.failure_working);
1152 break :handle_result;1156 break :handle_result;
1153 },1157 },
1154 error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),1158 error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
lib/compiler_rt.zig+1-1
...@@ -240,7 +240,7 @@ comptime {...@@ -240,7 +240,7 @@ comptime {
240 _ = @import("compiler_rt/udivmodti4.zig");240 _ = @import("compiler_rt/udivmodti4.zig");
241241
242 // extra242 // extra
243 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/os_version_check.zig");243 _ = @import("compiler_rt/os_version_check.zig");
244 _ = @import("compiler_rt/emutls.zig");244 _ = @import("compiler_rt/emutls.zig");
245 _ = @import("compiler_rt/arm.zig");245 _ = @import("compiler_rt/arm.zig");
246 _ = @import("compiler_rt/aulldiv.zig");246 _ = @import("compiler_rt/aulldiv.zig");
lib/std/Build.zig+151-76
...@@ -409,104 +409,179 @@ fn createChildOnly(...@@ -409,104 +409,179 @@ fn createChildOnly(
409 return child;409 return child;
410}410}
411411
412fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap {412fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap {
413 var user_input_options = UserInputOptionsMap.init(allocator);413 var map = UserInputOptionsMap.init(arena);
414 inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {414 inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
415 const v = @field(args, field.name);415 if (field.type == @Type(.null)) continue;
416 const T = @TypeOf(v);416 addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name));
417 switch (T) {417 }
418 Target.Query => {418 return map;
419 user_input_options.put(field.name, .{419}
420 .name = field.name,420
421 .value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") },421fn addUserInputOptionFromArg(
422 .used = false,422 arena: Allocator,
423 }) catch @panic("OOM");423 map: *UserInputOptionsMap,
424 user_input_options.put("cpu", .{424 field: std.builtin.Type.StructField,
425 .name = "cpu",425 comptime T: type,
426 .value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") },426 /// If null, the value won't be added, but `T` will still be type-checked.
427 .used = false,427 maybe_value: ?T,
428 }) catch @panic("OOM");428) void {
429 },429 switch (T) {
430 ResolvedTarget => {430 Target.Query => return if (maybe_value) |v| {
431 user_input_options.put(field.name, .{431 map.put(field.name, .{
432 .name = field.name,432 .name = field.name,
433 .value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") },433 .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") },
434 .used = false,434 .used = false,
435 }) catch @panic("OOM");435 }) catch @panic("OOM");
436 user_input_options.put("cpu", .{436 map.put("cpu", .{
437 .name = "cpu",437 .name = "cpu",
438 .value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") },438 .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") },
439 .used = false,439 .used = false,
440 }) catch @panic("OOM");440 }) catch @panic("OOM");
441 },441 },
442 LazyPath => {442 ResolvedTarget => return if (maybe_value) |v| {
443 user_input_options.put(field.name, .{443 map.put(field.name, .{
444 .name = field.name,
445 .value = .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") },
446 .used = false,
447 }) catch @panic("OOM");
448 map.put("cpu", .{
449 .name = "cpu",
450 .value = .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") },
451 .used = false,
452 }) catch @panic("OOM");
453 },
454 std.zig.BuildId => return if (maybe_value) |v| {
455 map.put(field.name, .{
456 .name = field.name,
457 .value = .{ .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM") },
458 .used = false,
459 }) catch @panic("OOM");
460 },
461 LazyPath => return if (maybe_value) |v| {
462 map.put(field.name, .{
463 .name = field.name,
464 .value = .{ .lazy_path = v.dupeInner(arena) },
465 .used = false,
466 }) catch @panic("OOM");
467 },
468 []const LazyPath => return if (maybe_value) |v| {
469 var list = ArrayList(LazyPath).initCapacity(arena, v.len) catch @panic("OOM");
470 for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(arena));
471 map.put(field.name, .{
472 .name = field.name,
473 .value = .{ .lazy_path_list = list },
474 .used = false,
475 }) catch @panic("OOM");
476 },
477 []const u8 => return if (maybe_value) |v| {
478 map.put(field.name, .{
479 .name = field.name,
480 .value = .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") },
481 .used = false,
482 }) catch @panic("OOM");
483 },
484 []const []const u8 => return if (maybe_value) |v| {
485 var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
486 for (v) |s| list.appendAssumeCapacity(arena.dupe(u8, s) catch @panic("OOM"));
487 map.put(field.name, .{
488 .name = field.name,
489 .value = .{ .list = list },
490 .used = false,
491 }) catch @panic("OOM");
492 },
493 else => switch (@typeInfo(T)) {
494 .bool => return if (maybe_value) |v| {
495 map.put(field.name, .{
444 .name = field.name,496 .name = field.name,
445 .value = .{ .lazy_path = v.dupeInner(allocator) },497 .value = .{ .scalar = if (v) "true" else "false" },
446 .used = false,498 .used = false,
447 }) catch @panic("OOM");499 }) catch @panic("OOM");
448 },500 },
449 []const LazyPath => {501 .@"enum", .enum_literal => return if (maybe_value) |v| {
450 var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");502 map.put(field.name, .{
451 for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
452 user_input_options.put(field.name, .{
453 .name = field.name,503 .name = field.name,
454 .value = .{ .lazy_path_list = list },504 .value = .{ .scalar = @tagName(v) },
455 .used = false,505 .used = false,
456 }) catch @panic("OOM");506 }) catch @panic("OOM");
457 },507 },
458 []const u8 => {508 .comptime_int, .int => return if (maybe_value) |v| {
459 user_input_options.put(field.name, .{509 map.put(field.name, .{
460 .name = field.name,510 .name = field.name,
461 .value = .{ .scalar = v },511 .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") },
462 .used = false,512 .used = false,
463 }) catch @panic("OOM");513 }) catch @panic("OOM");
464 },514 },
465 []const []const u8 => {515 .comptime_float, .float => return if (maybe_value) |v| {
466 var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM");516 map.put(field.name, .{
467 list.appendSliceAssumeCapacity(v);
468
469 user_input_options.put(field.name, .{
470 .name = field.name,517 .name = field.name,
471 .value = .{ .list = list },518 .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") },
472 .used = false,519 .used = false,
473 }) catch @panic("OOM");520 }) catch @panic("OOM");
474 },521 },
475 else => switch (@typeInfo(T)) {522 .pointer => |ptr_info| switch (ptr_info.size) {
476 .bool => {523 .one => switch (@typeInfo(ptr_info.child)) {
477 user_input_options.put(field.name, .{524 .array => |array_info| {
478 .name = field.name,525 comptime var slice_info = ptr_info;
479 .value = .{ .scalar = if (v) "true" else "false" },526 slice_info.size = .slice;
480 .used = false,527 slice_info.is_const = true;
481 }) catch @panic("OOM");528 slice_info.child = array_info.child;
482 },529 slice_info.sentinel_ptr = null;
483 .@"enum", .enum_literal => {530 addUserInputOptionFromArg(
484 user_input_options.put(field.name, .{531 arena,
485 .name = field.name,532 map,
486 .value = .{ .scalar = @tagName(v) },533 field,
487 .used = false,534 @Type(.{ .pointer = slice_info }),
488 }) catch @panic("OOM");535 maybe_value orelse null,
536 );
537 return;
538 },
539 else => {},
489 },540 },
490 .comptime_int, .int => {541 .slice => switch (@typeInfo(ptr_info.child)) {
491 user_input_options.put(field.name, .{542 .@"enum" => return if (maybe_value) |v| {
492 .name = field.name,543 var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
493 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") },544 for (v) |tag| list.appendAssumeCapacity(@tagName(tag));
494 .used = false,545 map.put(field.name, .{
495 }) catch @panic("OOM");546 .name = field.name,
547 .value = .{ .list = list },
548 .used = false,
549 }) catch @panic("OOM");
550 },
551 else => {
552 comptime var slice_info = ptr_info;
553 slice_info.is_const = true;
554 slice_info.sentinel_ptr = null;
555 addUserInputOptionFromArg(
556 arena,
557 map,
558 field,
559 @Type(.{ .pointer = slice_info }),
560 maybe_value orelse null,
561 );
562 return;
563 },
496 },564 },
497 .comptime_float, .float => {565 else => {},
498 user_input_options.put(field.name, .{566 },
499 .name = field.name,567 .null => unreachable,
500 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") },568 .optional => |info| switch (@typeInfo(info.child)) {
501 .used = false,569 .optional => {},
502 }) catch @panic("OOM");570 else => {
571 addUserInputOptionFromArg(
572 arena,
573 map,
574 field,
575 info.child,
576 maybe_value orelse null,
577 );
578 return;
503 },579 },
504 else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
505 },580 },
506 }581 else => {},
582 },
507 }583 }
508584 @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type));
509 return user_input_options;
510}585}
511586
512const OrderedUserValue = union(enum) {587const OrderedUserValue = union(enum) {
lib/std/Build/Step/Compile.zig+42-4
...@@ -681,10 +681,14 @@ pub fn producesImplib(compile: *Compile) bool {...@@ -681,10 +681,14 @@ pub fn producesImplib(compile: *Compile) bool {
681 return compile.isDll();681 return compile.isDll();
682}682}
683683
684/// Deprecated; use `compile.root_module.link_libc = true` instead.
685/// To be removed after 0.15.0 is tagged.
684pub fn linkLibC(compile: *Compile) void {686pub fn linkLibC(compile: *Compile) void {
685 compile.root_module.link_libc = true;687 compile.root_module.link_libc = true;
686}688}
687689
690/// Deprecated; use `compile.root_module.link_libcpp = true` instead.
691/// To be removed after 0.15.0 is tagged.
688pub fn linkLibCpp(compile: *Compile) void {692pub fn linkLibCpp(compile: *Compile) void {
689 compile.root_module.link_libcpp = true;693 compile.root_module.link_libcpp = true;
690}694}
...@@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {...@@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {
802 };806 };
803}807}
804808
809/// Deprecated; use `compile.root_module.linkSystemLibrary(name, .{})` instead.
810/// To be removed after 0.15.0 is tagged.
805pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void {811pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void {
806 return compile.root_module.linkSystemLibrary(name, .{});812 return compile.root_module.linkSystemLibrary(name, .{});
807}813}
808814
815/// Deprecated; use `compile.root_module.linkSystemLibrary(name, options)` instead.
816/// To be removed after 0.15.0 is tagged.
809pub fn linkSystemLibrary2(817pub fn linkSystemLibrary2(
810 compile: *Compile,818 compile: *Compile,
811 name: []const u8,819 name: []const u8,
...@@ -814,22 +822,26 @@ pub fn linkSystemLibrary2(...@@ -814,22 +822,26 @@ pub fn linkSystemLibrary2(
814 return compile.root_module.linkSystemLibrary(name, options);822 return compile.root_module.linkSystemLibrary(name, options);
815}823}
816824
825/// Deprecated; use `c.root_module.linkFramework(name, .{})` instead.
826/// To be removed after 0.15.0 is tagged.
817pub fn linkFramework(c: *Compile, name: []const u8) void {827pub fn linkFramework(c: *Compile, name: []const u8) void {
818 c.root_module.linkFramework(name, .{});828 c.root_module.linkFramework(name, .{});
819}829}
820830
821/// Handy when you have many C/C++ source files and want them all to have the same flags.831/// Deprecated; use `compile.root_module.addCSourceFiles(options)` instead.
832/// To be removed after 0.15.0 is tagged.
822pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {833pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {
823 compile.root_module.addCSourceFiles(options);834 compile.root_module.addCSourceFiles(options);
824}835}
825836
837/// Deprecated; use `compile.root_module.addCSourceFile(source)` instead.
838/// To be removed after 0.15.0 is tagged.
826pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {839pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {
827 compile.root_module.addCSourceFile(source);840 compile.root_module.addCSourceFile(source);
828}841}
829842
830/// Resource files must have the extension `.rc`.843/// Deprecated; use `compile.root_module.addWin32ResourceFile(source)` instead.
831/// Can be called regardless of target. The .rc file will be ignored844/// To be removed after 0.15.0 is tagged.
832/// if the target object format does not support embedded resources.
833pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {845pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {
834 compile.root_module.addWin32ResourceFile(source);846 compile.root_module.addWin32ResourceFile(source);
835}847}
...@@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {...@@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
915 return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);927 return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);
916}928}
917929
930/// Deprecated; use `compile.root_module.addAssemblyFile(source)` instead.
931/// To be removed after 0.15.0 is tagged.
918pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {932pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {
919 compile.root_module.addAssemblyFile(source);933 compile.root_module.addAssemblyFile(source);
920}934}
921935
936/// Deprecated; use `compile.root_module.addObjectFile(source)` instead.
937/// To be removed after 0.15.0 is tagged.
922pub fn addObjectFile(compile: *Compile, source: LazyPath) void {938pub fn addObjectFile(compile: *Compile, source: LazyPath) void {
923 compile.root_module.addObjectFile(source);939 compile.root_module.addObjectFile(source);
924}940}
925941
942/// Deprecated; use `compile.root_module.addObject(object)` instead.
943/// To be removed after 0.15.0 is tagged.
926pub fn addObject(compile: *Compile, object: *Compile) void {944pub fn addObject(compile: *Compile, object: *Compile) void {
927 compile.root_module.addObject(object);945 compile.root_module.addObject(object);
928}946}
929947
948/// Deprecated; use `compile.root_module.linkLibrary(library)` instead.
949/// To be removed after 0.15.0 is tagged.
930pub fn linkLibrary(compile: *Compile, library: *Compile) void {950pub fn linkLibrary(compile: *Compile, library: *Compile) void {
931 compile.root_module.linkLibrary(library);951 compile.root_module.linkLibrary(library);
932}952}
933953
954/// Deprecated; use `compile.root_module.addAfterIncludePath(lazy_path)` instead.
955/// To be removed after 0.15.0 is tagged.
934pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void {956pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void {
935 compile.root_module.addAfterIncludePath(lazy_path);957 compile.root_module.addAfterIncludePath(lazy_path);
936}958}
937959
960/// Deprecated; use `compile.root_module.addSystemIncludePath(lazy_path)` instead.
961/// To be removed after 0.15.0 is tagged.
938pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void {962pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void {
939 compile.root_module.addSystemIncludePath(lazy_path);963 compile.root_module.addSystemIncludePath(lazy_path);
940}964}
941965
966/// Deprecated; use `compile.root_module.addIncludePath(lazy_path)` instead.
967/// To be removed after 0.15.0 is tagged.
942pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void {968pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void {
943 compile.root_module.addIncludePath(lazy_path);969 compile.root_module.addIncludePath(lazy_path);
944}970}
945971
972/// Deprecated; use `compile.root_module.addConfigHeader(config_header)` instead.
973/// To be removed after 0.15.0 is tagged.
946pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void {974pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void {
947 compile.root_module.addConfigHeader(config_header);975 compile.root_module.addConfigHeader(config_header);
948}976}
949977
978/// Deprecated; use `compile.root_module.addEmbedPath(lazy_path)` instead.
979/// To be removed after 0.15.0 is tagged.
950pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void {980pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void {
951 compile.root_module.addEmbedPath(lazy_path);981 compile.root_module.addEmbedPath(lazy_path);
952}982}
953983
984/// Deprecated; use `compile.root_module.addLibraryPath(directory_path)` instead.
985/// To be removed after 0.15.0 is tagged.
954pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void {986pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void {
955 compile.root_module.addLibraryPath(directory_path);987 compile.root_module.addLibraryPath(directory_path);
956}988}
957989
990/// Deprecated; use `compile.root_module.addRPath(directory_path)` instead.
991/// To be removed after 0.15.0 is tagged.
958pub fn addRPath(compile: *Compile, directory_path: LazyPath) void {992pub fn addRPath(compile: *Compile, directory_path: LazyPath) void {
959 compile.root_module.addRPath(directory_path);993 compile.root_module.addRPath(directory_path);
960}994}
961995
996/// Deprecated; use `compile.root_module.addSystemFrameworkPath(directory_path)` instead.
997/// To be removed after 0.15.0 is tagged.
962pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void {998pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
963 compile.root_module.addSystemFrameworkPath(directory_path);999 compile.root_module.addSystemFrameworkPath(directory_path);
964}1000}
9651001
1002/// Deprecated; use `compile.root_module.addFrameworkPath(directory_path)` instead.
1003/// To be removed after 0.15.0 is tagged.
966pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void {1004pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
967 compile.root_module.addFrameworkPath(directory_path);1005 compile.root_module.addFrameworkPath(directory_path);
968}1006}
lib/std/Build/Step/Run.zig+10
...@@ -1391,6 +1391,16 @@ fn runCommand(...@@ -1391,6 +1391,16 @@ fn runCommand(
1391 }1391 }
1392 },1392 },
1393 else => {1393 else => {
1394 // On failure, print stderr if captured.
1395 const bad_exit = switch (result.term) {
1396 .Exited => |code| code != 0,
1397 .Signal, .Stopped, .Unknown => true,
1398 };
1399
1400 if (bad_exit) if (result.stdio.stderr) |err| {
1401 try step.addError("stderr:\n{s}", .{err});
1402 };
1403
1394 try step.handleChildProcessTerm(result.term, cwd, final_argv);1404 try step.handleChildProcessTerm(result.term, cwd, final_argv);
1395 },1405 },
1396 }1406 }
lib/std/Io.zig+1-2
...@@ -354,7 +354,7 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -354,7 +354,7 @@ pub fn Poller(comptime StreamEnum: type) type {
354 const unused = r.buffer[r.end..];354 const unused = r.buffer[r.end..];
355 if (unused.len >= min_len) return unused;355 if (unused.len >= min_len) return unused;
356 }356 }
357 if (r.seek > 0) r.rebase();357 if (r.seek > 0) r.rebase(r.buffer.len) catch unreachable;
358 {358 {
359 var list: std.ArrayListUnmanaged(u8) = .{359 var list: std.ArrayListUnmanaged(u8) = .{
360 .items = r.buffer[0..r.end],360 .items = r.buffer[0..r.end],
...@@ -544,7 +544,6 @@ pub fn PollFiles(comptime StreamEnum: type) type {...@@ -544,7 +544,6 @@ pub fn PollFiles(comptime StreamEnum: type) type {
544544
545test {545test {
546 _ = Reader;546 _ = Reader;
547 _ = Reader.Limited;
548 _ = Writer;547 _ = Writer;
549 _ = tty;548 _ = tty;
550 _ = @import("Io/test.zig");549 _ = @import("Io/test.zig");
lib/std/Io/DeprecatedReader.zig+1
...@@ -397,6 +397,7 @@ pub const Adapter = struct {...@@ -397,6 +397,7 @@ pub const Adapter = struct {
397 a.err = err;397 a.err = err;
398 return error.ReadFailed;398 return error.ReadFailed;
399 };399 };
400 if (n == 0) return error.EndOfStream;
400 w.advance(n);401 w.advance(n);
401 return n;402 return n;
402 }403 }
lib/std/Io/Reader.zig+284-213
...@@ -43,8 +43,8 @@ pub const VTable = struct {...@@ -43,8 +43,8 @@ pub const VTable = struct {
43 ///43 ///
44 /// In addition to, or instead of writing to `w`, the implementation may44 /// In addition to, or instead of writing to `w`, the implementation may
45 /// choose to store data in `buffer`, modifying `seek` and `end`45 /// choose to store data in `buffer`, modifying `seek` and `end`
46 /// accordingly. Stream implementations are encouraged to take advantage of46 /// accordingly. Implementations are encouraged to take advantage of
47 /// this if simplifies the logic.47 /// this if it simplifies the logic.
48 stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,48 stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,
4949
50 /// Consumes bytes from the internally tracked stream position without50 /// Consumes bytes from the internally tracked stream position without
...@@ -67,6 +67,37 @@ pub const VTable = struct {...@@ -67,6 +67,37 @@ pub const VTable = struct {
67 ///67 ///
68 /// This function is only called when `buffer` is empty.68 /// This function is only called when `buffer` is empty.
69 discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard,69 discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard,
70
71 /// Returns number of bytes written to `data`.
72 ///
73 /// `data` may not have nonzero length.
74 ///
75 /// `data` may not contain an alias to `Reader.buffer`.
76 ///
77 /// `data` is mutable because the implementation may to temporarily modify
78 /// the fields in order to handle partial reads. Implementations must
79 /// restore the original value before returning.
80 ///
81 /// Implementations may ignore `data`, writing directly to `Reader.buffer`,
82 /// modifying `seek` and `end` accordingly, and returning 0 from this
83 /// function. Implementations are encouraged to take advantage of this if
84 /// it simplifies the logic.
85 ///
86 /// The default implementation calls `stream` with either `data[0]` or
87 /// `Reader.buffer`, whichever is bigger.
88 readVec: *const fn (r: *Reader, data: [][]u8) Error!usize = defaultReadVec,
89
90 /// Ensures `capacity` more data can be buffered without rebasing.
91 ///
92 /// Asserts `capacity` is within buffer capacity, or that the stream ends
93 /// within `capacity` bytes.
94 ///
95 /// Only called when `capacity` cannot fit into the unused capacity of
96 /// `buffer`.
97 ///
98 /// The default implementation moves buffered data to the start of
99 /// `buffer`, setting `seek` to zero, and cannot fail.
100 rebase: *const fn (r: *Reader, capacity: usize) RebaseError!void = defaultRebase,
70};101};
71102
72pub const StreamError = error{103pub const StreamError = error{
...@@ -97,6 +128,10 @@ pub const ShortError = error{...@@ -97,6 +128,10 @@ pub const ShortError = error{
97 ReadFailed,128 ReadFailed,
98};129};
99130
131pub const RebaseError = error{
132 EndOfStream,
133};
134
100pub const failing: Reader = .{135pub const failing: Reader = .{
101 .vtable = &.{136 .vtable = &.{
102 .stream = failingStream,137 .stream = failingStream,
...@@ -122,6 +157,8 @@ pub fn fixed(buffer: []const u8) Reader {...@@ -122,6 +157,8 @@ pub fn fixed(buffer: []const u8) Reader {
122 .vtable = &.{157 .vtable = &.{
123 .stream = endingStream,158 .stream = endingStream,
124 .discard = endingDiscard,159 .discard = endingDiscard,
160 .readVec = endingReadVec,
161 .rebase = endingRebase,
125 },162 },
126 // This cast is safe because all potential writes to it will instead163 // This cast is safe because all potential writes to it will instead
127 // return `error.EndOfStream`.164 // return `error.EndOfStream`.
...@@ -153,18 +190,18 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize {...@@ -153,18 +190,18 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize {
153 }190 }
154 break :l .limited(n - buffered_len);191 break :l .limited(n - buffered_len);
155 } else .unlimited;192 } else .unlimited;
156 r.seek = 0;193 r.seek = r.end;
157 r.end = 0;
158 const n = try r.vtable.discard(r, remaining);194 const n = try r.vtable.discard(r, remaining);
159 assert(n <= @intFromEnum(remaining));195 assert(n <= @intFromEnum(remaining));
160 return buffered_len + n;196 return buffered_len + n;
161}197}
162198
163pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {199pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
164 assert(r.seek == 0);200 assert(r.seek == r.end);
165 assert(r.end == 0);201 r.seek = 0;
166 var dw: Writer.Discarding = .init(r.buffer);202 r.end = 0;
167 const n = r.stream(&dw.writer, limit) catch |err| switch (err) {203 var d: Writer.Discarding = .init(r.buffer);
204 const n = r.stream(&d.writer, limit) catch |err| switch (err) {
168 error.WriteFailed => unreachable,205 error.WriteFailed => unreachable,
169 error.ReadFailed => return error.ReadFailed,206 error.ReadFailed => return error.ReadFailed,
170 error.EndOfStream => return error.EndOfStream,207 error.EndOfStream => return error.EndOfStream,
...@@ -229,8 +266,7 @@ pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {...@@ -229,8 +266,7 @@ pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {
229/// number of bytes discarded.266/// number of bytes discarded.
230pub fn discardRemaining(r: *Reader) ShortError!usize {267pub fn discardRemaining(r: *Reader) ShortError!usize {
231 var offset: usize = r.end - r.seek;268 var offset: usize = r.end - r.seek;
232 r.seek = 0;269 r.seek = r.end;
233 r.end = 0;
234 while (true) {270 while (true) {
235 offset += r.vtable.discard(r, .unlimited) catch |err| switch (err) {271 offset += r.vtable.discard(r, .unlimited) catch |err| switch (err) {
236 error.EndOfStream => return offset,272 error.EndOfStream => return offset,
...@@ -277,7 +313,8 @@ pub fn appendRemaining(...@@ -277,7 +313,8 @@ pub fn appendRemaining(
277 list: *std.ArrayListAlignedUnmanaged(u8, alignment),313 list: *std.ArrayListAlignedUnmanaged(u8, alignment),
278 limit: Limit,314 limit: Limit,
279) LimitedAllocError!void {315) LimitedAllocError!void {
280 if (limit != .unlimited) assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.316 if (limit == .unlimited) return appendRemainingUnlimited(r, gpa, alignment, list, 1);
317 assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
281 const buffer_contents = r.buffer[r.seek..r.end];318 const buffer_contents = r.buffer[r.seek..r.end];
282 const copy_len = limit.minInt(buffer_contents.len);319 const copy_len = limit.minInt(buffer_contents.len);
283 try list.appendSlice(gpa, r.buffer[0..copy_len]);320 try list.appendSlice(gpa, r.buffer[0..copy_len]);
...@@ -286,32 +323,67 @@ pub fn appendRemaining(...@@ -286,32 +323,67 @@ pub fn appendRemaining(
286 r.seek = 0;323 r.seek = 0;
287 r.end = 0;324 r.end = 0;
288 var remaining = @intFromEnum(limit) - copy_len;325 var remaining = @intFromEnum(limit) - copy_len;
326 // From here, we leave `buffer` empty, appending directly to `list`.
327 var writer: Writer = .{
328 .buffer = undefined,
329 .end = undefined,
330 .vtable = &.{ .drain = Writer.fixedDrain },
331 };
289 while (true) {332 while (true) {
290 try list.ensureUnusedCapacity(gpa, 1);333 try list.ensureUnusedCapacity(gpa, 2);
291 const cap = list.unusedCapacitySlice();334 const cap = list.unusedCapacitySlice();
292 const dest = cap[0..@min(cap.len, remaining)];335 const dest = cap[0..@min(cap.len, remaining + 1)];
293 if (remaining - dest.len == 0) {336 writer.buffer = list.allocatedSlice();
294 // Additionally provides `buffer` to detect end.337 writer.end = list.items.len;
295 const new_remaining = readVecInner(r, &.{}, dest, remaining) catch |err| switch (err) {338 const n = r.vtable.stream(r, &writer, .limited(dest.len)) catch |err| switch (err) {
296 error.EndOfStream => {339 error.WriteFailed => unreachable, // Prevented by the limit.
297 if (r.bufferedLen() != 0) return error.StreamTooLong;340 error.EndOfStream => return,
298 return;341 error.ReadFailed => return error.ReadFailed,
299 },342 };
300 error.ReadFailed => return error.ReadFailed,343 list.items.len += n;
301 };344 if (n > remaining) {
302 list.items.len += remaining - new_remaining;345 // Move the byte to `Reader.buffer` so it is not lost.
303 remaining = new_remaining;346 assert(n - remaining == 1);
304 } else {347 assert(r.end == 0);
305 // Leave `buffer` empty, appending directly to `list`.348 r.buffer[0] = list.items[list.items.len - 1];
306 var dest_w: Writer = .fixed(dest);349 list.items.len -= 1;
307 const n = r.vtable.stream(r, &dest_w, .limited(dest.len)) catch |err| switch (err) {350 r.end = 1;
308 error.WriteFailed => unreachable, // Prevented by the limit.351 return;
309 error.EndOfStream => return,
310 error.ReadFailed => return error.ReadFailed,
311 };
312 list.items.len += n;
313 remaining -= n;
314 }352 }
353 remaining -= n;
354 }
355}
356
357pub const UnlimitedAllocError = Allocator.Error || ShortError;
358
359pub fn appendRemainingUnlimited(
360 r: *Reader,
361 gpa: Allocator,
362 comptime alignment: ?std.mem.Alignment,
363 list: *std.ArrayListAlignedUnmanaged(u8, alignment),
364 bump: usize,
365) UnlimitedAllocError!void {
366 const buffer_contents = r.buffer[r.seek..r.end];
367 try list.ensureUnusedCapacity(gpa, buffer_contents.len + bump);
368 list.appendSliceAssumeCapacity(buffer_contents);
369 r.seek = 0;
370 r.end = 0;
371 // From here, we leave `buffer` empty, appending directly to `list`.
372 var writer: Writer = .{
373 .buffer = undefined,
374 .end = undefined,
375 .vtable = &.{ .drain = Writer.fixedDrain },
376 };
377 while (true) {
378 try list.ensureUnusedCapacity(gpa, bump);
379 writer.buffer = list.allocatedSlice();
380 writer.end = list.items.len;
381 const n = r.vtable.stream(r, &writer, .limited(list.unusedCapacitySlice().len)) catch |err| switch (err) {
382 error.WriteFailed => unreachable, // Prevented by the limit.
383 error.EndOfStream => return,
384 error.ReadFailed => return error.ReadFailed,
385 };
386 list.items.len += n;
315 }387 }
316}388}
317389
...@@ -323,95 +395,50 @@ pub fn appendRemaining(...@@ -323,95 +395,50 @@ pub fn appendRemaining(
323///395///
324/// The reader's internal logical seek position moves forward in accordance396/// The reader's internal logical seek position moves forward in accordance
325/// with the number of bytes returned from this function.397/// with the number of bytes returned from this function.
326pub fn readVec(r: *Reader, data: []const []u8) Error!usize {398pub fn readVec(r: *Reader, data: [][]u8) Error!usize {
327 return readVecLimit(r, data, .unlimited);399 var seek = r.seek;
328}
329
330/// Equivalent to `readVec` but reads at most `limit` bytes.
331///
332/// This ultimately will lower to a call to `stream`, but it must ensure
333/// that the buffer used has at least as much capacity, in case that function
334/// depends on a minimum buffer capacity. It also ensures that if the `stream`
335/// implementation calls `Writer.writableVector`, it will get this data slice
336/// along with the buffer at the end.
337pub fn readVecLimit(r: *Reader, data: []const []u8, limit: Limit) Error!usize {
338 comptime assert(@intFromEnum(Limit.unlimited) == std.math.maxInt(usize));
339 var remaining = @intFromEnum(limit);
340 for (data, 0..) |buf, i| {400 for (data, 0..) |buf, i| {
341 const buffer_contents = r.buffer[r.seek..r.end];401 const contents = r.buffer[seek..r.end];
342 const copy_len = @min(buffer_contents.len, buf.len, remaining);402 const copy_len = @min(contents.len, buf.len);
343 @memcpy(buf[0..copy_len], buffer_contents[0..copy_len]);403 @memcpy(buf[0..copy_len], contents[0..copy_len]);
344 r.seek += copy_len;404 seek += copy_len;
345 remaining -= copy_len;
346 if (remaining == 0) break;
347 if (buf.len - copy_len == 0) continue;405 if (buf.len - copy_len == 0) continue;
348406
349 // All of `buffer` has been copied to `data`. We now set up a structure407 // All of `buffer` has been copied to `data`.
350 // that enables the `Writer.writableVector` API, while also ensuring408 const n = seek - r.seek;
351 // API that directly operates on the `Writable.buffer` has its minimum409 r.seek = seek;
352 // buffer capacity requirements met.410 data[i] = buf[copy_len..];
353 r.seek = 0;411 defer data[i] = buf;
354 r.end = 0;412 return n + (r.vtable.readVec(r, data[i..]) catch |err| switch (err) {
355 remaining = try readVecInner(r, data[i + 1 ..], buf[copy_len..], remaining);413 error.EndOfStream => if (n == 0) return error.EndOfStream else 0,
356 break;414 error.ReadFailed => return error.ReadFailed,
415 });
357 }416 }
358 return @intFromEnum(limit) - remaining;417 const n = seek - r.seek;
418 r.seek = seek;
419 return n;
359}420}
360421
361fn readVecInner(r: *Reader, middle: []const []u8, first: []u8, remaining: usize) Error!usize {422/// Writes to `Reader.buffer` or `data`, whichever has larger capacity.
362 var wrapper: Writer.VectorWrapper = .{423pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize {
363 .it = .{424 assert(r.seek == r.end);
364 .first = first,425 r.seek = 0;
365 .middle = middle,426 r.end = 0;
366 .last = r.buffer,427 const first = data[0];
367 },428 const direct = first.len >= r.buffer.len;
368 .writer = .{429 var writer: Writer = .{
369 .buffer = if (first.len >= r.buffer.len) first else r.buffer,430 .buffer = if (direct) first else r.buffer,
370 .vtable = Writer.VectorWrapper.vtable,431 .end = 0,
371 },432 .vtable = &.{ .drain = Writer.fixedDrain },
372 };
373 // If the limit may pass beyond user buffer into Reader buffer, use
374 // unlimited, allowing the Reader buffer to fill.
375 const limit: Limit = l: {
376 var n: usize = first.len;
377 for (middle) |m| n += m.len;
378 break :l if (remaining >= n) .unlimited else .limited(remaining);
379 };433 };
380 var n = r.vtable.stream(r, &wrapper.writer, limit) catch |err| switch (err) {434 const limit: Limit = .limited(writer.buffer.len - writer.end);
381 error.WriteFailed => {435 const n = r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
382 assert(!wrapper.used);436 error.WriteFailed => unreachable,
383 if (wrapper.writer.buffer.ptr == first.ptr) {
384 return remaining - wrapper.writer.end;
385 } else {
386 assert(wrapper.writer.end <= r.buffer.len);
387 r.end = wrapper.writer.end;
388 return remaining;
389 }
390 },
391 else => |e| return e,437 else => |e| return e,
392 };438 };
393 if (!wrapper.used) {439 if (direct) return n;
394 if (wrapper.writer.buffer.ptr == first.ptr) {440 r.end += n;
395 return remaining - n;441 return 0;
396 } else {
397 assert(n <= r.buffer.len);
398 r.end = n;
399 return remaining;
400 }
401 }
402 if (n < first.len) return remaining - n;
403 var result = remaining - first.len;
404 n -= first.len;
405 for (middle) |mid| {
406 if (n < mid.len) {
407 return result - n;
408 }
409 result -= mid.len;
410 n -= mid.len;
411 }
412 assert(n <= r.buffer.len);
413 r.end = n;
414 return result;
415}442}
416443
417pub fn buffered(r: *Reader) []u8 {444pub fn buffered(r: *Reader) []u8 {
...@@ -422,8 +449,8 @@ pub fn bufferedLen(r: *const Reader) usize {...@@ -422,8 +449,8 @@ pub fn bufferedLen(r: *const Reader) usize {
422 return r.end - r.seek;449 return r.end - r.seek;
423}450}
424451
425pub fn hashed(r: *Reader, hasher: anytype) Hashed(@TypeOf(hasher)) {452pub fn hashed(r: *Reader, hasher: anytype, buffer: []u8) Hashed(@TypeOf(hasher)) {
426 return .{ .in = r, .hasher = hasher };453 return .init(r, hasher, buffer);
427}454}
428455
429pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {456pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {
...@@ -498,8 +525,7 @@ pub fn toss(r: *Reader, n: usize) void {...@@ -498,8 +525,7 @@ pub fn toss(r: *Reader, n: usize) void {
498525
499/// Equivalent to `toss(r.bufferedLen())`.526/// Equivalent to `toss(r.bufferedLen())`.
500pub fn tossBuffered(r: *Reader) void {527pub fn tossBuffered(r: *Reader) void {
501 r.seek = 0;528 r.seek = r.end;
502 r.end = 0;
503}529}
504530
505/// Equivalent to `peek` followed by `toss`.531/// Equivalent to `peek` followed by `toss`.
...@@ -586,8 +612,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize {...@@ -586,8 +612,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
586 return n;612 return n;
587 }613 }
588 var remaining = n - (r.end - r.seek);614 var remaining = n - (r.end - r.seek);
589 r.end = 0;615 r.seek = r.end;
590 r.seek = 0;
591 while (true) {616 while (true) {
592 const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {617 const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {
593 error.EndOfStream => return n - remaining,618 error.EndOfStream => return n - remaining,
...@@ -625,29 +650,24 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {...@@ -625,29 +650,24 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
625/// See also:650/// See also:
626/// * `readSliceAll`651/// * `readSliceAll`
627pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {652pub fn readSliceShort(r: *Reader, buffer: []u8) ShortError!usize {
628 var i: usize = 0;653 const contents = r.buffer[r.seek..r.end];
654 const copy_len = @min(buffer.len, contents.len);
655 @memcpy(buffer[0..copy_len], contents[0..copy_len]);
656 r.seek += copy_len;
657 if (buffer.len - copy_len == 0) {
658 @branchHint(.likely);
659 return buffer.len;
660 }
661 var i: usize = copy_len;
662 var data: [1][]u8 = undefined;
629 while (true) {663 while (true) {
630 const buffer_contents = r.buffer[r.seek..r.end];664 data[0] = buffer[i..];
631 const dest = buffer[i..];665 i += readVec(r, &data) catch |err| switch (err) {
632 const copy_len = @min(dest.len, buffer_contents.len);
633 @memcpy(dest[0..copy_len], buffer_contents[0..copy_len]);
634 if (dest.len - copy_len == 0) {
635 @branchHint(.likely);
636 r.seek += copy_len;
637 return buffer.len;
638 }
639 i += copy_len;
640 r.end = 0;
641 r.seek = 0;
642 const remaining = buffer[i..];
643 const new_remaining_len = readVecInner(r, &.{}, remaining, remaining.len) catch |err| switch (err) {
644 error.EndOfStream => return i,666 error.EndOfStream => return i,
645 error.ReadFailed => return error.ReadFailed,667 error.ReadFailed => return error.ReadFailed,
646 };668 };
647 if (new_remaining_len == 0) return buffer.len;669 if (buffer.len - i == 0) return buffer.len;
648 i += remaining.len - new_remaining_len;
649 }670 }
650 return buffer.len;
651}671}
652672
653/// Fill `buffer` with the next `buffer.len` bytes from the stream, advancing673/// 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 {...@@ -780,11 +800,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
780 @branchHint(.likely);800 @branchHint(.likely);
781 return buffer[seek .. end + 1];801 return buffer[seek .. end + 1];
782 }802 }
783 if (r.vtable.stream == &endingStream) {803 // TODO take a parameter for max search length rather than relying on buffer capacity
784 // Protect the `@constCast` of `fixed`.804 try rebase(r, r.buffer.len);
785 return error.EndOfStream;
786 }
787 r.rebase();
788 while (r.buffer.len - r.end != 0) {805 while (r.buffer.len - r.end != 0) {
789 const end_cap = r.buffer[r.end..];806 const end_cap = r.buffer[r.end..];
790 var writer: Writer = .fixed(end_cap);807 var writer: Writer = .fixed(end_cap);
...@@ -1041,20 +1058,7 @@ pub fn fill(r: *Reader, n: usize) Error!void {...@@ -1041,20 +1058,7 @@ pub fn fill(r: *Reader, n: usize) Error!void {
1041/// Missing this optimization can result in wall-clock time for the most affected benchmarks1058/// Missing this optimization can result in wall-clock time for the most affected benchmarks
1042/// increasing by a factor of 5 or more.1059/// increasing by a factor of 5 or more.
1043fn fillUnbuffered(r: *Reader, n: usize) Error!void {1060fn fillUnbuffered(r: *Reader, n: usize) Error!void {
1044 if (r.seek + n <= r.buffer.len) while (true) {1061 try rebase(r, n);
1045 const end_cap = r.buffer[r.end..];
1046 var writer: Writer = .fixed(end_cap);
1047 r.end += r.vtable.stream(r, &writer, .limited(end_cap.len)) catch |err| switch (err) {
1048 error.WriteFailed => unreachable,
1049 else => |e| return e,
1050 };
1051 if (r.seek + n <= r.end) return;
1052 };
1053 if (r.vtable.stream == &endingStream) {
1054 // Protect the `@constCast` of `fixed`.
1055 return error.EndOfStream;
1056 }
1057 rebaseCapacity(r, n);
1058 var writer: Writer = .{1062 var writer: Writer = .{
1059 .buffer = r.buffer,1063 .buffer = r.buffer,
1060 .vtable = &.{ .drain = Writer.fixedDrain },1064 .vtable = &.{ .drain = Writer.fixedDrain },
...@@ -1074,7 +1078,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {...@@ -1074,7 +1078,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
1074///1078///
1075/// Asserts buffer capacity is at least 1.1079/// Asserts buffer capacity is at least 1.
1076pub fn fillMore(r: *Reader) Error!void {1080pub fn fillMore(r: *Reader) Error!void {
1077 rebaseCapacity(r, 1);1081 try rebase(r, 1);
1078 var writer: Writer = .{1082 var writer: Writer = .{
1079 .buffer = r.buffer,1083 .buffer = r.buffer,
1080 .end = r.end,1084 .end = r.end,
...@@ -1251,7 +1255,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {...@@ -1251,7 +1255,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
12511255
1252pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {1256pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {
1253 if (n <= r.buffer.len) return;1257 if (n <= r.buffer.len) return;
1254 if (r.seek > 0) rebase(r);1258 if (r.seek > 0) rebase(r, r.buffer.len);
1255 var list: ArrayList(u8) = .{1259 var list: ArrayList(u8) = .{
1256 .items = r.buffer[0..r.end],1260 .items = r.buffer[0..r.end],
1257 .capacity = r.buffer.len,1261 .capacity = r.buffer.len,
...@@ -1297,37 +1301,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu...@@ -1297,37 +1301,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu
1297 }1301 }
1298}1302}
12991303
1300/// Left-aligns data such that `r.seek` becomes zero.1304/// Ensures `capacity` more data can be buffered without rebasing.
1301///1305pub fn rebase(r: *Reader, capacity: usize) RebaseError!void {
1302/// If `r.seek` is not already zero then `buffer` is mutated, making it illegal1306 if (r.end + capacity <= r.buffer.len) return;
1303/// to call this function with a const-casted `buffer`, such as in the case of1307 return r.vtable.rebase(r, capacity);
1304/// `fixed`. This issue can be avoided:1308}
1305/// * in implementations, by attempting a read before a rebase, in which1309
1306/// case the read will return `error.EndOfStream`, preventing the rebase.1310pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void {
1307/// * in usage, by copying into a mutable buffer before initializing `fixed`.1311 if (r.end <= r.buffer.len - capacity) return;
1308pub fn rebase(r: *Reader) void {
1309 if (r.seek == 0) return;
1310 const data = r.buffer[r.seek..r.end];1312 const data = r.buffer[r.seek..r.end];
1311 @memmove(r.buffer[0..data.len], data);1313 @memmove(r.buffer[0..data.len], data);
1312 r.seek = 0;1314 r.seek = 0;
1313 r.end = data.len;1315 r.end = data.len;
1314}1316}
13151317
1316/// Ensures `capacity` more data can be buffered without rebasing, by rebasing
1317/// if necessary.
1318///
1319/// Asserts `capacity` is within the buffer capacity.
1320///
1321/// If the rebase occurs then `buffer` is mutated, making it illegal to call
1322/// this function with a const-casted `buffer`, such as in the case of `fixed`.
1323/// This issue can be avoided:
1324/// * in implementations, by attempting a read before a rebase, in which
1325/// case the read will return `error.EndOfStream`, preventing the rebase.
1326/// * in usage, by copying into a mutable buffer before initializing `fixed`.
1327pub fn rebaseCapacity(r: *Reader, capacity: usize) void {
1328 if (r.end > r.buffer.len - capacity) rebase(r);
1329}
1330
1331/// Advances the stream and decreases the size of the storage buffer by `n`,1318/// Advances the stream and decreases the size of the storage buffer by `n`,
1332/// returning the range of bytes no longer accessible by `r`.1319/// returning the range of bytes no longer accessible by `r`.
1333///1320///
...@@ -1648,19 +1635,6 @@ test readVec {...@@ -1648,19 +1635,6 @@ test readVec {
1648 try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]);1635 try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]);
1649}1636}
16501637
1651test readVecLimit {
1652 var r: Reader = .fixed(std.ascii.letters);
1653 var flat_buffer: [52]u8 = undefined;
1654 var bufs: [2][]u8 = .{
1655 flat_buffer[0..26],
1656 flat_buffer[26..],
1657 };
1658 // Short reads are possible with this function but not with fixed.
1659 try testing.expectEqual(50, try r.readVecLimit(&bufs, .limited(50)));
1660 try testing.expectEqualStrings(std.ascii.letters[0..26], bufs[0]);
1661 try testing.expectEqualStrings(std.ascii.letters[26..50], bufs[1][0..24]);
1662}
1663
1664test "expected error.EndOfStream" {1638test "expected error.EndOfStream" {
1665 // Unit test inspired by https://github.com/ziglang/zig/issues/177331639 // Unit test inspired by https://github.com/ziglang/zig/issues/17733
1666 var buffer: [3]u8 = undefined;1640 var buffer: [3]u8 = undefined;
...@@ -1670,6 +1644,17 @@ test "expected error.EndOfStream" {...@@ -1670,6 +1644,17 @@ test "expected error.EndOfStream" {
1670 try std.testing.expectError(error.EndOfStream, r.take(3));1644 try std.testing.expectError(error.EndOfStream, r.take(3));
1671}1645}
16721646
1647test "readVec at end" {
1648 var reader_buffer: [8]u8 = "abcd1234".*;
1649 var reader: testing.Reader = .init(&reader_buffer, &.{});
1650 reader.interface.end = reader_buffer.len;
1651
1652 var out: [16]u8 = undefined;
1653 var vecs: [1][]u8 = .{&out};
1654 try testing.expectEqual(8, try reader.interface.readVec(&vecs));
1655 try testing.expectEqualStrings("abcd1234", vecs[0][0..8]);
1656}
1657
1673fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {1658fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1674 _ = r;1659 _ = r;
1675 _ = w;1660 _ = w;
...@@ -1677,12 +1662,24 @@ fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {...@@ -1677,12 +1662,24 @@ fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1677 return error.EndOfStream;1662 return error.EndOfStream;
1678}1663}
16791664
1665fn endingReadVec(r: *Reader, data: [][]u8) Error!usize {
1666 _ = r;
1667 _ = data;
1668 return error.EndOfStream;
1669}
1670
1680fn endingDiscard(r: *Reader, limit: Limit) Error!usize {1671fn endingDiscard(r: *Reader, limit: Limit) Error!usize {
1681 _ = r;1672 _ = r;
1682 _ = limit;1673 _ = limit;
1683 return error.EndOfStream;1674 return error.EndOfStream;
1684}1675}
16851676
1677fn endingRebase(r: *Reader, capacity: usize) RebaseError!void {
1678 _ = r;
1679 _ = capacity;
1680 return error.EndOfStream;
1681}
1682
1686fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {1683fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1687 _ = r;1684 _ = r;
1688 _ = w;1685 _ = w;
...@@ -1696,6 +1693,15 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize {...@@ -1696,6 +1693,15 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
1696 return error.ReadFailed;1693 return error.ReadFailed;
1697}1694}
16981695
1696pub fn adaptToOldInterface(r: *Reader) std.Io.AnyReader {
1697 return .{ .context = r, .readFn = derpRead };
1698}
1699
1700fn derpRead(context: *const anyopaque, buffer: []u8) anyerror!usize {
1701 const r: *Reader = @constCast(@alignCast(@ptrCast(context)));
1702 return r.readSliceShort(buffer);
1703}
1704
1699test "readAlloc when the backing reader provides one byte at a time" {1705test "readAlloc when the backing reader provides one byte at a time" {
1700 const str = "This is a test";1706 const str = "This is a test";
1701 var tiny_buffer: [1]u8 = undefined;1707 var tiny_buffer: [1]u8 = undefined;
...@@ -1759,15 +1765,16 @@ pub fn Hashed(comptime Hasher: type) type {...@@ -1759,15 +1765,16 @@ pub fn Hashed(comptime Hasher: type) type {
1759 return struct {1765 return struct {
1760 in: *Reader,1766 in: *Reader,
1761 hasher: Hasher,1767 hasher: Hasher,
1762 interface: Reader,1768 reader: Reader,
17631769
1764 pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {1770 pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {
1765 return .{1771 return .{
1766 .in = in,1772 .in = in,
1767 .hasher = hasher,1773 .hasher = hasher,
1768 .interface = .{1774 .reader = .{
1769 .vtable = &.{1775 .vtable = &.{
1770 .read = @This().read,1776 .stream = @This().stream,
1777 .readVec = @This().readVec,
1771 .discard = @This().discard,1778 .discard = @This().discard,
1772 },1779 },
1773 .buffer = buffer,1780 .buffer = buffer,
...@@ -1777,33 +1784,97 @@ pub fn Hashed(comptime Hasher: type) type {...@@ -1777,33 +1784,97 @@ pub fn Hashed(comptime Hasher: type) type {
1777 };1784 };
1778 }1785 }
17791786
1780 fn read(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {1787 fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1781 const this: *@This() = @alignCast(@fieldParentPtr("interface", r));1788 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1782 const data = w.writableVector(limit);1789 const data = limit.slice(try w.writableSliceGreedy(1));
1790 var vec: [1][]u8 = .{data};
1791 const n = try this.in.readVec(&vec);
1792 this.hasher.update(data[0..n]);
1793 w.advance(n);
1794 return n;
1795 }
1796
1797 fn readVec(r: *Reader, data: [][]u8) Error!usize {
1798 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1783 const n = try this.in.readVec(data);1799 const n = try this.in.readVec(data);
1784 const result = w.advanceVector(n);
1785 var remaining: usize = n;1800 var remaining: usize = n;
1786 for (data) |slice| {1801 for (data) |slice| {
1787 if (remaining < slice.len) {1802 if (remaining < slice.len) {
1788 this.hasher.update(slice[0..remaining]);1803 this.hasher.update(slice[0..remaining]);
1789 return result;1804 return n;
1790 } else {1805 } else {
1791 remaining -= slice.len;1806 remaining -= slice.len;
1792 this.hasher.update(slice);1807 this.hasher.update(slice);
1793 }1808 }
1794 }1809 }
1795 assert(remaining == 0);1810 assert(remaining == 0);
1796 return result;1811 return n;
1797 }1812 }
17981813
1799 fn discard(r: *Reader, limit: Limit) Error!usize {1814 fn discard(r: *Reader, limit: Limit) Error!usize {
1800 const this: *@This() = @alignCast(@fieldParentPtr("interface", r));1815 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1801 var w = this.hasher.writer(&.{});1816 const peeked = limit.slice(try this.in.peekGreedy(1));
1802 const n = this.in.stream(&w, limit) catch |err| switch (err) {1817 this.hasher.update(peeked);
1803 error.WriteFailed => unreachable,1818 this.in.toss(peeked.len);
1804 else => |e| return e,1819 return peeked.len;
1805 };
1806 return n;
1807 }1820 }
1808 };1821 };
1809}1822}
1823
1824pub fn writableVectorPosix(r: *Reader, buffer: []std.posix.iovec, data: []const []u8) Error!struct { usize, usize } {
1825 var i: usize = 0;
1826 var n: usize = 0;
1827 for (data) |buf| {
1828 if (buffer.len - i == 0) return .{ i, n };
1829 if (buf.len != 0) {
1830 buffer[i] = .{ .base = buf.ptr, .len = buf.len };
1831 i += 1;
1832 n += buf.len;
1833 }
1834 }
1835 assert(r.seek == r.end);
1836 const buf = r.buffer;
1837 if (buf.len != 0) {
1838 buffer[i] = .{ .base = buf.ptr, .len = buf.len };
1839 i += 1;
1840 }
1841 return .{ i, n };
1842}
1843
1844pub fn writableVectorWsa(
1845 r: *Reader,
1846 buffer: []std.os.windows.ws2_32.WSABUF,
1847 data: []const []u8,
1848) Error!struct { usize, usize } {
1849 var i: usize = 0;
1850 var n: usize = 0;
1851 for (data) |buf| {
1852 if (buffer.len - i == 0) return .{ i, n };
1853 if (buf.len == 0) continue;
1854 if (std.math.cast(u32, buf.len)) |len| {
1855 buffer[i] = .{ .buf = buf.ptr, .len = len };
1856 i += 1;
1857 n += len;
1858 continue;
1859 }
1860 buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
1861 i += 1;
1862 n += std.math.maxInt(u32);
1863 return .{ i, n };
1864 }
1865 assert(r.seek == r.end);
1866 const buf = r.buffer;
1867 if (buf.len != 0) {
1868 if (std.math.cast(u32, buf.len)) |len| {
1869 buffer[i] = .{ .buf = buf.ptr, .len = len };
1870 } else {
1871 buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
1872 }
1873 i += 1;
1874 }
1875 return .{ i, n };
1876}
1877
1878test {
1879 _ = Limited;
1880}
lib/std/Io/Writer.zig+67-104
...@@ -342,97 +342,6 @@ pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error!...@@ -342,97 +342,6 @@ pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error!
342 return big_slice[0..len];342 return big_slice[0..len];
343}343}
344344
345pub const WritableVectorIterator = struct {
346 first: []u8,
347 middle: []const []u8 = &.{},
348 last: []u8 = &.{},
349 index: usize = 0,
350
351 pub fn next(it: *WritableVectorIterator) ?[]u8 {
352 while (true) {
353 const i = it.index;
354 it.index += 1;
355 if (i == 0) {
356 if (it.first.len == 0) continue;
357 return it.first;
358 }
359 const middle_index = i - 1;
360 if (middle_index < it.middle.len) {
361 const middle = it.middle[middle_index];
362 if (middle.len == 0) continue;
363 return middle;
364 }
365 if (middle_index == it.middle.len) {
366 if (it.last.len == 0) continue;
367 return it.last;
368 }
369 return null;
370 }
371 }
372};
373
374pub const VectorWrapper = struct {
375 writer: Writer,
376 it: WritableVectorIterator,
377 /// Tracks whether the "writable vector" API was used.
378 used: bool = false,
379 pub const vtable: *const VTable = &unique_vtable_allocation;
380 /// This is intended to be constant but it must be a unique address for
381 /// `@fieldParentPtr` to work.
382 var unique_vtable_allocation: VTable = .{ .drain = fixedDrain };
383};
384
385pub fn writableVectorIterator(w: *Writer) Error!WritableVectorIterator {
386 if (w.vtable == VectorWrapper.vtable) {
387 const wrapper: *VectorWrapper = @fieldParentPtr("writer", w);
388 wrapper.used = true;
389 return wrapper.it;
390 }
391 return .{ .first = try writableSliceGreedy(w, 1) };
392}
393
394pub fn writableVectorPosix(w: *Writer, buffer: []std.posix.iovec, limit: Limit) Error![]std.posix.iovec {
395 var it = try writableVectorIterator(w);
396 var i: usize = 0;
397 var remaining = limit;
398 while (it.next()) |full_buffer| {
399 if (!remaining.nonzero()) break;
400 if (buffer.len - i == 0) break;
401 const buf = remaining.slice(full_buffer);
402 if (buf.len == 0) continue;
403 buffer[i] = .{ .base = buf.ptr, .len = buf.len };
404 i += 1;
405 remaining = remaining.subtract(buf.len).?;
406 }
407 return buffer[0..i];
408}
409
410pub fn writableVectorWsa(
411 w: *Writer,
412 buffer: []std.os.windows.ws2_32.WSABUF,
413 limit: Limit,
414) Error![]std.os.windows.ws2_32.WSABUF {
415 var it = try writableVectorIterator(w);
416 var i: usize = 0;
417 var remaining = limit;
418 while (it.next()) |full_buffer| {
419 if (!remaining.nonzero()) break;
420 if (buffer.len - i == 0) break;
421 const buf = remaining.slice(full_buffer);
422 if (buf.len == 0) continue;
423 if (std.math.cast(u32, buf.len)) |len| {
424 buffer[i] = .{ .buf = buf.ptr, .len = len };
425 i += 1;
426 remaining = remaining.subtract(len).?;
427 continue;
428 }
429 buffer[i] = .{ .buf = buf.ptr, .len = std.math.maxInt(u32) };
430 i += 1;
431 break;
432 }
433 return buffer[0..i];
434}
435
436pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {345pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
437 _ = try writableSliceGreedy(w, n);346 _ = try writableSliceGreedy(w, n);
438}347}
...@@ -451,13 +360,6 @@ pub fn advance(w: *Writer, n: usize) void {...@@ -451,13 +360,6 @@ pub fn advance(w: *Writer, n: usize) void {
451 w.end = new_end;360 w.end = new_end;
452}361}
453362
454/// After calling `writableVector`, this function tracks how many bytes were
455/// written to it.
456pub fn advanceVector(w: *Writer, n: usize) usize {
457 if (w.vtable != VectorWrapper.vtable) advance(w, n);
458 return n;
459}
460
461/// The `data` parameter is mutable because this function needs to mutate the363/// The `data` parameter is mutable because this function needs to mutate the
462/// fields in order to handle partial writes from `VTable.writeSplat`.364/// fields in order to handle partial writes from `VTable.writeSplat`.
463pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void {365pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void {
...@@ -1614,17 +1516,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)...@@ -1614,17 +1516,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)
1614}1516}
16151517
1616pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {1518pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
1617 if (std.math.signbit(value)) try w.writeByte('-');1519 const v = switch (@TypeOf(value)) {
1618 if (std.math.isNan(value)) return w.writeAll(switch (case) {1520 // comptime_float internally is a f128; this preserves precision.
1521 comptime_float => @as(f128, value),
1522 else => value,
1523 };
1524
1525 if (std.math.signbit(v)) try w.writeByte('-');
1526 if (std.math.isNan(v)) return w.writeAll(switch (case) {
1619 .lower => "nan",1527 .lower => "nan",
1620 .upper => "NAN",1528 .upper => "NAN",
1621 });1529 });
1622 if (std.math.isInf(value)) return w.writeAll(switch (case) {1530 if (std.math.isInf(v)) return w.writeAll(switch (case) {
1623 .lower => "inf",1531 .lower => "inf",
1624 .upper => "INF",1532 .upper => "INF",
1625 });1533 });
16261534
1627 const T = @TypeOf(value);1535 const T = @TypeOf(v);
1628 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));1536 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
16291537
1630 const mantissa_bits = std.math.floatMantissaBits(T);1538 const mantissa_bits = std.math.floatMantissaBits(T);
...@@ -1634,7 +1542,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi...@@ -1634,7 +1542,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi
1634 const exponent_mask = (1 << exponent_bits) - 1;1542 const exponent_mask = (1 << exponent_bits) - 1;
1635 const exponent_bias = (1 << (exponent_bits - 1)) - 1;1543 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
16361544
1637 const as_bits: TU = @bitCast(value);1545 const as_bits: TU = @bitCast(v);
1638 var mantissa = as_bits & mantissa_mask;1546 var mantissa = as_bits & mantissa_mask;
1639 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));1547 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
16401548
...@@ -2361,7 +2269,7 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz...@@ -2361,7 +2269,7 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
2361 const pattern = data[data.len - 1];2269 const pattern = data[data.len - 1];
2362 const dest = w.buffer[w.end..];2270 const dest = w.buffer[w.end..];
2363 switch (pattern.len) {2271 switch (pattern.len) {
2364 0 => return w.end,2272 0 => return 0,
2365 1 => {2273 1 => {
2366 assert(splat >= dest.len);2274 assert(splat >= dest.len);
2367 @memset(dest, pattern[0]);2275 @memset(dest, pattern[0]);
...@@ -2381,6 +2289,13 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz...@@ -2381,6 +2289,13 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
2381 }2289 }
2382}2290}
23832291
2292pub fn unreachableDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2293 _ = w;
2294 _ = data;
2295 _ = splat;
2296 unreachable;
2297}
2298
2384/// Provides a `Writer` implementation based on calling `Hasher.update`, sending2299/// Provides a `Writer` implementation based on calling `Hasher.update`, sending
2385/// all data also to an underlying `Writer`.2300/// all data also to an underlying `Writer`.
2386///2301///
...@@ -2391,6 +2306,8 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz...@@ -2391,6 +2306,8 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
2391/// generic. A better solution will involve creating a writer for each hash2306/// generic. A better solution will involve creating a writer for each hash
2392/// function, where the splat buffer can be tailored to the hash implementation2307/// function, where the splat buffer can be tailored to the hash implementation
2393/// details.2308/// details.
2309///
2310/// Contrast with `Hashing` which terminates the stream pipeline.
2394pub fn Hashed(comptime Hasher: type) type {2311pub fn Hashed(comptime Hasher: type) type {
2395 return struct {2312 return struct {
2396 out: *Writer,2313 out: *Writer,
...@@ -2463,6 +2380,52 @@ pub fn Hashed(comptime Hasher: type) type {...@@ -2463,6 +2380,52 @@ pub fn Hashed(comptime Hasher: type) type {
2463 };2380 };
2464}2381}
24652382
2383/// Provides a `Writer` implementation based on calling `Hasher.update`,
2384/// discarding all data.
2385///
2386/// This implementation makes suboptimal buffering decisions due to being
2387/// generic. A better solution will involve creating a writer for each hash
2388/// function, where the splat buffer can be tailored to the hash implementation
2389/// details.
2390///
2391/// The total number of bytes written is stored in `hasher`.
2392///
2393/// Contrast with `Hashed` which also passes the data to an underlying stream.
2394pub fn Hashing(comptime Hasher: type) type {
2395 return struct {
2396 hasher: Hasher,
2397 writer: Writer,
2398
2399 pub fn init(buffer: []u8) @This() {
2400 return .initHasher(.init(.{}), buffer);
2401 }
2402
2403 pub fn initHasher(hasher: Hasher, buffer: []u8) @This() {
2404 return .{
2405 .hasher = hasher,
2406 .writer = .{
2407 .buffer = buffer,
2408 .vtable = &.{ .drain = @This().drain },
2409 },
2410 };
2411 }
2412
2413 fn drain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2414 const this: *@This() = @alignCast(@fieldParentPtr("writer", w));
2415 const hasher = &this.hasher;
2416 hasher.update(w.buffered());
2417 w.end = 0;
2418 var n: usize = 0;
2419 for (data[0 .. data.len - 1]) |slice| {
2420 hasher.update(slice);
2421 n += slice.len;
2422 }
2423 for (0..splat) |_| hasher.update(data[data.len - 1]);
2424 return n + splat * data[data.len - 1].len;
2425 }
2426 };
2427}
2428
2466/// Maintains `Writer` state such that it writes to the unused capacity of an2429/// Maintains `Writer` state such that it writes to the unused capacity of an
2467/// array list, filling it up completely before making a call through the2430/// array list, filling it up completely before making a call through the
2468/// vtable, causing a resize. Consequently, the same, optimized, non-generic2431/// vtable, causing a resize. Consequently, the same, optimized, non-generic
lib/std/Io/test.zig-45
...@@ -57,51 +57,6 @@ test "write a file, read it, then delete it" {...@@ -57,51 +57,6 @@ test "write a file, read it, then delete it" {
57 try tmp.dir.deleteFile(tmp_file_name);57 try tmp.dir.deleteFile(tmp_file_name);
58}58}
5959
60test "BitStreams with File Stream" {
61 var tmp = tmpDir(.{});
62 defer tmp.cleanup();
63
64 const tmp_file_name = "temp_test_file.txt";
65 {
66 var file = try tmp.dir.createFile(tmp_file_name, .{});
67 defer file.close();
68
69 var bit_stream = io.bitWriter(native_endian, file.deprecatedWriter());
70
71 try bit_stream.writeBits(@as(u2, 1), 1);
72 try bit_stream.writeBits(@as(u5, 2), 2);
73 try bit_stream.writeBits(@as(u128, 3), 3);
74 try bit_stream.writeBits(@as(u8, 4), 4);
75 try bit_stream.writeBits(@as(u9, 5), 5);
76 try bit_stream.writeBits(@as(u1, 1), 1);
77 try bit_stream.flushBits();
78 }
79 {
80 var file = try tmp.dir.openFile(tmp_file_name, .{});
81 defer file.close();
82
83 var bit_stream = io.bitReader(native_endian, file.deprecatedReader());
84
85 var out_bits: u16 = undefined;
86
87 try expect(1 == try bit_stream.readBits(u2, 1, &out_bits));
88 try expect(out_bits == 1);
89 try expect(2 == try bit_stream.readBits(u5, 2, &out_bits));
90 try expect(out_bits == 2);
91 try expect(3 == try bit_stream.readBits(u128, 3, &out_bits));
92 try expect(out_bits == 3);
93 try expect(4 == try bit_stream.readBits(u8, 4, &out_bits));
94 try expect(out_bits == 4);
95 try expect(5 == try bit_stream.readBits(u9, 5, &out_bits));
96 try expect(out_bits == 5);
97 try expect(1 == try bit_stream.readBits(u1, 1, &out_bits));
98 try expect(out_bits == 1);
99
100 try expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
101 }
102 try tmp.dir.deleteFile(tmp_file_name);
103}
104
105test "File seek ops" {60test "File seek ops" {
106 var tmp = tmpDir(.{});61 var tmp = tmpDir(.{});
107 defer tmp.cleanup();62 defer tmp.cleanup();
lib/std/Progress.zig+70-1
...@@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent,...@@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent,
25/// Accessed atomically.25/// Accessed atomically.
26done: bool,26done: bool,
27need_clear: bool,27need_clear: bool,
28status: Status,
2829
29refresh_rate_ns: u64,30refresh_rate_ns: u64,
30initial_delay_ns: u64,31initial_delay_ns: u64,
...@@ -47,6 +48,22 @@ node_freelist: Freelist,...@@ -47,6 +48,22 @@ node_freelist: Freelist,
47/// value may at times temporarily exceed the node count.48/// value may at times temporarily exceed the node count.
48node_end_index: u32,49node_end_index: u32,
4950
51pub const Status = enum {
52 /// Indicates the application is progressing towards completion of a task.
53 /// Unless the application is interactive, this is the only status the
54 /// program will ever have!
55 working,
56 /// The application has completed an operation, and is now waiting for user
57 /// input rather than calling exit(0).
58 success,
59 /// The application encountered an error, and is now waiting for user input
60 /// rather than calling exit(1).
61 failure,
62 /// The application encountered at least one error, but is still working on
63 /// more tasks.
64 failure_working,
65};
66
50const Freelist = packed struct(u32) {67const Freelist = packed struct(u32) {
51 head: Node.OptionalIndex,68 head: Node.OptionalIndex,
52 /// Whenever `node_freelist` is added to, this generation is incremented69 /// Whenever `node_freelist` is added to, this generation is incremented
...@@ -383,6 +400,7 @@ var global_progress: Progress = .{...@@ -383,6 +400,7 @@ var global_progress: Progress = .{
383 .draw_buffer = undefined,400 .draw_buffer = undefined,
384 .done = false,401 .done = false,
385 .need_clear = false,402 .need_clear = false,
403 .status = .working,
386404
387 .node_parents = &node_parents_buffer,405 .node_parents = &node_parents_buffer,
388 .node_storage = &node_storage_buffer,406 .node_storage = &node_storage_buffer,
...@@ -498,6 +516,11 @@ pub fn start(options: Options) Node {...@@ -498,6 +516,11 @@ pub fn start(options: Options) Node {
498 return root_node;516 return root_node;
499}517}
500518
519pub fn setStatus(new_status: Status) void {
520 if (noop_impl) return;
521 @atomicStore(Status, &global_progress.status, new_status, .monotonic);
522}
523
501/// Returns whether a resize is needed to learn the terminal size.524/// Returns whether a resize is needed to learn the terminal size.
502fn wait(timeout_ns: u64) bool {525fn wait(timeout_ns: u64) bool {
503 const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|526 const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|
...@@ -678,6 +701,14 @@ const save = "\x1b7";...@@ -678,6 +701,14 @@ const save = "\x1b7";
678const restore = "\x1b8";701const restore = "\x1b8";
679const finish_sync = "\x1b[?2026l";702const finish_sync = "\x1b[?2026l";
680703
704const progress_remove = "\x1b]9;4;0\x07";
705const @"progress_normal {d}" = "\x1b]9;4;1;{d}\x07";
706const @"progress_error {d}" = "\x1b]9;4;2;{d}\x07";
707const progress_pulsing = "\x1b]9;4;3\x07";
708const progress_pulsing_error = "\x1b]9;4;2\x07";
709const progress_normal_100 = "\x1b]9;4;1;100\x07";
710const progress_error_100 = "\x1b]9;4;2;100\x07";
711
681const TreeSymbol = enum {712const TreeSymbol = enum {
682 /// ├─713 /// ├─
683 tee,714 tee,
...@@ -760,7 +791,7 @@ fn clearWrittenWithEscapeCodes() anyerror!void {...@@ -760,7 +791,7 @@ fn clearWrittenWithEscapeCodes() anyerror!void {
760 if (noop_impl or !global_progress.need_clear) return;791 if (noop_impl or !global_progress.need_clear) return;
761792
762 global_progress.need_clear = false;793 global_progress.need_clear = false;
763 try write(clear);794 try write(clear ++ progress_remove);
764}795}
765796
766/// U+25BA or â–º797/// U+25BA or â–º
...@@ -1203,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {...@@ -1203,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
1203 i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index);1234 i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index);
12041235
1205 if (global_progress.terminal_mode == .ansi_escape_codes) {1236 if (global_progress.terminal_mode == .ansi_escape_codes) {
1237 {
1238 // Set progress state https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
1239 const root_storage = &serialized.storage[0];
1240 const storage = if (root_storage.name[0] != 0 or children[0].child == .none) root_storage else &serialized.storage[@intFromEnum(children[0].child)];
1241 const estimated_total = storage.estimated_total_count;
1242 const completed_items = storage.completed_count;
1243 const status = @atomicLoad(Status, &global_progress.status, .monotonic);
1244 switch (status) {
1245 .working => {
1246 if (estimated_total == 0) {
1247 buf[i..][0..progress_pulsing.len].* = progress_pulsing.*;
1248 i += progress_pulsing.len;
1249 } else {
1250 const percent = completed_items * 100 / estimated_total;
1251 i += (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent}) catch &.{}).len;
1252 }
1253 },
1254 .success => {
1255 buf[i..][0..progress_remove.len].* = progress_remove.*;
1256 i += progress_remove.len;
1257 },
1258 .failure => {
1259 buf[i..][0..progress_error_100.len].* = progress_error_100.*;
1260 i += progress_error_100.len;
1261 },
1262 .failure_working => {
1263 if (estimated_total == 0) {
1264 buf[i..][0..progress_pulsing_error.len].* = progress_pulsing_error.*;
1265 i += progress_pulsing_error.len;
1266 } else {
1267 const percent = completed_items * 100 / estimated_total;
1268 i += (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent}) catch &.{}).len;
1269 }
1270 },
1271 }
1272 }
1273
1206 if (nl_n > 0) {1274 if (nl_n > 0) {
1207 buf[i] = '\r';1275 buf[i] = '\r';
1208 i += 1;1276 i += 1;
...@@ -1480,6 +1548,7 @@ const have_sigwinch = switch (builtin.os.tag) {...@@ -1480,6 +1548,7 @@ const have_sigwinch = switch (builtin.os.tag) {
1480 .visionos,1548 .visionos,
1481 .dragonfly,1549 .dragonfly,
1482 .freebsd,1550 .freebsd,
1551 .serenity,
1483 => true,1552 => true,
14841553
1485 else => false,1554 else => false,
lib/std/builtin.zig+6-3
...@@ -897,8 +897,8 @@ pub const VaList = switch (builtin.cpu.arch) {...@@ -897,8 +897,8 @@ pub const VaList = switch (builtin.cpu.arch) {
897 .windows => *u8,897 .windows => *u8,
898 .ios, .macos, .tvos, .watchos, .visionos => *u8,898 .ios, .macos, .tvos, .watchos, .visionos => *u8,
899 else => switch (builtin.zig_backend) {899 else => switch (builtin.zig_backend) {
900 .stage2_aarch64 => VaListAarch64,900 else => VaListAarch64,
901 else => @compileError("disabled due to miscompilations"),901 .stage2_llvm => @compileError("disabled due to miscompilations"),
902 },902 },
903 },903 },
904 .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {904 .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {
...@@ -923,7 +923,10 @@ pub const VaList = switch (builtin.cpu.arch) {...@@ -923,7 +923,10 @@ pub const VaList = switch (builtin.cpu.arch) {
923 .wasm32, .wasm64 => *anyopaque,923 .wasm32, .wasm64 => *anyopaque,
924 .x86 => *u8,924 .x86 => *u8,
925 .x86_64 => switch (builtin.os.tag) {925 .x86_64 => switch (builtin.os.tag) {
926 .windows => @compileError("disabled due to miscompilations"), // *u8,926 .windows => switch (builtin.zig_backend) {
927 else => *u8,
928 .stage2_llvm => @compileError("disabled due to miscompilations"),
929 },
927 else => VaListX86_64,930 else => VaListX86_64,
928 },931 },
929 .xtensa => VaListXtensa,932 .xtensa => VaListXtensa,
lib/std/c.zig+44-15
...@@ -204,6 +204,29 @@ pub const passwd = switch (native_os) {...@@ -204,6 +204,29 @@ pub const passwd = switch (native_os) {
204 shell: ?[*:0]const u8, // default shell204 shell: ?[*:0]const u8, // default shell
205 expire: time_t, // account expiration205 expire: time_t, // account expiration
206 },206 },
207 .dragonfly, .freebsd => extern struct {
208 name: ?[*:0]const u8, // user name
209 passwd: ?[*:0]const u8, // encrypted password
210 uid: uid_t, // user uid
211 gid: gid_t, // user gid
212 change: time_t, // password change time
213 class: ?[*:0]const u8, // user access class
214 gecos: ?[*:0]const u8, // Honeywell login info
215 dir: ?[*:0]const u8, // home directory
216 shell: ?[*:0]const u8, // default shell
217 expire: time_t, // account expiration
218 fields: c_int, // internal
219 },
220 else => void,
221};
222
223pub const group = switch (native_os) {
224 .linux, .freebsd, .openbsd, .dragonfly, .netbsd, .macos => extern struct {
225 name: ?[*:0]const u8,
226 passwd: ?[*:0]const u8,
227 gid: gid_t,
228 mem: [*:null]?[*:0]const u8,
229 },
207 else => void,230 else => void,
208};231};
209232
...@@ -3291,8 +3314,8 @@ pub const T = switch (native_os) {...@@ -3291,8 +3314,8 @@ pub const T = switch (native_os) {
3291 .macos, .ios, .tvos, .watchos, .visionos => struct {3314 .macos, .ios, .tvos, .watchos, .visionos => struct {
3292 pub const IOCGWINSZ = ior(0x40000000, 't', 104, @sizeOf(winsize));3315 pub const IOCGWINSZ = ior(0x40000000, 't', 104, @sizeOf(winsize));
32933316
3294 fn ior(inout: u32, group: usize, num: usize, len: usize) usize {3317 fn ior(inout: u32, group_arg: usize, num: usize, len: usize) usize {
3295 return (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num));3318 return (inout | ((len & IOCPARM_MASK) << 16) | ((group_arg) << 8) | (num));
3296 }3319 }
3297 },3320 },
3298 .freebsd => struct {3321 .freebsd => struct {
...@@ -4121,7 +4144,7 @@ pub const msghdr_const = switch (native_os) {...@@ -4121,7 +4144,7 @@ pub const msghdr_const = switch (native_os) {
4121 .serenity => extern struct {4144 .serenity => extern struct {
4122 name: ?*const anyopaque,4145 name: ?*const anyopaque,
4123 namelen: socklen_t,4146 namelen: socklen_t,
4124 iov: [*]const iovec,4147 iov: [*]const iovec_const,
4125 iovlen: c_uint,4148 iovlen: c_uint,
4126 control: ?*const anyopaque,4149 control: ?*const anyopaque,
4127 controllen: socklen_t,4150 controllen: socklen_t,
...@@ -8604,7 +8627,7 @@ pub const O = switch (native_os) {...@@ -8604,7 +8627,7 @@ pub const O = switch (native_os) {
8604 },8627 },
8605 // https://github.com/SerenityOS/serenity/blob/2808b0376406a40e31293bb3bcb9170374e90506/Kernel/API/POSIX/fcntl.h#L28-L438628 // https://github.com/SerenityOS/serenity/blob/2808b0376406a40e31293bb3bcb9170374e90506/Kernel/API/POSIX/fcntl.h#L28-L43
8606 .serenity => packed struct(c_int) {8629 .serenity => packed struct(c_int) {
8607 ACCMODE: std.posix.ACCMODE = .RDONLY,8630 ACCMODE: std.posix.ACCMODE = .NONE,
8608 EXEC: bool = false,8631 EXEC: bool = false,
8609 CREAT: bool = false,8632 CREAT: bool = false,
8610 EXCL: bool = false,8633 EXCL: bool = false,
...@@ -8760,10 +8783,10 @@ pub const MAP = switch (native_os) {...@@ -8760,10 +8783,10 @@ pub const MAP = switch (native_os) {
8760 },8783 },
8761 // https://github.com/SerenityOS/serenity/blob/6d59d4d3d9e76e39112842ec487840828f1c9bfe/Kernel/API/POSIX/sys/mman.h#L16-L268784 // https://github.com/SerenityOS/serenity/blob/6d59d4d3d9e76e39112842ec487840828f1c9bfe/Kernel/API/POSIX/sys/mman.h#L16-L26
8762 .serenity => packed struct(c_int) {8785 .serenity => packed struct(c_int) {
8763 FILE: bool = false,8786 TYPE: enum(u4) {
8764 SHARED: bool = false,8787 SHARED = 0x01,
8765 PRIVATE: bool = false,8788 PRIVATE = 0x02,
8766 _3: u2 = 0,8789 },
8767 FIXED: bool = false,8790 FIXED: bool = false,
8768 ANONYMOUS: bool = false,8791 ANONYMOUS: bool = false,
8769 STACK: bool = false,8792 STACK: bool = false,
...@@ -8771,7 +8794,7 @@ pub const MAP = switch (native_os) {...@@ -8771,7 +8794,7 @@ pub const MAP = switch (native_os) {
8771 RANDOMIZED: bool = false,8794 RANDOMIZED: bool = false,
8772 PURGEABLE: bool = false,8795 PURGEABLE: bool = false,
8773 FIXED_NOREPLACE: bool = false,8796 FIXED_NOREPLACE: bool = false,
8774 _: std.meta.Int(.unsigned, @bitSizeOf(c_int) - 12) = 0,8797 _: std.meta.Int(.unsigned, @bitSizeOf(c_int) - 11) = 0,
8775 },8798 },
8776 else => void,8799 else => void,
8777};8800};
...@@ -10261,9 +10284,20 @@ pub const fstatat = switch (native_os) {...@@ -10261,9 +10284,20 @@ pub const fstatat = switch (native_os) {
10261 },10284 },
10262 else => private.fstatat,10285 else => private.fstatat,
10263};10286};
1026410287pub extern "c" fn getpwent() ?*passwd;
10288pub extern "c" fn endpwent() void;
10289pub extern "c" fn setpwent() void;
10265pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;10290pub extern "c" fn getpwnam(name: [*:0]const u8) ?*passwd;
10291pub extern "c" fn getpwnam_r(name: [*:0]const u8, pwd: *passwd, buf: [*]u8, buflen: usize, result: *?*passwd) c_int;
10266pub extern "c" fn getpwuid(uid: uid_t) ?*passwd;10292pub extern "c" fn getpwuid(uid: uid_t) ?*passwd;
10293pub extern "c" fn getpwuid_r(uid: uid_t, pwd: *passwd, buf: [*]u8, buflen: usize, result: *?*passwd) c_int;
10294pub extern "c" fn getgrent() ?*group;
10295pub extern "c" fn setgrent() void;
10296pub extern "c" fn endgrent() void;
10297pub extern "c" fn getgrnam(name: [*:0]const u8) ?*passwd;
10298pub extern "c" fn getgrnam_r(name: [*:0]const u8, grp: *group, buf: [*]u8, buflen: usize, result: *?*group) c_int;
10299pub extern "c" fn getgrgid(gid: gid_t) ?*group;
10300pub extern "c" fn getgrgid_r(gid: gid_t, grp: *group, buf: [*]u8, buflen: usize, result: *?*group) c_int;
10267pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;10301pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
10268pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;10302pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
10269pub extern "c" fn mmap64(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;10303pub 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;...@@ -10992,11 +11026,7 @@ pub const bcrypt = openbsd.bcrypt;
10992pub const bcrypt_checkpass = openbsd.bcrypt_checkpass;11026pub const bcrypt_checkpass = openbsd.bcrypt_checkpass;
10993pub const bcrypt_gensalt = openbsd.bcrypt_gensalt;11027pub const bcrypt_gensalt = openbsd.bcrypt_gensalt;
10994pub const bcrypt_newhash = openbsd.bcrypt_newhash;11028pub const bcrypt_newhash = openbsd.bcrypt_newhash;
10995pub const endpwent = openbsd.endpwent;
10996pub const getpwent = openbsd.getpwent;
10997pub const getpwnam_r = openbsd.getpwnam_r;
10998pub const getpwnam_shadow = openbsd.getpwnam_shadow;11029pub const getpwnam_shadow = openbsd.getpwnam_shadow;
10999pub const getpwuid_r = openbsd.getpwuid_r;
11000pub const getpwuid_shadow = openbsd.getpwuid_shadow;11030pub const getpwuid_shadow = openbsd.getpwuid_shadow;
11001pub const getthrid = openbsd.getthrid;11031pub const getthrid = openbsd.getthrid;
11002pub const login_cap_t = openbsd.login_cap_t;11032pub const login_cap_t = openbsd.login_cap_t;
...@@ -11013,7 +11043,6 @@ pub const pthread_spinlock_t = openbsd.pthread_spinlock_t;...@@ -11013,7 +11043,6 @@ pub const pthread_spinlock_t = openbsd.pthread_spinlock_t;
11013pub const pw_dup = openbsd.pw_dup;11043pub const pw_dup = openbsd.pw_dup;
11014pub const setclasscontext = openbsd.setclasscontext;11044pub const setclasscontext = openbsd.setclasscontext;
11015pub const setpassent = openbsd.setpassent;11045pub const setpassent = openbsd.setpassent;
11016pub const setpwent = openbsd.setpwent;
11017pub const setusercontext = openbsd.setusercontext;11046pub const setusercontext = openbsd.setusercontext;
11018pub const uid_from_user = openbsd.uid_from_user;11047pub const uid_from_user = openbsd.uid_from_user;
11019pub const unveil = openbsd.unveil;11048pub const unveil = openbsd.unveil;
lib/std/c/openbsd.zig-5
...@@ -81,11 +81,6 @@ pub extern "c" fn auth_checknologin(lc: *login_cap_t) void;...@@ -81,11 +81,6 @@ pub extern "c" fn auth_checknologin(lc: *login_cap_t) void;
8181
82pub extern "c" fn getpwuid_shadow(uid: uid_t) ?*passwd;82pub extern "c" fn getpwuid_shadow(uid: uid_t) ?*passwd;
83pub extern "c" fn getpwnam_shadow(name: [*:0]const u8) ?*passwd;83pub extern "c" fn getpwnam_shadow(name: [*:0]const u8) ?*passwd;
84pub extern "c" fn getpwnam_r(name: [*:0]const u8, pw: *passwd, buf: [*]u8, buflen: usize, pwretp: *?*passwd) c_int;
85pub extern "c" fn getpwuid_r(uid: uid_t, pw: *passwd, buf: [*]u8, buflen: usize, pwretp: *?*passwd) c_int;
86pub extern "c" fn getpwent() ?*passwd;
87pub extern "c" fn setpwent() void;
88pub extern "c" fn endpwent() void;
89pub extern "c" fn setpassent(stayopen: c_int) c_int;84pub extern "c" fn setpassent(stayopen: c_int) c_int;
90pub extern "c" fn uid_from_user(name: [*:0]const u8, uid: *uid_t) c_int;85pub extern "c" fn uid_from_user(name: [*:0]const u8, uid: *uid_t) c_int;
91pub extern "c" fn user_from_uid(uid: uid_t, noname: c_int) ?[*:0]const u8;86pub extern "c" fn user_from_uid(uid: uid_t, noname: c_int) ?[*:0]const u8;
lib/std/compress/flate.zig+43-497
...@@ -1,7 +1,23 @@...@@ -1,7 +1,23 @@
1const builtin = @import("builtin");
2const std = @import("../std.zig");1const std = @import("../std.zig");
3const testing = std.testing;2
4const Writer = std.io.Writer;3/// When decompressing, the output buffer is used as the history window, so
4/// less than this may result in failure to decompress streams that were
5/// compressed with a larger window.
6pub const max_window_len = history_len * 2;
7
8pub const history_len = 32768;
9
10/// Deflate is a lossless data compression file format that uses a combination
11/// of LZ77 and Huffman coding.
12pub const Compress = @import("flate/Compress.zig");
13
14/// Inflate is the decoding process that consumes a Deflate bitstream and
15/// produces the original full-size data.
16pub const Decompress = @import("flate/Decompress.zig");
17
18/// Compression without Lempel-Ziv match searching. Faster compression, less
19/// memory requirements but bigger compressed sizes.
20pub const HuffmanEncoder = @import("flate/HuffmanEncoder.zig");
521
6/// Container of the deflate bit stream body. Container adds header before22/// Container of the deflate bit stream body. Container adds header before
7/// deflate bit stream and footer after. It can bi gzip, zlib or raw (no header,23/// deflate bit stream and footer after. It can bi gzip, zlib or raw (no header,
...@@ -13,7 +29,6 @@ const Writer = std.io.Writer;...@@ -13,7 +29,6 @@ const Writer = std.io.Writer;
13/// Gzip format is defined in rfc 1952. Header has 10+ bytes and footer 4 bytes29/// Gzip format is defined in rfc 1952. Header has 10+ bytes and footer 4 bytes
14/// crc32 checksum and 4 bytes of uncompressed data length.30/// crc32 checksum and 4 bytes of uncompressed data length.
15///31///
16///
17/// rfc 1950: https://datatracker.ietf.org/doc/html/rfc1950#page-432/// rfc 1950: https://datatracker.ietf.org/doc/html/rfc1950#page-4
18/// rfc 1952: https://datatracker.ietf.org/doc/html/rfc1952#page-533/// rfc 1952: https://datatracker.ietf.org/doc/html/rfc1952#page-5
19pub const Container = enum {34pub const Container = enum {
...@@ -77,14 +92,14 @@ pub const Container = enum {...@@ -77,14 +92,14 @@ pub const Container = enum {
77 raw: void,92 raw: void,
78 gzip: struct {93 gzip: struct {
79 crc: std.hash.Crc32 = .init(),94 crc: std.hash.Crc32 = .init(),
80 count: usize = 0,95 count: u32 = 0,
81 },96 },
82 zlib: std.hash.Adler32,97 zlib: std.hash.Adler32,
8398
84 pub fn init(containter: Container) Hasher {99 pub fn init(containter: Container) Hasher {
85 return switch (containter) {100 return switch (containter) {
86 .gzip => .{ .gzip = .{} },101 .gzip => .{ .gzip = .{} },
87 .zlib => .{ .zlib = .init() },102 .zlib => .{ .zlib = .{} },
88 .raw => .raw,103 .raw => .raw,
89 };104 };
90 }105 }
...@@ -98,7 +113,7 @@ pub const Container = enum {...@@ -98,7 +113,7 @@ pub const Container = enum {
98 .raw => {},113 .raw => {},
99 .gzip => |*gzip| {114 .gzip => |*gzip| {
100 gzip.update(buf);115 gzip.update(buf);
101 gzip.count += buf.len;116 gzip.count +%= buf.len;
102 },117 },
103 .zlib => |*zlib| {118 .zlib => |*zlib| {
104 zlib.update(buf);119 zlib.update(buf);
...@@ -107,7 +122,7 @@ pub const Container = enum {...@@ -107,7 +122,7 @@ pub const Container = enum {
107 }122 }
108 }123 }
109124
110 pub fn writeFooter(hasher: *Hasher, writer: *Writer) Writer.Error!void {125 pub fn writeFooter(hasher: *Hasher, writer: *std.Io.Writer) std.Io.Writer.Error!void {
111 var bits: [4]u8 = undefined;126 var bits: [4]u8 = undefined;
112 switch (hasher.*) {127 switch (hasher.*) {
113 .gzip => |*gzip| {128 .gzip => |*gzip| {
...@@ -133,502 +148,33 @@ pub const Container = enum {...@@ -133,502 +148,33 @@ pub const Container = enum {
133 }148 }
134 }149 }
135 };150 };
136};
137
138/// When decompressing, the output buffer is used as the history window, so
139/// less than this may result in failure to decompress streams that were
140/// compressed with a larger window.
141pub const max_window_len = 1 << 16;
142
143/// Deflate is a lossless data compression file format that uses a combination
144/// of LZ77 and Huffman coding.
145pub const Compress = @import("flate/Compress.zig");
146
147/// Inflate is the decoding process that takes a Deflate bitstream for
148/// decompression and correctly produces the original full-size data or file.
149pub const Decompress = @import("flate/Decompress.zig");
150
151/// Huffman only compression. Without Lempel-Ziv match searching. Faster
152/// compression, less memory requirements but bigger compressed sizes.
153pub const huffman = struct {
154 // The odd order in which the codegen code sizes are written.
155 pub const codegen_order = [_]u32{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
156 // The number of codegen codes.
157 pub const codegen_code_count = 19;
158
159 // The largest distance code.
160 pub const distance_code_count = 30;
161
162 // Maximum number of literals.
163 pub const max_num_lit = 286;
164
165 // Max number of frequencies used for a Huffman Code
166 // Possible lengths are codegen_code_count (19), distance_code_count (30) and max_num_lit (286).
167 // The largest of these is max_num_lit.
168 pub const max_num_frequencies = max_num_lit;
169
170 // Biggest block size for uncompressed block.
171 pub const max_store_block_size = 65535;
172 // The special code used to mark the end of a block.
173 pub const end_block_marker = 256;
174};
175
176test {
177 _ = Compress;
178 _ = Decompress;
179}
180151
181test "compress/decompress" {152 pub const Metadata = union(Container) {
182 const print = std.debug.print;153 raw: void,
183 var cmp_buf: [64 * 1024]u8 = undefined; // compressed data buffer154 gzip: struct {
184 var dcm_buf: [64 * 1024]u8 = undefined; // decompressed data buffer155 crc: u32 = 0,
185156 count: u32 = 0,
186 const levels = [_]Compress.Level{ .level_4, .level_5, .level_6, .level_7, .level_8, .level_9 };
187 const cases = [_]struct {
188 data: []const u8, // uncompressed content
189 // compressed data sizes per level 4-9
190 gzip_sizes: [levels.len]usize = [_]usize{0} ** levels.len,
191 huffman_only_size: usize = 0,
192 store_size: usize = 0,
193 }{
194 .{
195 .data = @embedFile("flate/testdata/rfc1951.txt"),
196 .gzip_sizes = [_]usize{ 11513, 11217, 11139, 11126, 11122, 11119 },
197 .huffman_only_size = 20287,
198 .store_size = 36967,
199 },
200 .{
201 .data = @embedFile("flate/testdata/fuzz/roundtrip1.input"),
202 .gzip_sizes = [_]usize{ 373, 370, 370, 370, 370, 370 },
203 .huffman_only_size = 393,
204 .store_size = 393,
205 },
206 .{
207 .data = @embedFile("flate/testdata/fuzz/roundtrip2.input"),
208 .gzip_sizes = [_]usize{ 373, 373, 373, 373, 373, 373 },
209 .huffman_only_size = 394,
210 .store_size = 394,
211 },157 },
212 .{158 zlib: struct {
213 .data = @embedFile("flate/testdata/fuzz/deflate-stream.expect"),159 adler: u32 = 0,
214 .gzip_sizes = [_]usize{ 351, 347, 347, 347, 347, 347 },
215 .huffman_only_size = 498,
216 .store_size = 747,
217 },160 },
218 };
219
220 for (cases, 0..) |case, case_no| { // for each case
221 const data = case.data;
222
223 for (levels, 0..) |level, i| { // for each compression level
224
225 inline for (Container.list) |container| { // for each wrapping
226 var compressed_size: usize = if (case.gzip_sizes[i] > 0)
227 case.gzip_sizes[i] - Container.gzip.size() + container.size()
228 else
229 0;
230
231 // compress original stream to compressed stream
232 {
233 var original: std.io.Reader = .fixed(data);
234 var compressed: Writer = .fixed(&cmp_buf);
235 var compress: Compress = .init(&original, &.{}, .{ .container = .raw, .level = level });
236 const n = try compress.reader.streamRemaining(&compressed);
237 if (compressed_size == 0) {
238 if (container == .gzip)
239 print("case {d} gzip level {} compressed size: {d}\n", .{ case_no, level, compressed.pos });
240 compressed_size = compressed.end;
241 }
242 try testing.expectEqual(compressed_size, n);
243 try testing.expectEqual(compressed_size, compressed.end);
244 }
245 // decompress compressed stream to decompressed stream
246 {
247 var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
248 var decompressed: Writer = .fixed(&dcm_buf);
249 try Decompress.pump(container, &compressed, &decompressed);
250 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
251 }
252
253 // compressor writer interface
254 {
255 var compressed: Writer = .fixed(&cmp_buf);
256 var cmp = try Compress.init(container, &compressed, .{ .level = level });
257 var cmp_wrt = cmp.writer();
258 try cmp_wrt.writeAll(data);
259 try cmp.finish();
260
261 try testing.expectEqual(compressed_size, compressed.pos);
262 }
263 // decompressor reader interface
264 {
265 var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
266 var dcm = Decompress.pump(container, &compressed);
267 var dcm_rdr = dcm.reader();
268 const n = try dcm_rdr.readAll(&dcm_buf);
269 try testing.expectEqual(data.len, n);
270 try testing.expectEqualSlices(u8, data, dcm_buf[0..n]);
271 }
272 }
273 }
274 // huffman only compression
275 {
276 inline for (Container.list) |container| { // for each wrapping
277 var compressed_size: usize = if (case.huffman_only_size > 0)
278 case.huffman_only_size - Container.gzip.size() + container.size()
279 else
280 0;
281
282 // compress original stream to compressed stream
283 {
284 var original: std.io.Reader = .fixed(data);
285 var compressed: Writer = .fixed(&cmp_buf);
286 var cmp = try Compress.Huffman.init(container, &compressed);
287 try cmp.compress(original.reader());
288 try cmp.finish();
289 if (compressed_size == 0) {
290 if (container == .gzip)
291 print("case {d} huffman only compressed size: {d}\n", .{ case_no, compressed.pos });
292 compressed_size = compressed.pos;
293 }
294 try testing.expectEqual(compressed_size, compressed.pos);
295 }
296 // decompress compressed stream to decompressed stream
297 {
298 var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
299 var decompressed: Writer = .fixed(&dcm_buf);
300 try Decompress.pump(container, &compressed, &decompressed);
301 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
302 }
303 }
304 }
305
306 // store only
307 {
308 inline for (Container.list) |container| { // for each wrapping
309 var compressed_size: usize = if (case.store_size > 0)
310 case.store_size - Container.gzip.size() + container.size()
311 else
312 0;
313
314 // compress original stream to compressed stream
315 {
316 var original: std.io.Reader = .fixed(data);
317 var compressed: Writer = .fixed(&cmp_buf);
318 var cmp = try Compress.SimpleCompressor(.store, container).init(&compressed);
319 try cmp.compress(original.reader());
320 try cmp.finish();
321 if (compressed_size == 0) {
322 if (container == .gzip)
323 print("case {d} store only compressed size: {d}\n", .{ case_no, compressed.pos });
324 compressed_size = compressed.pos;
325 }
326
327 try testing.expectEqual(compressed_size, compressed.pos);
328 }
329 // decompress compressed stream to decompressed stream
330 {
331 var compressed: std.io.Reader = .fixed(cmp_buf[0..compressed_size]);
332 var decompressed: Writer = .fixed(&dcm_buf);
333 try Decompress.pump(container, &compressed, &decompressed);
334 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
335 }
336 }
337 }
338 }
339}
340
341fn testDecompress(comptime container: Container, compressed: []const u8, expected_plain: []const u8) !void {
342 var in: std.io.Reader = .fixed(compressed);
343 var out: std.io.Writer.Allocating = .init(testing.allocator);
344 defer out.deinit();
345
346 try Decompress.pump(container, &in, &out.interface);
347 try testing.expectEqualSlices(u8, expected_plain, out.items);
348}
349161
350test "don't read past deflate stream's end" {162 pub fn init(containter: Container) Metadata {
351 try testDecompress(.zlib, &[_]u8{163 return switch (containter) {
352 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0xc0, 0x00, 0xc1, 0xff,164 .gzip => .{ .gzip = .{} },
353 0xff, 0x43, 0x30, 0x03, 0x03, 0xc3, 0xff, 0xff, 0xff, 0x01,165 .zlib => .{ .zlib = .{} },
354 0x83, 0x95, 0x0b, 0xf5,166 .raw => .raw,
355 }, &[_]u8{167 };
356 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
357 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
358 0x00, 0x00, 0xff, 0xff, 0xff,
359 });
360}
361
362test "zlib header" {
363 // Truncated header
364 try testing.expectError(
365 error.EndOfStream,
366 testDecompress(.zlib, &[_]u8{0x78}, ""),
367 );
368 // Wrong CM
369 try testing.expectError(
370 error.BadZlibHeader,
371 testDecompress(.zlib, &[_]u8{ 0x79, 0x94 }, ""),
372 );
373 // Wrong CINFO
374 try testing.expectError(
375 error.BadZlibHeader,
376 testDecompress(.zlib, &[_]u8{ 0x88, 0x98 }, ""),
377 );
378 // Wrong checksum
379 try testing.expectError(
380 error.WrongZlibChecksum,
381 testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, ""),
382 );
383 // Truncated checksum
384 try testing.expectError(
385 error.EndOfStream,
386 testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, ""),
387 );
388}
389
390test "gzip header" {
391 // Truncated header
392 try testing.expectError(
393 error.EndOfStream,
394 testDecompress(.gzip, &[_]u8{ 0x1f, 0x8B }, undefined),
395 );
396 // Wrong CM
397 try testing.expectError(
398 error.BadGzipHeader,
399 testDecompress(.gzip, &[_]u8{
400 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
401 0x00, 0x03,
402 }, undefined),
403 );
404
405 // Wrong checksum
406 try testing.expectError(
407 error.WrongGzipChecksum,
408 testDecompress(.gzip, &[_]u8{
409 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
410 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
411 0x00, 0x00, 0x00, 0x00,
412 }, undefined),
413 );
414 // Truncated checksum
415 try testing.expectError(
416 error.EndOfStream,
417 testDecompress(.gzip, &[_]u8{
418 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
419 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
420 }, undefined),
421 );
422 // Wrong initial size
423 try testing.expectError(
424 error.WrongGzipSize,
425 testDecompress(.gzip, &[_]u8{
426 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
427 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
428 0x00, 0x00, 0x00, 0x01,
429 }, undefined),
430 );
431 // Truncated initial size field
432 try testing.expectError(
433 error.EndOfStream,
434 testDecompress(.gzip, &[_]u8{
435 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
436 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
437 0x00, 0x00, 0x00,
438 }, undefined),
439 );
440
441 try testDecompress(.gzip, &[_]u8{
442 // GZIP header
443 0x1f, 0x8b, 0x08, 0x12, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00,
444 // header.FHCRC (should cover entire header)
445 0x99, 0xd6,
446 // GZIP data
447 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
448 }, "");
449}
450
451test "public interface" {
452 const plain_data_buf = [_]u8{ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a };
453
454 // deflate final stored block, header + plain (stored) data
455 const deflate_block = [_]u8{
456 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
457 } ++ plain_data_buf;
458
459 const plain_data: []const u8 = &plain_data_buf;
460 const gzip_data: []const u8 = &deflate_block;
461
462 //// gzip header/footer + deflate block
463 //const gzip_data =
464 // [_]u8{ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 } ++ // gzip header (10 bytes)
465 // deflate_block ++
466 // [_]u8{ 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00 }; // gzip footer checksum (4 byte), size (4 bytes)
467
468 //// zlib header/footer + deflate block
469 //const zlib_data = [_]u8{ 0x78, 0b10_0_11100 } ++ // zlib header (2 bytes)}
470 // deflate_block ++
471 // [_]u8{ 0x1c, 0xf2, 0x04, 0x47 }; // zlib footer: checksum
472
473 // TODO
474 //const gzip = @import("gzip.zig");
475 //const zlib = @import("zlib.zig");
476
477 var buffer1: [64]u8 = undefined;
478 var buffer2: [64]u8 = undefined;
479
480 // TODO These used to be functions, need to migrate the tests
481 const decompress = void;
482 const compress = void;
483 const store = void;
484
485 // decompress
486 {
487 var plain: Writer = .fixed(&buffer2);
488
489 var in: std.io.Reader = .fixed(gzip_data);
490 try decompress(&in, &plain);
491 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
492 }
493
494 // compress/decompress
495 {
496 var plain: Writer = .fixed(&buffer2);
497 var compressed: Writer = .fixed(&buffer1);
498
499 var in: std.io.Reader = .fixed(plain_data);
500 try compress(&in, &compressed, .{});
501
502 var compressed_br: std.io.Reader = .fixed(&buffer1);
503 try decompress(&compressed_br, &plain);
504 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
505 }
506
507 // compressor/decompressor
508 {
509 var plain: Writer = .fixed(&buffer2);
510 var compressed: Writer = .fixed(&buffer1);
511
512 var in: std.io.Reader = .fixed(plain_data);
513 var cmp = try Compress(&compressed, .{});
514 try cmp.compress(&in);
515 try cmp.finish();
516
517 var compressed_br: std.io.Reader = .fixed(&buffer1);
518 var dcp = Decompress(&compressed_br);
519 try dcp.decompress(&plain);
520 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
521 }
522
523 // huffman
524 {
525 // huffman compress/decompress
526 {
527 var plain: Writer = .fixed(&buffer2);
528 var compressed: Writer = .fixed(&buffer1);
529
530 var in: std.io.Reader = .fixed(plain_data);
531 try huffman.compress(&in, &compressed);
532
533 var compressed_br: std.io.Reader = .fixed(&buffer1);
534 try decompress(&compressed_br, &plain);
535 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
536 }
537
538 // huffman compressor/decompressor
539 {
540 var plain: Writer = .fixed(&buffer2);
541 var compressed: Writer = .fixed(&buffer1);
542
543 var in: std.io.Reader = .fixed(plain_data);
544 var cmp = try huffman.Compressor(&compressed);
545 try cmp.compress(&in);
546 try cmp.finish();
547
548 var compressed_br: std.io.Reader = .fixed(&buffer1);
549 try decompress(&compressed_br, &plain);
550 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
551 }
552 }
553
554 // store
555 {
556 // store compress/decompress
557 {
558 var plain: Writer = .fixed(&buffer2);
559 var compressed: Writer = .fixed(&buffer1);
560
561 var in: std.io.Reader = .fixed(plain_data);
562 try store.compress(&in, &compressed);
563
564 var compressed_br: std.io.Reader = .fixed(&buffer1);
565 try decompress(&compressed_br, &plain);
566 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
567 }168 }
568169
569 // store compressor/decompressor170 pub fn container(m: Metadata) Container {
570 {171 return m;
571 var plain: Writer = .fixed(&buffer2);
572 var compressed: Writer = .fixed(&buffer1);
573
574 var in: std.io.Reader = .fixed(plain_data);
575 var cmp = try store.compressor(&compressed);
576 try cmp.compress(&in);
577 try cmp.finish();
578
579 var compressed_br: std.io.Reader = .fixed(&buffer1);
580 try decompress(&compressed_br, &plain);
581 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
582 }172 }
583 }
584}
585
586pub const match = struct {
587 pub const base_length = 3; // smallest match length per the RFC section 3.2.5
588 pub const min_length = 4; // min length used in this algorithm
589 pub const max_length = 258;
590
591 pub const min_distance = 1;
592 pub const max_distance = 32768;
593};
594
595pub const history_len = match.max_distance;
596
597pub const lookup = struct {
598 pub const bits = 15;
599 pub const len = 1 << bits;
600 pub const shift = 32 - bits;
601};
602
603test "zlib should not overshoot" {
604 // Compressed zlib data with extra 4 bytes at the end.
605 const data = [_]u8{
606 0x78, 0x9c, 0x73, 0xce, 0x2f, 0xa8, 0x2c, 0xca, 0x4c, 0xcf, 0x28, 0x51, 0x08, 0xcf, 0xcc, 0xc9,
607 0x49, 0xcd, 0x55, 0x28, 0x4b, 0xcc, 0x53, 0x08, 0x4e, 0xce, 0x48, 0xcc, 0xcc, 0xd6, 0x51, 0x08,
608 0xce, 0xcc, 0x4b, 0x4f, 0x2c, 0xc8, 0x2f, 0x4a, 0x55, 0x30, 0xb4, 0xb4, 0x34, 0xd5, 0xb5, 0x34,
609 0x03, 0x00, 0x8b, 0x61, 0x0f, 0xa4, 0x52, 0x5a, 0x94, 0x12,
610 };173 };
174};
611175
612 var stream: std.io.Reader = .fixed(&data);176test {
613 const reader = stream.reader();177 _ = HuffmanEncoder;
614178 _ = Compress;
615 var dcp = Decompress.init(reader);179 _ = Decompress;
616 var out: [128]u8 = undefined;
617
618 // Decompress
619 var n = try dcp.reader().readAll(out[0..]);
620
621 // Expected decompressed data
622 try std.testing.expectEqual(46, n);
623 try std.testing.expectEqualStrings("Copyright Willem van Schaik, Singapore 1995-96", out[0..n]);
624
625 // Decompressor don't overshoot underlying reader.
626 // It is leaving it at the end of compressed data chunk.
627 try std.testing.expectEqual(data.len - 4, stream.getPos());
628 try std.testing.expectEqual(0, dcp.unreadBytes());
629
630 // 4 bytes after compressed chunk are available in reader.
631 n = try reader.readAll(out[0..]);
632 try std.testing.expectEqual(n, 4);
633 try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]);
634}180}
lib/std/compress/flate/BlockWriter.zig+83-187
...@@ -8,34 +8,54 @@ const Writer = std.io.Writer;...@@ -8,34 +8,54 @@ const Writer = std.io.Writer;
8const BlockWriter = @This();8const BlockWriter = @This();
9const flate = @import("../flate.zig");9const flate = @import("../flate.zig");
10const Compress = flate.Compress;10const Compress = flate.Compress;
11const huffman = flate.huffman;11const HuffmanEncoder = flate.HuffmanEncoder;
12const Token = @import("Token.zig");12const Token = @import("Token.zig");
1313
14const codegen_order = huffman.codegen_order;14const codegen_order = HuffmanEncoder.codegen_order;
15const end_code_mark = 255;15const end_code_mark = 255;
1616
17output: *Writer,17output: *Writer,
1818
19codegen_freq: [huffman.codegen_code_count]u16 = undefined,19codegen_freq: [HuffmanEncoder.codegen_code_count]u16,
20literal_freq: [huffman.max_num_lit]u16 = undefined,20literal_freq: [HuffmanEncoder.max_num_lit]u16,
21distance_freq: [huffman.distance_code_count]u16 = undefined,21distance_freq: [HuffmanEncoder.distance_code_count]u16,
22codegen: [huffman.max_num_lit + huffman.distance_code_count + 1]u8 = undefined,22codegen: [HuffmanEncoder.max_num_lit + HuffmanEncoder.distance_code_count + 1]u8,
23literal_encoding: Compress.LiteralEncoder = .{},23literal_encoding: HuffmanEncoder,
24distance_encoding: Compress.DistanceEncoder = .{},24distance_encoding: HuffmanEncoder,
25codegen_encoding: Compress.CodegenEncoder = .{},25codegen_encoding: HuffmanEncoder,
26fixed_literal_encoding: Compress.LiteralEncoder,26fixed_literal_encoding: HuffmanEncoder,
27fixed_distance_encoding: Compress.DistanceEncoder,27fixed_distance_encoding: HuffmanEncoder,
28huff_distance: Compress.DistanceEncoder,28huff_distance: HuffmanEncoder,
29
30fixed_literal_codes: [HuffmanEncoder.max_num_frequencies]HuffmanEncoder.Code,
31fixed_distance_codes: [HuffmanEncoder.distance_code_count]HuffmanEncoder.Code,
32distance_codes: [HuffmanEncoder.distance_code_count]HuffmanEncoder.Code,
2933
30pub fn init(output: *Writer) BlockWriter {34pub fn init(output: *Writer) BlockWriter {
31 return .{35 return .{
32 .output = output,36 .output = output,
33 .fixed_literal_encoding = Compress.fixedLiteralEncoder(),37 .codegen_freq = undefined,
34 .fixed_distance_encoding = Compress.fixedDistanceEncoder(),38 .literal_freq = undefined,
35 .huff_distance = Compress.huffmanDistanceEncoder(),39 .distance_freq = undefined,
40 .codegen = undefined,
41 .literal_encoding = undefined,
42 .distance_encoding = undefined,
43 .codegen_encoding = undefined,
44 .fixed_literal_encoding = undefined,
45 .fixed_distance_encoding = undefined,
46 .huff_distance = undefined,
47 .fixed_literal_codes = undefined,
48 .fixed_distance_codes = undefined,
49 .distance_codes = undefined,
36 };50 };
37}51}
3852
53pub fn initBuffers(bw: *BlockWriter) void {
54 bw.fixed_literal_encoding = .fixedLiteralEncoder(&bw.fixed_literal_codes);
55 bw.fixed_distance_encoding = .fixedDistanceEncoder(&bw.fixed_distance_codes);
56 bw.huff_distance = .huffmanDistanceEncoder(&bw.distance_codes);
57}
58
39/// Flush intrenal bit buffer to the writer.59/// Flush intrenal bit buffer to the writer.
40/// Should be called only when bit stream is at byte boundary.60/// Should be called only when bit stream is at byte boundary.
41///61///
...@@ -46,27 +66,23 @@ pub fn flush(self: *BlockWriter) Writer.Error!void {...@@ -46,27 +66,23 @@ pub fn flush(self: *BlockWriter) Writer.Error!void {
46 try self.bit_writer.flush();66 try self.bit_writer.flush();
47}67}
4868
49pub fn setWriter(self: *BlockWriter, new_writer: *Writer) void {
50 self.bit_writer.setWriter(new_writer);
51}
52
53fn writeCode(self: *BlockWriter, c: Compress.HuffCode) Writer.Error!void {69fn writeCode(self: *BlockWriter, c: Compress.HuffCode) Writer.Error!void {
54 try self.bit_writer.writeBits(c.code, c.len);70 try self.bit_writer.writeBits(c.code, c.len);
55}71}
5672
57// RFC 1951 3.2.7 specifies a special run-length encoding for specifying73/// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
58// the literal and distance lengths arrays (which are concatenated into a single74/// the literal and distance lengths arrays (which are concatenated into a single
59// array). This method generates that run-length encoding.75/// array). This method generates that run-length encoding.
60//76///
61// The result is written into the codegen array, and the frequencies77/// The result is written into the codegen array, and the frequencies
62// of each code is written into the codegen_freq array.78/// of each code is written into the codegen_freq array.
63// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional79/// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
64// information. Code bad_code is an end marker80/// information. Code bad_code is an end marker
65//81///
66// num_literals: The number of literals in literal_encoding82/// num_literals: The number of literals in literal_encoding
67// num_distances: The number of distances in distance_encoding83/// num_distances: The number of distances in distance_encoding
68// lit_enc: The literal encoder to use84/// lit_enc: The literal encoder to use
69// dist_enc: The distance encoder to use85/// dist_enc: The distance encoder to use
70fn generateCodegen(86fn generateCodegen(
71 self: *BlockWriter,87 self: *BlockWriter,
72 num_literals: u32,88 num_literals: u32,
...@@ -167,7 +183,7 @@ const DynamicSize = struct {...@@ -167,7 +183,7 @@ const DynamicSize = struct {
167 num_codegens: u32,183 num_codegens: u32,
168};184};
169185
170// dynamicSize returns the size of dynamically encoded data in bits.186/// dynamicSize returns the size of dynamically encoded data in bits.
171fn dynamicSize(187fn dynamicSize(
172 self: *BlockWriter,188 self: *BlockWriter,
173 lit_enc: *Compress.LiteralEncoder, // literal encoder189 lit_enc: *Compress.LiteralEncoder, // literal encoder
...@@ -194,7 +210,7 @@ fn dynamicSize(...@@ -194,7 +210,7 @@ fn dynamicSize(
194 };210 };
195}211}
196212
197// fixedSize returns the size of dynamically encoded data in bits.213/// fixedSize returns the size of dynamically encoded data in bits.
198fn fixedSize(self: *BlockWriter, extra_bits: u32) u32 {214fn fixedSize(self: *BlockWriter, extra_bits: u32) u32 {
199 return 3 +215 return 3 +
200 self.fixed_literal_encoding.bitLength(&self.literal_freq) +216 self.fixed_literal_encoding.bitLength(&self.literal_freq) +
...@@ -207,25 +223,25 @@ const StoredSize = struct {...@@ -207,25 +223,25 @@ const StoredSize = struct {
207 storable: bool,223 storable: bool,
208};224};
209225
210// storedSizeFits calculates the stored size, including header.226/// storedSizeFits calculates the stored size, including header.
211// The function returns the size in bits and whether the block227/// The function returns the size in bits and whether the block
212// fits inside a single block.228/// fits inside a single block.
213fn storedSizeFits(in: ?[]const u8) StoredSize {229fn storedSizeFits(in: ?[]const u8) StoredSize {
214 if (in == null) {230 if (in == null) {
215 return .{ .size = 0, .storable = false };231 return .{ .size = 0, .storable = false };
216 }232 }
217 if (in.?.len <= huffman.max_store_block_size) {233 if (in.?.len <= HuffmanEncoder.max_store_block_size) {
218 return .{ .size = @as(u32, @intCast((in.?.len + 5) * 8)), .storable = true };234 return .{ .size = @as(u32, @intCast((in.?.len + 5) * 8)), .storable = true };
219 }235 }
220 return .{ .size = 0, .storable = false };236 return .{ .size = 0, .storable = false };
221}237}
222238
223// Write the header of a dynamic Huffman block to the output stream.239/// Write the header of a dynamic Huffman block to the output stream.
224//240///
225// num_literals: The number of literals specified in codegen241/// num_literals: The number of literals specified in codegen
226// num_distances: The number of distances specified in codegen242/// num_distances: The number of distances specified in codegen
227// num_codegens: The number of codegens used in codegen243/// num_codegens: The number of codegens used in codegen
228// eof: Is it the end-of-file? (end of stream)244/// eof: Is it the end-of-file? (end of stream)
229fn dynamicHeader(245fn dynamicHeader(
230 self: *BlockWriter,246 self: *BlockWriter,
231 num_literals: u32,247 num_literals: u32,
...@@ -291,11 +307,11 @@ fn fixedHeader(self: *BlockWriter, eof: bool) Writer.Error!void {...@@ -291,11 +307,11 @@ fn fixedHeader(self: *BlockWriter, eof: bool) Writer.Error!void {
291 try self.bit_writer.writeBits(value, 3);307 try self.bit_writer.writeBits(value, 3);
292}308}
293309
294// Write a block of tokens with the smallest encoding. Will choose block type.310/// Write a block of tokens with the smallest encoding. Will choose block type.
295// The original input can be supplied, and if the huffman encoded data311/// The original input can be supplied, and if the huffman encoded data
296// is larger than the original bytes, the data will be written as a312/// is larger than the original bytes, the data will be written as a
297// stored block.313/// stored block.
298// If the input is null, the tokens will always be Huffman encoded.314/// If the input is null, the tokens will always be Huffman encoded.
299pub fn write(self: *BlockWriter, tokens: []const Token, eof: bool, input: ?[]const u8) Writer.Error!void {315pub fn write(self: *BlockWriter, tokens: []const Token, eof: bool, input: ?[]const u8) Writer.Error!void {
300 const lit_and_dist = self.indexTokens(tokens);316 const lit_and_dist = self.indexTokens(tokens);
301 const num_literals = lit_and_dist.num_literals;317 const num_literals = lit_and_dist.num_literals;
...@@ -379,11 +395,11 @@ pub fn storedBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Erro...@@ -379,11 +395,11 @@ pub fn storedBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Erro
379 try self.bit_writer.writeBytes(input);395 try self.bit_writer.writeBytes(input);
380}396}
381397
382// writeBlockDynamic encodes a block using a dynamic Huffman table.398/// writeBlockDynamic encodes a block using a dynamic Huffman table.
383// This should be used if the symbols used have a disproportionate399/// This should be used if the symbols used have a disproportionate
384// histogram distribution.400/// histogram distribution.
385// If input is supplied and the compression savings are below 1/16th of the401/// If input is supplied and the compression savings are below 1/16th of the
386// input size the block is stored.402/// input size the block is stored.
387fn dynamicBlock(403fn dynamicBlock(
388 self: *BlockWriter,404 self: *BlockWriter,
389 tokens: []const Token,405 tokens: []const Token,
...@@ -429,10 +445,10 @@ const TotalIndexedTokens = struct {...@@ -429,10 +445,10 @@ const TotalIndexedTokens = struct {
429 num_distances: u32,445 num_distances: u32,
430};446};
431447
432// Indexes a slice of tokens followed by an end_block_marker, and updates448/// Indexes a slice of tokens followed by an end_block_marker, and updates
433// literal_freq and distance_freq, and generates literal_encoding449/// literal_freq and distance_freq, and generates literal_encoding
434// and distance_encoding.450/// and distance_encoding.
435// The number of literal and distance tokens is returned.451/// The number of literal and distance tokens is returned.
436fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {452fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
437 var num_literals: u32 = 0;453 var num_literals: u32 = 0;
438 var num_distances: u32 = 0;454 var num_distances: u32 = 0;
...@@ -453,7 +469,7 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {...@@ -453,7 +469,7 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
453 self.distance_freq[t.distanceCode()] += 1;469 self.distance_freq[t.distanceCode()] += 1;
454 }470 }
455 // add end_block_marker token at the end471 // add end_block_marker token at the end
456 self.literal_freq[huffman.end_block_marker] += 1;472 self.literal_freq[HuffmanEncoder.end_block_marker] += 1;
457473
458 // get the number of literals474 // get the number of literals
459 num_literals = @as(u32, @intCast(self.literal_freq.len));475 num_literals = @as(u32, @intCast(self.literal_freq.len));
...@@ -479,8 +495,8 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {...@@ -479,8 +495,8 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
479 };495 };
480}496}
481497
482// Writes a slice of tokens to the output followed by and end_block_marker.498/// Writes a slice of tokens to the output followed by and end_block_marker.
483// codes for literal and distance encoding must be supplied.499/// codes for literal and distance encoding must be supplied.
484fn writeTokens(500fn writeTokens(
485 self: *BlockWriter,501 self: *BlockWriter,
486 tokens: []const Token,502 tokens: []const Token,
...@@ -508,18 +524,18 @@ fn writeTokens(...@@ -508,18 +524,18 @@ fn writeTokens(
508 }524 }
509 }525 }
510 // add end_block_marker at the end526 // add end_block_marker at the end
511 try self.writeCode(le_codes[huffman.end_block_marker]);527 try self.writeCode(le_codes[HuffmanEncoder.end_block_marker]);
512}528}
513529
514// Encodes a block of bytes as either Huffman encoded literals or uncompressed bytes530/// Encodes a block of bytes as either Huffman encoded literals or uncompressed bytes
515// if the results only gains very little from compression.531/// if the results only gains very little from compression.
516pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Error!void {532pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Error!void {
517 // Add everything as literals533 // Add everything as literals
518 histogram(input, &self.literal_freq);534 histogram(input, &self.literal_freq);
519535
520 self.literal_freq[huffman.end_block_marker] = 1;536 self.literal_freq[HuffmanEncoder.end_block_marker] = 1;
521537
522 const num_literals = huffman.end_block_marker + 1;538 const num_literals = HuffmanEncoder.end_block_marker + 1;
523 self.distance_freq[0] = 1;539 self.distance_freq[0] = 1;
524 const num_distances = 1;540 const num_distances = 1;
525541
...@@ -560,10 +576,9 @@ pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Err...@@ -560,10 +576,9 @@ pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Err
560 const c = encoding[t];576 const c = encoding[t];
561 try self.bit_writer.writeBits(c.code, c.len);577 try self.bit_writer.writeBits(c.code, c.len);
562 }578 }
563 try self.writeCode(encoding[huffman.end_block_marker]);579 try self.writeCode(encoding[HuffmanEncoder.end_block_marker]);
564}580}
565581
566// histogram accumulates a histogram of b in h.
567fn histogram(b: []const u8, h: *[286]u16) void {582fn histogram(b: []const u8, h: *[286]u16) void {
568 // Clear histogram583 // Clear histogram
569 for (h, 0..) |_, i| {584 for (h, 0..) |_, i| {
...@@ -575,122 +590,3 @@ fn histogram(b: []const u8, h: *[286]u16) void {...@@ -575,122 +590,3 @@ fn histogram(b: []const u8, h: *[286]u16) void {
575 lh[t] += 1;590 lh[t] += 1;
576 }591 }
577}592}
578
579// tests
580const expect = std.testing.expect;
581const fmt = std.fmt;
582const testing = std.testing;
583const ArrayList = std.ArrayList;
584
585const TestCase = @import("testdata/block_writer.zig").TestCase;
586const testCases = @import("testdata/block_writer.zig").testCases;
587
588// tests if the writeBlock encoding has changed.
589test "write" {
590 inline for (0..testCases.len) |i| {
591 try testBlock(testCases[i], .write_block);
592 }
593}
594
595// tests if the writeBlockDynamic encoding has changed.
596test "dynamicBlock" {
597 inline for (0..testCases.len) |i| {
598 try testBlock(testCases[i], .write_dyn_block);
599 }
600}
601
602test "huffmanBlock" {
603 inline for (0..testCases.len) |i| {
604 try testBlock(testCases[i], .write_huffman_block);
605 }
606 try testBlock(.{
607 .tokens = &[_]Token{},
608 .input = "huffman-rand-max.input",
609 .want = "huffman-rand-max.{s}.expect",
610 }, .write_huffman_block);
611}
612
613const TestFn = enum {
614 write_block,
615 write_dyn_block, // write dynamic block
616 write_huffman_block,
617
618 fn to_s(self: TestFn) []const u8 {
619 return switch (self) {
620 .write_block => "wb",
621 .write_dyn_block => "dyn",
622 .write_huffman_block => "huff",
623 };
624 }
625
626 fn write(
627 comptime self: TestFn,
628 bw: anytype,
629 tok: []const Token,
630 input: ?[]const u8,
631 final: bool,
632 ) !void {
633 switch (self) {
634 .write_block => try bw.write(tok, final, input),
635 .write_dyn_block => try bw.dynamicBlock(tok, final, input),
636 .write_huffman_block => try bw.huffmanBlock(input.?, final),
637 }
638 try bw.flush();
639 }
640};
641
642// testBlock tests a block against its references
643//
644// size
645// 64K [file-name].input - input non compressed file
646// 8.1K [file-name].golden -
647// 78 [file-name].dyn.expect - output with writeBlockDynamic
648// 78 [file-name].wb.expect - output with writeBlock
649// 8.1K [file-name].huff.expect - output with writeBlockHuff
650// 78 [file-name].dyn.expect-noinput - output with writeBlockDynamic when input is null
651// 78 [file-name].wb.expect-noinput - output with writeBlock when input is null
652//
653// wb - writeBlock
654// dyn - writeBlockDynamic
655// huff - writeBlockHuff
656//
657fn testBlock(comptime tc: TestCase, comptime tfn: TestFn) !void {
658 if (tc.input.len != 0 and tc.want.len != 0) {
659 const want_name = comptime fmt.comptimePrint(tc.want, .{tfn.to_s()});
660 const input = @embedFile("testdata/block_writer/" ++ tc.input);
661 const want = @embedFile("testdata/block_writer/" ++ want_name);
662 try testWriteBlock(tfn, input, want, tc.tokens);
663 }
664
665 if (tfn == .write_huffman_block) {
666 return;
667 }
668
669 const want_name_no_input = comptime fmt.comptimePrint(tc.want_no_input, .{tfn.to_s()});
670 const want = @embedFile("testdata/block_writer/" ++ want_name_no_input);
671 try testWriteBlock(tfn, null, want, tc.tokens);
672}
673
674// Uses writer function `tfn` to write `tokens`, tests that we got `want` as output.
675fn testWriteBlock(comptime tfn: TestFn, input: ?[]const u8, want: []const u8, tokens: []const Token) !void {
676 var buf = ArrayList(u8).init(testing.allocator);
677 var bw: BlockWriter = .init(buf.writer());
678 try tfn.write(&bw, tokens, input, false);
679 var got = buf.items;
680 try testing.expectEqualSlices(u8, want, got); // expect writeBlock to yield expected result
681 try expect(got[0] & 0b0000_0001 == 0); // bfinal is not set
682 //
683 // Test if the writer produces the same output after reset.
684 buf.deinit();
685 buf = ArrayList(u8).init(testing.allocator);
686 defer buf.deinit();
687 bw.setWriter(buf.writer());
688
689 try tfn.write(&bw, tokens, input, true);
690 try bw.flush();
691 got = buf.items;
692
693 try expect(got[0] & 1 == 1); // bfinal is set
694 buf.items[0] &= 0b1111_1110; // remove bfinal bit, so we can run test slices
695 try testing.expectEqualSlices(u8, want, got); // expect writeBlock to yield expected result
696}
lib/std/compress/flate/Compress.zig+108-1041
...@@ -39,16 +39,15 @@...@@ -39,16 +39,15 @@
39//!39//!
40//!40//!
41//! Allocates statically ~400K (192K lookup, 128K tokens, 64K window).41//! Allocates statically ~400K (192K lookup, 128K tokens, 64K window).
42
42const builtin = @import("builtin");43const builtin = @import("builtin");
43const std = @import("std");44const std = @import("std");
44const io = std.io;
45const assert = std.debug.assert;45const assert = std.debug.assert;
46const testing = std.testing;46const testing = std.testing;
47const expect = testing.expect;47const expect = testing.expect;
48const mem = std.mem;48const mem = std.mem;
49const math = std.math;49const math = std.math;
50const Writer = std.io.Writer;50const Writer = std.Io.Writer;
51const Reader = std.io.Reader;
5251
53const Compress = @This();52const Compress = @This();
54const Token = @import("Token.zig");53const Token = @import("Token.zig");
...@@ -56,26 +55,23 @@ const BlockWriter = @import("BlockWriter.zig");...@@ -56,26 +55,23 @@ const BlockWriter = @import("BlockWriter.zig");
56const flate = @import("../flate.zig");55const flate = @import("../flate.zig");
57const Container = flate.Container;56const Container = flate.Container;
58const Lookup = @import("Lookup.zig");57const Lookup = @import("Lookup.zig");
59const huffman = flate.huffman;58const HuffmanEncoder = flate.HuffmanEncoder;
59const LiteralNode = HuffmanEncoder.LiteralNode;
6060
61lookup: Lookup = .{},61lookup: Lookup = .{},
62tokens: Tokens = .{},62tokens: Tokens = .{},
63/// Asserted to have a buffer capacity of at least `flate.max_window_len`.
64input: *std.io.Reader,
65block_writer: BlockWriter,63block_writer: BlockWriter,
66level: LevelArgs,64level: LevelArgs,
67hasher: Container.Hasher,65hasher: Container.Hasher,
68reader: std.io.Reader,66writer: Writer,
67state: State,
6968
70// Match and literal at the previous position.69// Match and literal at the previous position.
71// Used for lazy match finding in processWindow.70// Used for lazy match finding in processWindow.
72prev_match: ?Token = null,71prev_match: ?Token = null,
73prev_literal: ?u8 = null,72prev_literal: ?u8 = null,
7473
75pub const Options = struct {74pub const State = enum { header, middle, ended };
76 level: Level = .default,
77 container: Container = .raw,
78};
7975
80/// Trades between speed and compression size.76/// Trades between speed and compression size.
81/// Starts with level 4: in [zlib](https://github.com/madler/zlib/blob/abd3d1a28930f89375d4b41408b39f6c1be157b2/deflate.c#L115C1-L117C43)77/// Starts with level 4: in [zlib](https://github.com/madler/zlib/blob/abd3d1a28930f89375d4b41408b39f6c1be157b2/deflate.c#L115C1-L117C43)
...@@ -119,188 +115,24 @@ const LevelArgs = struct {...@@ -119,188 +115,24 @@ const LevelArgs = struct {
119 }115 }
120};116};
121117
122pub fn init(input: *std.io.Reader, buffer: []u8, options: Options) Compress {118pub const Options = struct {
119 level: Level = .default,
120 container: Container = .raw,
121};
122
123pub fn init(output: *Writer, buffer: []u8, options: Options) Compress {
123 return .{124 return .{
124 .input = input,125 .block_writer = .init(output),
125 .block_writer = undefined,
126 .level = .get(options.level),126 .level = .get(options.level),
127 .hasher = .init(options.container),127 .hasher = .init(options.container),
128 .state = .header,128 .state = .header,
129 .reader = .{129 .writer = .{
130 .buffer = buffer,130 .buffer = buffer,
131 .stream = stream,131 .vtable = &.{ .drain = drain },
132 },132 },
133 };133 };
134}134}
135135
136const FlushOption = enum { none, flush, final };
137
138/// Process data in window and create tokens. If token buffer is full
139/// flush tokens to the token writer.
140///
141/// Returns number of bytes consumed from `lh`.
142fn tokenizeSlice(c: *Compress, bw: *Writer, limit: std.io.Limit, lh: []const u8) !usize {
143 _ = bw;
144 _ = limit;
145 if (true) @panic("TODO");
146 var step: u16 = 1; // 1 in the case of literal, match length otherwise
147 const pos: u16 = c.win.pos();
148 const literal = lh[0]; // literal at current position
149 const min_len: u16 = if (c.prev_match) |m| m.length() else 0;
150
151 // Try to find match at least min_len long.
152 if (c.findMatch(pos, lh, min_len)) |match| {
153 // Found better match than previous.
154 try c.addPrevLiteral();
155
156 // Is found match length good enough?
157 if (match.length() >= c.level.lazy) {
158 // Don't try to lazy find better match, use this.
159 step = try c.addMatch(match);
160 } else {
161 // Store this match.
162 c.prev_literal = literal;
163 c.prev_match = match;
164 }
165 } else {
166 // There is no better match at current pos then it was previous.
167 // Write previous match or literal.
168 if (c.prev_match) |m| {
169 // Write match from previous position.
170 step = try c.addMatch(m) - 1; // we already advanced 1 from previous position
171 } else {
172 // No match at previous position.
173 // Write previous literal if any, and remember this literal.
174 try c.addPrevLiteral();
175 c.prev_literal = literal;
176 }
177 }
178 // Advance window and add hashes.
179 c.windowAdvance(step, lh, pos);
180}
181
182fn windowAdvance(self: *Compress, step: u16, lh: []const u8, pos: u16) void {
183 // current position is already added in findMatch
184 self.lookup.bulkAdd(lh[1..], step - 1, pos + 1);
185 self.win.advance(step);
186}
187
188// Add previous literal (if any) to the tokens list.
189fn addPrevLiteral(self: *Compress) !void {
190 if (self.prev_literal) |l| try self.addToken(Token.initLiteral(l));
191}
192
193// Add match to the tokens list, reset prev pointers.
194// Returns length of the added match.
195fn addMatch(self: *Compress, m: Token) !u16 {
196 try self.addToken(m);
197 self.prev_literal = null;
198 self.prev_match = null;
199 return m.length();
200}
201
202fn addToken(self: *Compress, token: Token) !void {
203 self.tokens.add(token);
204 if (self.tokens.full()) try self.flushTokens(.none);
205}
206
207// Finds largest match in the history window with the data at current pos.
208fn findMatch(self: *Compress, pos: u16, lh: []const u8, min_len: u16) ?Token {
209 var len: u16 = min_len;
210 // Previous location with the same hash (same 4 bytes).
211 var prev_pos = self.lookup.add(lh, pos);
212 // Last found match.
213 var match: ?Token = null;
214
215 // How much back-references to try, performance knob.
216 var chain: usize = self.level.chain;
217 if (len >= self.level.good) {
218 // If we've got a match that's good enough, only look in 1/4 the chain.
219 chain >>= 2;
220 }
221
222 // Hot path loop!
223 while (prev_pos > 0 and chain > 0) : (chain -= 1) {
224 const distance = pos - prev_pos;
225 if (distance > flate.match.max_distance)
226 break;
227
228 const new_len = self.win.match(prev_pos, pos, len);
229 if (new_len > len) {
230 match = Token.initMatch(@intCast(distance), new_len);
231 if (new_len >= self.level.nice) {
232 // The match is good enough that we don't try to find a better one.
233 return match;
234 }
235 len = new_len;
236 }
237 prev_pos = self.lookup.prev(prev_pos);
238 }
239
240 return match;
241}
242
243fn flushTokens(self: *Compress, flush_opt: FlushOption) !void {
244 // Pass tokens to the token writer
245 try self.block_writer.write(self.tokens.tokens(), flush_opt == .final, self.win.tokensBuffer());
246 // Stored block ensures byte alignment.
247 // It has 3 bits (final, block_type) and then padding until byte boundary.
248 // After that everything is aligned to the boundary in the stored block.
249 // Empty stored block is Ob000 + (0-7) bits of padding + 0x00 0x00 0xFF 0xFF.
250 // Last 4 bytes are byte aligned.
251 if (flush_opt == .flush) {
252 try self.block_writer.storedBlock("", false);
253 }
254 if (flush_opt != .none) {
255 // Safe to call only when byte aligned or it is OK to add
256 // padding bits (on last byte of the final block).
257 try self.block_writer.flush();
258 }
259 // Reset internal tokens store.
260 self.tokens.reset();
261 // Notify win that tokens are flushed.
262 self.win.flush();
263}
264
265// Slide win and if needed lookup tables.
266fn slide(self: *Compress) void {
267 const n = self.win.slide();
268 self.lookup.slide(n);
269}
270
271/// Flushes internal buffers to the output writer. Outputs empty stored
272/// block to sync bit stream to the byte boundary, so that the
273/// decompressor can get all input data available so far.
274///
275/// It is useful mainly in compressed network protocols, to ensure that
276/// deflate bit stream can be used as byte stream. May degrade
277/// compression so it should be used only when necessary.
278///
279/// Completes the current deflate block and follows it with an empty
280/// stored block that is three zero bits plus filler bits to the next
281/// byte, followed by four bytes (00 00 ff ff).
282///
283pub fn flush(c: *Compress) !void {
284 try c.tokenize(.flush);
285}
286
287/// Completes deflate bit stream by writing any pending data as deflate
288/// final deflate block. HAS to be called once all data are written to
289/// the compressor as a signal that next block has to have final bit
290/// set.
291///
292pub fn finish(c: *Compress) !void {
293 _ = c;
294 @panic("TODO");
295}
296
297/// Use another writer while preserving history. Most probably flush
298/// should be called on old writer before setting new.
299pub fn setWriter(self: *Compress, new_writer: *Writer) void {
300 self.block_writer.setWriter(new_writer);
301 self.output = new_writer;
302}
303
304// Tokens store136// Tokens store
305const Tokens = struct {137const Tokens = struct {
306 list: [n_tokens]Token = undefined,138 list: [n_tokens]Token = undefined,
...@@ -324,527 +156,112 @@ const Tokens = struct {...@@ -324,527 +156,112 @@ const Tokens = struct {
324 }156 }
325};157};
326158
327/// Creates huffman only deflate blocks. Disables Lempel-Ziv match searching and159fn drain(me: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {
328/// only performs Huffman entropy encoding. Results in faster compression, much160 _ = data;
329/// less memory requirements during compression but bigger compressed sizes.161 _ = splat;
330pub const Huffman = SimpleCompressor(.huffman, .raw);162 const c: *Compress = @fieldParentPtr("writer", me);
331163 const out = c.block_writer.output;
332/// Creates store blocks only. Data are not compressed only packed into deflate164 switch (c.state) {
333/// store blocks. That adds 9 bytes of header for each block. Max stored block165 .header => {
334/// size is 64K. Block is emitted when flush is called on on finish.166 c.state = .middle;
335pub const store = struct {167 const header = c.hasher.container().header();
336 pub fn Compressor(comptime container: Container, comptime WriterType: type) type {168 try out.writeAll(header);
337 return SimpleCompressor(.store, container, WriterType);169 return header.len;
338 }170 },
339171 .middle => {},
340 pub fn compressor(comptime container: Container, writer: anytype) !store.Compressor(container, @TypeOf(writer)) {172 .ended => unreachable,
341 return try store.Compressor(container, @TypeOf(writer)).init(writer);
342 }173 }
343};
344174
345const SimpleCompressorKind = enum {175 const buffered = me.buffered();
346 huffman,176 const min_lookahead = Token.min_length + Token.max_length;
347 store,177 const history_plus_lookahead_len = flate.history_len + min_lookahead;
348};178 if (buffered.len < history_plus_lookahead_len) return 0;
179 const lookahead = buffered[flate.history_len..];
349180
350fn simpleCompressor(181 // TODO tokenize
351 comptime kind: SimpleCompressorKind,182 _ = lookahead;
352 comptime container: Container,183 //c.hasher.update(lookahead[0..n]);
353 writer: anytype,184 @panic("TODO");
354) !SimpleCompressor(kind, container, @TypeOf(writer)) {
355 return try SimpleCompressor(kind, container, @TypeOf(writer)).init(writer);
356}185}
357186
358fn SimpleCompressor(187pub fn end(c: *Compress) !void {
359 comptime kind: SimpleCompressorKind,188 try endUnflushed(c);
360 comptime container: Container,189 const out = c.block_writer.output;
361 comptime WriterType: type,190 try out.flush();
362) type {
363 const BlockWriterType = BlockWriter(WriterType);
364 return struct {
365 buffer: [65535]u8 = undefined, // because store blocks are limited to 65535 bytes
366 wp: usize = 0,
367
368 output: WriterType,
369 block_writer: BlockWriterType,
370 hasher: container.Hasher() = .{},
371
372 const Self = @This();
373
374 pub fn init(output: WriterType) !Self {
375 const self = Self{
376 .output = output,
377 .block_writer = BlockWriterType.init(output),
378 };
379 try container.writeHeader(self.output);
380 return self;
381 }
382
383 pub fn flush(self: *Self) !void {
384 try self.flushBuffer(false);
385 try self.block_writer.storedBlock("", false);
386 try self.block_writer.flush();
387 }
388
389 pub fn finish(self: *Self) !void {
390 try self.flushBuffer(true);
391 try self.block_writer.flush();
392 try container.writeFooter(&self.hasher, self.output);
393 }
394
395 fn flushBuffer(self: *Self, final: bool) !void {
396 const buf = self.buffer[0..self.wp];
397 switch (kind) {
398 .huffman => try self.block_writer.huffmanBlock(buf, final),
399 .store => try self.block_writer.storedBlock(buf, final),
400 }
401 self.wp = 0;
402 }
403 };
404}191}
405192
406const LiteralNode = struct {193pub fn endUnflushed(c: *Compress) !void {
407 literal: u16,194 while (c.writer.end != 0) _ = try drain(&c.writer, &.{""}, 1);
408 freq: u16,195 c.state = .ended;
409};
410
411// Describes the state of the constructed tree for a given depth.
412const LevelInfo = struct {
413 // Our level. for better printing
414 level: u32,
415
416 // The frequency of the last node at this level
417 last_freq: u32,
418196
419 // The frequency of the next character to add to this level197 const out = c.block_writer.output;
420 next_char_freq: u32,
421
422 // The frequency of the next pair (from level below) to add to this level.
423 // Only valid if the "needed" value of the next lower level is 0.
424 next_pair_freq: u32,
425
426 // The number of chains remaining to generate for this level before moving
427 // up to the next level
428 needed: u32,
429};
430198
431// hcode is a huffman code with a bit code and bit length.199 // TODO flush tokens
432pub const HuffCode = struct {
433 code: u16 = 0,
434 len: u16 = 0,
435200
436 // set sets the code and length of an hcode.201 switch (c.hasher) {
437 fn set(self: *HuffCode, code: u16, length: u16) void {202 .gzip => |*gzip| {
438 self.len = length;203 // GZIP 8 bytes footer
439 self.code = code;204 // - 4 bytes, CRC32 (CRC-32)
205 // - 4 bytes, ISIZE (Input SIZE) - size of the original (uncompressed) input data modulo 2^32
206 const footer = try out.writableArray(8);
207 std.mem.writeInt(u32, footer[0..4], gzip.crc.final(), .little);
208 std.mem.writeInt(u32, footer[4..8], @truncate(gzip.count), .little);
209 },
210 .zlib => |*zlib| {
211 // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
212 // 4 bytes of ADLER32 (Adler-32 checksum)
213 // Checksum value of the uncompressed data (excluding any
214 // dictionary data) computed according to Adler-32
215 // algorithm.
216 std.mem.writeInt(u32, try out.writableArray(4), zlib.adler, .big);
217 },
218 .raw => {},
440 }219 }
441};
442
443pub fn HuffmanEncoder(comptime size: usize) type {
444 return struct {
445 codes: [size]HuffCode = undefined,
446 // Reusable buffer with the longest possible frequency table.
447 freq_cache: [huffman.max_num_frequencies + 1]LiteralNode = undefined,
448 bit_count: [17]u32 = undefined,
449 lns: []LiteralNode = undefined, // sorted by literal, stored to avoid repeated allocation in generate
450 lfs: []LiteralNode = undefined, // sorted by frequency, stored to avoid repeated allocation in generate
451
452 const Self = @This();
453
454 // Update this Huffman Code object to be the minimum code for the specified frequency count.
455 //
456 // freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
457 // max_bits The maximum number of bits to use for any literal.
458 pub fn generate(self: *Self, freq: []u16, max_bits: u32) void {
459 var list = self.freq_cache[0 .. freq.len + 1];
460 // Number of non-zero literals
461 var count: u32 = 0;
462 // Set list to be the set of all non-zero literals and their frequencies
463 for (freq, 0..) |f, i| {
464 if (f != 0) {
465 list[count] = LiteralNode{ .literal = @as(u16, @intCast(i)), .freq = f };
466 count += 1;
467 } else {
468 list[count] = LiteralNode{ .literal = 0x00, .freq = 0 };
469 self.codes[i].len = 0;
470 }
471 }
472 list[freq.len] = LiteralNode{ .literal = 0x00, .freq = 0 };
473
474 list = list[0..count];
475 if (count <= 2) {
476 // Handle the small cases here, because they are awkward for the general case code. With
477 // two or fewer literals, everything has bit length 1.
478 for (list, 0..) |node, i| {
479 // "list" is in order of increasing literal value.
480 self.codes[node.literal].set(@as(u16, @intCast(i)), 1);
481 }
482 return;
483 }
484 self.lfs = list;
485 mem.sort(LiteralNode, self.lfs, {}, byFreq);
486
487 // Get the number of literals for each bit count
488 const bit_count = self.bitCounts(list, max_bits);
489 // And do the assignment
490 self.assignEncodingAndSize(bit_count, list);
491 }
492
493 pub fn bitLength(self: *Self, freq: []u16) u32 {
494 var total: u32 = 0;
495 for (freq, 0..) |f, i| {
496 if (f != 0) {
497 total += @as(u32, @intCast(f)) * @as(u32, @intCast(self.codes[i].len));
498 }
499 }
500 return total;
501 }
502
503 // Return the number of literals assigned to each bit size in the Huffman encoding
504 //
505 // This method is only called when list.len >= 3
506 // The cases of 0, 1, and 2 literals are handled by special case code.
507 //
508 // list: An array of the literals with non-zero frequencies
509 // and their associated frequencies. The array is in order of increasing
510 // frequency, and has as its last element a special element with frequency
511 // `math.maxInt(i32)`
512 //
513 // max_bits: The maximum number of bits that should be used to encode any literal.
514 // Must be less than 16.
515 //
516 // Returns an integer array in which array[i] indicates the number of literals
517 // that should be encoded in i bits.
518 fn bitCounts(self: *Self, list: []LiteralNode, max_bits_to_use: usize) []u32 {
519 var max_bits = max_bits_to_use;
520 const n = list.len;
521 const max_bits_limit = 16;
522
523 assert(max_bits < max_bits_limit);
524
525 // The tree can't have greater depth than n - 1, no matter what. This
526 // saves a little bit of work in some small cases
527 max_bits = @min(max_bits, n - 1);
528
529 // Create information about each of the levels.
530 // A bogus "Level 0" whose sole purpose is so that
531 // level1.prev.needed == 0. This makes level1.next_pair_freq
532 // be a legitimate value that never gets chosen.
533 var levels: [max_bits_limit]LevelInfo = mem.zeroes([max_bits_limit]LevelInfo);
534 // leaf_counts[i] counts the number of literals at the left
535 // of ancestors of the rightmost node at level i.
536 // leaf_counts[i][j] is the number of literals at the left
537 // of the level j ancestor.
538 var leaf_counts: [max_bits_limit][max_bits_limit]u32 = mem.zeroes([max_bits_limit][max_bits_limit]u32);
539
540 {
541 var level = @as(u32, 1);
542 while (level <= max_bits) : (level += 1) {
543 // For every level, the first two items are the first two characters.
544 // We initialize the levels as if we had already figured this out.
545 levels[level] = LevelInfo{
546 .level = level,
547 .last_freq = list[1].freq,
548 .next_char_freq = list[2].freq,
549 .next_pair_freq = list[0].freq + list[1].freq,
550 .needed = 0,
551 };
552 leaf_counts[level][level] = 2;
553 if (level == 1) {
554 levels[level].next_pair_freq = math.maxInt(i32);
555 }
556 }
557 }
558
559 // We need a total of 2*n - 2 items at top level and have already generated 2.
560 levels[max_bits].needed = 2 * @as(u32, @intCast(n)) - 4;
561
562 {
563 var level = max_bits;
564 while (true) {
565 var l = &levels[level];
566 if (l.next_pair_freq == math.maxInt(i32) and l.next_char_freq == math.maxInt(i32)) {
567 // We've run out of both leaves and pairs.
568 // End all calculations for this level.
569 // To make sure we never come back to this level or any lower level,
570 // set next_pair_freq impossibly large.
571 l.needed = 0;
572 levels[level + 1].next_pair_freq = math.maxInt(i32);
573 level += 1;
574 continue;
575 }
576
577 const prev_freq = l.last_freq;
578 if (l.next_char_freq < l.next_pair_freq) {
579 // The next item on this row is a leaf node.
580 const next = leaf_counts[level][level] + 1;
581 l.last_freq = l.next_char_freq;
582 // Lower leaf_counts are the same of the previous node.
583 leaf_counts[level][level] = next;
584 if (next >= list.len) {
585 l.next_char_freq = maxNode().freq;
586 } else {
587 l.next_char_freq = list[next].freq;
588 }
589 } else {
590 // The next item on this row is a pair from the previous row.
591 // next_pair_freq isn't valid until we generate two
592 // more values in the level below
593 l.last_freq = l.next_pair_freq;
594 // Take leaf counts from the lower level, except counts[level] remains the same.
595 @memcpy(leaf_counts[level][0..level], leaf_counts[level - 1][0..level]);
596 levels[l.level - 1].needed = 2;
597 }
598
599 l.needed -= 1;
600 if (l.needed == 0) {
601 // We've done everything we need to do for this level.
602 // Continue calculating one level up. Fill in next_pair_freq
603 // of that level with the sum of the two nodes we've just calculated on
604 // this level.
605 if (l.level == max_bits) {
606 // All done!
607 break;
608 }
609 levels[l.level + 1].next_pair_freq = prev_freq + l.last_freq;
610 level += 1;
611 } else {
612 // If we stole from below, move down temporarily to replenish it.
613 while (levels[level - 1].needed > 0) {
614 level -= 1;
615 if (level == 0) {
616 break;
617 }
618 }
619 }
620 }
621 }
622
623 // Somethings is wrong if at the end, the top level is null or hasn't used
624 // all of the leaves.
625 assert(leaf_counts[max_bits][max_bits] == n);
626
627 var bit_count = self.bit_count[0 .. max_bits + 1];
628 var bits: u32 = 1;
629 const counts = &leaf_counts[max_bits];
630 {
631 var level = max_bits;
632 while (level > 0) : (level -= 1) {
633 // counts[level] gives the number of literals requiring at least "bits"
634 // bits to encode.
635 bit_count[bits] = counts[level] - counts[level - 1];
636 bits += 1;
637 if (level == 0) {
638 break;
639 }
640 }
641 }
642 return bit_count;
643 }
644
645 // Look at the leaves and assign them a bit count and an encoding as specified
646 // in RFC 1951 3.2.2
647 fn assignEncodingAndSize(self: *Self, bit_count: []u32, list_arg: []LiteralNode) void {
648 var code = @as(u16, 0);
649 var list = list_arg;
650
651 for (bit_count, 0..) |bits, n| {
652 code <<= 1;
653 if (n == 0 or bits == 0) {
654 continue;
655 }
656 // The literals list[list.len-bits] .. list[list.len-bits]
657 // are encoded using "bits" bits, and get the values
658 // code, code + 1, .... The code values are
659 // assigned in literal order (not frequency order).
660 const chunk = list[list.len - @as(u32, @intCast(bits)) ..];
661
662 self.lns = chunk;
663 mem.sort(LiteralNode, self.lns, {}, byLiteral);
664
665 for (chunk) |node| {
666 self.codes[node.literal] = HuffCode{
667 .code = bitReverse(u16, code, @as(u5, @intCast(n))),
668 .len = @as(u16, @intCast(n)),
669 };
670 code += 1;
671 }
672 list = list[0 .. list.len - @as(u32, @intCast(bits))];
673 }
674 }
675 };
676}220}
677221
678fn maxNode() LiteralNode {222pub const Simple = struct {
679 return LiteralNode{223 /// Note that store blocks are limited to 65535 bytes.
680 .literal = math.maxInt(u16),224 buffer: []u8,
681 .freq = math.maxInt(u16),225 wp: usize,
682 };226 block_writer: BlockWriter,
683}227 hasher: Container.Hasher,
684228 strategy: Strategy,
685pub fn huffmanEncoder(comptime size: u32) HuffmanEncoder(size) {
686 return .{};
687}
688229
689pub const LiteralEncoder = HuffmanEncoder(huffman.max_num_frequencies);230 pub const Strategy = enum { huffman, store };
690pub const DistanceEncoder = HuffmanEncoder(huffman.distance_code_count);
691pub const CodegenEncoder = HuffmanEncoder(19);
692231
693// Generates a HuffmanCode corresponding to the fixed literal table232 pub fn init(output: *Writer, buffer: []u8, container: Container, strategy: Strategy) !Simple {
694pub fn fixedLiteralEncoder() LiteralEncoder {233 const header = container.header();
695 var h: LiteralEncoder = undefined;234 try output.writeAll(header);
696 var ch: u16 = 0;235 return .{
697236 .buffer = buffer,
698 while (ch < huffman.max_num_frequencies) : (ch += 1) {237 .wp = 0,
699 var bits: u16 = undefined;238 .block_writer = .init(output),
700 var size: u16 = undefined;239 .hasher = .init(container),
701 switch (ch) {240 .strategy = strategy,
702 0...143 => {241 };
703 // size 8, 000110000 .. 10111111
704 bits = ch + 48;
705 size = 8;
706 },
707 144...255 => {
708 // size 9, 110010000 .. 111111111
709 bits = ch + 400 - 144;
710 size = 9;
711 },
712 256...279 => {
713 // size 7, 0000000 .. 0010111
714 bits = ch - 256;
715 size = 7;
716 },
717 else => {
718 // size 8, 11000000 .. 11000111
719 bits = ch + 192 - 280;
720 size = 8;
721 },
722 }
723 h.codes[ch] = HuffCode{ .code = bitReverse(u16, bits, @as(u5, @intCast(size))), .len = size };
724 }242 }
725 return h;
726}
727243
728pub fn fixedDistanceEncoder() DistanceEncoder {244 pub fn flush(self: *Simple) !void {
729 var h: DistanceEncoder = undefined;245 try self.flushBuffer(false);
730 for (h.codes, 0..) |_, ch| {246 try self.block_writer.storedBlock("", false);
731 h.codes[ch] = HuffCode{ .code = bitReverse(u16, @as(u16, @intCast(ch)), 5), .len = 5 };247 try self.block_writer.flush();
732 }248 }
733 return h;
734}
735
736pub fn huffmanDistanceEncoder() DistanceEncoder {
737 var distance_freq = [1]u16{0} ** huffman.distance_code_count;
738 distance_freq[0] = 1;
739 // huff_distance is a static distance encoder used for huffman only encoding.
740 // It can be reused since we will not be encoding distance values.
741 var h: DistanceEncoder = .{};
742 h.generate(distance_freq[0..], 15);
743 return h;
744}
745249
746fn byLiteral(context: void, a: LiteralNode, b: LiteralNode) bool {250 pub fn finish(self: *Simple) !void {
747 _ = context;251 try self.flushBuffer(true);
748 return a.literal < b.literal;252 try self.block_writer.flush();
749}253 try self.hasher.container().writeFooter(&self.hasher, self.block_writer.output);
750
751fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool {
752 _ = context;
753 if (a.freq == b.freq) {
754 return a.literal < b.literal;
755 }254 }
756 return a.freq < b.freq;
757}
758
759fn stream(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {
760 const c: *Compress = @fieldParentPtr("reader", r);
761 switch (c.state) {
762 .header => |i| {
763 const header = c.hasher.container().header();
764 const n = try w.write(header[i..]);
765 if (header.len - i - n == 0) {
766 c.state = .middle;
767 } else {
768 c.state.header += n;
769 }
770 return n;
771 },
772 .middle => {
773 c.input.fillMore() catch |err| switch (err) {
774 error.EndOfStream => {
775 c.state = .final;
776 return 0;
777 },
778 else => |e| return e,
779 };
780 const buffer_contents = c.input.buffered();
781 const min_lookahead = flate.match.min_length + flate.match.max_length;
782 const history_plus_lookahead_len = flate.history_len + min_lookahead;
783 if (buffer_contents.len < history_plus_lookahead_len) return 0;
784 const lookahead = buffer_contents[flate.history_len..];
785 const start = w.count;
786 const n = try c.tokenizeSlice(w, limit, lookahead) catch |err| switch (err) {
787 error.WriteFailed => return error.WriteFailed,
788 };
789 c.hasher.update(lookahead[0..n]);
790 c.input.toss(n);
791 return w.count - start;
792 },
793 .final => {
794 const buffer_contents = c.input.buffered();
795 const start = w.count;
796 const n = c.tokenizeSlice(w, limit, buffer_contents) catch |err| switch (err) {
797 error.WriteFailed => return error.WriteFailed,
798 };
799 if (buffer_contents.len - n == 0) {
800 c.hasher.update(buffer_contents);
801 c.input.tossAll();
802 {
803 // In the case of flushing, last few lookahead buffers were
804 // smaller than min match len, so only last literal can be
805 // unwritten.
806 assert(c.prev_match == null);
807 try c.addPrevLiteral();
808 c.prev_literal = null;
809255
810 try c.flushTokens(.final);256 fn flushBuffer(self: *Simple, final: bool) !void {
811 }257 const buf = self.buffer[0..self.wp];
812 switch (c.hasher) {258 switch (self.strategy) {
813 .gzip => |*gzip| {259 .huffman => try self.block_writer.huffmanBlock(buf, final),
814 // GZIP 8 bytes footer260 .store => try self.block_writer.storedBlock(buf, final),
815 // - 4 bytes, CRC32 (CRC-32)261 }
816 // - 4 bytes, ISIZE (Input SIZE) - size of the original (uncompressed) input data modulo 2^32262 self.wp = 0;
817 comptime assert(c.footer_buffer.len == 8);
818 std.mem.writeInt(u32, c.footer_buffer[0..4], gzip.final(), .little);
819 std.mem.writeInt(u32, c.footer_buffer[4..8], gzip.bytes_read, .little);
820 c.state = .{ .footer = 0 };
821 },
822 .zlib => |*zlib| {
823 // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
824 // 4 bytes of ADLER32 (Adler-32 checksum)
825 // Checksum value of the uncompressed data (excluding any
826 // dictionary data) computed according to Adler-32
827 // algorithm.
828 comptime assert(c.footer_buffer.len == 8);
829 std.mem.writeInt(u32, c.footer_buffer[4..8], zlib.final, .big);
830 c.state = .{ .footer = 4 };
831 },
832 .raw => {
833 c.state = .ended;
834 },
835 }
836 }
837 return w.count - start;
838 },
839 .ended => return error.EndOfStream,
840 .footer => |i| {
841 const remaining = c.footer_buffer[i..];
842 const n = try w.write(limit.slice(remaining));
843 c.state = if (n == remaining) .ended else .{ .footer = i - n };
844 return n;
845 },
846 }263 }
847}264};
848265
849test "generate a Huffman code from an array of frequencies" {266test "generate a Huffman code from an array of frequencies" {
850 var freqs: [19]u16 = [_]u16{267 var freqs: [19]u16 = [_]u16{
...@@ -869,7 +286,14 @@ test "generate a Huffman code from an array of frequencies" {...@@ -869,7 +286,14 @@ test "generate a Huffman code from an array of frequencies" {
869 5, // 18286 5, // 18
870 };287 };
871288
872 var enc = huffmanEncoder(19);289 var codes: [19]HuffmanEncoder.Code = undefined;
290 var enc: HuffmanEncoder = .{
291 .codes = &codes,
292 .freq_cache = undefined,
293 .bit_count = undefined,
294 .lns = undefined,
295 .lfs = undefined,
296 };
873 enc.generate(freqs[0..], 7);297 enc.generate(freqs[0..], 7);
874298
875 try testing.expectEqual(@as(u32, 141), enc.bitLength(freqs[0..]));299 try testing.expectEqual(@as(u32, 141), enc.bitLength(freqs[0..]));
...@@ -906,360 +330,3 @@ test "generate a Huffman code from an array of frequencies" {...@@ -906,360 +330,3 @@ test "generate a Huffman code from an array of frequencies" {
906 try testing.expectEqual(@as(u16, 0x1f), enc.codes[7].code);330 try testing.expectEqual(@as(u16, 0x1f), enc.codes[7].code);
907 try testing.expectEqual(@as(u16, 0x3f), enc.codes[16].code);331 try testing.expectEqual(@as(u16, 0x3f), enc.codes[16].code);
908}332}
909
910test "generate a Huffman code for the fixed literal table specific to Deflate" {
911 const enc = fixedLiteralEncoder();
912 for (enc.codes) |c| {
913 switch (c.len) {
914 7 => {
915 const v = @bitReverse(@as(u7, @intCast(c.code)));
916 try testing.expect(v <= 0b0010111);
917 },
918 8 => {
919 const v = @bitReverse(@as(u8, @intCast(c.code)));
920 try testing.expect((v >= 0b000110000 and v <= 0b10111111) or
921 (v >= 0b11000000 and v <= 11000111));
922 },
923 9 => {
924 const v = @bitReverse(@as(u9, @intCast(c.code)));
925 try testing.expect(v >= 0b110010000 and v <= 0b111111111);
926 },
927 else => unreachable,
928 }
929 }
930}
931
932test "generate a Huffman code for the 30 possible relative distances (LZ77 distances) of Deflate" {
933 const enc = fixedDistanceEncoder();
934 for (enc.codes) |c| {
935 const v = @bitReverse(@as(u5, @intCast(c.code)));
936 try testing.expect(v <= 29);
937 try testing.expect(c.len == 5);
938 }
939}
940
941// Reverse bit-by-bit a N-bit code.
942fn bitReverse(comptime T: type, value: T, n: usize) T {
943 const r = @bitReverse(value);
944 return r >> @as(math.Log2Int(T), @intCast(@typeInfo(T).int.bits - n));
945}
946
947test bitReverse {
948 const ReverseBitsTest = struct {
949 in: u16,
950 bit_count: u5,
951 out: u16,
952 };
953
954 const reverse_bits_tests = [_]ReverseBitsTest{
955 .{ .in = 1, .bit_count = 1, .out = 1 },
956 .{ .in = 1, .bit_count = 2, .out = 2 },
957 .{ .in = 1, .bit_count = 3, .out = 4 },
958 .{ .in = 1, .bit_count = 4, .out = 8 },
959 .{ .in = 1, .bit_count = 5, .out = 16 },
960 .{ .in = 17, .bit_count = 5, .out = 17 },
961 .{ .in = 257, .bit_count = 9, .out = 257 },
962 .{ .in = 29, .bit_count = 5, .out = 23 },
963 };
964
965 for (reverse_bits_tests) |h| {
966 const v = bitReverse(u16, h.in, h.bit_count);
967 try std.testing.expectEqual(h.out, v);
968 }
969}
970
971test "fixedLiteralEncoder codes" {
972 var al = std.ArrayList(u8).init(testing.allocator);
973 defer al.deinit();
974 var bw = std.io.bitWriter(.little, al.writer());
975
976 const f = fixedLiteralEncoder();
977 for (f.codes) |c| {
978 try bw.writeBits(c.code, c.len);
979 }
980 try testing.expectEqualSlices(u8, &fixed_codes, al.items);
981}
982
983pub const fixed_codes = [_]u8{
984 0b00001100, 0b10001100, 0b01001100, 0b11001100, 0b00101100, 0b10101100, 0b01101100, 0b11101100,
985 0b00011100, 0b10011100, 0b01011100, 0b11011100, 0b00111100, 0b10111100, 0b01111100, 0b11111100,
986 0b00000010, 0b10000010, 0b01000010, 0b11000010, 0b00100010, 0b10100010, 0b01100010, 0b11100010,
987 0b00010010, 0b10010010, 0b01010010, 0b11010010, 0b00110010, 0b10110010, 0b01110010, 0b11110010,
988 0b00001010, 0b10001010, 0b01001010, 0b11001010, 0b00101010, 0b10101010, 0b01101010, 0b11101010,
989 0b00011010, 0b10011010, 0b01011010, 0b11011010, 0b00111010, 0b10111010, 0b01111010, 0b11111010,
990 0b00000110, 0b10000110, 0b01000110, 0b11000110, 0b00100110, 0b10100110, 0b01100110, 0b11100110,
991 0b00010110, 0b10010110, 0b01010110, 0b11010110, 0b00110110, 0b10110110, 0b01110110, 0b11110110,
992 0b00001110, 0b10001110, 0b01001110, 0b11001110, 0b00101110, 0b10101110, 0b01101110, 0b11101110,
993 0b00011110, 0b10011110, 0b01011110, 0b11011110, 0b00111110, 0b10111110, 0b01111110, 0b11111110,
994 0b00000001, 0b10000001, 0b01000001, 0b11000001, 0b00100001, 0b10100001, 0b01100001, 0b11100001,
995 0b00010001, 0b10010001, 0b01010001, 0b11010001, 0b00110001, 0b10110001, 0b01110001, 0b11110001,
996 0b00001001, 0b10001001, 0b01001001, 0b11001001, 0b00101001, 0b10101001, 0b01101001, 0b11101001,
997 0b00011001, 0b10011001, 0b01011001, 0b11011001, 0b00111001, 0b10111001, 0b01111001, 0b11111001,
998 0b00000101, 0b10000101, 0b01000101, 0b11000101, 0b00100101, 0b10100101, 0b01100101, 0b11100101,
999 0b00010101, 0b10010101, 0b01010101, 0b11010101, 0b00110101, 0b10110101, 0b01110101, 0b11110101,
1000 0b00001101, 0b10001101, 0b01001101, 0b11001101, 0b00101101, 0b10101101, 0b01101101, 0b11101101,
1001 0b00011101, 0b10011101, 0b01011101, 0b11011101, 0b00111101, 0b10111101, 0b01111101, 0b11111101,
1002 0b00010011, 0b00100110, 0b01001110, 0b10011010, 0b00111100, 0b01100101, 0b11101010, 0b10110100,
1003 0b11101001, 0b00110011, 0b01100110, 0b11001110, 0b10011010, 0b00111101, 0b01100111, 0b11101110,
1004 0b10111100, 0b11111001, 0b00001011, 0b00010110, 0b00101110, 0b01011010, 0b10111100, 0b01100100,
1005 0b11101001, 0b10110010, 0b11100101, 0b00101011, 0b01010110, 0b10101110, 0b01011010, 0b10111101,
1006 0b01100110, 0b11101101, 0b10111010, 0b11110101, 0b00011011, 0b00110110, 0b01101110, 0b11011010,
1007 0b10111100, 0b01100101, 0b11101011, 0b10110110, 0b11101101, 0b00111011, 0b01110110, 0b11101110,
1008 0b11011010, 0b10111101, 0b01100111, 0b11101111, 0b10111110, 0b11111101, 0b00000111, 0b00001110,
1009 0b00011110, 0b00111010, 0b01111100, 0b11100100, 0b11101000, 0b10110001, 0b11100011, 0b00100111,
1010 0b01001110, 0b10011110, 0b00111010, 0b01111101, 0b11100110, 0b11101100, 0b10111001, 0b11110011,
1011 0b00010111, 0b00101110, 0b01011110, 0b10111010, 0b01111100, 0b11100101, 0b11101010, 0b10110101,
1012 0b11101011, 0b00110111, 0b01101110, 0b11011110, 0b10111010, 0b01111101, 0b11100111, 0b11101110,
1013 0b10111101, 0b11111011, 0b00001111, 0b00011110, 0b00111110, 0b01111010, 0b11111100, 0b11100100,
1014 0b11101001, 0b10110011, 0b11100111, 0b00101111, 0b01011110, 0b10111110, 0b01111010, 0b11111101,
1015 0b11100110, 0b11101101, 0b10111011, 0b11110111, 0b00011111, 0b00111110, 0b01111110, 0b11111010,
1016 0b11111100, 0b11100101, 0b11101011, 0b10110111, 0b11101111, 0b00111111, 0b01111110, 0b11111110,
1017 0b11111010, 0b11111101, 0b11100111, 0b11101111, 0b10111111, 0b11111111, 0b00000000, 0b00100000,
1018 0b00001000, 0b00001100, 0b10000001, 0b11000010, 0b11100000, 0b00001000, 0b00100100, 0b00001010,
1019 0b10001101, 0b11000001, 0b11100010, 0b11110000, 0b00000100, 0b00100010, 0b10001001, 0b01001100,
1020 0b10100001, 0b11010010, 0b11101000, 0b00000011, 0b10000011, 0b01000011, 0b11000011, 0b00100011,
1021 0b10100011,
1022};
1023
1024test "tokenization" {
1025 const L = Token.initLiteral;
1026 const M = Token.initMatch;
1027
1028 const cases = [_]struct {
1029 data: []const u8,
1030 tokens: []const Token,
1031 }{
1032 .{
1033 .data = "Blah blah blah blah blah!",
1034 .tokens = &[_]Token{ L('B'), L('l'), L('a'), L('h'), L(' '), L('b'), M(5, 18), L('!') },
1035 },
1036 .{
1037 .data = "ABCDEABCD ABCDEABCD",
1038 .tokens = &[_]Token{
1039 L('A'), L('B'), L('C'), L('D'), L('E'), L('A'), L('B'), L('C'), L('D'), L(' '),
1040 L('A'), M(10, 8),
1041 },
1042 },
1043 };
1044
1045 for (cases) |c| {
1046 inline for (Container.list) |container| { // for each wrapping
1047
1048 var cw = io.countingWriter(io.null_writer);
1049 const cww = cw.writer();
1050 var df = try Compress(container, @TypeOf(cww), TestTokenWriter).init(cww, .{});
1051
1052 _ = try df.write(c.data);
1053 try df.flush();
1054
1055 // df.token_writer.show();
1056 try expect(df.block_writer.pos == c.tokens.len); // number of tokens written
1057 try testing.expectEqualSlices(Token, df.block_writer.get(), c.tokens); // tokens match
1058
1059 try testing.expectEqual(container.headerSize(), cw.bytes_written);
1060 try df.finish();
1061 try testing.expectEqual(container.size(), cw.bytes_written);
1062 }
1063 }
1064}
1065
1066// Tests that tokens written are equal to expected token list.
1067const TestTokenWriter = struct {
1068 const Self = @This();
1069
1070 pos: usize = 0,
1071 actual: [128]Token = undefined,
1072
1073 pub fn init(_: anytype) Self {
1074 return .{};
1075 }
1076 pub fn write(self: *Self, tokens: []const Token, _: bool, _: ?[]const u8) !void {
1077 for (tokens) |t| {
1078 self.actual[self.pos] = t;
1079 self.pos += 1;
1080 }
1081 }
1082
1083 pub fn storedBlock(_: *Self, _: []const u8, _: bool) !void {}
1084
1085 pub fn get(self: *Self) []Token {
1086 return self.actual[0..self.pos];
1087 }
1088
1089 pub fn show(self: *Self) void {
1090 std.debug.print("\n", .{});
1091 for (self.get()) |t| {
1092 t.show();
1093 }
1094 }
1095
1096 pub fn flush(_: *Self) !void {}
1097};
1098
1099test "file tokenization" {
1100 const levels = [_]Level{ .level_4, .level_5, .level_6, .level_7, .level_8, .level_9 };
1101 const cases = [_]struct {
1102 data: []const u8, // uncompressed content
1103 // expected number of tokens producet in deflate tokenization
1104 tokens_count: [levels.len]usize = .{0} ** levels.len,
1105 }{
1106 .{
1107 .data = @embedFile("testdata/rfc1951.txt"),
1108 .tokens_count = .{ 7675, 7672, 7599, 7594, 7598, 7599 },
1109 },
1110
1111 .{
1112 .data = @embedFile("testdata/block_writer/huffman-null-max.input"),
1113 .tokens_count = .{ 257, 257, 257, 257, 257, 257 },
1114 },
1115 .{
1116 .data = @embedFile("testdata/block_writer/huffman-pi.input"),
1117 .tokens_count = .{ 2570, 2564, 2564, 2564, 2564, 2564 },
1118 },
1119 .{
1120 .data = @embedFile("testdata/block_writer/huffman-text.input"),
1121 .tokens_count = .{ 235, 234, 234, 234, 234, 234 },
1122 },
1123 .{
1124 .data = @embedFile("testdata/fuzz/roundtrip1.input"),
1125 .tokens_count = .{ 333, 331, 331, 331, 331, 331 },
1126 },
1127 .{
1128 .data = @embedFile("testdata/fuzz/roundtrip2.input"),
1129 .tokens_count = .{ 334, 334, 334, 334, 334, 334 },
1130 },
1131 };
1132
1133 for (cases) |case| { // for each case
1134 const data = case.data;
1135
1136 for (levels, 0..) |level, i| { // for each compression level
1137 var original: std.io.Reader = .fixed(data);
1138
1139 // buffer for decompressed data
1140 var al = std.ArrayList(u8).init(testing.allocator);
1141 defer al.deinit();
1142 const writer = al.writer();
1143
1144 // create compressor
1145 const WriterType = @TypeOf(writer);
1146 const TokenWriter = TokenDecoder(@TypeOf(writer));
1147 var cmp = try Compress(.raw, WriterType, TokenWriter).init(writer, .{ .level = level });
1148
1149 // Stream uncompressed `original` data to the compressor. It will
1150 // produce tokens list and pass that list to the TokenDecoder. This
1151 // TokenDecoder uses CircularBuffer from inflate to convert list of
1152 // tokens back to the uncompressed stream.
1153 try cmp.compress(original.reader());
1154 try cmp.flush();
1155 const expected_count = case.tokens_count[i];
1156 const actual = cmp.block_writer.tokens_count;
1157 if (expected_count == 0) {
1158 std.debug.print("actual token count {d}\n", .{actual});
1159 } else {
1160 try testing.expectEqual(expected_count, actual);
1161 }
1162
1163 try testing.expectEqual(data.len, al.items.len);
1164 try testing.expectEqualSlices(u8, data, al.items);
1165 }
1166 }
1167}
1168
1169const TokenDecoder = struct {
1170 output: *Writer,
1171 tokens_count: usize,
1172
1173 pub fn init(output: *Writer) TokenDecoder {
1174 return .{
1175 .output = output,
1176 .tokens_count = 0,
1177 };
1178 }
1179
1180 pub fn write(self: *TokenDecoder, tokens: []const Token, _: bool, _: ?[]const u8) !void {
1181 self.tokens_count += tokens.len;
1182 for (tokens) |t| {
1183 switch (t.kind) {
1184 .literal => self.hist.write(t.literal()),
1185 .match => try self.hist.writeMatch(t.length(), t.distance()),
1186 }
1187 if (self.hist.free() < 285) try self.flushWin();
1188 }
1189 try self.flushWin();
1190 }
1191
1192 fn flushWin(self: *TokenDecoder) !void {
1193 while (true) {
1194 const buf = self.hist.read();
1195 if (buf.len == 0) break;
1196 try self.output.writeAll(buf);
1197 }
1198 }
1199};
1200
1201test "store simple compressor" {
1202 const data = "Hello world!";
1203 const expected = [_]u8{
1204 0x1, // block type 0, final bit set
1205 0xc, 0x0, // len = 12
1206 0xf3, 0xff, // ~len
1207 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', //
1208 //0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21,
1209 };
1210
1211 var fbs: std.io.Reader = .fixed(data);
1212 var al = std.ArrayList(u8).init(testing.allocator);
1213 defer al.deinit();
1214
1215 var cmp = try store.compressor(.raw, al.writer());
1216 try cmp.compress(&fbs);
1217 try cmp.finish();
1218 try testing.expectEqualSlices(u8, &expected, al.items);
1219
1220 fbs = .fixed(data);
1221 try al.resize(0);
1222
1223 // huffman only compresoor will also emit store block for this small sample
1224 var hc = try huffman.compressor(.raw, al.writer());
1225 try hc.compress(&fbs);
1226 try hc.finish();
1227 try testing.expectEqualSlices(u8, &expected, al.items);
1228}
1229
1230test "sliding window match" {
1231 const data = "Blah blah blah blah blah!";
1232 var win: Writer = .{};
1233 try expect(win.write(data) == data.len);
1234 try expect(win.wp == data.len);
1235 try expect(win.rp == 0);
1236
1237 // length between l symbols
1238 try expect(win.match(1, 6, 0) == 18);
1239 try expect(win.match(1, 11, 0) == 13);
1240 try expect(win.match(1, 16, 0) == 8);
1241 try expect(win.match(1, 21, 0) == 0);
1242
1243 // position 15 = "blah blah!"
1244 // position 20 = "blah!"
1245 try expect(win.match(15, 20, 0) == 4);
1246 try expect(win.match(15, 20, 3) == 4);
1247 try expect(win.match(15, 20, 4) == 0);
1248}
1249
1250test "sliding window slide" {
1251 var win: Writer = .{};
1252 win.wp = Writer.buffer_len - 11;
1253 win.rp = Writer.buffer_len - 111;
1254 win.buffer[win.rp] = 0xab;
1255 try expect(win.lookahead().len == 100);
1256 try expect(win.tokensBuffer().?.len == win.rp);
1257
1258 const n = win.slide();
1259 try expect(n == 32757);
1260 try expect(win.buffer[win.rp] == 0xab);
1261 try expect(win.rp == Writer.hist_len - 111);
1262 try expect(win.wp == Writer.hist_len - 11);
1263 try expect(win.lookahead().len == 100);
1264 try expect(win.tokensBuffer() == null);
1265}
lib/std/compress/flate/Decompress.zig+694-321
...@@ -1,16 +1,21 @@...@@ -1,16 +1,21 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const assert = std.debug.assert;
2const flate = std.compress.flate;3const flate = std.compress.flate;
3const Container = flate.Container;
4const Token = @import("Token.zig");
5const testing = std.testing;4const testing = std.testing;
5const Writer = std.Io.Writer;
6const Reader = std.Io.Reader;
7const Container = flate.Container;
8
6const Decompress = @This();9const Decompress = @This();
7const Writer = std.io.Writer;10const Token = @import("Token.zig");
8const Reader = std.io.Reader;
911
10input: *Reader,12input: *Reader,
13next_bits: usize,
14remaining_bits: std.math.Log2Int(usize),
15
11reader: Reader,16reader: Reader,
12/// Hashes, produces checksum, of uncompressed data for gzip/zlib footer.17
13hasher: Container.Hasher,18container_metadata: Container.Metadata,
1419
15lit_dec: LiteralDecoder,20lit_dec: LiteralDecoder,
16dst_dec: DistanceDecoder,21dst_dec: DistanceDecoder,
...@@ -18,7 +23,7 @@ dst_dec: DistanceDecoder,...@@ -18,7 +23,7 @@ dst_dec: DistanceDecoder,
18final_block: bool,23final_block: bool,
19state: State,24state: State,
2025
21read_err: ?Error,26err: ?Error,
2227
23const BlockType = enum(u2) {28const BlockType = enum(u2) {
24 stored = 0,29 stored = 0,
...@@ -32,6 +37,8 @@ const State = union(enum) {...@@ -32,6 +37,8 @@ const State = union(enum) {
32 stored_block: u16,37 stored_block: u16,
33 fixed_block,38 fixed_block,
34 dynamic_block,39 dynamic_block,
40 dynamic_block_literal: u8,
41 dynamic_block_match: u16,
35 protocol_footer,42 protocol_footer,
36 end,43 end,
37};44};
...@@ -39,43 +46,139 @@ const State = union(enum) {...@@ -39,43 +46,139 @@ const State = union(enum) {
39pub const Error = Container.Error || error{46pub const Error = Container.Error || error{
40 InvalidCode,47 InvalidCode,
41 InvalidMatch,48 InvalidMatch,
42 InvalidBlockType,
43 WrongStoredBlockNlen,49 WrongStoredBlockNlen,
44 InvalidDynamicBlockHeader,50 InvalidDynamicBlockHeader,
45 EndOfStream,
46 ReadFailed,51 ReadFailed,
47 OversubscribedHuffmanTree,52 OversubscribedHuffmanTree,
48 IncompleteHuffmanTree,53 IncompleteHuffmanTree,
49 MissingEndOfBlockCode,54 MissingEndOfBlockCode,
55 EndOfStream,
56};
57
58const direct_vtable: Reader.VTable = .{
59 .stream = streamDirect,
60 .rebase = rebaseFallible,
61 .discard = discard,
62 .readVec = readVec,
63};
64
65const indirect_vtable: Reader.VTable = .{
66 .stream = streamIndirect,
67 .rebase = rebaseFallible,
68 .discard = discardIndirect,
69 .readVec = readVec,
50};70};
5171
52pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {72pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
53 return .{73 return .{
54 .reader = .{74 .reader = .{
55 // TODO populate discard so that when an amount is discarded that75 .vtable = if (buffer.len == 0) &direct_vtable else &indirect_vtable,
56 // includes an entire frame, skip decoding that frame.
57 .vtable = &.{ .stream = stream },
58 .buffer = buffer,76 .buffer = buffer,
59 .seek = 0,77 .seek = 0,
60 .end = 0,78 .end = 0,
61 },79 },
62 .input = input,80 .input = input,
63 .hasher = .init(container),81 .next_bits = 0,
82 .remaining_bits = 0,
83 .container_metadata = .init(container),
64 .lit_dec = .{},84 .lit_dec = .{},
65 .dst_dec = .{},85 .dst_dec = .{},
66 .final_block = false,86 .final_block = false,
67 .state = .protocol_header,87 .state = .protocol_header,
68 .read_err = null,88 .err = null,
69 };89 };
70}90}
7191
92fn rebaseFallible(r: *Reader, capacity: usize) Reader.RebaseError!void {
93 rebase(r, capacity);
94}
95
96fn rebase(r: *Reader, capacity: usize) void {
97 assert(capacity <= r.buffer.len - flate.history_len);
98 assert(r.end + capacity > r.buffer.len);
99 const discard_n = r.end - flate.history_len;
100 const keep = r.buffer[discard_n..r.end];
101 @memmove(r.buffer[0..keep.len], keep);
102 assert(keep.len != 0);
103 r.end = keep.len;
104 r.seek -= discard_n;
105}
106
107/// This could be improved so that when an amount is discarded that includes an
108/// entire frame, skip decoding that frame.
109fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
110 if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len);
111 var writer: Writer = .{
112 .vtable = &.{
113 .drain = std.Io.Writer.Discarding.drain,
114 .sendFile = std.Io.Writer.Discarding.sendFile,
115 },
116 .buffer = r.buffer,
117 .end = r.end,
118 };
119 defer {
120 assert(writer.end != 0);
121 r.end = writer.end;
122 r.seek = r.end;
123 }
124 const n = r.stream(&writer, limit) catch |err| switch (err) {
125 error.WriteFailed => unreachable,
126 error.ReadFailed => return error.ReadFailed,
127 error.EndOfStream => return error.EndOfStream,
128 };
129 assert(n <= @intFromEnum(limit));
130 return n;
131}
132
133fn discardIndirect(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
134 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
135 if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len);
136 var writer: Writer = .{
137 .buffer = r.buffer,
138 .end = r.end,
139 .vtable = &.{ .drain = Writer.unreachableDrain },
140 };
141 {
142 defer r.end = writer.end;
143 _ = streamFallible(d, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
144 error.WriteFailed => unreachable,
145 else => |e| return e,
146 };
147 }
148 const n = limit.minInt(r.end - r.seek);
149 r.seek += n;
150 return n;
151}
152
153fn readVec(r: *Reader, data: [][]u8) Reader.Error!usize {
154 _ = data;
155 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
156 return streamIndirectInner(d);
157}
158
159fn streamIndirectInner(d: *Decompress) Reader.Error!usize {
160 const r = &d.reader;
161 if (r.end + flate.history_len > r.buffer.len) rebase(r, flate.history_len);
162 var writer: Writer = .{
163 .buffer = r.buffer,
164 .end = r.end,
165 .vtable = &.{ .drain = Writer.unreachableDrain },
166 };
167 defer r.end = writer.end;
168 _ = streamFallible(d, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
169 error.WriteFailed => unreachable,
170 else => |e| return e,
171 };
172 return 0;
173}
174
72fn decodeLength(self: *Decompress, code: u8) !u16 {175fn decodeLength(self: *Decompress, code: u8) !u16 {
73 if (code > 28) return error.InvalidCode;176 if (code > 28) return error.InvalidCode;
74 const ml = Token.matchLength(code);177 const ml = Token.matchLength(code);
75 return if (ml.extra_bits == 0) // 0 - 5 extra bits178 return if (ml.extra_bits == 0) // 0 - 5 extra bits
76 ml.base179 ml.base
77 else180 else
78 ml.base + try self.takeNBitsBuffered(ml.extra_bits);181 ml.base + try self.takeBitsRuntime(ml.extra_bits);
79}182}
80183
81fn decodeDistance(self: *Decompress, code: u8) !u16 {184fn decodeDistance(self: *Decompress, code: u8) !u16 {
...@@ -84,7 +187,7 @@ fn decodeDistance(self: *Decompress, code: u8) !u16 {...@@ -84,7 +187,7 @@ fn decodeDistance(self: *Decompress, code: u8) !u16 {
84 return if (md.extra_bits == 0) // 0 - 13 extra bits187 return if (md.extra_bits == 0) // 0 - 13 extra bits
85 md.base188 md.base
86 else189 else
87 md.base + try self.takeNBitsBuffered(md.extra_bits);190 md.base + try self.takeBitsRuntime(md.extra_bits);
88}191}
89192
90// Decode code length symbol to code length. Writes decoded length into193// 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...@@ -119,34 +222,50 @@ fn dynamicCodeLength(self: *Decompress, code: u16, lens: []u4, pos: usize) !usiz
119 }222 }
120}223}
121224
122// Peek 15 bits from bits reader (maximum code len is 15 bits). Use
123// decoder to find symbol for that code. We then know how many bits is
124// used. Shift bit reader for that much bits, those bits are used. And
125// return symbol.
126fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {225fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {
127 const sym = try decoder.find(try self.peekBitsReverseBuffered(u15));226 // Maximum code len is 15 bits.
128 try self.shiftBits(sym.code_bits);227 const sym = try decoder.find(@bitReverse(try self.peekBits(u15)));
228 try self.tossBits(sym.code_bits);
129 return sym;229 return sym;
130}230}
131231
132pub fn stream(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {232fn streamDirect(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
133 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));233 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
134 return readInner(d, w, limit) catch |err| switch (err) {234 return streamFallible(d, w, limit);
135 error.EndOfStream => return error.EndOfStream,235}
236
237fn streamIndirect(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
238 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
239 _ = limit;
240 _ = w;
241 return streamIndirectInner(d);
242}
243
244fn streamFallible(d: *Decompress, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
245 return streamInner(d, w, limit) catch |err| switch (err) {
246 error.EndOfStream => {
247 if (d.state == .end) {
248 return error.EndOfStream;
249 } else {
250 d.err = error.EndOfStream;
251 return error.ReadFailed;
252 }
253 },
136 error.WriteFailed => return error.WriteFailed,254 error.WriteFailed => return error.WriteFailed,
137 else => |e| {255 else => |e| {
138 // In the event of an error, state is unmodified so that it can be256 // In the event of an error, state is unmodified so that it can be
139 // better used to diagnose the failure.257 // better used to diagnose the failure.
140 d.read_err = e;258 d.err = e;
141 return error.ReadFailed;259 return error.ReadFailed;
142 },260 },
143 };261 };
144}262}
145263
146fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.StreamError)!usize {264fn streamInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.StreamError)!usize {
265 var remaining = @intFromEnum(limit);
147 const in = d.input;266 const in = d.input;
148 sw: switch (d.state) {267 sw: switch (d.state) {
149 .protocol_header => switch (d.hasher.container()) {268 .protocol_header => switch (d.container_metadata.container()) {
150 .gzip => {269 .gzip => {
151 const Header = extern struct {270 const Header = extern struct {
152 magic: u16 align(1),271 magic: u16 align(1),
...@@ -163,7 +282,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -163,7 +282,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
163 xfl: u8,282 xfl: u8,
164 os: u8,283 os: u8,
165 };284 };
166 const header = try in.takeStructEndian(Header, .little);285 const header = try in.takeStruct(Header, .little);
167 if (header.magic != 0x8b1f or header.method != 0x08)286 if (header.magic != 0x8b1f or header.method != 0x08)
168 return error.BadGzipHeader;287 return error.BadGzipHeader;
169 if (header.flags.extra) {288 if (header.flags.extra) {
...@@ -171,10 +290,10 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -171,10 +290,10 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
171 try in.discardAll(extra_len);290 try in.discardAll(extra_len);
172 }291 }
173 if (header.flags.name) {292 if (header.flags.name) {
174 try in.discardDelimiterInclusive(0);293 _ = try in.discardDelimiterInclusive(0);
175 }294 }
176 if (header.flags.comment) {295 if (header.flags.comment) {
177 try in.discardDelimiterInclusive(0);296 _ = try in.discardDelimiterInclusive(0);
178 }297 }
179 if (header.flags.hcrc) {298 if (header.flags.hcrc) {
180 try in.discardAll(2);299 try in.discardAll(2);
...@@ -182,25 +301,19 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -182,25 +301,19 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
182 continue :sw .block_header;301 continue :sw .block_header;
183 },302 },
184 .zlib => {303 .zlib => {
185 const Header = extern struct {304 const header = try in.takeArray(2);
186 cmf: packed struct(u8) {305 const cmf: packed struct(u8) { cm: u4, cinfo: u4 } = @bitCast(header[0]);
187 cm: u4,306 if (cmf.cm != 8 or cmf.cinfo > 7) return error.BadZlibHeader;
188 cinfo: u4,
189 },
190 flg: u8,
191 };
192 const header = try in.takeStruct(Header);
193 if (header.cmf.cm != 8 or header.cmf.cinfo > 7) return error.BadZlibHeader;
194 continue :sw .block_header;307 continue :sw .block_header;
195 },308 },
196 .raw => continue :sw .block_header,309 .raw => continue :sw .block_header,
197 },310 },
198 .block_header => {311 .block_header => {
199 d.final_block = (try d.takeBits(u1)) != 0;312 d.final_block = (try d.takeBits(u1)) != 0;
200 const block_type = try d.takeBits(BlockType);313 const block_type: BlockType = @enumFromInt(try d.takeBits(u2));
201 switch (block_type) {314 switch (block_type) {
202 .stored => {315 .stored => {
203 d.alignBitsToByte(); // skip padding until byte boundary316 d.alignBitsDiscarding();
204 // everything after this is byte aligned in stored block317 // everything after this is byte aligned in stored block
205 const len = try in.takeInt(u16, .little);318 const len = try in.takeInt(u16, .little);
206 const nlen = try in.takeInt(u16, .little);319 const nlen = try in.takeInt(u16, .little);
...@@ -217,19 +330,20 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -217,19 +330,20 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
217 return error.InvalidDynamicBlockHeader;330 return error.InvalidDynamicBlockHeader;
218331
219 // lengths for code lengths332 // lengths for code lengths
220 var cl_lens = [_]u4{0} ** 19;333 var cl_lens: [19]u4 = @splat(0);
221 for (0..hclen) |i| {334 for (flate.HuffmanEncoder.codegen_order[0..hclen]) |i| {
222 cl_lens[flate.huffman.codegen_order[i]] = try d.takeBits(u3);335 cl_lens[i] = try d.takeBits(u3);
223 }336 }
224 var cl_dec: CodegenDecoder = .{};337 var cl_dec: CodegenDecoder = .{};
225 try cl_dec.generate(&cl_lens);338 try cl_dec.generate(&cl_lens);
226339
227 // decoded code lengths340 // decoded code lengths
228 var dec_lens = [_]u4{0} ** (286 + 30);341 var dec_lens: [286 + 30]u4 = @splat(0);
229 var pos: usize = 0;342 var pos: usize = 0;
230 while (pos < hlit + hdist) {343 while (pos < hlit + hdist) {
231 const sym = try cl_dec.find(try d.peekBitsReverse(u7));344 const peeked = @bitReverse(try d.peekBits(u7));
232 try d.shiftBits(sym.code_bits);345 const sym = try cl_dec.find(peeked);
346 try d.tossBits(sym.code_bits);
233 pos += try d.dynamicCodeLength(sym.symbol, &dec_lens, pos);347 pos += try d.dynamicCodeLength(sym.symbol, &dec_lens, pos);
234 }348 }
235 if (pos > hlit + hdist) {349 if (pos > hlit + hdist) {
...@@ -240,7 +354,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -240,7 +354,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
240 try d.lit_dec.generate(dec_lens[0..hlit]);354 try d.lit_dec.generate(dec_lens[0..hlit]);
241355
242 // distance code lengths to distance decoder356 // distance code lengths to distance decoder
243 try d.dst_dec.generate(dec_lens[hlit .. hlit + hdist]);357 try d.dst_dec.generate(dec_lens[hlit..][0..hdist]);
244358
245 continue :sw .dynamic_block;359 continue :sw .dynamic_block;
246 },360 },
...@@ -248,8 +362,8 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -248,8 +362,8 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
248 },362 },
249 .stored_block => |remaining_len| {363 .stored_block => |remaining_len| {
250 const out = try w.writableSliceGreedyPreserve(flate.history_len, 1);364 const out = try w.writableSliceGreedyPreserve(flate.history_len, 1);
251 const limited_out = limit.min(.limited(remaining_len)).slice(out);365 var limited_out: [1][]u8 = .{limit.min(.limited(remaining_len)).slice(out)};
252 const n = try d.input.readVec(&.{limited_out});366 const n = try d.input.readVec(&limited_out);
253 if (remaining_len - n == 0) {367 if (remaining_len - n == 0) {
254 d.state = if (d.final_block) .protocol_footer else .block_header;368 d.state = if (d.final_block) .protocol_footer else .block_header;
255 } else {369 } else {
...@@ -259,68 +373,99 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -259,68 +373,99 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
259 return n;373 return n;
260 },374 },
261 .fixed_block => {375 .fixed_block => {
262 const start = w.count;376 while (remaining > 0) {
263 while (@intFromEnum(limit) > w.count - start) {
264 const code = try d.readFixedCode();377 const code = try d.readFixedCode();
265 switch (code) {378 switch (code) {
266 0...255 => try w.writeBytePreserve(flate.history_len, @intCast(code)),379 0...255 => {
380 try w.writeBytePreserve(flate.history_len, @intCast(code));
381 remaining -= 1;
382 },
267 256 => {383 256 => {
268 d.state = if (d.final_block) .protocol_footer else .block_header;384 d.state = if (d.final_block) .protocol_footer else .block_header;
269 return w.count - start;385 return @intFromEnum(limit) - remaining;
270 },386 },
271 257...285 => {387 257...285 => {
272 // Handles fixed block non literal (length) code.388 // Handles fixed block non literal (length) code.
273 // Length code is followed by 5 bits of distance code.389 // Length code is followed by 5 bits of distance code.
274 const length = try d.decodeLength(@intCast(code - 257));390 const length = try d.decodeLength(@intCast(code - 257));
275 const distance = try d.decodeDistance(try d.takeBitsReverseBuffered(u5));391 const distance = try d.decodeDistance(@bitReverse(try d.takeBits(u5)));
276 try writeMatch(w, length, distance);392 try writeMatch(w, length, distance);
393 remaining -= length;
277 },394 },
278 else => return error.InvalidCode,395 else => return error.InvalidCode,
279 }396 }
280 }397 }
281 d.state = .fixed_block;398 d.state = .fixed_block;
282 return w.count - start;399 return @intFromEnum(limit) - remaining;
283 },400 },
284 .dynamic_block => {401 .dynamic_block => {
285 // In larger archives most blocks are usually dynamic, so decompression402 // In larger archives most blocks are usually dynamic, so
286 // performance depends on this logic.403 // decompression performance depends on this logic.
287 const start = w.count;404 var sym = try d.decodeSymbol(&d.lit_dec);
288 while (@intFromEnum(limit) > w.count - start) {405 sym: switch (sym.kind) {
289 const sym = try d.decodeSymbol(&d.lit_dec);406 .literal => {
290407 if (remaining != 0) {
291 switch (sym.kind) {408 @branchHint(.likely);
292 .literal => try w.writeBytePreserve(flate.history_len, sym.symbol),409 remaining -= 1;
293 .match => {410 try w.writeBytePreserve(flate.history_len, sym.symbol);
294 // Decode match backreference <length, distance>411 sym = try d.decodeSymbol(&d.lit_dec);
295 const length = try d.decodeLength(sym.symbol);412 continue :sym sym.kind;
296 const dsm = try d.decodeSymbol(&d.dst_dec);413 } else {
297 const distance = try d.decodeDistance(dsm.symbol);414 d.state = .{ .dynamic_block_literal = sym.symbol };
298 try writeMatch(w, length, distance);415 return @intFromEnum(limit) - remaining;
299 },416 }
300 .end_of_block => {417 },
301 d.state = if (d.final_block) .protocol_footer else .block_header;418 .match => {
302 return w.count - start;419 // Decode match backreference <length, distance>
303 },420 const length = try d.decodeLength(sym.symbol);
304 }421 continue :sw .{ .dynamic_block_match = length };
422 },
423 .end_of_block => {
424 d.state = if (d.final_block) .protocol_footer else .block_header;
425 continue :sw d.state;
426 },
427 }
428 },
429 .dynamic_block_literal => |symbol| {
430 assert(remaining != 0);
431 remaining -= 1;
432 try w.writeBytePreserve(flate.history_len, symbol);
433 continue :sw .dynamic_block;
434 },
435 .dynamic_block_match => |length| {
436 if (remaining >= length) {
437 @branchHint(.likely);
438 remaining -= length;
439 const dsm = try d.decodeSymbol(&d.dst_dec);
440 const distance = try d.decodeDistance(dsm.symbol);
441 try writeMatch(w, length, distance);
442 continue :sw .dynamic_block;
443 } else {
444 d.state = .{ .dynamic_block_match = length };
445 return @intFromEnum(limit) - remaining;
305 }446 }
306 d.state = .dynamic_block;
307 return w.count - start;
308 },447 },
309 .protocol_footer => {448 .protocol_footer => {
310 d.alignBitsToByte();449 switch (d.container_metadata) {
311 switch (d.hasher) {
312 .gzip => |*gzip| {450 .gzip => |*gzip| {
313 if (try in.takeInt(u32, .little) != gzip.crc.final()) return error.WrongGzipChecksum;451 d.alignBitsDiscarding();
314 if (try in.takeInt(u32, .little) != gzip.count) return error.WrongGzipSize;452 gzip.* = .{
453 .crc = try in.takeInt(u32, .little),
454 .count = try in.takeInt(u32, .little),
455 };
315 },456 },
316 .zlib => |*zlib| {457 .zlib => |*zlib| {
317 const chksum: u32 = @byteSwap(zlib.final());458 d.alignBitsDiscarding();
318 if (try in.takeInt(u32, .big) != chksum) return error.WrongZlibChecksum;459 zlib.* = .{
460 .adler = try in.takeInt(u32, .little),
461 };
462 },
463 .raw => {
464 d.alignBitsPreserving();
319 },465 },
320 .raw => {},
321 }466 }
322 d.state = .end;467 d.state = .end;
323 return 0;468 return @intFromEnum(limit) - remaining;
324 },469 },
325 .end => return error.EndOfStream,470 .end => return error.EndOfStream,
326 }471 }
...@@ -328,53 +473,184 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S...@@ -328,53 +473,184 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
328473
329/// Write match (back-reference to the same data slice) starting at `distance`474/// Write match (back-reference to the same data slice) starting at `distance`
330/// back from current write position, and `length` of bytes.475/// back from current write position, and `length` of bytes.
331fn writeMatch(bw: *Writer, length: u16, distance: u16) !void {476fn writeMatch(w: *Writer, length: u16, distance: u16) !void {
332 _ = bw;477 if (w.end < distance) return error.InvalidMatch;
333 _ = length;478 if (length < Token.base_length) return error.InvalidMatch;
334 _ = distance;479 if (length > Token.max_length) return error.InvalidMatch;
335 @panic("TODO");480 if (distance < Token.min_distance) return error.InvalidMatch;
481 if (distance > Token.max_distance) return error.InvalidMatch;
482
483 // This is not a @memmove; it intentionally repeats patterns caused by
484 // iterating one byte at a time.
485 const dest = try w.writableSlicePreserve(flate.history_len, length);
486 const end = dest.ptr - w.buffer.ptr;
487 const src = w.buffer[end - distance ..][0..length];
488 for (dest, src) |*d, s| d.* = s;
489}
490
491fn takeBits(d: *Decompress, comptime U: type) !U {
492 const remaining_bits = d.remaining_bits;
493 const next_bits = d.next_bits;
494 if (remaining_bits >= @bitSizeOf(U)) {
495 const u: U = @truncate(next_bits);
496 d.next_bits = next_bits >> @bitSizeOf(U);
497 d.remaining_bits = remaining_bits - @bitSizeOf(U);
498 return u;
499 }
500 const in = d.input;
501 const next_int = in.takeInt(usize, .little) catch |err| switch (err) {
502 error.ReadFailed => return error.ReadFailed,
503 error.EndOfStream => return takeBitsEnding(d, U),
504 };
505 const needed_bits = @bitSizeOf(U) - remaining_bits;
506 const u: U = @intCast(((next_int & ((@as(usize, 1) << needed_bits) - 1)) << remaining_bits) | next_bits);
507 d.next_bits = next_int >> needed_bits;
508 d.remaining_bits = @intCast(@bitSizeOf(usize) - @as(usize, needed_bits));
509 return u;
336}510}
337511
338fn takeBits(d: *Decompress, comptime T: type) !T {512fn takeBitsEnding(d: *Decompress, comptime U: type) !U {
339 _ = d;513 const remaining_bits = d.remaining_bits;
340 @panic("TODO");514 const next_bits = d.next_bits;
515 const in = d.input;
516 const n = in.bufferedLen();
517 assert(n < @sizeOf(usize));
518 const needed_bits = @bitSizeOf(U) - remaining_bits;
519 if (n * 8 < needed_bits) return error.EndOfStream;
520 const next_int = in.takeVarInt(usize, .little, n) catch |err| switch (err) {
521 error.ReadFailed => return error.ReadFailed,
522 error.EndOfStream => unreachable,
523 };
524 const u: U = @intCast(((next_int & ((@as(usize, 1) << needed_bits) - 1)) << remaining_bits) | next_bits);
525 d.next_bits = next_int >> needed_bits;
526 d.remaining_bits = @intCast(n * 8 - @as(usize, needed_bits));
527 return u;
528}
529
530fn peekBits(d: *Decompress, comptime U: type) !U {
531 const remaining_bits = d.remaining_bits;
532 const next_bits = d.next_bits;
533 if (remaining_bits >= @bitSizeOf(U)) return @truncate(next_bits);
534 const in = d.input;
535 const next_int = in.peekInt(usize, .little) catch |err| switch (err) {
536 error.ReadFailed => return error.ReadFailed,
537 error.EndOfStream => return peekBitsEnding(d, U),
538 };
539 const needed_bits = @bitSizeOf(U) - remaining_bits;
540 return @intCast(((next_int & ((@as(usize, 1) << needed_bits) - 1)) << remaining_bits) | next_bits);
541}
542
543fn peekBitsEnding(d: *Decompress, comptime U: type) !U {
544 const remaining_bits = d.remaining_bits;
545 const next_bits = d.next_bits;
546 const in = d.input;
547 var u: usize = 0;
548 var remaining_needed_bits = @bitSizeOf(U) - remaining_bits;
549 var i: usize = 0;
550 while (remaining_needed_bits >= 8) {
551 const byte = try specialPeek(in, next_bits, i);
552 u |= @as(usize, byte) << @intCast(i * 8);
553 remaining_needed_bits -= 8;
554 i += 1;
555 }
556 if (remaining_needed_bits != 0) {
557 const byte = try specialPeek(in, next_bits, i);
558 u |= @as(usize, byte) << @intCast((i * 8) + remaining_needed_bits);
559 }
560 return @truncate((u << remaining_bits) | next_bits);
341}561}
342562
343fn takeBitsReverseBuffered(d: *Decompress, comptime T: type) !T {563/// If there is any unconsumed data, handles EndOfStream by pretending there
344 _ = d;564/// are zeroes afterwards.
345 @panic("TODO");565fn specialPeek(in: *Reader, next_bits: usize, i: usize) Reader.Error!u8 {
566 const peeked = in.peek(i + 1) catch |err| switch (err) {
567 error.ReadFailed => return error.ReadFailed,
568 error.EndOfStream => if (next_bits == 0 and i == 0) return error.EndOfStream else return 0,
569 };
570 return peeked[i];
346}571}
347572
348fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 {573fn tossBits(d: *Decompress, n: u4) !void {
349 _ = d;574 const remaining_bits = d.remaining_bits;
350 _ = n;575 const next_bits = d.next_bits;
351 @panic("TODO");576 if (remaining_bits >= n) {
577 d.next_bits = next_bits >> n;
578 d.remaining_bits = remaining_bits - n;
579 } else {
580 const in = d.input;
581 const next_int = in.takeInt(usize, .little) catch |err| switch (err) {
582 error.ReadFailed => return error.ReadFailed,
583 error.EndOfStream => return tossBitsEnding(d, n),
584 };
585 const needed_bits = n - remaining_bits;
586 d.next_bits = next_int >> needed_bits;
587 d.remaining_bits = @intCast(@bitSizeOf(usize) - @as(usize, needed_bits));
588 }
352}589}
353590
354fn peekBitsReverse(d: *Decompress, comptime T: type) !T {591fn tossBitsEnding(d: *Decompress, n: u4) !void {
355 _ = d;592 const remaining_bits = d.remaining_bits;
356 @panic("TODO");593 const in = d.input;
594 const buffered_n = in.bufferedLen();
595 if (buffered_n == 0) return error.EndOfStream;
596 assert(buffered_n < @sizeOf(usize));
597 const needed_bits = n - remaining_bits;
598 const next_int = in.takeVarInt(usize, .little, buffered_n) catch |err| switch (err) {
599 error.ReadFailed => return error.ReadFailed,
600 error.EndOfStream => unreachable,
601 };
602 d.next_bits = next_int >> needed_bits;
603 d.remaining_bits = @intCast(@as(usize, n) * 8 -| @as(usize, needed_bits));
357}604}
358605
359fn peekBitsReverseBuffered(d: *Decompress, comptime T: type) !T {606fn takeBitsRuntime(d: *Decompress, n: u4) !u16 {
360 _ = d;607 const x = try peekBits(d, u16);
361 @panic("TODO");608 const mask: u16 = (@as(u16, 1) << n) - 1;
609 const u: u16 = @as(u16, @truncate(x)) & mask;
610 try tossBits(d, n);
611 return u;
362}612}
363613
364fn alignBitsToByte(d: *Decompress) void {614fn alignBitsDiscarding(d: *Decompress) void {
365 _ = d;615 const remaining_bits = d.remaining_bits;
366 @panic("TODO");616 if (remaining_bits == 0) return;
617 const n_bytes = remaining_bits / 8;
618 const in = d.input;
619 in.seek -= n_bytes;
620 d.remaining_bits = 0;
621 d.next_bits = 0;
367}622}
368623
369fn shiftBits(d: *Decompress, n: u6) !void {624fn alignBitsPreserving(d: *Decompress) void {
370 _ = d;625 const remaining_bits: usize = d.remaining_bits;
371 _ = n;626 if (remaining_bits == 0) return;
372 @panic("TODO");627 const n_bytes = (remaining_bits + 7) / 8;
628 const in = d.input;
629 in.seek -= n_bytes;
630 d.remaining_bits = 0;
631 d.next_bits = 0;
373}632}
374633
634/// Reads first 7 bits, and then maybe 1 or 2 more to get full 7,8 or 9 bit code.
635/// ref: https://datatracker.ietf.org/doc/html/rfc1951#page-12
636/// Lit Value Bits Codes
637/// --------- ---- -----
638/// 0 - 143 8 00110000 through
639/// 10111111
640/// 144 - 255 9 110010000 through
641/// 111111111
642/// 256 - 279 7 0000000 through
643/// 0010111
644/// 280 - 287 8 11000000 through
645/// 11000111
375fn readFixedCode(d: *Decompress) !u16 {646fn readFixedCode(d: *Decompress) !u16 {
376 _ = d;647 const code7 = @bitReverse(try d.takeBits(u7));
377 @panic("TODO");648 return switch (code7) {
649 0...0b0010_111 => @as(u16, code7) + 256,
650 0b0010_111 + 1...0b1011_111 => (@as(u16, code7) << 1) + @as(u16, try d.takeBits(u1)) - 0b0011_0000,
651 0b1011_111 + 1...0b1100_011 => (@as(u16, code7 - 0b1100000) << 1) + try d.takeBits(u1) + 280,
652 else => (@as(u16, code7 - 0b1100_100) << 2) + @as(u16, @bitReverse(try d.takeBits(u2))) + 144,
653 };
378}654}
379655
380pub const Symbol = packed struct {656pub const Symbol = packed struct {
...@@ -620,10 +896,15 @@ test "init/find" {...@@ -620,10 +896,15 @@ test "init/find" {
620}896}
621897
622test "encode/decode literals" {898test "encode/decode literals" {
623 const LiteralEncoder = std.compress.flate.Compress.LiteralEncoder;899 var codes: [flate.HuffmanEncoder.max_num_frequencies]flate.HuffmanEncoder.Code = undefined;
624
625 for (1..286) |j| { // for all different number of codes900 for (1..286) |j| { // for all different number of codes
626 var enc: LiteralEncoder = .{};901 var enc: flate.HuffmanEncoder = .{
902 .codes = &codes,
903 .freq_cache = undefined,
904 .bit_count = undefined,
905 .lns = undefined,
906 .lfs = undefined,
907 };
627 // create frequencies908 // create frequencies
628 var freq = [_]u16{0} ** 286;909 var freq = [_]u16{0} ** 286;
629 freq[256] = 1; // ensure we have end of block code910 freq[256] = 1; // ensure we have end of block code
...@@ -670,214 +951,210 @@ test "encode/decode literals" {...@@ -670,214 +951,210 @@ test "encode/decode literals" {
670 }951 }
671}952}
672953
673test "decompress" {954test "non compressed block (type 0)" {
674 const cases = [_]struct {955 try testDecompress(.raw, &[_]u8{
675 in: []const u8,956 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
676 out: []const u8,957 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
677 }{958 }, "Hello world\n");
678 // non compressed block (type 0)
679 .{
680 .in = &[_]u8{
681 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
682 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
683 },
684 .out = "Hello world\n",
685 },
686 // fixed code block (type 1)
687 .{
688 .in = &[_]u8{
689 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
690 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
691 },
692 .out = "Hello world\n",
693 },
694 // dynamic block (type 2)
695 .{
696 .in = &[_]u8{
697 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
698 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
699 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
700 },
701 .out = "ABCDEABCD ABCDEABCD",
702 },
703 };
704 for (cases) |c| {
705 var fb: Reader = .fixed(c.in);
706 var aw: Writer.Allocating = .init(testing.allocator);
707 defer aw.deinit();
708
709 var decompress: Decompress = .init(&fb, .raw);
710 var decompress_br = decompress.readable(&.{});
711 _ = try decompress_br.streamRemaining(&aw.interface);
712 try testing.expectEqualStrings(c.out, aw.getWritten());
713 }
714}959}
715960
716test "gzip decompress" {961test "fixed code block (type 1)" {
717 const cases = [_]struct {962 try testDecompress(.raw, &[_]u8{
718 in: []const u8,963 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
719 out: []const u8,964 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
720 }{965 }, "Hello world\n");
721 // non compressed block (type 0)
722 .{
723 .in = &[_]u8{
724 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
725 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
726 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
727 0xd5, 0xe0, 0x39, 0xb7, // gzip footer: checksum
728 0x0c, 0x00, 0x00, 0x00, // gzip footer: size
729 },
730 .out = "Hello world\n",
731 },
732 // fixed code block (type 1)
733 .{
734 .in = &[_]u8{
735 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, // gzip header (10 bytes)
736 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
737 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
738 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
739 },
740 .out = "Hello world\n",
741 },
742 // dynamic block (type 2)
743 .{
744 .in = &[_]u8{
745 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
746 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
747 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
748 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
749 0x17, 0x1c, 0x39, 0xb4, 0x13, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
750 },
751 .out = "ABCDEABCD ABCDEABCD",
752 },
753 // gzip header with name
754 .{
755 .in = &[_]u8{
756 0x1f, 0x8b, 0x08, 0x08, 0xe5, 0x70, 0xb1, 0x65, 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
757 0x74, 0x78, 0x74, 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
758 0x02, 0x00, 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00,
759 },
760 .out = "Hello world\n",
761 },
762 };
763 for (cases) |c| {
764 var fb: Reader = .fixed(c.in);
765 var aw: Writer.Allocating = .init(testing.allocator);
766 defer aw.deinit();
767
768 var decompress: Decompress = .init(&fb, .gzip);
769 var decompress_br = decompress.readable(&.{});
770 _ = try decompress_br.streamRemaining(&aw.interface);
771 try testing.expectEqualStrings(c.out, aw.getWritten());
772 }
773}966}
774967
775test "zlib decompress" {968test "dynamic block (type 2)" {
776 const cases = [_]struct {969 try testDecompress(.raw, &[_]u8{
777 in: []const u8,970 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
778 out: []const u8,971 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
779 }{972 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
780 // non compressed block (type 0)973 }, "ABCDEABCD ABCDEABCD");
781 .{
782 .in = &[_]u8{
783 0x78, 0b10_0_11100, // zlib header (2 bytes)
784 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
785 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
786 0x1c, 0xf2, 0x04, 0x47, // zlib footer: checksum
787 },
788 .out = "Hello world\n",
789 },
790 };
791 for (cases) |c| {
792 var fb: Reader = .fixed(c.in);
793 var aw: Writer.Allocating = .init(testing.allocator);
794 defer aw.deinit();
795
796 var decompress: Decompress = .init(&fb, .zlib);
797 var decompress_br = decompress.readable(&.{});
798 _ = try decompress_br.streamRemaining(&aw.interface);
799 try testing.expectEqualStrings(c.out, aw.getWritten());
800 }
801}974}
802975
803test "fuzzing tests" {976test "gzip non compressed block (type 0)" {
804 const cases = [_]struct {977 try testDecompress(.gzip, &[_]u8{
805 input: []const u8,978 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
806 out: []const u8 = "",979 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
807 err: ?anyerror = null,980 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
808 }{981 0xd5, 0xe0, 0x39, 0xb7, // gzip footer: checksum
809 .{ .input = "deflate-stream", .out = @embedFile("testdata/fuzz/deflate-stream.expect") }, // 0982 0x0c, 0x00, 0x00, 0x00, // gzip footer: size
810 .{ .input = "empty-distance-alphabet01" },983 }, "Hello world\n");
811 .{ .input = "empty-distance-alphabet02" },984}
812 .{ .input = "end-of-stream", .err = error.EndOfStream },
813 .{ .input = "invalid-distance", .err = error.InvalidMatch },
814 .{ .input = "invalid-tree01", .err = error.IncompleteHuffmanTree }, // 5
815 .{ .input = "invalid-tree02", .err = error.IncompleteHuffmanTree },
816 .{ .input = "invalid-tree03", .err = error.IncompleteHuffmanTree },
817 .{ .input = "lengths-overflow", .err = error.InvalidDynamicBlockHeader },
818 .{ .input = "out-of-codes", .err = error.InvalidCode },
819 .{ .input = "puff01", .err = error.WrongStoredBlockNlen }, // 10
820 .{ .input = "puff02", .err = error.EndOfStream },
821 .{ .input = "puff03", .out = &[_]u8{0xa} },
822 .{ .input = "puff04", .err = error.InvalidCode },
823 .{ .input = "puff05", .err = error.EndOfStream },
824 .{ .input = "puff06", .err = error.EndOfStream },
825 .{ .input = "puff08", .err = error.InvalidCode },
826 .{ .input = "puff09", .out = "P" },
827 .{ .input = "puff10", .err = error.InvalidCode },
828 .{ .input = "puff11", .err = error.InvalidMatch },
829 .{ .input = "puff12", .err = error.InvalidDynamicBlockHeader }, // 20
830 .{ .input = "puff13", .err = error.IncompleteHuffmanTree },
831 .{ .input = "puff14", .err = error.EndOfStream },
832 .{ .input = "puff15", .err = error.IncompleteHuffmanTree },
833 .{ .input = "puff16", .err = error.InvalidDynamicBlockHeader },
834 .{ .input = "puff17", .err = error.MissingEndOfBlockCode }, // 25
835 .{ .input = "fuzz1", .err = error.InvalidDynamicBlockHeader },
836 .{ .input = "fuzz2", .err = error.InvalidDynamicBlockHeader },
837 .{ .input = "fuzz3", .err = error.InvalidMatch },
838 .{ .input = "fuzz4", .err = error.OversubscribedHuffmanTree },
839 .{ .input = "puff18", .err = error.OversubscribedHuffmanTree }, // 30
840 .{ .input = "puff19", .err = error.OversubscribedHuffmanTree },
841 .{ .input = "puff20", .err = error.OversubscribedHuffmanTree },
842 .{ .input = "puff21", .err = error.OversubscribedHuffmanTree },
843 .{ .input = "puff22", .err = error.OversubscribedHuffmanTree },
844 .{ .input = "puff23", .err = error.OversubscribedHuffmanTree }, // 35
845 .{ .input = "puff24", .err = error.IncompleteHuffmanTree },
846 .{ .input = "puff25", .err = error.OversubscribedHuffmanTree },
847 .{ .input = "puff26", .err = error.InvalidDynamicBlockHeader },
848 .{ .input = "puff27", .err = error.InvalidDynamicBlockHeader },
849 };
850985
851 inline for (cases, 0..) |c, case_no| {986test "gzip fixed code block (type 1)" {
852 var in: Reader = .fixed(@embedFile("testdata/fuzz/" ++ c.input ++ ".input"));987 try testDecompress(.gzip, &[_]u8{
853 var aw: Writer.Allocating = .init(testing.allocator);988 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, // gzip header (10 bytes)
854 defer aw.deinit();989 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
855 errdefer std.debug.print("test case failed {}\n", .{case_no});990 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
856991 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
857 var decompress: Decompress = .init(&in, .raw);992 }, "Hello world\n");
858 var decompress_br = decompress.readable(&.{});
859 if (c.err) |expected_err| {
860 try testing.expectError(error.ReadFailed, decompress_br.streamRemaining(&aw.interface));
861 try testing.expectError(expected_err, decompress.read_err.?);
862 } else {
863 _ = try decompress_br.streamRemaining(&aw.interface);
864 try testing.expectEqualStrings(c.out, aw.getWritten());
865 }
866 }
867}993}
868994
869test "bug 18966" {995test "gzip dynamic block (type 2)" {
870 const input = @embedFile("testdata/fuzz/bug_18966.input");996 try testDecompress(.gzip, &[_]u8{
871 const expect = @embedFile("testdata/fuzz/bug_18966.expect");997 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
998 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
999 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
1000 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
1001 0x17, 0x1c, 0x39, 0xb4, 0x13, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
1002 }, "ABCDEABCD ABCDEABCD");
1003}
8721004
873 var in: Reader = .fixed(input);1005test "gzip header with name" {
874 var aw: Writer.Allocating = .init(testing.allocator);1006 try testDecompress(.gzip, &[_]u8{
875 defer aw.deinit();1007 0x1f, 0x8b, 0x08, 0x08, 0xe5, 0x70, 0xb1, 0x65, 0x00, 0x03, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2e,
1008 0x74, 0x78, 0x74, 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0xe1,
1009 0x02, 0x00, 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00,
1010 }, "Hello world\n");
1011}
8761012
877 var decompress: Decompress = .init(&in, .gzip);1013test "zlib decompress non compressed block (type 0)" {
878 var decompress_br = decompress.readable(&.{});1014 try testDecompress(.zlib, &[_]u8{
879 _ = try decompress_br.streamRemaining(&aw.interface);1015 0x78, 0b10_0_11100, // zlib header (2 bytes)
880 try testing.expectEqualStrings(expect, aw.getWritten());1016 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
1017 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
1018 0x1c, 0xf2, 0x04, 0x47, // zlib footer: checksum
1019 }, "Hello world\n");
1020}
1021
1022test "failing end-of-stream" {
1023 try testFailure(.raw, @embedFile("testdata/fuzz/end-of-stream.input"), error.EndOfStream);
1024}
1025test "failing invalid-distance" {
1026 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-distance.input"), error.InvalidMatch);
1027}
1028test "failing invalid-tree01" {
1029 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree);
1030}
1031test "failing invalid-tree02" {
1032 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree02.input"), error.EndOfStream);
1033}
1034test "failing invalid-tree03" {
1035 try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree);
1036}
1037test "failing lengths-overflow" {
1038 try testFailure(.raw, @embedFile("testdata/fuzz/lengths-overflow.input"), error.InvalidDynamicBlockHeader);
1039}
1040test "failing out-of-codes" {
1041 try testFailure(.raw, @embedFile("testdata/fuzz/out-of-codes.input"), error.InvalidCode);
1042}
1043test "failing puff01" {
1044 try testFailure(.raw, @embedFile("testdata/fuzz/puff01.input"), error.WrongStoredBlockNlen);
1045}
1046test "failing puff02" {
1047 try testFailure(.raw, @embedFile("testdata/fuzz/puff02.input"), error.EndOfStream);
1048}
1049test "failing puff04" {
1050 try testFailure(.raw, @embedFile("testdata/fuzz/puff04.input"), error.InvalidCode);
1051}
1052test "failing puff05" {
1053 try testFailure(.raw, @embedFile("testdata/fuzz/puff05.input"), error.EndOfStream);
1054}
1055test "failing puff06" {
1056 try testFailure(.raw, @embedFile("testdata/fuzz/puff06.input"), error.EndOfStream);
1057}
1058test "failing puff08" {
1059 try testFailure(.raw, @embedFile("testdata/fuzz/puff08.input"), error.InvalidCode);
1060}
1061test "failing puff10" {
1062 try testFailure(.raw, @embedFile("testdata/fuzz/puff10.input"), error.InvalidCode);
1063}
1064test "failing puff11" {
1065 try testFailure(.raw, @embedFile("testdata/fuzz/puff11.input"), error.EndOfStream);
1066}
1067test "failing puff12" {
1068 try testFailure(.raw, @embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader);
1069}
1070test "failing puff13" {
1071 try testFailure(.raw, @embedFile("testdata/fuzz/puff13.input"), error.IncompleteHuffmanTree);
1072}
1073test "failing puff14" {
1074 try testFailure(.raw, @embedFile("testdata/fuzz/puff14.input"), error.EndOfStream);
1075}
1076test "failing puff15" {
1077 try testFailure(.raw, @embedFile("testdata/fuzz/puff15.input"), error.IncompleteHuffmanTree);
1078}
1079test "failing puff16" {
1080 try testFailure(.raw, @embedFile("testdata/fuzz/puff16.input"), error.InvalidDynamicBlockHeader);
1081}
1082test "failing puff17" {
1083 try testFailure(.raw, @embedFile("testdata/fuzz/puff17.input"), error.MissingEndOfBlockCode);
1084}
1085test "failing fuzz1" {
1086 try testFailure(.raw, @embedFile("testdata/fuzz/fuzz1.input"), error.InvalidDynamicBlockHeader);
1087}
1088test "failing fuzz2" {
1089 try testFailure(.raw, @embedFile("testdata/fuzz/fuzz2.input"), error.InvalidDynamicBlockHeader);
1090}
1091test "failing fuzz3" {
1092 try testFailure(.raw, @embedFile("testdata/fuzz/fuzz3.input"), error.InvalidMatch);
1093}
1094test "failing fuzz4" {
1095 try testFailure(.raw, @embedFile("testdata/fuzz/fuzz4.input"), error.OversubscribedHuffmanTree);
1096}
1097test "failing puff18" {
1098 try testFailure(.raw, @embedFile("testdata/fuzz/puff18.input"), error.OversubscribedHuffmanTree);
1099}
1100test "failing puff19" {
1101 try testFailure(.raw, @embedFile("testdata/fuzz/puff19.input"), error.OversubscribedHuffmanTree);
1102}
1103test "failing puff20" {
1104 try testFailure(.raw, @embedFile("testdata/fuzz/puff20.input"), error.OversubscribedHuffmanTree);
1105}
1106test "failing puff21" {
1107 try testFailure(.raw, @embedFile("testdata/fuzz/puff21.input"), error.OversubscribedHuffmanTree);
1108}
1109test "failing puff22" {
1110 try testFailure(.raw, @embedFile("testdata/fuzz/puff22.input"), error.OversubscribedHuffmanTree);
1111}
1112test "failing puff23" {
1113 try testFailure(.raw, @embedFile("testdata/fuzz/puff23.input"), error.OversubscribedHuffmanTree);
1114}
1115test "failing puff24" {
1116 try testFailure(.raw, @embedFile("testdata/fuzz/puff24.input"), error.IncompleteHuffmanTree);
1117}
1118test "failing puff25" {
1119 try testFailure(.raw, @embedFile("testdata/fuzz/puff25.input"), error.OversubscribedHuffmanTree);
1120}
1121test "failing puff26" {
1122 try testFailure(.raw, @embedFile("testdata/fuzz/puff26.input"), error.InvalidDynamicBlockHeader);
1123}
1124test "failing puff27" {
1125 try testFailure(.raw, @embedFile("testdata/fuzz/puff27.input"), error.InvalidDynamicBlockHeader);
1126}
1127
1128test "deflate-stream" {
1129 try testDecompress(
1130 .raw,
1131 @embedFile("testdata/fuzz/deflate-stream.input"),
1132 @embedFile("testdata/fuzz/deflate-stream.expect"),
1133 );
1134}
1135
1136test "empty-distance-alphabet01" {
1137 try testFailure(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), error.EndOfStream);
1138}
1139
1140test "empty-distance-alphabet02" {
1141 try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet02.input"), "");
1142}
1143
1144test "puff03" {
1145 try testDecompress(.raw, @embedFile("testdata/fuzz/puff03.input"), &.{0xa});
1146}
1147
1148test "puff09" {
1149 try testDecompress(.raw, @embedFile("testdata/fuzz/puff09.input"), "P");
1150}
1151
1152test "bug 18966" {
1153 try testDecompress(
1154 .gzip,
1155 @embedFile("testdata/fuzz/bug_18966.input"),
1156 @embedFile("testdata/fuzz/bug_18966.expect"),
1157 );
881}1158}
8821159
883test "reading into empty buffer" {1160test "reading into empty buffer" {
...@@ -887,8 +1164,104 @@ test "reading into empty buffer" {...@@ -887,8 +1164,104 @@ test "reading into empty buffer" {
887 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data1164 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
888 };1165 };
889 var in: Reader = .fixed(input);1166 var in: Reader = .fixed(input);
890 var decomp: Decompress = .init(&in, .raw);1167 var decomp: Decompress = .init(&in, .raw, &.{});
891 var decompress_br = decomp.readable(&.{});1168 const r = &decomp.reader;
892 var buf: [0]u8 = undefined;1169 var bufs: [1][]u8 = .{&.{}};
893 try testing.expectEqual(0, try decompress_br.readVec(&.{&buf}));1170 try testing.expectEqual(0, try r.readVec(&bufs));
1171}
1172
1173test "zlib header" {
1174 // Truncated header
1175 try testFailure(.zlib, &[_]u8{0x78}, error.EndOfStream);
1176
1177 // Wrong CM
1178 try testFailure(.zlib, &[_]u8{ 0x79, 0x94 }, error.BadZlibHeader);
1179
1180 // Wrong CINFO
1181 try testFailure(.zlib, &[_]u8{ 0x88, 0x98 }, error.BadZlibHeader);
1182
1183 // Truncated checksum
1184 try testFailure(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, error.EndOfStream);
1185}
1186
1187test "gzip header" {
1188 // Truncated header
1189 try testFailure(.gzip, &[_]u8{ 0x1f, 0x8B }, error.EndOfStream);
1190
1191 // Wrong CM
1192 try testFailure(.gzip, &[_]u8{
1193 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
1194 0x00, 0x03,
1195 }, error.BadGzipHeader);
1196
1197 // Truncated checksum
1198 try testFailure(.gzip, &[_]u8{
1199 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1200 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
1201 }, error.EndOfStream);
1202
1203 // Truncated initial size field
1204 try testFailure(.gzip, &[_]u8{
1205 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
1206 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
1207 0x00, 0x00, 0x00,
1208 }, error.EndOfStream);
1209
1210 try testDecompress(.gzip, &[_]u8{
1211 // GZIP header
1212 0x1f, 0x8b, 0x08, 0x12, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00,
1213 // header.FHCRC (should cover entire header)
1214 0x99, 0xd6,
1215 // GZIP data
1216 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1217 }, "");
1218}
1219
1220test "zlib should not overshoot" {
1221 // Compressed zlib data with extra 4 bytes at the end.
1222 const data = [_]u8{
1223 0x78, 0x9c, 0x73, 0xce, 0x2f, 0xa8, 0x2c, 0xca, 0x4c, 0xcf, 0x28, 0x51, 0x08, 0xcf, 0xcc, 0xc9,
1224 0x49, 0xcd, 0x55, 0x28, 0x4b, 0xcc, 0x53, 0x08, 0x4e, 0xce, 0x48, 0xcc, 0xcc, 0xd6, 0x51, 0x08,
1225 0xce, 0xcc, 0x4b, 0x4f, 0x2c, 0xc8, 0x2f, 0x4a, 0x55, 0x30, 0xb4, 0xb4, 0x34, 0xd5, 0xb5, 0x34,
1226 0x03, 0x00, 0x8b, 0x61, 0x0f, 0xa4, 0x52, 0x5a, 0x94, 0x12,
1227 };
1228
1229 var reader: std.Io.Reader = .fixed(&data);
1230
1231 var decompress_buffer: [flate.max_window_len]u8 = undefined;
1232 var decompress: Decompress = .init(&reader, .zlib, &decompress_buffer);
1233 var out: [128]u8 = undefined;
1234
1235 {
1236 const n = try decompress.reader.readSliceShort(&out);
1237 try std.testing.expectEqual(46, n);
1238 try std.testing.expectEqualStrings("Copyright Willem van Schaik, Singapore 1995-96", out[0..n]);
1239 }
1240
1241 // 4 bytes after compressed chunk are available in reader.
1242 const n = try reader.readSliceShort(&out);
1243 try std.testing.expectEqual(n, 4);
1244 try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]);
1245}
1246
1247fn testFailure(container: Container, in: []const u8, expected_err: anyerror) !void {
1248 var reader: Reader = .fixed(in);
1249 var aw: Writer.Allocating = .init(testing.allocator);
1250 try aw.ensureUnusedCapacity(flate.history_len);
1251 defer aw.deinit();
1252
1253 var decompress: Decompress = .init(&reader, container, &.{});
1254 try testing.expectError(error.ReadFailed, decompress.reader.streamRemaining(&aw.writer));
1255 try testing.expectEqual(expected_err, decompress.err orelse return error.TestFailed);
1256}
1257
1258fn testDecompress(container: Container, compressed: []const u8, expected_plain: []const u8) !void {
1259 var in: std.Io.Reader = .fixed(compressed);
1260 var aw: std.Io.Writer.Allocating = .init(testing.allocator);
1261 try aw.ensureUnusedCapacity(flate.history_len);
1262 defer aw.deinit();
1263
1264 var decompress: Decompress = .init(&in, container, &.{});
1265 _ = try decompress.reader.streamRemaining(&aw.writer);
1266 try testing.expectEqualSlices(u8, expected_plain, aw.getWritten());
894}1267}
lib/std/compress/flate/HuffmanEncoder.zig created+463
...@@ -0,0 +1,463 @@
1const HuffmanEncoder = @This();
2const std = @import("std");
3const assert = std.debug.assert;
4const testing = std.testing;
5
6codes: []Code,
7// Reusable buffer with the longest possible frequency table.
8freq_cache: [max_num_frequencies + 1]LiteralNode,
9bit_count: [17]u32,
10lns: []LiteralNode, // sorted by literal, stored to avoid repeated allocation in generate
11lfs: []LiteralNode, // sorted by frequency, stored to avoid repeated allocation in generate
12
13pub const LiteralNode = struct {
14 literal: u16,
15 freq: u16,
16
17 pub fn max() LiteralNode {
18 return .{
19 .literal = std.math.maxInt(u16),
20 .freq = std.math.maxInt(u16),
21 };
22 }
23};
24
25pub const Code = struct {
26 code: u16 = 0,
27 len: u16 = 0,
28};
29
30/// The odd order in which the codegen code sizes are written.
31pub const codegen_order = [_]u32{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
32/// The number of codegen codes.
33pub const codegen_code_count = 19;
34
35/// The largest distance code.
36pub const distance_code_count = 30;
37
38/// Maximum number of literals.
39pub const max_num_lit = 286;
40
41/// Max number of frequencies used for a Huffman Code
42/// Possible lengths are codegen_code_count (19), distance_code_count (30) and max_num_lit (286).
43/// The largest of these is max_num_lit.
44pub const max_num_frequencies = max_num_lit;
45
46/// Biggest block size for uncompressed block.
47pub const max_store_block_size = 65535;
48/// The special code used to mark the end of a block.
49pub const end_block_marker = 256;
50
51/// Update this Huffman Code object to be the minimum code for the specified frequency count.
52///
53/// freq An array of frequencies, in which frequency[i] gives the frequency of literal i.
54/// max_bits The maximum number of bits to use for any literal.
55pub fn generate(self: *HuffmanEncoder, freq: []u16, max_bits: u32) void {
56 var list = self.freq_cache[0 .. freq.len + 1];
57 // Number of non-zero literals
58 var count: u32 = 0;
59 // Set list to be the set of all non-zero literals and their frequencies
60 for (freq, 0..) |f, i| {
61 if (f != 0) {
62 list[count] = LiteralNode{ .literal = @as(u16, @intCast(i)), .freq = f };
63 count += 1;
64 } else {
65 list[count] = LiteralNode{ .literal = 0x00, .freq = 0 };
66 self.codes[i].len = 0;
67 }
68 }
69 list[freq.len] = LiteralNode{ .literal = 0x00, .freq = 0 };
70
71 list = list[0..count];
72 if (count <= 2) {
73 // Handle the small cases here, because they are awkward for the general case code. With
74 // two or fewer literals, everything has bit length 1.
75 for (list, 0..) |node, i| {
76 // "list" is in order of increasing literal value.
77 self.codes[node.literal] = .{
78 .code = @intCast(i),
79 .len = 1,
80 };
81 }
82 return;
83 }
84 self.lfs = list;
85 std.mem.sort(LiteralNode, self.lfs, {}, byFreq);
86
87 // Get the number of literals for each bit count
88 const bit_count = self.bitCounts(list, max_bits);
89 // And do the assignment
90 self.assignEncodingAndSize(bit_count, list);
91}
92
93pub fn bitLength(self: *HuffmanEncoder, freq: []u16) u32 {
94 var total: u32 = 0;
95 for (freq, 0..) |f, i| {
96 if (f != 0) {
97 total += @as(u32, @intCast(f)) * @as(u32, @intCast(self.codes[i].len));
98 }
99 }
100 return total;
101}
102
103/// Return the number of literals assigned to each bit size in the Huffman encoding
104///
105/// This method is only called when list.len >= 3
106/// The cases of 0, 1, and 2 literals are handled by special case code.
107///
108/// list: An array of the literals with non-zero frequencies
109/// and their associated frequencies. The array is in order of increasing
110/// frequency, and has as its last element a special element with frequency
111/// `math.maxInt(i32)`
112///
113/// max_bits: The maximum number of bits that should be used to encode any literal.
114/// Must be less than 16.
115///
116/// Returns an integer array in which array[i] indicates the number of literals
117/// that should be encoded in i bits.
118fn bitCounts(self: *HuffmanEncoder, list: []LiteralNode, max_bits_to_use: usize) []u32 {
119 var max_bits = max_bits_to_use;
120 const n = list.len;
121 const max_bits_limit = 16;
122
123 assert(max_bits < max_bits_limit);
124
125 // The tree can't have greater depth than n - 1, no matter what. This
126 // saves a little bit of work in some small cases
127 max_bits = @min(max_bits, n - 1);
128
129 // Create information about each of the levels.
130 // A bogus "Level 0" whose sole purpose is so that
131 // level1.prev.needed == 0. This makes level1.next_pair_freq
132 // be a legitimate value that never gets chosen.
133 var levels: [max_bits_limit]LevelInfo = std.mem.zeroes([max_bits_limit]LevelInfo);
134 // leaf_counts[i] counts the number of literals at the left
135 // of ancestors of the rightmost node at level i.
136 // leaf_counts[i][j] is the number of literals at the left
137 // of the level j ancestor.
138 var leaf_counts: [max_bits_limit][max_bits_limit]u32 = @splat(@splat(0));
139
140 {
141 var level = @as(u32, 1);
142 while (level <= max_bits) : (level += 1) {
143 // For every level, the first two items are the first two characters.
144 // We initialize the levels as if we had already figured this out.
145 levels[level] = LevelInfo{
146 .level = level,
147 .last_freq = list[1].freq,
148 .next_char_freq = list[2].freq,
149 .next_pair_freq = list[0].freq + list[1].freq,
150 .needed = 0,
151 };
152 leaf_counts[level][level] = 2;
153 if (level == 1) {
154 levels[level].next_pair_freq = std.math.maxInt(i32);
155 }
156 }
157 }
158
159 // We need a total of 2*n - 2 items at top level and have already generated 2.
160 levels[max_bits].needed = 2 * @as(u32, @intCast(n)) - 4;
161
162 {
163 var level = max_bits;
164 while (true) {
165 var l = &levels[level];
166 if (l.next_pair_freq == std.math.maxInt(i32) and l.next_char_freq == std.math.maxInt(i32)) {
167 // We've run out of both leaves and pairs.
168 // End all calculations for this level.
169 // To make sure we never come back to this level or any lower level,
170 // set next_pair_freq impossibly large.
171 l.needed = 0;
172 levels[level + 1].next_pair_freq = std.math.maxInt(i32);
173 level += 1;
174 continue;
175 }
176
177 const prev_freq = l.last_freq;
178 if (l.next_char_freq < l.next_pair_freq) {
179 // The next item on this row is a leaf node.
180 const next = leaf_counts[level][level] + 1;
181 l.last_freq = l.next_char_freq;
182 // Lower leaf_counts are the same of the previous node.
183 leaf_counts[level][level] = next;
184 if (next >= list.len) {
185 l.next_char_freq = LiteralNode.max().freq;
186 } else {
187 l.next_char_freq = list[next].freq;
188 }
189 } else {
190 // The next item on this row is a pair from the previous row.
191 // next_pair_freq isn't valid until we generate two
192 // more values in the level below
193 l.last_freq = l.next_pair_freq;
194 // Take leaf counts from the lower level, except counts[level] remains the same.
195 @memcpy(leaf_counts[level][0..level], leaf_counts[level - 1][0..level]);
196 levels[l.level - 1].needed = 2;
197 }
198
199 l.needed -= 1;
200 if (l.needed == 0) {
201 // We've done everything we need to do for this level.
202 // Continue calculating one level up. Fill in next_pair_freq
203 // of that level with the sum of the two nodes we've just calculated on
204 // this level.
205 if (l.level == max_bits) {
206 // All done!
207 break;
208 }
209 levels[l.level + 1].next_pair_freq = prev_freq + l.last_freq;
210 level += 1;
211 } else {
212 // If we stole from below, move down temporarily to replenish it.
213 while (levels[level - 1].needed > 0) {
214 level -= 1;
215 if (level == 0) {
216 break;
217 }
218 }
219 }
220 }
221 }
222
223 // Somethings is wrong if at the end, the top level is null or hasn't used
224 // all of the leaves.
225 assert(leaf_counts[max_bits][max_bits] == n);
226
227 var bit_count = self.bit_count[0 .. max_bits + 1];
228 var bits: u32 = 1;
229 const counts = &leaf_counts[max_bits];
230 {
231 var level = max_bits;
232 while (level > 0) : (level -= 1) {
233 // counts[level] gives the number of literals requiring at least "bits"
234 // bits to encode.
235 bit_count[bits] = counts[level] - counts[level - 1];
236 bits += 1;
237 if (level == 0) {
238 break;
239 }
240 }
241 }
242 return bit_count;
243}
244
245/// Look at the leaves and assign them a bit count and an encoding as specified
246/// in RFC 1951 3.2.2
247fn assignEncodingAndSize(self: *HuffmanEncoder, bit_count: []u32, list_arg: []LiteralNode) void {
248 var code = @as(u16, 0);
249 var list = list_arg;
250
251 for (bit_count, 0..) |bits, n| {
252 code <<= 1;
253 if (n == 0 or bits == 0) {
254 continue;
255 }
256 // The literals list[list.len-bits] .. list[list.len-bits]
257 // are encoded using "bits" bits, and get the values
258 // code, code + 1, .... The code values are
259 // assigned in literal order (not frequency order).
260 const chunk = list[list.len - @as(u32, @intCast(bits)) ..];
261
262 self.lns = chunk;
263 std.mem.sort(LiteralNode, self.lns, {}, byLiteral);
264
265 for (chunk) |node| {
266 self.codes[node.literal] = .{
267 .code = bitReverse(u16, code, @as(u5, @intCast(n))),
268 .len = @as(u16, @intCast(n)),
269 };
270 code += 1;
271 }
272 list = list[0 .. list.len - @as(u32, @intCast(bits))];
273 }
274}
275
276fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool {
277 _ = context;
278 if (a.freq == b.freq) {
279 return a.literal < b.literal;
280 }
281 return a.freq < b.freq;
282}
283
284/// Describes the state of the constructed tree for a given depth.
285const LevelInfo = struct {
286 /// Our level. for better printing
287 level: u32,
288 /// The frequency of the last node at this level
289 last_freq: u32,
290 /// The frequency of the next character to add to this level
291 next_char_freq: u32,
292 /// The frequency of the next pair (from level below) to add to this level.
293 /// Only valid if the "needed" value of the next lower level is 0.
294 next_pair_freq: u32,
295 /// The number of chains remaining to generate for this level before moving
296 /// up to the next level
297 needed: u32,
298};
299
300fn byLiteral(context: void, a: LiteralNode, b: LiteralNode) bool {
301 _ = context;
302 return a.literal < b.literal;
303}
304
305/// Reverse bit-by-bit a N-bit code.
306fn bitReverse(comptime T: type, value: T, n: usize) T {
307 const r = @bitReverse(value);
308 return r >> @as(std.math.Log2Int(T), @intCast(@typeInfo(T).int.bits - n));
309}
310
311test bitReverse {
312 const ReverseBitsTest = struct {
313 in: u16,
314 bit_count: u5,
315 out: u16,
316 };
317
318 const reverse_bits_tests = [_]ReverseBitsTest{
319 .{ .in = 1, .bit_count = 1, .out = 1 },
320 .{ .in = 1, .bit_count = 2, .out = 2 },
321 .{ .in = 1, .bit_count = 3, .out = 4 },
322 .{ .in = 1, .bit_count = 4, .out = 8 },
323 .{ .in = 1, .bit_count = 5, .out = 16 },
324 .{ .in = 17, .bit_count = 5, .out = 17 },
325 .{ .in = 257, .bit_count = 9, .out = 257 },
326 .{ .in = 29, .bit_count = 5, .out = 23 },
327 };
328
329 for (reverse_bits_tests) |h| {
330 const v = bitReverse(u16, h.in, h.bit_count);
331 try std.testing.expectEqual(h.out, v);
332 }
333}
334
335/// Generates a HuffmanCode corresponding to the fixed literal table
336pub fn fixedLiteralEncoder(codes: *[max_num_frequencies]Code) HuffmanEncoder {
337 var h: HuffmanEncoder = undefined;
338 h.codes = codes;
339 var ch: u16 = 0;
340
341 while (ch < max_num_frequencies) : (ch += 1) {
342 var bits: u16 = undefined;
343 var size: u16 = undefined;
344 switch (ch) {
345 0...143 => {
346 // size 8, 000110000 .. 10111111
347 bits = ch + 48;
348 size = 8;
349 },
350 144...255 => {
351 // size 9, 110010000 .. 111111111
352 bits = ch + 400 - 144;
353 size = 9;
354 },
355 256...279 => {
356 // size 7, 0000000 .. 0010111
357 bits = ch - 256;
358 size = 7;
359 },
360 else => {
361 // size 8, 11000000 .. 11000111
362 bits = ch + 192 - 280;
363 size = 8;
364 },
365 }
366 h.codes[ch] = .{ .code = bitReverse(u16, bits, @as(u5, @intCast(size))), .len = size };
367 }
368 return h;
369}
370
371pub fn fixedDistanceEncoder(codes: *[distance_code_count]Code) HuffmanEncoder {
372 var h: HuffmanEncoder = undefined;
373 h.codes = codes;
374 for (h.codes, 0..) |_, ch| {
375 h.codes[ch] = .{ .code = bitReverse(u16, @as(u16, @intCast(ch)), 5), .len = 5 };
376 }
377 return h;
378}
379
380pub fn huffmanDistanceEncoder(codes: *[distance_code_count]Code) HuffmanEncoder {
381 var distance_freq: [distance_code_count]u16 = @splat(0);
382 distance_freq[0] = 1;
383 // huff_distance is a static distance encoder used for huffman only encoding.
384 // It can be reused since we will not be encoding distance values.
385 var h: HuffmanEncoder = .{};
386 h.codes = codes;
387 h.generate(distance_freq[0..], 15);
388 return h;
389}
390
391test "generate a Huffman code for the fixed literal table specific to Deflate" {
392 var codes: [max_num_frequencies]Code = undefined;
393 const enc: HuffmanEncoder = .fixedLiteralEncoder(&codes);
394 for (enc.codes) |c| {
395 switch (c.len) {
396 7 => {
397 const v = @bitReverse(@as(u7, @intCast(c.code)));
398 try testing.expect(v <= 0b0010111);
399 },
400 8 => {
401 const v = @bitReverse(@as(u8, @intCast(c.code)));
402 try testing.expect((v >= 0b000110000 and v <= 0b10111111) or
403 (v >= 0b11000000 and v <= 11000111));
404 },
405 9 => {
406 const v = @bitReverse(@as(u9, @intCast(c.code)));
407 try testing.expect(v >= 0b110010000 and v <= 0b111111111);
408 },
409 else => unreachable,
410 }
411 }
412}
413
414test "generate a Huffman code for the 30 possible relative distances (LZ77 distances) of Deflate" {
415 var codes: [distance_code_count]Code = undefined;
416 const enc = fixedDistanceEncoder(&codes);
417 for (enc.codes) |c| {
418 const v = @bitReverse(@as(u5, @intCast(c.code)));
419 try testing.expect(v <= 29);
420 try testing.expect(c.len == 5);
421 }
422}
423
424pub const fixed_codes = [_]u8{
425 0b00001100, 0b10001100, 0b01001100, 0b11001100, 0b00101100, 0b10101100, 0b01101100, 0b11101100,
426 0b00011100, 0b10011100, 0b01011100, 0b11011100, 0b00111100, 0b10111100, 0b01111100, 0b11111100,
427 0b00000010, 0b10000010, 0b01000010, 0b11000010, 0b00100010, 0b10100010, 0b01100010, 0b11100010,
428 0b00010010, 0b10010010, 0b01010010, 0b11010010, 0b00110010, 0b10110010, 0b01110010, 0b11110010,
429 0b00001010, 0b10001010, 0b01001010, 0b11001010, 0b00101010, 0b10101010, 0b01101010, 0b11101010,
430 0b00011010, 0b10011010, 0b01011010, 0b11011010, 0b00111010, 0b10111010, 0b01111010, 0b11111010,
431 0b00000110, 0b10000110, 0b01000110, 0b11000110, 0b00100110, 0b10100110, 0b01100110, 0b11100110,
432 0b00010110, 0b10010110, 0b01010110, 0b11010110, 0b00110110, 0b10110110, 0b01110110, 0b11110110,
433 0b00001110, 0b10001110, 0b01001110, 0b11001110, 0b00101110, 0b10101110, 0b01101110, 0b11101110,
434 0b00011110, 0b10011110, 0b01011110, 0b11011110, 0b00111110, 0b10111110, 0b01111110, 0b11111110,
435 0b00000001, 0b10000001, 0b01000001, 0b11000001, 0b00100001, 0b10100001, 0b01100001, 0b11100001,
436 0b00010001, 0b10010001, 0b01010001, 0b11010001, 0b00110001, 0b10110001, 0b01110001, 0b11110001,
437 0b00001001, 0b10001001, 0b01001001, 0b11001001, 0b00101001, 0b10101001, 0b01101001, 0b11101001,
438 0b00011001, 0b10011001, 0b01011001, 0b11011001, 0b00111001, 0b10111001, 0b01111001, 0b11111001,
439 0b00000101, 0b10000101, 0b01000101, 0b11000101, 0b00100101, 0b10100101, 0b01100101, 0b11100101,
440 0b00010101, 0b10010101, 0b01010101, 0b11010101, 0b00110101, 0b10110101, 0b01110101, 0b11110101,
441 0b00001101, 0b10001101, 0b01001101, 0b11001101, 0b00101101, 0b10101101, 0b01101101, 0b11101101,
442 0b00011101, 0b10011101, 0b01011101, 0b11011101, 0b00111101, 0b10111101, 0b01111101, 0b11111101,
443 0b00010011, 0b00100110, 0b01001110, 0b10011010, 0b00111100, 0b01100101, 0b11101010, 0b10110100,
444 0b11101001, 0b00110011, 0b01100110, 0b11001110, 0b10011010, 0b00111101, 0b01100111, 0b11101110,
445 0b10111100, 0b11111001, 0b00001011, 0b00010110, 0b00101110, 0b01011010, 0b10111100, 0b01100100,
446 0b11101001, 0b10110010, 0b11100101, 0b00101011, 0b01010110, 0b10101110, 0b01011010, 0b10111101,
447 0b01100110, 0b11101101, 0b10111010, 0b11110101, 0b00011011, 0b00110110, 0b01101110, 0b11011010,
448 0b10111100, 0b01100101, 0b11101011, 0b10110110, 0b11101101, 0b00111011, 0b01110110, 0b11101110,
449 0b11011010, 0b10111101, 0b01100111, 0b11101111, 0b10111110, 0b11111101, 0b00000111, 0b00001110,
450 0b00011110, 0b00111010, 0b01111100, 0b11100100, 0b11101000, 0b10110001, 0b11100011, 0b00100111,
451 0b01001110, 0b10011110, 0b00111010, 0b01111101, 0b11100110, 0b11101100, 0b10111001, 0b11110011,
452 0b00010111, 0b00101110, 0b01011110, 0b10111010, 0b01111100, 0b11100101, 0b11101010, 0b10110101,
453 0b11101011, 0b00110111, 0b01101110, 0b11011110, 0b10111010, 0b01111101, 0b11100111, 0b11101110,
454 0b10111101, 0b11111011, 0b00001111, 0b00011110, 0b00111110, 0b01111010, 0b11111100, 0b11100100,
455 0b11101001, 0b10110011, 0b11100111, 0b00101111, 0b01011110, 0b10111110, 0b01111010, 0b11111101,
456 0b11100110, 0b11101101, 0b10111011, 0b11110111, 0b00011111, 0b00111110, 0b01111110, 0b11111010,
457 0b11111100, 0b11100101, 0b11101011, 0b10110111, 0b11101111, 0b00111111, 0b01111110, 0b11111110,
458 0b11111010, 0b11111101, 0b11100111, 0b11101111, 0b10111111, 0b11111111, 0b00000000, 0b00100000,
459 0b00001000, 0b00001100, 0b10000001, 0b11000010, 0b11100000, 0b00001000, 0b00100100, 0b00001010,
460 0b10001101, 0b11000001, 0b11100010, 0b11110000, 0b00000100, 0b00100010, 0b10001001, 0b01001100,
461 0b10100001, 0b11010010, 0b11101000, 0b00000011, 0b10000011, 0b01000011, 0b11000011, 0b00100011,
462 0b10100011,
463};
lib/std/compress/flate/Lookup.zig+10-5
...@@ -6,14 +6,19 @@ const std = @import("std");...@@ -6,14 +6,19 @@ const std = @import("std");
6const testing = std.testing;6const testing = std.testing;
7const expect = testing.expect;7const expect = testing.expect;
8const flate = @import("../flate.zig");8const flate = @import("../flate.zig");
9const Token = @import("Token.zig");
910
10const Lookup = @This();11const Lookup = @This();
1112
12const prime4 = 0x9E3779B1; // 4 bytes prime number 265443576113const prime4 = 0x9E3779B1; // 4 bytes prime number 2654435761
13const chain_len = 2 * flate.history_len;14const chain_len = 2 * flate.history_len;
1415
16pub const bits = 15;
17pub const len = 1 << bits;
18pub const shift = 32 - bits;
19
15// Maps hash => first position20// Maps hash => first position
16head: [flate.lookup.len]u16 = [_]u16{0} ** flate.lookup.len,21head: [len]u16 = [_]u16{0} ** len,
17// Maps position => previous positions for the same hash value22// Maps position => previous positions for the same hash value
18chain: [chain_len]u16 = [_]u16{0} ** (chain_len),23chain: [chain_len]u16 = [_]u16{0} ** (chain_len),
1924
...@@ -52,8 +57,8 @@ pub fn slide(self: *Lookup, n: u16) void {...@@ -52,8 +57,8 @@ pub fn slide(self: *Lookup, n: u16) void {
5257
53// Add `len` 4 bytes hashes from `data` into lookup.58// Add `len` 4 bytes hashes from `data` into lookup.
54// Position of the first byte is `pos`.59// Position of the first byte is `pos`.
55pub fn bulkAdd(self: *Lookup, data: []const u8, len: u16, pos: u16) void {60pub fn bulkAdd(self: *Lookup, data: []const u8, length: u16, pos: u16) void {
56 if (len == 0 or data.len < flate.match.min_length) {61 if (length == 0 or data.len < Token.min_length) {
57 return;62 return;
58 }63 }
59 var hb =64 var hb =
...@@ -64,7 +69,7 @@ pub fn bulkAdd(self: *Lookup, data: []const u8, len: u16, pos: u16) void {...@@ -64,7 +69,7 @@ pub fn bulkAdd(self: *Lookup, data: []const u8, len: u16, pos: u16) void {
64 _ = self.set(hashu(hb), pos);69 _ = self.set(hashu(hb), pos);
6570
66 var i = pos;71 var i = pos;
67 for (4..@min(len + 3, data.len)) |j| {72 for (4..@min(length + 3, data.len)) |j| {
68 hb = (hb << 8) | @as(u32, data[j]);73 hb = (hb << 8) | @as(u32, data[j]);
69 i += 1;74 i += 1;
70 _ = self.set(hashu(hb), i);75 _ = self.set(hashu(hb), i);
...@@ -80,7 +85,7 @@ fn hash(b: *const [4]u8) u32 {...@@ -80,7 +85,7 @@ fn hash(b: *const [4]u8) u32 {
80}85}
8186
82fn hashu(v: u32) u32 {87fn hashu(v: u32) u32 {
83 return @intCast((v *% prime4) >> flate.lookup.shift);88 return @intCast((v *% prime4) >> shift);
84}89}
8590
86test add {91test add {
lib/std/compress/flate/Token.zig+13-7
...@@ -6,7 +6,6 @@ const std = @import("std");...@@ -6,7 +6,6 @@ const std = @import("std");
6const assert = std.debug.assert;6const assert = std.debug.assert;
7const print = std.debug.print;7const print = std.debug.print;
8const expect = std.testing.expect;8const expect = std.testing.expect;
9const match = std.compress.flate.match;
109
11const Token = @This();10const Token = @This();
1211
...@@ -21,16 +20,23 @@ dist: u15 = 0,...@@ -21,16 +20,23 @@ dist: u15 = 0,
21len_lit: u8 = 0,20len_lit: u8 = 0,
22kind: Kind = .literal,21kind: Kind = .literal,
2322
23pub const base_length = 3; // smallest match length per the RFC section 3.2.5
24pub const min_length = 4; // min length used in this algorithm
25pub const max_length = 258;
26
27pub const min_distance = 1;
28pub const max_distance = std.compress.flate.history_len;
29
24pub fn literal(t: Token) u8 {30pub fn literal(t: Token) u8 {
25 return t.len_lit;31 return t.len_lit;
26}32}
2733
28pub fn distance(t: Token) u16 {34pub fn distance(t: Token) u16 {
29 return @as(u16, t.dist) + match.min_distance;35 return @as(u16, t.dist) + min_distance;
30}36}
3137
32pub fn length(t: Token) u16 {38pub fn length(t: Token) u16 {
33 return @as(u16, t.len_lit) + match.base_length;39 return @as(u16, t.len_lit) + base_length;
34}40}
3541
36pub fn initLiteral(lit: u8) Token {42pub fn initLiteral(lit: u8) Token {
...@@ -40,12 +46,12 @@ pub fn initLiteral(lit: u8) Token {...@@ -40,12 +46,12 @@ pub fn initLiteral(lit: u8) Token {
40// distance range 1 - 32768, stored in dist as 0 - 32767 (u15)46// distance range 1 - 32768, stored in dist as 0 - 32767 (u15)
41// length range 3 - 258, stored in len_lit as 0 - 255 (u8)47// length range 3 - 258, stored in len_lit as 0 - 255 (u8)
42pub fn initMatch(dist: u16, len: u16) Token {48pub fn initMatch(dist: u16, len: u16) Token {
43 assert(len >= match.min_length and len <= match.max_length);49 assert(len >= min_length and len <= max_length);
44 assert(dist >= match.min_distance and dist <= match.max_distance);50 assert(dist >= min_distance and dist <= max_distance);
45 return .{51 return .{
46 .kind = .match,52 .kind = .match,
47 .dist = @intCast(dist - match.min_distance),53 .dist = @intCast(dist - min_distance),
48 .len_lit = @intCast(len - match.base_length),54 .len_lit = @intCast(len - base_length),
49 };55 };
50}56}
5157
lib/std/compress/flate/testdata/block_writer.zig deleted-606
...@@ -1,606 +0,0 @@
1const Token = @import("../Token.zig");
2
3pub const TestCase = struct {
4 tokens: []const Token,
5 input: []const u8 = "", // File name of input data matching the tokens.
6 want: []const u8 = "", // File name of data with the expected output with input available.
7 want_no_input: []const u8 = "", // File name of the expected output when no input is available.
8};
9
10pub const testCases = blk: {
11 @setEvalBranchQuota(4096 * 2);
12
13 const L = Token.initLiteral;
14 const M = Token.initMatch;
15 const ml = M(1, 258); // Maximum length token. Used to reduce the size of writeBlockTests
16
17 break :blk &[_]TestCase{
18 TestCase{
19 .input = "huffman-null-max.input",
20 .want = "huffman-null-max.{s}.expect",
21 .want_no_input = "huffman-null-max.{s}.expect-noinput",
22 .tokens = &[_]Token{
23 L(0x0), ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
24 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
25 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
26 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
27 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
28 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
29 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
30 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
31 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
32 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
33 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
34 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
35 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, L(0x0), L(0x0),
36 },
37 },
38 TestCase{
39 .input = "huffman-pi.input",
40 .want = "huffman-pi.{s}.expect",
41 .want_no_input = "huffman-pi.{s}.expect-noinput",
42 .tokens = &[_]Token{
43 L('3'), L('.'), L('1'), L('4'), L('1'), L('5'), L('9'), L('2'),
44 L('6'), L('5'), L('3'), L('5'), L('8'), L('9'), L('7'), L('9'),
45 L('3'), L('2'), L('3'), L('8'), L('4'), L('6'), L('2'), L('6'),
46 L('4'), L('3'), L('3'), L('8'), L('3'), L('2'), L('7'), L('9'),
47 L('5'), L('0'), L('2'), L('8'), L('8'), L('4'), L('1'), L('9'),
48 L('7'), L('1'), L('6'), L('9'), L('3'), L('9'), L('9'), L('3'),
49 L('7'), L('5'), L('1'), L('0'), L('5'), L('8'), L('2'), L('0'),
50 L('9'), L('7'), L('4'), L('9'), L('4'), L('4'), L('5'), L('9'),
51 L('2'), L('3'), L('0'), L('7'), L('8'), L('1'), L('6'), L('4'),
52 L('0'), L('6'), L('2'), L('8'), L('6'), L('2'), L('0'), L('8'),
53 L('9'), L('9'), L('8'), L('6'), L('2'), L('8'), L('0'), L('3'),
54 L('4'), L('8'), L('2'), L('5'), L('3'), L('4'), L('2'), L('1'),
55 L('1'), L('7'), L('0'), L('6'), L('7'), L('9'), L('8'), L('2'),
56 L('1'), L('4'), L('8'), L('0'), L('8'), L('6'), L('5'), L('1'),
57 L('3'), L('2'), L('8'), L('2'), L('3'), L('0'), L('6'), L('6'),
58 L('4'), L('7'), L('0'), L('9'), L('3'), L('8'), L('4'), L('4'),
59 L('6'), L('0'), L('9'), L('5'), L('5'), L('0'), L('5'), L('8'),
60 L('2'), L('2'), L('3'), L('1'), L('7'), L('2'), L('5'), L('3'),
61 L('5'), L('9'), L('4'), L('0'), L('8'), L('1'), L('2'), L('8'),
62 L('4'), L('8'), L('1'), L('1'), L('1'), L('7'), L('4'), M(127, 4),
63 L('4'), L('1'), L('0'), L('2'), L('7'), L('0'), L('1'), L('9'),
64 L('3'), L('8'), L('5'), L('2'), L('1'), L('1'), L('0'), L('5'),
65 L('5'), L('5'), L('9'), L('6'), L('4'), L('4'), L('6'), L('2'),
66 L('2'), L('9'), L('4'), L('8'), L('9'), L('5'), L('4'), L('9'),
67 L('3'), L('0'), L('3'), L('8'), L('1'), M(19, 4), L('2'), L('8'),
68 L('8'), L('1'), L('0'), L('9'), L('7'), L('5'), L('6'), L('6'),
69 L('5'), L('9'), L('3'), L('3'), L('4'), L('4'), L('6'), M(72, 4),
70 L('7'), L('5'), L('6'), L('4'), L('8'), L('2'), L('3'), L('3'),
71 L('7'), L('8'), L('6'), L('7'), L('8'), L('3'), L('1'), L('6'),
72 L('5'), L('2'), L('7'), L('1'), L('2'), L('0'), L('1'), L('9'),
73 L('0'), L('9'), L('1'), L('4'), M(27, 4), L('5'), L('6'), L('6'),
74 L('9'), L('2'), L('3'), L('4'), L('6'), M(179, 4), L('6'), L('1'),
75 L('0'), L('4'), L('5'), L('4'), L('3'), L('2'), L('6'), M(51, 4),
76 L('1'), L('3'), L('3'), L('9'), L('3'), L('6'), L('0'), L('7'),
77 L('2'), L('6'), L('0'), L('2'), L('4'), L('9'), L('1'), L('4'),
78 L('1'), L('2'), L('7'), L('3'), L('7'), L('2'), L('4'), L('5'),
79 L('8'), L('7'), L('0'), L('0'), L('6'), L('6'), L('0'), L('6'),
80 L('3'), L('1'), L('5'), L('5'), L('8'), L('8'), L('1'), L('7'),
81 L('4'), L('8'), L('8'), L('1'), L('5'), L('2'), L('0'), L('9'),
82 L('2'), L('0'), L('9'), L('6'), L('2'), L('8'), L('2'), L('9'),
83 L('2'), L('5'), L('4'), L('0'), L('9'), L('1'), L('7'), L('1'),
84 L('5'), L('3'), L('6'), L('4'), L('3'), L('6'), L('7'), L('8'),
85 L('9'), L('2'), L('5'), L('9'), L('0'), L('3'), L('6'), L('0'),
86 L('0'), L('1'), L('1'), L('3'), L('3'), L('0'), L('5'), L('3'),
87 L('0'), L('5'), L('4'), L('8'), L('8'), L('2'), L('0'), L('4'),
88 L('6'), L('6'), L('5'), L('2'), L('1'), L('3'), L('8'), L('4'),
89 L('1'), L('4'), L('6'), L('9'), L('5'), L('1'), L('9'), L('4'),
90 L('1'), L('5'), L('1'), L('1'), L('6'), L('0'), L('9'), L('4'),
91 L('3'), L('3'), L('0'), L('5'), L('7'), L('2'), L('7'), L('0'),
92 L('3'), L('6'), L('5'), L('7'), L('5'), L('9'), L('5'), L('9'),
93 L('1'), L('9'), L('5'), L('3'), L('0'), L('9'), L('2'), L('1'),
94 L('8'), L('6'), L('1'), L('1'), L('7'), M(234, 4), L('3'), L('2'),
95 M(10, 4), L('9'), L('3'), L('1'), L('0'), L('5'), L('1'), L('1'),
96 L('8'), L('5'), L('4'), L('8'), L('0'), L('7'), M(271, 4), L('3'),
97 L('7'), L('9'), L('9'), L('6'), L('2'), L('7'), L('4'), L('9'),
98 L('5'), L('6'), L('7'), L('3'), L('5'), L('1'), L('8'), L('8'),
99 L('5'), L('7'), L('5'), L('2'), L('7'), L('2'), L('4'), L('8'),
100 L('9'), L('1'), L('2'), L('2'), L('7'), L('9'), L('3'), L('8'),
101 L('1'), L('8'), L('3'), L('0'), L('1'), L('1'), L('9'), L('4'),
102 L('9'), L('1'), L('2'), L('9'), L('8'), L('3'), L('3'), L('6'),
103 L('7'), L('3'), L('3'), L('6'), L('2'), L('4'), L('4'), L('0'),
104 L('6'), L('5'), L('6'), L('6'), L('4'), L('3'), L('0'), L('8'),
105 L('6'), L('0'), L('2'), L('1'), L('3'), L('9'), L('4'), L('9'),
106 L('4'), L('6'), L('3'), L('9'), L('5'), L('2'), L('2'), L('4'),
107 L('7'), L('3'), L('7'), L('1'), L('9'), L('0'), L('7'), L('0'),
108 L('2'), L('1'), L('7'), L('9'), L('8'), M(154, 5), L('7'), L('0'),
109 L('2'), L('7'), L('7'), L('0'), L('5'), L('3'), L('9'), L('2'),
110 L('1'), L('7'), L('1'), L('7'), L('6'), L('2'), L('9'), L('3'),
111 L('1'), L('7'), L('6'), L('7'), L('5'), M(563, 5), L('7'), L('4'),
112 L('8'), L('1'), M(7, 4), L('6'), L('6'), L('9'), L('4'), L('0'),
113 M(488, 4), L('0'), L('0'), L('0'), L('5'), L('6'), L('8'), L('1'),
114 L('2'), L('7'), L('1'), L('4'), L('5'), L('2'), L('6'), L('3'),
115 L('5'), L('6'), L('0'), L('8'), L('2'), L('7'), L('7'), L('8'),
116 L('5'), L('7'), L('7'), L('1'), L('3'), L('4'), L('2'), L('7'),
117 L('5'), L('7'), L('7'), L('8'), L('9'), L('6'), M(298, 4), L('3'),
118 L('6'), L('3'), L('7'), L('1'), L('7'), L('8'), L('7'), L('2'),
119 L('1'), L('4'), L('6'), L('8'), L('4'), L('4'), L('0'), L('9'),
120 L('0'), L('1'), L('2'), L('2'), L('4'), L('9'), L('5'), L('3'),
121 L('4'), L('3'), L('0'), L('1'), L('4'), L('6'), L('5'), L('4'),
122 L('9'), L('5'), L('8'), L('5'), L('3'), L('7'), L('1'), L('0'),
123 L('5'), L('0'), L('7'), L('9'), M(203, 4), L('6'), M(340, 4), L('8'),
124 L('9'), L('2'), L('3'), L('5'), L('4'), M(458, 4), L('9'), L('5'),
125 L('6'), L('1'), L('1'), L('2'), L('1'), L('2'), L('9'), L('0'),
126 L('2'), L('1'), L('9'), L('6'), L('0'), L('8'), L('6'), L('4'),
127 L('0'), L('3'), L('4'), L('4'), L('1'), L('8'), L('1'), L('5'),
128 L('9'), L('8'), L('1'), L('3'), L('6'), L('2'), L('9'), L('7'),
129 L('7'), L('4'), M(117, 4), L('0'), L('9'), L('9'), L('6'), L('0'),
130 L('5'), L('1'), L('8'), L('7'), L('0'), L('7'), L('2'), L('1'),
131 L('1'), L('3'), L('4'), L('9'), M(1, 5), L('8'), L('3'), L('7'),
132 L('2'), L('9'), L('7'), L('8'), L('0'), L('4'), L('9'), L('9'),
133 M(731, 4), L('9'), L('7'), L('3'), L('1'), L('7'), L('3'), L('2'),
134 L('8'), M(395, 4), L('6'), L('3'), L('1'), L('8'), L('5'), M(770, 4),
135 M(745, 4), L('4'), L('5'), L('5'), L('3'), L('4'), L('6'), L('9'),
136 L('0'), L('8'), L('3'), L('0'), L('2'), L('6'), L('4'), L('2'),
137 L('5'), L('2'), L('2'), L('3'), L('0'), M(740, 4), M(616, 4), L('8'),
138 L('5'), L('0'), L('3'), L('5'), L('2'), L('6'), L('1'), L('9'),
139 L('3'), L('1'), L('1'), M(531, 4), L('1'), L('0'), L('1'), L('0'),
140 L('0'), L('0'), L('3'), L('1'), L('3'), L('7'), L('8'), L('3'),
141 L('8'), L('7'), L('5'), L('2'), L('8'), L('8'), L('6'), L('5'),
142 L('8'), L('7'), L('5'), L('3'), L('3'), L('2'), L('0'), L('8'),
143 L('3'), L('8'), L('1'), L('4'), L('2'), L('0'), L('6'), M(321, 4),
144 M(300, 4), L('1'), L('4'), L('7'), L('3'), L('0'), L('3'), L('5'),
145 L('9'), M(815, 5), L('9'), L('0'), L('4'), L('2'), L('8'), L('7'),
146 L('5'), L('5'), L('4'), L('6'), L('8'), L('7'), L('3'), L('1'),
147 L('1'), L('5'), L('9'), L('5'), M(854, 4), L('3'), L('8'), L('8'),
148 L('2'), L('3'), L('5'), L('3'), L('7'), L('8'), L('7'), L('5'),
149 M(896, 5), L('9'), M(315, 4), L('1'), M(329, 4), L('8'), L('0'), L('5'),
150 L('3'), M(395, 4), L('2'), L('2'), L('6'), L('8'), L('0'), L('6'),
151 L('6'), L('1'), L('3'), L('0'), L('0'), L('1'), L('9'), L('2'),
152 L('7'), L('8'), L('7'), L('6'), L('6'), L('1'), L('1'), L('1'),
153 L('9'), L('5'), L('9'), M(568, 4), L('6'), M(293, 5), L('8'), L('9'),
154 L('3'), L('8'), L('0'), L('9'), L('5'), L('2'), L('5'), L('7'),
155 L('2'), L('0'), L('1'), L('0'), L('6'), L('5'), L('4'), L('8'),
156 L('5'), L('8'), L('6'), L('3'), L('2'), L('7'), M(155, 4), L('9'),
157 L('3'), L('6'), L('1'), L('5'), L('3'), M(545, 4), M(349, 5), L('2'),
158 L('3'), L('0'), L('3'), L('0'), L('1'), L('9'), L('5'), L('2'),
159 L('0'), L('3'), L('5'), L('3'), L('0'), L('1'), L('8'), L('5'),
160 L('2'), M(370, 4), M(118, 4), L('3'), L('6'), L('2'), L('2'), L('5'),
161 L('9'), L('9'), L('4'), L('1'), L('3'), M(597, 4), L('4'), L('9'),
162 L('7'), L('2'), L('1'), L('7'), M(223, 4), L('3'), L('4'), L('7'),
163 L('9'), L('1'), L('3'), L('1'), L('5'), L('1'), L('5'), L('5'),
164 L('7'), L('4'), L('8'), L('5'), L('7'), L('2'), L('4'), L('2'),
165 L('4'), L('5'), L('4'), L('1'), L('5'), L('0'), L('6'), L('9'),
166 M(320, 4), L('8'), L('2'), L('9'), L('5'), L('3'), L('3'), L('1'),
167 L('1'), L('6'), L('8'), L('6'), L('1'), L('7'), L('2'), L('7'),
168 L('8'), M(824, 4), L('9'), L('0'), L('7'), L('5'), L('0'), L('9'),
169 M(270, 4), L('7'), L('5'), L('4'), L('6'), L('3'), L('7'), L('4'),
170 L('6'), L('4'), L('9'), L('3'), L('9'), L('3'), L('1'), L('9'),
171 L('2'), L('5'), L('5'), L('0'), L('6'), L('0'), L('4'), L('0'),
172 L('0'), L('9'), M(620, 4), L('1'), L('6'), L('7'), L('1'), L('1'),
173 L('3'), L('9'), L('0'), L('0'), L('9'), L('8'), M(822, 4), L('4'),
174 L('0'), L('1'), L('2'), L('8'), L('5'), L('8'), L('3'), L('6'),
175 L('1'), L('6'), L('0'), L('3'), L('5'), L('6'), L('3'), L('7'),
176 L('0'), L('7'), L('6'), L('6'), L('0'), L('1'), L('0'), L('4'),
177 M(371, 4), L('8'), L('1'), L('9'), L('4'), L('2'), L('9'), M(1055, 5),
178 M(240, 4), M(652, 4), L('7'), L('8'), L('3'), L('7'), L('4'), M(1193, 4),
179 L('8'), L('2'), L('5'), L('5'), L('3'), L('7'), M(522, 5), L('2'),
180 L('6'), L('8'), M(47, 4), L('4'), L('0'), L('4'), L('7'), M(466, 4),
181 L('4'), M(1206, 4), M(910, 4), L('8'), L('4'), M(937, 4), L('6'), M(800, 6),
182 L('3'), L('3'), L('1'), L('3'), L('6'), L('7'), L('7'), L('0'),
183 L('2'), L('8'), L('9'), L('8'), L('9'), L('1'), L('5'), L('2'),
184 M(99, 4), L('5'), L('2'), L('1'), L('6'), L('2'), L('0'), L('5'),
185 L('6'), L('9'), L('6'), M(1042, 4), L('0'), L('5'), L('8'), M(1144, 4),
186 L('5'), M(1177, 4), L('5'), L('1'), L('1'), M(522, 4), L('8'), L('2'),
187 L('4'), L('3'), L('0'), L('0'), L('3'), L('5'), L('5'), L('8'),
188 L('7'), L('6'), L('4'), L('0'), L('2'), L('4'), L('7'), L('4'),
189 L('9'), L('6'), L('4'), L('7'), L('3'), L('2'), L('6'), L('3'),
190 M(1087, 4), L('9'), L('9'), L('2'), M(1100, 4), L('4'), L('2'), L('6'),
191 L('9'), M(710, 6), L('7'), M(471, 4), L('4'), M(1342, 4), M(1054, 4), L('9'),
192 L('3'), L('4'), L('1'), L('7'), M(430, 4), L('1'), L('2'), M(43, 4),
193 L('4'), M(415, 4), L('1'), L('5'), L('0'), L('3'), L('0'), L('2'),
194 L('8'), L('6'), L('1'), L('8'), L('2'), L('9'), L('7'), L('4'),
195 L('5'), L('5'), L('5'), L('7'), L('0'), L('6'), L('7'), L('4'),
196 M(310, 4), L('5'), L('0'), L('5'), L('4'), L('9'), L('4'), L('5'),
197 L('8'), M(454, 4), L('9'), M(82, 4), L('5'), L('6'), M(493, 4), L('7'),
198 L('2'), L('1'), L('0'), L('7'), L('9'), M(346, 4), L('3'), L('0'),
199 M(267, 4), L('3'), L('2'), L('1'), L('1'), L('6'), L('5'), L('3'),
200 L('4'), L('4'), L('9'), L('8'), L('7'), L('2'), L('0'), L('2'),
201 L('7'), M(284, 4), L('0'), L('2'), L('3'), L('6'), L('4'), M(559, 4),
202 L('5'), L('4'), L('9'), L('9'), L('1'), L('1'), L('9'), L('8'),
203 M(1049, 4), L('4'), M(284, 4), L('5'), L('3'), L('5'), L('6'), L('6'),
204 L('3'), L('6'), L('9'), M(1105, 4), L('2'), L('6'), L('5'), M(741, 4),
205 L('7'), L('8'), L('6'), L('2'), L('5'), L('5'), L('1'), M(987, 4),
206 L('1'), L('7'), L('5'), L('7'), L('4'), L('6'), L('7'), L('2'),
207 L('8'), L('9'), L('0'), L('9'), L('7'), L('7'), L('7'), L('7'),
208 M(1108, 5), L('0'), L('0'), L('0'), M(1534, 4), L('7'), L('0'), M(1248, 4),
209 L('6'), M(1002, 4), L('4'), L('9'), L('1'), M(1055, 4), M(664, 4), L('2'),
210 L('1'), L('4'), L('7'), L('7'), L('2'), L('3'), L('5'), L('0'),
211 L('1'), L('4'), L('1'), L('4'), M(1604, 4), L('3'), L('5'), L('6'),
212 M(1200, 4), L('1'), L('6'), L('1'), L('3'), L('6'), L('1'), L('1'),
213 L('5'), L('7'), L('3'), L('5'), L('2'), L('5'), M(1285, 4), L('3'),
214 L('4'), M(92, 4), L('1'), L('8'), M(1148, 4), L('8'), L('4'), M(1512, 4),
215 L('3'), L('3'), L('2'), L('3'), L('9'), L('0'), L('7'), L('3'),
216 L('9'), L('4'), L('1'), L('4'), L('3'), L('3'), L('3'), L('4'),
217 L('5'), L('4'), L('7'), L('7'), L('6'), L('2'), L('4'), M(579, 4),
218 L('2'), L('5'), L('1'), L('8'), L('9'), L('8'), L('3'), L('5'),
219 L('6'), L('9'), L('4'), L('8'), L('5'), L('5'), L('6'), L('2'),
220 L('0'), L('9'), L('9'), L('2'), L('1'), L('9'), L('2'), L('2'),
221 L('2'), L('1'), L('8'), L('4'), L('2'), L('7'), M(575, 4), L('2'),
222 M(187, 4), L('6'), L('8'), L('8'), L('7'), L('6'), L('7'), L('1'),
223 L('7'), L('9'), L('0'), M(86, 4), L('0'), M(263, 5), L('6'), L('6'),
224 M(1000, 4), L('8'), L('8'), L('6'), L('2'), L('7'), L('2'), M(1757, 4),
225 L('1'), L('7'), L('8'), L('6'), L('0'), L('8'), L('5'), L('7'),
226 M(116, 4), L('3'), M(765, 5), L('7'), L('9'), L('7'), L('6'), L('6'),
227 L('8'), L('1'), M(702, 4), L('0'), L('0'), L('9'), L('5'), L('3'),
228 L('8'), L('8'), M(1593, 4), L('3'), M(1702, 4), L('0'), L('6'), L('8'),
229 L('0'), L('0'), L('6'), L('4'), L('2'), L('2'), L('5'), L('1'),
230 L('2'), L('5'), L('2'), M(1404, 4), L('7'), L('3'), L('9'), L('2'),
231 M(664, 4), M(1141, 4), L('4'), M(1716, 5), L('8'), L('6'), L('2'), L('6'),
232 L('9'), L('4'), L('5'), M(486, 4), L('4'), L('1'), L('9'), L('6'),
233 L('5'), L('2'), L('8'), L('5'), L('0'), M(154, 4), M(925, 4), L('1'),
234 L('8'), L('6'), L('3'), M(447, 4), L('4'), M(341, 5), L('2'), L('0'),
235 L('3'), L('9'), M(1420, 4), L('4'), L('5'), M(701, 4), L('2'), L('3'),
236 L('7'), M(1069, 4), L('6'), M(1297, 4), L('5'), L('6'), M(1593, 4), L('7'),
237 L('1'), L('9'), L('1'), L('7'), L('2'), L('8'), M(370, 4), L('7'),
238 L('6'), L('4'), L('6'), L('5'), L('7'), L('5'), L('7'), L('3'),
239 L('9'), M(258, 4), L('3'), L('8'), L('9'), M(1865, 4), L('8'), L('3'),
240 L('2'), L('6'), L('4'), L('5'), L('9'), L('9'), L('5'), L('8'),
241 M(1704, 4), L('0'), L('4'), L('7'), L('8'), M(479, 4), M(809, 4), L('9'),
242 M(46, 4), L('6'), L('4'), L('0'), L('7'), L('8'), L('9'), L('5'),
243 L('1'), M(143, 4), L('6'), L('8'), L('3'), M(304, 4), L('2'), L('5'),
244 L('9'), L('5'), L('7'), L('0'), M(1129, 4), L('8'), L('2'), L('2'),
245 M(713, 4), L('2'), M(1564, 4), L('4'), L('0'), L('7'), L('7'), L('2'),
246 L('6'), L('7'), L('1'), L('9'), L('4'), L('7'), L('8'), M(794, 4),
247 L('8'), L('2'), L('6'), L('0'), L('1'), L('4'), L('7'), L('6'),
248 L('9'), L('9'), L('0'), L('9'), M(1257, 4), L('0'), L('1'), L('3'),
249 L('6'), L('3'), L('9'), L('4'), L('4'), L('3'), M(640, 4), L('3'),
250 L('0'), M(262, 4), L('2'), L('0'), L('3'), L('4'), L('9'), L('6'),
251 L('2'), L('5'), L('2'), L('4'), L('5'), L('1'), L('7'), M(950, 4),
252 L('9'), L('6'), L('5'), L('1'), L('4'), L('3'), L('1'), L('4'),
253 L('2'), L('9'), L('8'), L('0'), L('9'), L('1'), L('9'), L('0'),
254 L('6'), L('5'), L('9'), L('2'), M(643, 4), L('7'), L('2'), L('2'),
255 L('1'), L('6'), L('9'), L('6'), L('4'), L('6'), M(1050, 4), M(123, 4),
256 L('5'), M(1295, 4), L('4'), M(1382, 5), L('8'), M(1370, 4), L('9'), L('7'),
257 M(1404, 4), L('5'), L('4'), M(1182, 4), M(575, 4), L('7'), M(1627, 4), L('8'),
258 L('4'), L('6'), L('8'), L('1'), L('3'), M(141, 4), L('6'), L('8'),
259 L('3'), L('8'), L('6'), L('8'), L('9'), L('4'), L('2'), L('7'),
260 L('7'), L('4'), L('1'), L('5'), L('5'), L('9'), L('9'), L('1'),
261 L('8'), L('5'), M(91, 4), L('2'), L('4'), L('5'), L('9'), L('5'),
262 L('3'), L('9'), L('5'), L('9'), L('4'), L('3'), L('1'), M(1464, 4),
263 L('7'), M(19, 4), L('6'), L('8'), L('0'), L('8'), L('4'), L('5'),
264 M(744, 4), L('7'), L('3'), M(2079, 4), L('9'), L('5'), L('8'), L('4'),
265 L('8'), L('6'), L('5'), L('3'), L('8'), M(1769, 4), L('6'), L('2'),
266 M(243, 4), L('6'), L('0'), L('9'), M(1207, 4), L('6'), L('0'), L('8'),
267 L('0'), L('5'), L('1'), L('2'), L('4'), L('3'), L('8'), L('8'),
268 L('4'), M(315, 4), M(12, 4), L('4'), L('1'), L('3'), M(784, 4), L('7'),
269 L('6'), L('2'), L('7'), L('8'), M(834, 4), L('7'), L('1'), L('5'),
270 M(1436, 4), L('3'), L('5'), L('9'), L('9'), L('7'), L('7'), L('0'),
271 L('0'), L('1'), L('2'), L('9'), M(1139, 4), L('8'), L('9'), L('4'),
272 L('4'), L('1'), M(632, 4), L('6'), L('8'), L('5'), L('5'), M(96, 4),
273 L('4'), L('0'), L('6'), L('3'), M(2279, 4), L('2'), L('0'), L('7'),
274 L('2'), L('2'), M(345, 4), M(516, 5), L('4'), L('8'), L('1'), L('5'),
275 L('8'), M(518, 4), M(511, 4), M(635, 4), M(665, 4), L('3'), L('9'), L('4'),
276 L('5'), L('2'), L('2'), L('6'), L('7'), M(1175, 6), L('8'), M(1419, 4),
277 L('2'), L('1'), M(747, 4), L('2'), M(904, 4), L('5'), L('4'), L('6'),
278 L('6'), L('6'), M(1308, 4), L('2'), L('3'), L('9'), L('8'), L('6'),
279 L('4'), L('5'), L('6'), M(1221, 4), L('1'), L('6'), L('3'), L('5'),
280 M(596, 5), M(2066, 4), L('7'), M(2222, 4), L('9'), L('8'), M(1119, 4), L('9'),
281 L('3'), L('6'), L('3'), L('4'), M(1884, 4), L('7'), L('4'), L('3'),
282 L('2'), L('4'), M(1148, 4), L('1'), L('5'), L('0'), L('7'), L('6'),
283 M(1212, 4), L('7'), L('9'), L('4'), L('5'), L('1'), L('0'), L('9'),
284 M(63, 4), L('0'), L('9'), L('4'), L('0'), M(1703, 4), L('8'), L('8'),
285 L('7'), L('9'), L('7'), L('1'), L('0'), L('8'), L('9'), L('3'),
286 M(2289, 4), L('6'), L('9'), L('1'), L('3'), L('6'), L('8'), L('6'),
287 L('7'), L('2'), M(604, 4), M(511, 4), L('5'), M(1344, 4), M(1129, 4), M(2050, 4),
288 L('1'), L('7'), L('9'), L('2'), L('8'), L('6'), L('8'), M(2253, 4),
289 L('8'), L('7'), L('4'), L('7'), M(1951, 5), L('8'), L('2'), L('4'),
290 M(2427, 4), L('8'), M(604, 4), L('7'), L('1'), L('4'), L('9'), L('0'),
291 L('9'), L('6'), L('7'), L('5'), L('9'), L('8'), M(1776, 4), L('3'),
292 L('6'), L('5'), M(309, 4), L('8'), L('1'), M(93, 4), M(1862, 4), M(2359, 4),
293 L('6'), L('8'), L('2'), L('9'), M(1407, 4), L('8'), L('7'), L('2'),
294 L('2'), L('6'), L('5'), L('8'), L('8'), L('0'), M(1554, 4), L('5'),
295 M(586, 4), L('4'), L('2'), L('7'), L('0'), L('4'), L('7'), L('7'),
296 L('5'), L('5'), M(2079, 4), L('3'), L('7'), L('9'), L('6'), L('4'),
297 L('1'), L('4'), L('5'), L('1'), L('5'), L('2'), M(1534, 4), L('2'),
298 L('3'), L('4'), L('3'), L('6'), L('4'), L('5'), L('4'), M(1503, 4),
299 L('4'), L('4'), L('4'), L('7'), L('9'), L('5'), M(61, 4), M(1316, 4),
300 M(2279, 5), L('4'), L('1'), M(1323, 4), L('3'), M(773, 4), L('5'), L('2'),
301 L('3'), L('1'), M(2114, 5), L('1'), L('6'), L('6'), L('1'), M(2227, 4),
302 L('5'), L('9'), L('6'), L('9'), L('5'), L('3'), L('6'), L('2'),
303 L('3'), L('1'), L('4'), M(1536, 4), L('2'), L('4'), L('8'), L('4'),
304 L('9'), L('3'), L('7'), L('1'), L('8'), L('7'), L('1'), L('1'),
305 L('0'), L('1'), L('4'), L('5'), L('7'), L('6'), L('5'), L('4'),
306 M(1890, 4), L('0'), L('2'), L('7'), L('9'), L('9'), L('3'), L('4'),
307 L('4'), L('0'), L('3'), L('7'), L('4'), L('2'), L('0'), L('0'),
308 L('7'), M(2368, 4), L('7'), L('8'), L('5'), L('3'), L('9'), L('0'),
309 L('6'), L('2'), L('1'), L('9'), M(666, 5), M(838, 4), L('8'), L('4'),
310 L('7'), M(979, 5), L('8'), L('3'), L('3'), L('2'), L('1'), L('4'),
311 L('4'), L('5'), L('7'), L('1'), M(645, 4), M(1911, 4), L('4'), L('3'),
312 L('5'), L('0'), M(2345, 4), M(1129, 4), L('5'), L('3'), L('1'), L('9'),
313 L('1'), L('0'), L('4'), L('8'), L('4'), L('8'), L('1'), L('0'),
314 L('0'), L('5'), L('3'), L('7'), L('0'), L('6'), M(2237, 4), M(1438, 5),
315 M(1922, 5), L('1'), M(1370, 4), L('7'), M(796, 4), L('5'), M(2029, 4), M(1037, 4),
316 L('6'), L('3'), M(2013, 5), L('4'), M(2418, 4), M(847, 5), M(1014, 5), L('8'),
317 M(1326, 5), M(2184, 5), L('9'), M(392, 4), L('9'), L('1'), M(2255, 4), L('8'),
318 L('1'), L('4'), L('6'), L('7'), L('5'), L('1'), M(1580, 4), L('1'),
319 L('2'), L('3'), L('9'), M(426, 6), L('9'), L('0'), L('7'), L('1'),
320 L('8'), L('6'), L('4'), L('9'), L('4'), L('2'), L('3'), L('1'),
321 L('9'), L('6'), L('1'), L('5'), L('6'), M(493, 4), M(1725, 4), L('9'),
322 L('5'), M(2343, 4), M(1130, 4), M(284, 4), L('6'), L('0'), L('3'), L('8'),
323 M(2598, 4), M(368, 4), M(901, 4), L('6'), L('2'), M(1115, 4), L('5'), M(2125, 4),
324 L('6'), L('3'), L('8'), L('9'), L('3'), L('7'), L('7'), L('8'),
325 L('7'), M(2246, 4), M(249, 4), L('9'), L('7'), L('9'), L('2'), L('0'),
326 L('7'), L('7'), L('3'), M(1496, 4), L('2'), L('1'), L('8'), L('2'),
327 L('5'), L('6'), M(2016, 4), L('6'), L('6'), M(1751, 4), L('4'), L('2'),
328 M(1663, 5), L('6'), M(1767, 4), L('4'), L('4'), M(37, 4), L('5'), L('4'),
329 L('9'), L('2'), L('0'), L('2'), L('6'), L('0'), L('5'), M(2740, 4),
330 M(997, 5), L('2'), L('0'), L('1'), L('4'), L('9'), M(1235, 4), L('8'),
331 L('5'), L('0'), L('7'), L('3'), M(1434, 4), L('6'), L('6'), L('6'),
332 L('0'), M(405, 4), L('2'), L('4'), L('3'), L('4'), L('0'), M(136, 4),
333 L('0'), M(1900, 4), L('8'), L('6'), L('3'), M(2391, 4), M(2021, 4), M(1068, 4),
334 M(373, 4), L('5'), L('7'), L('9'), L('6'), L('2'), L('6'), L('8'),
335 L('5'), L('6'), M(321, 4), L('5'), L('0'), L('8'), M(1316, 4), L('5'),
336 L('8'), L('7'), L('9'), L('6'), L('9'), L('9'), M(1810, 4), L('5'),
337 L('7'), L('4'), M(2585, 4), L('8'), L('4'), L('0'), M(2228, 4), L('1'),
338 L('4'), L('5'), L('9'), L('1'), M(1933, 4), L('7'), L('0'), M(565, 4),
339 L('0'), L('1'), M(3048, 4), L('1'), L('2'), M(3189, 4), L('0'), M(964, 4),
340 L('3'), L('9'), M(2859, 4), M(275, 4), L('7'), L('1'), L('5'), M(945, 4),
341 L('4'), L('2'), L('0'), M(3059, 5), L('9'), M(3011, 4), L('0'), L('7'),
342 M(834, 4), M(1942, 4), M(2736, 4), M(3171, 4), L('2'), L('1'), M(2401, 4), L('2'),
343 L('5'), L('1'), M(1404, 4), M(2373, 4), L('9'), L('2'), M(435, 4), L('8'),
344 L('2'), L('6'), M(2919, 4), L('2'), M(633, 4), L('3'), L('2'), L('1'),
345 L('5'), L('7'), L('9'), L('1'), L('9'), L('8'), L('4'), L('1'),
346 L('4'), M(2172, 5), L('9'), L('1'), L('6'), L('4'), M(1769, 5), L('9'),
347 M(2905, 5), M(2268, 4), L('7'), L('2'), L('2'), M(802, 4), L('5'), M(2213, 4),
348 M(322, 4), L('9'), L('1'), L('0'), M(189, 4), M(3164, 4), L('5'), L('2'),
349 L('8'), L('0'), L('1'), L('7'), M(562, 4), L('7'), L('1'), L('2'),
350 M(2325, 4), L('8'), L('3'), L('2'), M(884, 4), L('1'), M(1418, 4), L('0'),
351 L('9'), L('3'), L('5'), L('3'), L('9'), L('6'), L('5'), L('7'),
352 M(1612, 4), L('1'), L('0'), L('8'), L('3'), M(106, 4), L('5'), L('1'),
353 M(1915, 4), M(3419, 4), L('1'), L('4'), L('4'), L('4'), L('2'), L('1'),
354 L('0'), L('0'), M(515, 4), L('0'), L('3'), M(413, 4), L('1'), L('1'),
355 L('0'), L('3'), M(3202, 4), M(10, 4), M(39, 4), M(1539, 6), L('5'), L('1'),
356 L('6'), M(1498, 4), M(2180, 5), M(2347, 4), L('5'), M(3139, 5), L('8'), L('5'),
357 L('1'), L('7'), L('1'), L('4'), L('3'), L('7'), M(1542, 4), M(110, 4),
358 L('1'), L('5'), L('5'), L('6'), L('5'), L('0'), L('8'), L('8'),
359 M(954, 4), L('9'), L('8'), L('9'), L('8'), L('5'), L('9'), L('9'),
360 L('8'), L('2'), L('3'), L('8'), M(464, 4), M(2491, 4), L('3'), M(365, 4),
361 M(1087, 4), M(2500, 4), L('8'), M(3590, 5), L('3'), L('2'), M(264, 4), L('5'),
362 M(774, 4), L('3'), M(459, 4), L('9'), M(1052, 4), L('9'), L('8'), M(2174, 4),
363 L('4'), M(3257, 4), L('7'), M(1612, 4), L('0'), L('7'), M(230, 4), L('4'),
364 L('8'), L('1'), L('4'), L('1'), M(1338, 4), L('8'), L('5'), L('9'),
365 L('4'), L('6'), L('1'), M(3018, 4), L('8'), L('0'),
366 },
367 },
368 TestCase{
369 .input = "huffman-rand-1k.input",
370 .want = "huffman-rand-1k.{s}.expect",
371 .want_no_input = "huffman-rand-1k.{s}.expect-noinput",
372 .tokens = &[_]Token{
373 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),
374 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),
375 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),
376 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),
377 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),
378 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),
379 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),
380 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),
381 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),
382 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),
383 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),
384 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),
385 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),
386 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),
387 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),
388 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),
389 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),
390 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),
391 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),
392 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),
393 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),
394 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),
395 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),
396 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),
397 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),
398 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),
399 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),
400 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),
401 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),
402 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),
403 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),
404 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),
405 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),
406 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),
407 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),
408 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),
409 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),
410 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),
411 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),
412 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),
413 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),
414 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),
415 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),
416 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),
417 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),
418 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),
419 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),
420 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),
421 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),
422 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),
423 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),
424 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),
425 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),
426 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),
427 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),
428 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),
429 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),
430 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),
431 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),
432 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),
433 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),
434 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),
435 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),
436 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),
437 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),
438 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),
439 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),
440 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),
441 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),
442 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),
443 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),
444 L(0xfa), L(0x8), L(0xb1), L(0xde), L(0x17), L(0x4a),
445 },
446 },
447 TestCase{
448 .input = "huffman-rand-limit.input",
449 .want = "huffman-rand-limit.{s}.expect",
450 .want_no_input = "huffman-rand-limit.{s}.expect-noinput",
451 .tokens = &[_]Token{
452 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),
453 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),
454 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),
455 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),
456 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),
457 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),
458 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),
459 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),
460 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),
461 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),
462 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),
463 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),
464 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),
465 L(0x75), L(0xda), L(0xea), L(0x9b), L(0xa),
466 },
467 },
468 TestCase{
469 .input = "huffman-shifts.input",
470 .want = "huffman-shifts.{s}.expect",
471 .want_no_input = "huffman-shifts.{s}.expect-noinput",
472 .tokens = &[_]Token{
473 L('1'), L('0'), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258),
474 M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258),
475 M(2, 258), M(2, 76), L(0xd), L(0xa), L('2'), L('3'), M(2, 258), M(2, 258),
476 M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 258), M(2, 256),
477 },
478 },
479 TestCase{
480 .input = "huffman-text-shift.input",
481 .want = "huffman-text-shift.{s}.expect",
482 .want_no_input = "huffman-text-shift.{s}.expect-noinput",
483 .tokens = &[_]Token{
484 L('/'), L('/'), L('C'), L('o'), L('p'), L('y'), L('r'), L('i'),
485 L('g'), L('h'), L('t'), L('2'), L('0'), L('0'), L('9'), L('T'),
486 L('h'), L('G'), L('o'), L('A'), L('u'), L('t'), L('h'), L('o'),
487 L('r'), L('.'), L('A'), L('l'), L('l'), M(23, 5), L('r'), L('r'),
488 L('v'), L('d'), L('.'), L(0xd), L(0xa), L('/'), L('/'), L('U'),
489 L('o'), L('f'), L('t'), L('h'), L('i'), L('o'), L('u'), L('r'),
490 L('c'), L('c'), L('o'), L('d'), L('i'), L('g'), L('o'), L('v'),
491 L('r'), L('n'), L('d'), L('b'), L('y'), L('B'), L('S'), L('D'),
492 L('-'), L('t'), L('y'), L('l'), M(33, 4), L('l'), L('i'), L('c'),
493 L('n'), L('t'), L('h'), L('t'), L('c'), L('n'), L('b'), L('f'),
494 L('o'), L('u'), L('n'), L('d'), L('i'), L('n'), L('t'), L('h'),
495 L('L'), L('I'), L('C'), L('E'), L('N'), L('S'), L('E'), L('f'),
496 L('i'), L('l'), L('.'), L(0xd), L(0xa), L(0xd), L(0xa), L('p'),
497 L('c'), L('k'), L('g'), L('m'), L('i'), L('n'), M(11, 4), L('i'),
498 L('m'), L('p'), L('o'), L('r'), L('t'), L('"'), L('o'), L('"'),
499 M(13, 4), L('f'), L('u'), L('n'), L('c'), L('m'), L('i'), L('n'),
500 L('('), L(')'), L('{'), L(0xd), L(0xa), L(0x9), L('v'), L('r'),
501 L('b'), L('='), L('m'), L('k'), L('('), L('['), L(']'), L('b'),
502 L('y'), L('t'), L(','), L('6'), L('5'), L('5'), L('3'), L('5'),
503 L(')'), L(0xd), L(0xa), L(0x9), L('f'), L(','), L('_'), L(':'),
504 L('='), L('o'), L('.'), L('C'), L('r'), L('t'), L('('), L('"'),
505 L('h'), L('u'), L('f'), L('f'), L('m'), L('n'), L('-'), L('n'),
506 L('u'), L('l'), L('l'), L('-'), L('m'), L('x'), L('.'), L('i'),
507 L('n'), L('"'), M(34, 5), L('.'), L('W'), L('r'), L('i'), L('t'),
508 L('('), L('b'), L(')'), L(0xd), L(0xa), L('}'), L(0xd), L(0xa),
509 L('A'), L('B'), L('C'), L('D'), L('E'), L('F'), L('G'), L('H'),
510 L('I'), L('J'), L('K'), L('L'), L('M'), L('N'), L('O'), L('P'),
511 L('Q'), L('R'), L('S'), L('T'), L('U'), L('V'), L('X'), L('x'),
512 L('y'), L('z'), L('!'), L('"'), L('#'), L(0xc2), L(0xa4), L('%'),
513 L('&'), L('/'), L('?'), L('"'),
514 },
515 },
516 TestCase{
517 .input = "huffman-text.input",
518 .want = "huffman-text.{s}.expect",
519 .want_no_input = "huffman-text.{s}.expect-noinput",
520 .tokens = &[_]Token{
521 L('/'), L('/'), L(' '), L('z'), L('i'), L('g'), L(' '), L('v'),
522 L('0'), L('.'), L('1'), L('0'), L('.'), L('0'), L(0xa), L('/'),
523 L('/'), L(' '), L('c'), L('r'), L('e'), L('a'), L('t'), L('e'),
524 L(' '), L('a'), L(' '), L('f'), L('i'), L('l'), L('e'), M(5, 4),
525 L('l'), L('e'), L('d'), L(' '), L('w'), L('i'), L('t'), L('h'),
526 L(' '), L('0'), L('x'), L('0'), L('0'), L(0xa), L('c'), L('o'),
527 L('n'), L('s'), L('t'), L(' '), L('s'), L('t'), L('d'), L(' '),
528 L('='), L(' '), L('@'), L('i'), L('m'), L('p'), L('o'), L('r'),
529 L('t'), L('('), L('"'), L('s'), L('t'), L('d'), L('"'), L(')'),
530 L(';'), L(0xa), L(0xa), L('p'), L('u'), L('b'), L(' '), L('f'),
531 L('n'), L(' '), L('m'), L('a'), L('i'), L('n'), L('('), L(')'),
532 L(' '), L('!'), L('v'), L('o'), L('i'), L('d'), L(' '), L('{'),
533 L(0xa), L(' '), L(' '), L(' '), L(' '), L('v'), L('a'), L('r'),
534 L(' '), L('b'), L(' '), L('='), L(' '), L('['), L('1'), L(']'),
535 L('u'), L('8'), L('{'), L('0'), L('}'), L(' '), L('*'), L('*'),
536 L(' '), L('6'), L('5'), L('5'), L('3'), L('5'), L(';'), M(31, 5),
537 M(86, 6), L('f'), L(' '), L('='), L(' '), L('t'), L('r'), L('y'),
538 M(94, 4), L('.'), L('f'), L('s'), L('.'), L('c'), L('w'), L('d'),
539 L('('), L(')'), L('.'), M(144, 6), L('F'), L('i'), L('l'), L('e'),
540 L('('), M(43, 5), M(1, 4), L('"'), L('h'), L('u'), L('f'), L('f'),
541 L('m'), L('a'), L('n'), L('-'), L('n'), L('u'), L('l'), L('l'),
542 L('-'), L('m'), L('a'), L('x'), L('.'), L('i'), L('n'), L('"'),
543 L(','), M(31, 9), L('.'), L('{'), L(' '), L('.'), L('r'), L('e'),
544 L('a'), L('d'), M(79, 5), L('u'), L('e'), L(' '), L('}'), M(27, 6),
545 L(')'), M(108, 6), L('d'), L('e'), L('f'), L('e'), L('r'), L(' '),
546 L('f'), L('.'), L('c'), L('l'), L('o'), L('s'), L('e'), L('('),
547 M(183, 4), M(22, 4), L('_'), M(124, 7), L('f'), L('.'), L('w'), L('r'),
548 L('i'), L('t'), L('e'), L('A'), L('l'), L('l'), L('('), L('b'),
549 L('['), L('0'), L('.'), L('.'), L(']'), L(')'), L(';'), L(0xa),
550 L('}'), L(0xa),
551 },
552 },
553 TestCase{
554 .input = "huffman-zero.input",
555 .want = "huffman-zero.{s}.expect",
556 .want_no_input = "huffman-zero.{s}.expect-noinput",
557 .tokens = &[_]Token{ L(0x30), ml, M(1, 49) },
558 },
559 TestCase{
560 .input = "",
561 .want = "",
562 .want_no_input = "null-long-match.{s}.expect-noinput",
563 .tokens = &[_]Token{
564 L(0x0), ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
565 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
566 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
567 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
568 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
569 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
570 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
571 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
572 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
573 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
574 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
575 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
576 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
577 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
578 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
579 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
580 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
581 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
582 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
583 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
584 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
585 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
586 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
587 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
588 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
589 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
590 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
591 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
592 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
593 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
594 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
595 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
596 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
597 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
598 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
599 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
600 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
601 ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,
602 ml, ml, ml, M(1, 8),
603 },
604 },
605 };
606};
lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-null-max.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-null-max.input deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.input and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-null-max.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-pi.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-pi.input deleted-1
...@@ -1 +0,0 @@
13.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278865936153381827968230301952035301852968995773622599413891249721775283479131515574857242454150695950829533116861727855889075098381754637464939319255060400927701671139009848824012858361603563707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104752162056966024058038150193511253382430035587640247496473263914199272604269922796782354781636009341721641219924586315030286182974555706749838505494588586926995690927210797509302955321165344987202755960236480665499119881834797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548161361157352552133475741849468438523323907394143334547762416862518983569485562099219222184272550254256887671790494601653466804988627232791786085784383827967976681454100953883786360950680064225125205117392984896084128488626945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645995813390478027590099465764078951269468398352595709825822620522489407726719478268482601476990902640136394437455305068203496252451749399651431429809190659250937221696461515709858387410597885959772975498930161753928468138268683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244136549762780797715691435997700129616089441694868555848406353422072225828488648158456028506016842739452267467678895252138522549954666727823986456596116354886230577456498035593634568174324112515076069479451096596094025228879710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821682998948722658804857564014270477555132379641451523746234364542858444795265867821051141354735739523113427166102135969536231442952484937187110145765403590279934403742007310578539062198387447808478489683321445713868751943506430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675142691239748940907186494231961567945208095146550225231603881930142093762137855956638937787083039069792077346722182562599661501421503068038447734549202605414665925201497442850732518666002132434088190710486331734649651453905796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007230558763176359421873125147120532928191826186125867321579198414848829164470609575270695722091756711672291098169091528017350671274858322287183520935396572512108357915136988209144421006751033467110314126711136990865851639831501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064204675259070915481416549859461637180
\ No newline at end of file
lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-pi.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.input deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.input and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-1k.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.input deleted-4
...@@ -1,4 +0,0 @@
1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
2���vH
3��%������ ��ɷ���}��>���ls���m�IGH����1Y�4�[�� 0ˆ[|]o#�
4�-#���ul���pf��ٱ�n�Y�ԀY�w�C8ɯ02� F=gn�r�N!O���{����k�*�w(��b� ��kQC9/��lu>�5�C.��u�
lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-limit.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-max.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-rand-max.input deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-rand-max.input and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-shifts.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-shifts.input deleted-2
...@@ -1,2 +0,0 @@
1101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010
2232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323
\ No newline at end of file
lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-shifts.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text-shift.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text-shift.input deleted-14
...@@ -1,14 +0,0 @@
1//Copyright2009ThGoAuthor.Allrightrrvd.
2//UofthiourccodigovrndbyBSD-tyl
3//licnthtcnbfoundinthLICENSEfil.
4
5pckgmin
6
7import"o"
8
9funcmin(){
10 vrb=mk([]byt,65535)
11 f,_:=o.Crt("huffmn-null-mx.in")
12 f.Writ(b)
13}
14ABCDEFGHIJKLMNOPQRSTUVXxyz!"#¤%&/?"
\ No newline at end of file
lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text-shift.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text.input deleted-14
...@@ -1,14 +0,0 @@
1// zig v0.10.0
2// create a file filled with 0x00
3const std = @import("std");
4
5pub fn main() !void {
6 var b = [1]u8{0} ** 65535;
7 const f = try std.fs.cwd().createFile(
8 "huffman-null-max.in",
9 .{ .read = true },
10 );
11 defer f.close();
12
13 _ = try f.writeAll(b[0..]);
14}
lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-text.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-zero.huff.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.huff.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-zero.input deleted-1
...@@ -1 +0,0 @@
100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
\ No newline at end of file
lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect and /dev/null differ
lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/huffman-zero.wb.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/null-long-match.dyn.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/null-long-match.dyn.expect-noinput and /dev/null differ
lib/std/compress/flate/testdata/block_writer/null-long-match.wb.expect-noinput deleted
Binary files a/lib/std/compress/flate/testdata/block_writer/null-long-match.wb.expect-noinput and /dev/null differ
lib/std/compress/xz.zig+5-11
...@@ -12,17 +12,11 @@ pub const Check = enum(u4) {...@@ -12,17 +12,11 @@ pub const Check = enum(u4) {
12};12};
1313
14fn readStreamFlags(reader: anytype, check: *Check) !void {14fn readStreamFlags(reader: anytype, check: *Check) !void {
15 var bit_reader = std.io.bitReader(.little, reader);15 const reserved1 = try reader.readByte();
1616 if (reserved1 != 0) return error.CorruptInput;
17 const reserved1 = try bit_reader.readBitsNoEof(u8, 8);17 const byte = try reader.readByte();
18 if (reserved1 != 0)18 if ((byte >> 4) != 0) return error.CorruptInput;
19 return error.CorruptInput;19 check.* = @enumFromInt(@as(u4, @truncate(byte)));
20
21 check.* = @as(Check, @enumFromInt(try bit_reader.readBitsNoEof(u4, 4)));
22
23 const reserved2 = try bit_reader.readBitsNoEof(u4, 4);
24 if (reserved2 != 0)
25 return error.CorruptInput;
26}20}
2721
28pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) {22pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) {
lib/std/compress/zstd/Decompress.zig+70-4
...@@ -31,7 +31,12 @@ pub const Options = struct {...@@ -31,7 +31,12 @@ pub const Options = struct {
31 /// Verifying checksums is not implemented yet and will cause a panic if31 /// Verifying checksums is not implemented yet and will cause a panic if
32 /// you set this to true.32 /// you set this to true.
33 verify_checksum: bool = false,33 verify_checksum: bool = false,
34 /// Affects the minimum capacity of the provided buffer.34
35 /// The output buffer is asserted to have capacity for `window_len` plus
36 /// `zstd.block_size_max`.
37 ///
38 /// If `window_len` is too small, then some streams will fail to decompress
39 /// with `error.OutputBufferUndersize`.
35 window_len: u32 = zstd.default_window_len,40 window_len: u32 = zstd.default_window_len,
36};41};
3742
...@@ -69,8 +74,10 @@ pub const Error = error{...@@ -69,8 +74,10 @@ pub const Error = error{
69 WindowSizeUnknown,74 WindowSizeUnknown,
70};75};
7176
72/// If buffer that is written to is not big enough, some streams will fail with77/// When connecting `reader` to a `Writer`, `buffer` should be empty, and
73/// `error.OutputBufferUndersize`. A safe value is `zstd.default_window_len * 2`.78/// `Writer.buffer` capacity has requirements based on `Options.window_len`.
79///
80/// Otherwise, `buffer` has those requirements.
74pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {81pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
75 return .{82 return .{
76 .input = input,83 .input = input,
...@@ -78,7 +85,12 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {...@@ -78,7 +85,12 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
78 .verify_checksum = options.verify_checksum,85 .verify_checksum = options.verify_checksum,
79 .window_len = options.window_len,86 .window_len = options.window_len,
80 .reader = .{87 .reader = .{
81 .vtable = &.{ .stream = stream },88 .vtable = &.{
89 .stream = stream,
90 .rebase = rebase,
91 .discard = discard,
92 .readVec = readVec,
93 },
82 .buffer = buffer,94 .buffer = buffer,
83 .seek = 0,95 .seek = 0,
84 .end = 0,96 .end = 0,
...@@ -86,6 +98,60 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {...@@ -86,6 +98,60 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
86 };98 };
87}99}
88100
101fn rebase(r: *Reader, capacity: usize) Reader.RebaseError!void {
102 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
103 assert(capacity <= r.buffer.len - d.window_len);
104 assert(r.end + capacity > r.buffer.len);
105 const discard_n = r.end - d.window_len;
106 const keep = r.buffer[discard_n..r.end];
107 @memmove(r.buffer[0..keep.len], keep);
108 r.end = keep.len;
109 r.seek -= discard_n;
110}
111
112/// This could be improved so that when an amount is discarded that includes an
113/// entire frame, skip decoding that frame.
114fn discard(r: *Reader, limit: std.Io.Limit) Reader.Error!usize {
115 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
116 r.rebase(d.window_len) catch unreachable;
117 var writer: Writer = .{
118 .vtable = &.{
119 .drain = std.Io.Writer.Discarding.drain,
120 .sendFile = std.Io.Writer.Discarding.sendFile,
121 },
122 .buffer = r.buffer,
123 .end = r.end,
124 };
125 defer {
126 r.end = writer.end;
127 r.seek = r.end;
128 }
129 const n = r.stream(&writer, limit) catch |err| switch (err) {
130 error.WriteFailed => unreachable,
131 error.ReadFailed => return error.ReadFailed,
132 error.EndOfStream => return error.EndOfStream,
133 };
134 assert(n <= @intFromEnum(limit));
135 return n;
136}
137
138fn readVec(r: *Reader, data: [][]u8) Reader.Error!usize {
139 _ = data;
140 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
141 assert(r.seek == r.end);
142 r.rebase(d.window_len) catch unreachable;
143 var writer: Writer = .{
144 .buffer = r.buffer,
145 .end = r.end,
146 .vtable = &.{ .drain = Writer.fixedDrain },
147 };
148 r.end += r.vtable.stream(r, &writer, .limited(writer.buffer.len - writer.end)) catch |err| switch (err) {
149 error.WriteFailed => unreachable,
150 else => |e| return e,
151 };
152 return 0;
153}
154
89fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {155fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
90 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));156 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
91 const in = d.input;157 const in = d.input;
lib/std/debug/Dwarf.zig+16-12
...@@ -2019,10 +2019,14 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 {...@@ -2019,10 +2019,14 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 {
2019/// This function is to make it handy to comment out the return and make it2019/// This function is to make it handy to comment out the return and make it
2020/// into a crash when working on this file.2020/// into a crash when working on this file.
2021pub fn bad() error{InvalidDebugInfo} {2021pub fn bad() error{InvalidDebugInfo} {
2022 if (debug_debug_mode) @panic("bad dwarf");2022 invalidDebugInfoDetected();
2023 return error.InvalidDebugInfo;2023 return error.InvalidDebugInfo;
2024}2024}
20252025
2026fn invalidDebugInfoDetected() void {
2027 if (debug_debug_mode) @panic("bad dwarf");
2028}
2029
2026fn missing() error{MissingDebugInfo} {2030fn missing() error{MissingDebugInfo} {
2027 if (debug_debug_mode) @panic("missing dwarf");2031 if (debug_debug_mode) @panic("missing dwarf");
2028 return error.MissingDebugInfo;2032 return error.MissingDebugInfo;
...@@ -2235,23 +2239,23 @@ pub const ElfModule = struct {...@@ -2235,23 +2239,23 @@ pub const ElfModule = struct {
22352239
2236 const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);2240 const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
2237 sections[section_index.?] = if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) blk: {2241 sections[section_index.?] = if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) blk: {
2238 var section_reader: std.io.Reader = .fixed(section_bytes);2242 var section_reader: std.Io.Reader = .fixed(section_bytes);
2239 const chdr = section_reader.takeStruct(elf.Chdr) catch continue;2243 const chdr = section_reader.takeStruct(elf.Chdr, endian) catch continue;
2240 if (chdr.ch_type != .ZLIB) continue;2244 if (chdr.ch_type != .ZLIB) continue;
2241 const ch_size = chdr.ch_size;
22422245
2243 var zlib_stream: std.compress.flate.Decompress = .init(&section_reader, .zlib, &.{});2246 var decompress: std.compress.flate.Decompress = .init(&section_reader, .zlib, &.{});
22442247 var decompressed_section: std.ArrayListUnmanaged(u8) = .empty;
2245 const decompressed_section = zlib_stream.reader.allocRemaining(gpa, .limited(ch_size)) catch2248 defer decompressed_section.deinit(gpa);
2249 decompress.reader.appendRemainingUnlimited(gpa, null, &decompressed_section, std.compress.flate.history_len) catch {
2250 invalidDebugInfoDetected();
2246 continue;2251 continue;
2247 if (decompressed_section.len != ch_size) {2252 };
2248 gpa.free(decompressed_section);2253 if (chdr.ch_size != decompressed_section.items.len) {
2254 invalidDebugInfoDetected();
2249 continue;2255 continue;
2250 }2256 }
2251 errdefer gpa.free(decompressed_section);
2252
2253 break :blk .{2257 break :blk .{
2254 .data = decompressed_section,2258 .data = try decompressed_section.toOwnedSlice(gpa),
2255 .virtual_address = shdr.sh_addr,2259 .virtual_address = shdr.sh_addr,
2256 .owned = true,2260 .owned = true,
2257 };2261 };
lib/std/enums.zig+34-20
...@@ -1317,9 +1317,9 @@ test "EnumSet non-exhaustive" {...@@ -1317,9 +1317,9 @@ test "EnumSet non-exhaustive" {
1317}1317}
13181318
1319pub fn EnumIndexer(comptime E: type) type {1319pub fn EnumIndexer(comptime E: type) type {
1320 // Assumes that the enum fields are sorted in ascending order (optimistic).1320 // n log n for `std.mem.sortUnstable` call below.
1321 // Unsorted enums may require the user to manually increase the quota.1321 const fields_len = @typeInfo(E).@"enum".fields.len;
1322 @setEvalBranchQuota(3 * @typeInfo(E).@"enum".fields.len + eval_branch_quota_cushion);1322 @setEvalBranchQuota(3 * fields_len * std.math.log2(@max(fields_len, 1)) + eval_branch_quota_cushion);
13231323
1324 if (!@typeInfo(E).@"enum".is_exhaustive) {1324 if (!@typeInfo(E).@"enum".is_exhaustive) {
1325 const BackingInt = @typeInfo(E).@"enum".tag_type;1325 const BackingInt = @typeInfo(E).@"enum".tag_type;
...@@ -1354,10 +1354,6 @@ pub fn EnumIndexer(comptime E: type) type {...@@ -1354,10 +1354,6 @@ pub fn EnumIndexer(comptime E: type) type {
1354 };1354 };
1355 }1355 }
13561356
1357 const const_fields = @typeInfo(E).@"enum".fields;
1358 var fields = const_fields[0..const_fields.len].*;
1359 const fields_len = fields.len;
1360
1361 if (fields_len == 0) {1357 if (fields_len == 0) {
1362 return struct {1358 return struct {
1363 pub const Key = E;1359 pub const Key = E;
...@@ -1373,22 +1369,17 @@ pub fn EnumIndexer(comptime E: type) type {...@@ -1373,22 +1369,17 @@ pub fn EnumIndexer(comptime E: type) type {
1373 };1369 };
1374 }1370 }
13751371
1376 const min = fields[0].value;1372 var fields: [fields_len]EnumField = @typeInfo(E).@"enum".fields[0..].*;
1377 const max = fields[fields.len - 1].value;
1378
1379 const SortContext = struct {
1380 fields: []EnumField,
13811373
1382 pub fn lessThan(comptime ctx: @This(), comptime a: usize, comptime b: usize) bool {1374 std.mem.sortUnstable(EnumField, &fields, {}, struct {
1383 return ctx.fields[a].value < ctx.fields[b].value;1375 fn lessThan(ctx: void, lhs: EnumField, rhs: EnumField) bool {
1376 ctx;
1377 return lhs.value < rhs.value;
1384 }1378 }
1379 }.lessThan);
13851380
1386 pub fn swap(comptime ctx: @This(), comptime a: usize, comptime b: usize) void {1381 const min = fields[0].value;
1387 return std.mem.swap(EnumField, &ctx.fields[a], &ctx.fields[b]);1382 const max = fields[fields_len - 1].value;
1388 }
1389 };
1390 std.sort.insertionContext(0, fields_len, SortContext{ .fields = &fields });
1391
1392 if (max - min == fields.len - 1) {1383 if (max - min == fields.len - 1) {
1393 return struct {1384 return struct {
1394 pub const Key = E;1385 pub const Key = E;
...@@ -1538,6 +1529,29 @@ test "EnumIndexer empty" {...@@ -1538,6 +1529,29 @@ test "EnumIndexer empty" {
1538 try testing.expectEqual(0, Indexer.count);1529 try testing.expectEqual(0, Indexer.count);
1539}1530}
15401531
1532test "EnumIndexer large dense unsorted" {
1533 @setEvalBranchQuota(500_000); // many `comptimePrint`s
1534 // Make an enum with 500 fields with values in *descending* order.
1535 const E = @Type(.{ .@"enum" = .{
1536 .tag_type = u32,
1537 .fields = comptime fields: {
1538 var fields: [500]EnumField = undefined;
1539 for (&fields, 0..) |*f, i| f.* = .{
1540 .name = std.fmt.comptimePrint("f{d}", .{i}),
1541 .value = 500 - i,
1542 };
1543 break :fields &fields;
1544 },
1545 .decls = &.{},
1546 .is_exhaustive = true,
1547 } });
1548 const Indexer = EnumIndexer(E);
1549 try testing.expectEqual(E.f0, Indexer.keyForIndex(499));
1550 try testing.expectEqual(E.f499, Indexer.keyForIndex(0));
1551 try testing.expectEqual(499, Indexer.indexOf(.f0));
1552 try testing.expectEqual(0, Indexer.indexOf(.f499));
1553}
1554
1541test values {1555test values {
1542 const E = enum {1556 const E = enum {
1543 X,1557 X,
lib/std/fmt.zig+2
...@@ -1101,6 +1101,8 @@ test "float.libc.sanity" {...@@ -1101,6 +1101,8 @@ test "float.libc.sanity" {
1101}1101}
11021102
1103test "union" {1103test "union" {
1104 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1105
1104 const TU = union(enum) {1106 const TU = union(enum) {
1105 float: f32,1107 float: f32,
1106 int: u32,1108 int: u32,
lib/std/fs/File.zig+57-31
...@@ -912,7 +912,7 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError...@@ -912,7 +912,7 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError
912/// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`)912/// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`)
913/// versus plain variants (e.g. `read`).913/// versus plain variants (e.g. `read`).
914///914///
915/// Fulfills the `std.io.Reader` interface.915/// Fulfills the `std.Io.Reader` interface.
916pub const Reader = struct {916pub const Reader = struct {
917 file: File,917 file: File,
918 err: ?ReadError = null,918 err: ?ReadError = null,
...@@ -923,7 +923,7 @@ pub const Reader = struct {...@@ -923,7 +923,7 @@ pub const Reader = struct {
923 size: ?u64 = null,923 size: ?u64 = null,
924 size_err: ?GetEndPosError = null,924 size_err: ?GetEndPosError = null,
925 seek_err: ?Reader.SeekError = null,925 seek_err: ?Reader.SeekError = null,
926 interface: std.io.Reader,926 interface: std.Io.Reader,
927927
928 pub const SeekError = File.SeekError || error{928 pub const SeekError = File.SeekError || error{
929 /// Seeking fell back to reading, and reached the end before the requested seek position.929 /// Seeking fell back to reading, and reached the end before the requested seek position.
...@@ -960,11 +960,12 @@ pub const Reader = struct {...@@ -960,11 +960,12 @@ pub const Reader = struct {
960 }960 }
961 };961 };
962962
963 pub fn initInterface(buffer: []u8) std.io.Reader {963 pub fn initInterface(buffer: []u8) std.Io.Reader {
964 return .{964 return .{
965 .vtable = &.{965 .vtable = &.{
966 .stream = Reader.stream,966 .stream = Reader.stream,
967 .discard = Reader.discard,967 .discard = Reader.discard,
968 .readVec = Reader.readVec,
968 },969 },
969 .buffer = buffer,970 .buffer = buffer,
970 .seek = 0,971 .seek = 0,
...@@ -1077,7 +1078,7 @@ pub const Reader = struct {...@@ -1077,7 +1078,7 @@ pub const Reader = struct {
1077 /// vectors through the underlying read calls as possible.1078 /// vectors through the underlying read calls as possible.
1078 const max_buffers_len = 16;1079 const max_buffers_len = 16;
10791080
1080 fn stream(io_reader: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {1081 fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
1081 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));1082 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
1082 switch (r.mode) {1083 switch (r.mode) {
1083 .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) {1084 .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) {
...@@ -1088,16 +1089,33 @@ pub const Reader = struct {...@@ -1088,16 +1089,33 @@ pub const Reader = struct {
1088 else => |e| return e,1089 else => |e| return e,
1089 },1090 },
1090 .positional_reading => {1091 .positional_reading => {
1092 const dest = limit.slice(try w.writableSliceGreedy(1));
1093 const n = try readPositional(r, dest);
1094 w.advance(n);
1095 return n;
1096 },
1097 .streaming_reading => {
1098 const dest = limit.slice(try w.writableSliceGreedy(1));
1099 const n = try readStreaming(r, dest);
1100 w.advance(n);
1101 return n;
1102 },
1103 .failure => return error.ReadFailed,
1104 }
1105 }
1106
1107 fn readVec(io_reader: *std.Io.Reader, data: [][]u8) std.Io.Reader.Error!usize {
1108 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
1109 switch (r.mode) {
1110 .positional, .positional_reading => {
1091 if (is_windows) {1111 if (is_windows) {
1092 // Unfortunately, `ReadFileScatter` cannot be used since it1112 // Unfortunately, `ReadFileScatter` cannot be used since it
1093 // requires page alignment.1113 // requires page alignment.
1094 const dest = limit.slice(try w.writableSliceGreedy(1));1114 return readPositional(r, data[0]);
1095 const n = try readPositional(r, dest);
1096 w.advance(n);
1097 return n;
1098 }1115 }
1099 var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;1116 var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
1100 const dest = try w.writableVectorPosix(&iovecs_buffer, limit);1117 const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);
1118 const dest = iovecs_buffer[0..dest_n];
1101 assert(dest[0].len > 0);1119 assert(dest[0].len > 0);
1102 const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) {1120 const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) {
1103 error.Unseekable => {1121 error.Unseekable => {
...@@ -1122,19 +1140,22 @@ pub const Reader = struct {...@@ -1122,19 +1140,22 @@ pub const Reader = struct {
1122 return error.EndOfStream;1140 return error.EndOfStream;
1123 }1141 }
1124 r.pos += n;1142 r.pos += n;
1125 return w.advanceVector(n);1143 if (n > data_size) {
1144 io_reader.seek = 0;
1145 io_reader.end = n - data_size;
1146 return data_size;
1147 }
1148 return n;
1126 },1149 },
1127 .streaming_reading => {1150 .streaming, .streaming_reading => {
1128 if (is_windows) {1151 if (is_windows) {
1129 // Unfortunately, `ReadFileScatter` cannot be used since it1152 // Unfortunately, `ReadFileScatter` cannot be used since it
1130 // requires page alignment.1153 // requires page alignment.
1131 const dest = limit.slice(try w.writableSliceGreedy(1));1154 return readStreaming(r, data[0]);
1132 const n = try readStreaming(r, dest);
1133 w.advance(n);
1134 return n;
1135 }1155 }
1136 var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;1156 var iovecs_buffer: [max_buffers_len]posix.iovec = undefined;
1137 const dest = try w.writableVectorPosix(&iovecs_buffer, limit);1157 const dest_n, const data_size = try io_reader.writableVectorPosix(&iovecs_buffer, data);
1158 const dest = iovecs_buffer[0..dest_n];
1138 assert(dest[0].len > 0);1159 assert(dest[0].len > 0);
1139 const n = posix.readv(r.file.handle, dest) catch |err| {1160 const n = posix.readv(r.file.handle, dest) catch |err| {
1140 r.err = err;1161 r.err = err;
...@@ -1145,13 +1166,18 @@ pub const Reader = struct {...@@ -1145,13 +1166,18 @@ pub const Reader = struct {
1145 return error.EndOfStream;1166 return error.EndOfStream;
1146 }1167 }
1147 r.pos += n;1168 r.pos += n;
1148 return w.advanceVector(n);1169 if (n > data_size) {
1170 io_reader.seek = 0;
1171 io_reader.end = n - data_size;
1172 return data_size;
1173 }
1174 return n;
1149 },1175 },
1150 .failure => return error.ReadFailed,1176 .failure => return error.ReadFailed,
1151 }1177 }
1152 }1178 }
11531179
1154 fn discard(io_reader: *std.io.Reader, limit: std.io.Limit) std.io.Reader.Error!usize {1180 fn discard(io_reader: *std.Io.Reader, limit: std.Io.Limit) std.Io.Reader.Error!usize {
1155 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));1181 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
1156 const file = r.file;1182 const file = r.file;
1157 const pos = r.pos;1183 const pos = r.pos;
...@@ -1230,7 +1256,7 @@ pub const Reader = struct {...@@ -1230,7 +1256,7 @@ pub const Reader = struct {
1230 }1256 }
1231 }1257 }
12321258
1233 pub fn readPositional(r: *Reader, dest: []u8) std.io.Reader.Error!usize {1259 pub fn readPositional(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
1234 const n = r.file.pread(dest, r.pos) catch |err| switch (err) {1260 const n = r.file.pread(dest, r.pos) catch |err| switch (err) {
1235 error.Unseekable => {1261 error.Unseekable => {
1236 r.mode = r.mode.toStreaming();1262 r.mode = r.mode.toStreaming();
...@@ -1257,7 +1283,7 @@ pub const Reader = struct {...@@ -1257,7 +1283,7 @@ pub const Reader = struct {
1257 return n;1283 return n;
1258 }1284 }
12591285
1260 pub fn readStreaming(r: *Reader, dest: []u8) std.io.Reader.Error!usize {1286 pub fn readStreaming(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
1261 const n = r.file.read(dest) catch |err| {1287 const n = r.file.read(dest) catch |err| {
1262 r.err = err;1288 r.err = err;
1263 return error.ReadFailed;1289 return error.ReadFailed;
...@@ -1270,7 +1296,7 @@ pub const Reader = struct {...@@ -1270,7 +1296,7 @@ pub const Reader = struct {
1270 return n;1296 return n;
1271 }1297 }
12721298
1273 pub fn read(r: *Reader, dest: []u8) std.io.Reader.Error!usize {1299 pub fn read(r: *Reader, dest: []u8) std.Io.Reader.Error!usize {
1274 switch (r.mode) {1300 switch (r.mode) {
1275 .positional, .positional_reading => return readPositional(r, dest),1301 .positional, .positional_reading => return readPositional(r, dest),
1276 .streaming, .streaming_reading => return readStreaming(r, dest),1302 .streaming, .streaming_reading => return readStreaming(r, dest),
...@@ -1296,7 +1322,7 @@ pub const Writer = struct {...@@ -1296,7 +1322,7 @@ pub const Writer = struct {
1296 copy_file_range_err: ?CopyFileRangeError = null,1322 copy_file_range_err: ?CopyFileRangeError = null,
1297 fcopyfile_err: ?FcopyfileError = null,1323 fcopyfile_err: ?FcopyfileError = null,
1298 seek_err: ?SeekError = null,1324 seek_err: ?SeekError = null,
1299 interface: std.io.Writer,1325 interface: std.Io.Writer,
13001326
1301 pub const Mode = Reader.Mode;1327 pub const Mode = Reader.Mode;
13021328
...@@ -1333,13 +1359,13 @@ pub const Writer = struct {...@@ -1333,13 +1359,13 @@ pub const Writer = struct {
1333 };1359 };
1334 }1360 }
13351361
1336 pub fn initInterface(buffer: []u8) std.io.Writer {1362 pub fn initInterface(buffer: []u8) std.Io.Writer {
1337 return .{1363 return .{
1338 .vtable = &.{1364 .vtable = &.{
1339 .drain = drain,1365 .drain = drain,
1340 .sendFile = switch (builtin.zig_backend) {1366 .sendFile = switch (builtin.zig_backend) {
1341 else => sendFile,1367 else => sendFile,
1342 .stage2_aarch64 => std.io.Writer.unimplementedSendFile,1368 .stage2_aarch64 => std.Io.Writer.unimplementedSendFile,
1343 },1369 },
1344 },1370 },
1345 .buffer = buffer,1371 .buffer = buffer,
...@@ -1357,7 +1383,7 @@ pub const Writer = struct {...@@ -1357,7 +1383,7 @@ pub const Writer = struct {
1357 };1383 };
1358 }1384 }
13591385
1360 pub fn drain(io_w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {1386 pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
1361 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));1387 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
1362 const handle = w.file.handle;1388 const handle = w.file.handle;
1363 const buffered = io_w.buffered();1389 const buffered = io_w.buffered();
...@@ -1507,10 +1533,10 @@ pub const Writer = struct {...@@ -1507,10 +1533,10 @@ pub const Writer = struct {
1507 }1533 }
15081534
1509 pub fn sendFile(1535 pub fn sendFile(
1510 io_w: *std.io.Writer,1536 io_w: *std.Io.Writer,
1511 file_reader: *Reader,1537 file_reader: *Reader,
1512 limit: std.io.Limit,1538 limit: std.Io.Limit,
1513 ) std.io.Writer.FileError!usize {1539 ) std.Io.Writer.FileError!usize {
1514 const reader_buffered = file_reader.interface.buffered();1540 const reader_buffered = file_reader.interface.buffered();
1515 if (reader_buffered.len >= @intFromEnum(limit))1541 if (reader_buffered.len >= @intFromEnum(limit))
1516 return sendFileBuffered(io_w, file_reader, reader_buffered);1542 return sendFileBuffered(io_w, file_reader, reader_buffered);
...@@ -1772,10 +1798,10 @@ pub const Writer = struct {...@@ -1772,10 +1798,10 @@ pub const Writer = struct {
1772 }1798 }
17731799
1774 fn sendFileBuffered(1800 fn sendFileBuffered(
1775 io_w: *std.io.Writer,1801 io_w: *std.Io.Writer,
1776 file_reader: *Reader,1802 file_reader: *Reader,
1777 reader_buffered: []const u8,1803 reader_buffered: []const u8,
1778 ) std.io.Writer.FileError!usize {1804 ) std.Io.Writer.FileError!usize {
1779 const n = try drain(io_w, &.{reader_buffered}, 1);1805 const n = try drain(io_w, &.{reader_buffered}, 1);
1780 file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed;1806 file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed;
1781 return n;1807 return n;
...@@ -1798,7 +1824,7 @@ pub const Writer = struct {...@@ -1798,7 +1824,7 @@ pub const Writer = struct {
1798 }1824 }
1799 }1825 }
18001826
1801 pub const EndError = SetEndPosError || std.io.Writer.Error;1827 pub const EndError = SetEndPosError || std.Io.Writer.Error;
18021828
1803 /// Flushes any buffered data and sets the end position of the file.1829 /// Flushes any buffered data and sets the end position of the file.
1804 ///1830 ///
lib/std/hash.zig+2-3
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const adler = @import("hash/adler.zig");1pub const Adler32 = @import("hash/Adler32.zig");
2pub const Adler32 = adler.Adler32;
32
4const auto_hash = @import("hash/auto_hash.zig");3const auto_hash = @import("hash/auto_hash.zig");
5pub const autoHash = auto_hash.autoHash;4pub const autoHash = auto_hash.autoHash;
...@@ -115,7 +114,7 @@ test int {...@@ -115,7 +114,7 @@ test int {
115}114}
116115
117test {116test {
118 _ = adler;117 _ = Adler32;
119 _ = auto_hash;118 _ = auto_hash;
120 _ = crc;119 _ = crc;
121 _ = fnv;120 _ = fnv;
lib/std/hash/Adler32.zig created+117
...@@ -0,0 +1,117 @@
1//! https://tools.ietf.org/html/rfc1950#section-9
2//! https://github.com/madler/zlib/blob/master/adler32.c
3
4const Adler32 = @This();
5const std = @import("std");
6const testing = std.testing;
7
8adler: u32 = 1,
9
10pub fn permute(state: u32, input: []const u8) u32 {
11 const base = 65521;
12 const nmax = 5552;
13
14 var s1 = state & 0xffff;
15 var s2 = (state >> 16) & 0xffff;
16
17 if (input.len == 1) {
18 s1 +%= input[0];
19 if (s1 >= base) {
20 s1 -= base;
21 }
22 s2 +%= s1;
23 if (s2 >= base) {
24 s2 -= base;
25 }
26 } else if (input.len < 16) {
27 for (input) |b| {
28 s1 +%= b;
29 s2 +%= s1;
30 }
31 if (s1 >= base) {
32 s1 -= base;
33 }
34
35 s2 %= base;
36 } else {
37 const n = nmax / 16; // note: 16 | nmax
38
39 var i: usize = 0;
40
41 while (i + nmax <= input.len) {
42 var rounds: usize = 0;
43 while (rounds < n) : (rounds += 1) {
44 comptime var j: usize = 0;
45 inline while (j < 16) : (j += 1) {
46 s1 +%= input[i + j];
47 s2 +%= s1;
48 }
49 i += 16;
50 }
51
52 s1 %= base;
53 s2 %= base;
54 }
55
56 if (i < input.len) {
57 while (i + 16 <= input.len) : (i += 16) {
58 comptime var j: usize = 0;
59 inline while (j < 16) : (j += 1) {
60 s1 +%= input[i + j];
61 s2 +%= s1;
62 }
63 }
64 while (i < input.len) : (i += 1) {
65 s1 +%= input[i];
66 s2 +%= s1;
67 }
68
69 s1 %= base;
70 s2 %= base;
71 }
72 }
73
74 return s1 | (s2 << 16);
75}
76
77pub fn update(a: *Adler32, input: []const u8) void {
78 a.adler = permute(a.adler, input);
79}
80
81pub fn hash(input: []const u8) u32 {
82 return permute(1, input);
83}
84
85test "sanity" {
86 try testing.expectEqual(@as(u32, 0x620062), hash("a"));
87 try testing.expectEqual(@as(u32, 0xbc002ed), hash("example"));
88}
89
90test "long" {
91 const long1 = [_]u8{1} ** 1024;
92 try testing.expectEqual(@as(u32, 0x06780401), hash(long1[0..]));
93
94 const long2 = [_]u8{1} ** 1025;
95 try testing.expectEqual(@as(u32, 0x0a7a0402), hash(long2[0..]));
96}
97
98test "very long" {
99 const long = [_]u8{1} ** 5553;
100 try testing.expectEqual(@as(u32, 0x707f15b2), hash(long[0..]));
101}
102
103test "very long with variation" {
104 const long = comptime blk: {
105 @setEvalBranchQuota(7000);
106 var result: [6000]u8 = undefined;
107
108 var i: usize = 0;
109 while (i < result.len) : (i += 1) {
110 result[i] = @as(u8, @truncate(i));
111 }
112
113 break :blk result;
114 };
115
116 try testing.expectEqual(@as(u32, 0x5af38d6e), hash(long[0..]));
117}
lib/std/hash/adler.zig deleted-134
...@@ -1,134 +0,0 @@
1// Adler32 checksum.
2//
3// https://tools.ietf.org/html/rfc1950#section-9
4// https://github.com/madler/zlib/blob/master/adler32.c
5
6const std = @import("std");
7const testing = std.testing;
8
9pub const Adler32 = struct {
10 const base = 65521;
11 const nmax = 5552;
12
13 adler: u32,
14
15 pub fn init() Adler32 {
16 return Adler32{ .adler = 1 };
17 }
18
19 // This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
20 // buffer inputs and should be much quicker.
21 pub fn update(self: *Adler32, input: []const u8) void {
22 var s1 = self.adler & 0xffff;
23 var s2 = (self.adler >> 16) & 0xffff;
24
25 if (input.len == 1) {
26 s1 +%= input[0];
27 if (s1 >= base) {
28 s1 -= base;
29 }
30 s2 +%= s1;
31 if (s2 >= base) {
32 s2 -= base;
33 }
34 } else if (input.len < 16) {
35 for (input) |b| {
36 s1 +%= b;
37 s2 +%= s1;
38 }
39 if (s1 >= base) {
40 s1 -= base;
41 }
42
43 s2 %= base;
44 } else {
45 const n = nmax / 16; // note: 16 | nmax
46
47 var i: usize = 0;
48
49 while (i + nmax <= input.len) {
50 var rounds: usize = 0;
51 while (rounds < n) : (rounds += 1) {
52 comptime var j: usize = 0;
53 inline while (j < 16) : (j += 1) {
54 s1 +%= input[i + j];
55 s2 +%= s1;
56 }
57 i += 16;
58 }
59
60 s1 %= base;
61 s2 %= base;
62 }
63
64 if (i < input.len) {
65 while (i + 16 <= input.len) : (i += 16) {
66 comptime var j: usize = 0;
67 inline while (j < 16) : (j += 1) {
68 s1 +%= input[i + j];
69 s2 +%= s1;
70 }
71 }
72 while (i < input.len) : (i += 1) {
73 s1 +%= input[i];
74 s2 +%= s1;
75 }
76
77 s1 %= base;
78 s2 %= base;
79 }
80 }
81
82 self.adler = s1 | (s2 << 16);
83 }
84
85 pub fn final(self: *Adler32) u32 {
86 return self.adler;
87 }
88
89 pub fn hash(input: []const u8) u32 {
90 var c = Adler32.init();
91 c.update(input);
92 return c.final();
93 }
94};
95
96test "adler32 sanity" {
97 try testing.expectEqual(@as(u32, 0x620062), Adler32.hash("a"));
98 try testing.expectEqual(@as(u32, 0xbc002ed), Adler32.hash("example"));
99}
100
101test "adler32 long" {
102 const long1 = [_]u8{1} ** 1024;
103 try testing.expectEqual(@as(u32, 0x06780401), Adler32.hash(long1[0..]));
104
105 const long2 = [_]u8{1} ** 1025;
106 try testing.expectEqual(@as(u32, 0x0a7a0402), Adler32.hash(long2[0..]));
107}
108
109test "adler32 very long" {
110 const long = [_]u8{1} ** 5553;
111 try testing.expectEqual(@as(u32, 0x707f15b2), Adler32.hash(long[0..]));
112}
113
114test "adler32 very long with variation" {
115 const long = comptime blk: {
116 @setEvalBranchQuota(7000);
117 var result: [6000]u8 = undefined;
118
119 var i: usize = 0;
120 while (i < result.len) : (i += 1) {
121 result[i] = @as(u8, @truncate(i));
122 }
123
124 break :blk result;
125 };
126
127 try testing.expectEqual(@as(u32, 0x5af38d6e), std.hash.Adler32.hash(long[0..]));
128}
129
130const verify = @import("verify.zig");
131
132test "adler32 iterative" {
133 try verify.iterativeApi(Adler32);
134}
lib/std/hash/verify.zig+1-1
...@@ -45,7 +45,7 @@ pub fn smhasher(comptime hash_fn: anytype) u32 {...@@ -45,7 +45,7 @@ pub fn smhasher(comptime hash_fn: anytype) u32 {
4545
46pub fn iterativeApi(comptime Hash: anytype) !void {46pub fn iterativeApi(comptime Hash: anytype) !void {
47 // Sum(1..32) = 52847 // Sum(1..32) = 528
48 var buf: [528]u8 = [_]u8{0} ** 528;48 var buf: [528]u8 = @splat(0);
49 var len: usize = 0;49 var len: usize = 0;
50 const seed = 0;50 const seed = 0;
5151
lib/std/heap.zig+1-1
...@@ -146,7 +146,7 @@ const CAllocator = struct {...@@ -146,7 +146,7 @@ const CAllocator = struct {
146 else {};146 else {};
147147
148 pub const supports_posix_memalign = switch (builtin.os.tag) {148 pub const supports_posix_memalign = switch (builtin.os.tag) {
149 .dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .linux, .macos, .ios, .tvos, .watchos, .visionos => true,149 .dragonfly, .netbsd, .freebsd, .solaris, .openbsd, .linux, .macos, .ios, .tvos, .watchos, .visionos, .serenity => true,
150 else => false,150 else => false,
151 };151 };
152152
lib/std/math.zig+7-3
...@@ -1358,11 +1358,15 @@ pub fn lossyCast(comptime T: type, value: anytype) T {...@@ -1358,11 +1358,15 @@ pub fn lossyCast(comptime T: type, value: anytype) T {
1358 }1358 }
1359 },1359 },
1360 .float, .comptime_float => {1360 .float, .comptime_float => {
1361 // In extreme cases, we probably need a language enhancement to be able to
1362 // specify a rounding mode here to prevent `@intFromFloat` panics.
1363 const max: @TypeOf(value) = @floatFromInt(maxInt(T));
1364 const min: @TypeOf(value) = @floatFromInt(minInt(T));
1361 if (isNan(value)) {1365 if (isNan(value)) {
1362 return 0;1366 return 0;
1363 } else if (value >= maxInt(T)) {1367 } else if (value >= max) {
1364 return maxInt(T);1368 return maxInt(T);
1365 } else if (value <= minInt(T)) {1369 } else if (value <= min) {
1366 return minInt(T);1370 return minInt(T);
1367 } else {1371 } else {
1368 return @intFromFloat(value);1372 return @intFromFloat(value);
...@@ -1379,7 +1383,7 @@ test lossyCast {...@@ -1379,7 +1383,7 @@ test lossyCast {
1379 try testing.expect(lossyCast(i16, 70000.0) == @as(i16, 32767));1383 try testing.expect(lossyCast(i16, 70000.0) == @as(i16, 32767));
1380 try testing.expect(lossyCast(u32, @as(i16, -255)) == @as(u32, 0));1384 try testing.expect(lossyCast(u32, @as(i16, -255)) == @as(u32, 0));
1381 try testing.expect(lossyCast(i9, @as(u32, 200)) == @as(i9, 200));1385 try testing.expect(lossyCast(i9, @as(u32, 200)) == @as(i9, 200));
1382 try testing.expect(lossyCast(u32, @as(f32, maxInt(u32))) == maxInt(u32));1386 try testing.expect(lossyCast(u32, @as(f32, @floatFromInt(maxInt(u32)))) == maxInt(u32));
1383 try testing.expect(lossyCast(u32, nan(f32)) == 0);1387 try testing.expect(lossyCast(u32, nan(f32)) == 0);
1384}1388}
13851389
lib/std/math/gamma.zig+16-16
...@@ -189,19 +189,19 @@ fn series(comptime T: type, abs: T) T {...@@ -189,19 +189,19 @@ fn series(comptime T: type, abs: T) T {
189 2.5066282746310002701649081771338373386264310793408,189 2.5066282746310002701649081771338373386264310793408,
190 };190 };
191 const denominator = [_]T{191 const denominator = [_]T{
192 0,192 0.0,
193 39916800,193 39916800.0,
194 120543840,194 120543840.0,
195 150917976,195 150917976.0,
196 105258076,196 105258076.0,
197 45995730,197 45995730.0,
198 13339535,198 13339535.0,
199 2637558,199 2637558.0,
200 357423,200 357423.0,
201 32670,201 32670.0,
202 1925,202 1925.0,
203 66,203 66.0,
204 1,204 1.0,
205 };205 };
206 var num: T = 0;206 var num: T = 0;
207 var den: T = 0;207 var den: T = 0;
...@@ -244,9 +244,9 @@ const expectApproxEqRel = std.testing.expectApproxEqRel;...@@ -244,9 +244,9 @@ const expectApproxEqRel = std.testing.expectApproxEqRel;
244test gamma {244test gamma {
245 inline for (&.{ f32, f64 }) |T| {245 inline for (&.{ f32, f64 }) |T| {
246 const eps = @sqrt(std.math.floatEps(T));246 const eps = @sqrt(std.math.floatEps(T));
247 try expectApproxEqRel(@as(T, 120), gamma(T, 6), eps);247 try expectApproxEqRel(@as(T, 120.0), gamma(T, 6), eps);
248 try expectApproxEqRel(@as(T, 362880), gamma(T, 10), eps);248 try expectApproxEqRel(@as(T, 362880.0), gamma(T, 10), eps);
249 try expectApproxEqRel(@as(T, 6402373705728000), gamma(T, 19), eps);249 try expectApproxEqRel(@as(T, 6402373705728000.0), gamma(T, 19), eps);
250250
251 try expectApproxEqRel(@as(T, 332.7590766955334570), gamma(T, 0.003), eps);251 try expectApproxEqRel(@as(T, 332.7590766955334570), gamma(T, 0.003), eps);
252 try expectApproxEqRel(@as(T, 1.377260301981044573), gamma(T, 0.654), eps);252 try expectApproxEqRel(@as(T, 1.377260301981044573), gamma(T, 0.654), eps);
lib/std/math/modf.zig+1-1
...@@ -74,7 +74,7 @@ fn ModfTests(comptime T: type) type {...@@ -74,7 +74,7 @@ fn ModfTests(comptime T: type) type {
74 r = modf(@as(T, 43874.3));74 r = modf(@as(T, 43874.3));
75 try expectEqual(43874.0, r.ipart);75 try expectEqual(43874.0, r.ipart);
76 // account for precision error76 // account for precision error
77 const expected_b: T = 43874.3 - @as(T, 43874);77 const expected_b: T = 43874.3 - @as(T, 43874.0);
78 try expectApproxEqAbs(expected_b, r.fpart, epsilon);78 try expectApproxEqAbs(expected_b, r.fpart, epsilon);
7979
80 r = modf(@as(T, 1234.340780));80 r = modf(@as(T, 1234.340780));
lib/std/math/pow.zig+2-2
...@@ -192,8 +192,8 @@ fn isOddInteger(x: f64) bool {...@@ -192,8 +192,8 @@ fn isOddInteger(x: f64) bool {
192}192}
193193
194test isOddInteger {194test isOddInteger {
195 try expect(isOddInteger(math.maxInt(i64) * 2) == false);195 try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2)) == false);
196 try expect(isOddInteger(math.maxInt(i64) * 2 + 1) == false);196 try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2 + 1)) == false);
197 try expect(isOddInteger(1 << 53) == false);197 try expect(isOddInteger(1 << 53) == false);
198 try expect(isOddInteger(12.0) == false);198 try expect(isOddInteger(12.0) == false);
199 try expect(isOddInteger(15.0) == true);199 try expect(isOddInteger(15.0) == true);
lib/std/net.zig+35-18
...@@ -7,7 +7,7 @@ const net = @This();...@@ -7,7 +7,7 @@ const net = @This();
7const mem = std.mem;7const mem = std.mem;
8const posix = std.posix;8const posix = std.posix;
9const fs = std.fs;9const fs = std.fs;
10const io = std.io;10const Io = std.Io;
11const native_endian = builtin.target.cpu.arch.endian();11const native_endian = builtin.target.cpu.arch.endian();
12const native_os = builtin.os.tag;12const native_os = builtin.os.tag;
13const windows = std.os.windows;13const windows = std.os.windows;
...@@ -165,7 +165,7 @@ pub const Address = extern union {...@@ -165,7 +165,7 @@ pub const Address = extern union {
165 }165 }
166 }166 }
167167
168 pub fn format(self: Address, w: *std.io.Writer) std.io.Writer.Error!void {168 pub fn format(self: Address, w: *Io.Writer) Io.Writer.Error!void {
169 switch (self.any.family) {169 switch (self.any.family) {
170 posix.AF.INET => try self.in.format(w),170 posix.AF.INET => try self.in.format(w),
171 posix.AF.INET6 => try self.in6.format(w),171 posix.AF.INET6 => try self.in6.format(w),
...@@ -342,7 +342,7 @@ pub const Ip4Address = extern struct {...@@ -342,7 +342,7 @@ pub const Ip4Address = extern struct {
342 self.sa.port = mem.nativeToBig(u16, port);342 self.sa.port = mem.nativeToBig(u16, port);
343 }343 }
344344
345 pub fn format(self: Ip4Address, w: *std.io.Writer) std.io.Writer.Error!void {345 pub fn format(self: Ip4Address, w: *Io.Writer) Io.Writer.Error!void {
346 const bytes: *const [4]u8 = @ptrCast(&self.sa.addr);346 const bytes: *const [4]u8 = @ptrCast(&self.sa.addr);
347 try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], self.getPort() });347 try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], self.getPort() });
348 }348 }
...@@ -633,7 +633,7 @@ pub const Ip6Address = extern struct {...@@ -633,7 +633,7 @@ pub const Ip6Address = extern struct {
633 self.sa.port = mem.nativeToBig(u16, port);633 self.sa.port = mem.nativeToBig(u16, port);
634 }634 }
635635
636 pub fn format(self: Ip6Address, w: *std.io.Writer) std.io.Writer.Error!void {636 pub fn format(self: Ip6Address, w: *Io.Writer) Io.Writer.Error!void {
637 const port = mem.bigToNative(u16, self.sa.port);637 const port = mem.bigToNative(u16, self.sa.port);
638 if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {638 if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
639 try w.print("[::ffff:{d}.{d}.{d}.{d}]:{d}", .{639 try w.print("[::ffff:{d}.{d}.{d}.{d}]:{d}", .{
...@@ -1348,7 +1348,7 @@ fn parseHosts(...@@ -1348,7 +1348,7 @@ fn parseHosts(
1348 name: []const u8,1348 name: []const u8,
1349 family: posix.sa_family_t,1349 family: posix.sa_family_t,
1350 port: u16,1350 port: u16,
1351 br: *io.Reader,1351 br: *Io.Reader,
1352) error{ OutOfMemory, ReadFailed }!void {1352) error{ OutOfMemory, ReadFailed }!void {
1353 while (true) {1353 while (true) {
1354 const line = br.takeDelimiterExclusive('\n') catch |err| switch (err) {1354 const line = br.takeDelimiterExclusive('\n') catch |err| switch (err) {
...@@ -1402,7 +1402,7 @@ test parseHosts {...@@ -1402,7 +1402,7 @@ test parseHosts {
1402 // TODO parsing addresses should not have OS dependencies1402 // TODO parsing addresses should not have OS dependencies
1403 return error.SkipZigTest;1403 return error.SkipZigTest;
1404 }1404 }
1405 var reader: std.io.Reader = .fixed(1405 var reader: Io.Reader = .fixed(
1406 \\127.0.0.1 localhost1406 \\127.0.0.1 localhost
1407 \\::1 localhost1407 \\::1 localhost
1408 \\127.0.0.2 abcd1408 \\127.0.0.2 abcd
...@@ -1583,7 +1583,7 @@ const ResolvConf = struct {...@@ -1583,7 +1583,7 @@ const ResolvConf = struct {
1583 const Directive = enum { options, nameserver, domain, search };1583 const Directive = enum { options, nameserver, domain, search };
1584 const Option = enum { ndots, attempts, timeout };1584 const Option = enum { ndots, attempts, timeout };
15851585
1586 fn parse(rc: *ResolvConf, reader: *io.Reader) !void {1586 fn parse(rc: *ResolvConf, reader: *Io.Reader) !void {
1587 const gpa = rc.gpa;1587 const gpa = rc.gpa;
1588 while (reader.takeSentinel('\n')) |line_with_comment| {1588 while (reader.takeSentinel('\n')) |line_with_comment| {
1589 const line = line: {1589 const line = line: {
...@@ -1894,7 +1894,7 @@ pub const Stream = struct {...@@ -1894,7 +1894,7 @@ pub const Stream = struct {
1894 pub const Reader = switch (native_os) {1894 pub const Reader = switch (native_os) {
1895 .windows => struct {1895 .windows => struct {
1896 /// Use `interface` for portable code.1896 /// Use `interface` for portable code.
1897 interface_state: io.Reader,1897 interface_state: Io.Reader,
1898 /// Use `getStream` for portable code.1898 /// Use `getStream` for portable code.
1899 net_stream: Stream,1899 net_stream: Stream,
1900 /// Use `getError` for portable code.1900 /// Use `getError` for portable code.
...@@ -1910,14 +1910,17 @@ pub const Stream = struct {...@@ -1910,14 +1910,17 @@ pub const Stream = struct {
1910 return r.error_state;1910 return r.error_state;
1911 }1911 }
19121912
1913 pub fn interface(r: *Reader) *io.Reader {1913 pub fn interface(r: *Reader) *Io.Reader {
1914 return &r.interface_state;1914 return &r.interface_state;
1915 }1915 }
19161916
1917 pub fn init(net_stream: Stream, buffer: []u8) Reader {1917 pub fn init(net_stream: Stream, buffer: []u8) Reader {
1918 return .{1918 return .{
1919 .interface_state = .{1919 .interface_state = .{
1920 .vtable = &.{ .stream = stream },1920 .vtable = &.{
1921 .stream = stream,
1922 .readVec = readVec,
1923 },
1921 .buffer = buffer,1924 .buffer = buffer,
1922 .seek = 0,1925 .seek = 0,
1923 .end = 0,1926 .end = 0,
...@@ -1927,16 +1930,30 @@ pub const Stream = struct {...@@ -1927,16 +1930,30 @@ pub const Stream = struct {
1927 };1930 };
1928 }1931 }
19291932
1930 fn stream(io_r: *io.Reader, io_w: *io.Writer, limit: io.Limit) io.Reader.StreamError!usize {1933 fn stream(io_r: *Io.Reader, io_w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize {
1934 const dest = limit.slice(try io_w.writableSliceGreedy(1));
1935 var bufs: [1][]u8 = .{dest};
1936 const n = try readVec(io_r, &bufs);
1937 io_w.advance(n);
1938 return n;
1939 }
1940
1941 fn readVec(io_r: *std.Io.Reader, data: [][]u8) Io.Reader.Error!usize {
1931 const r: *Reader = @alignCast(@fieldParentPtr("interface_state", io_r));1942 const r: *Reader = @alignCast(@fieldParentPtr("interface_state", io_r));
1932 var iovecs: [max_buffers_len]windows.ws2_32.WSABUF = undefined;1943 var iovecs: [max_buffers_len]windows.ws2_32.WSABUF = undefined;
1933 const bufs = try io_w.writableVectorWsa(&iovecs, limit);1944 const bufs_n, const data_size = try io_r.writableVectorWsa(&iovecs, data);
1945 const bufs = iovecs[0..bufs_n];
1934 assert(bufs[0].len != 0);1946 assert(bufs[0].len != 0);
1935 const n = streamBufs(r, bufs) catch |err| {1947 const n = streamBufs(r, bufs) catch |err| {
1936 r.error_state = err;1948 r.error_state = err;
1937 return error.ReadFailed;1949 return error.ReadFailed;
1938 };1950 };
1939 if (n == 0) return error.EndOfStream;1951 if (n == 0) return error.EndOfStream;
1952 if (n > data_size) {
1953 io_r.seek = 0;
1954 io_r.end = n - data_size;
1955 return data_size;
1956 }
1940 return n;1957 return n;
1941 }1958 }
19421959
...@@ -1968,7 +1985,7 @@ pub const Stream = struct {...@@ -1968,7 +1985,7 @@ pub const Stream = struct {
19681985
1969 pub const Error = ReadError;1986 pub const Error = ReadError;
19701987
1971 pub fn interface(r: *Reader) *io.Reader {1988 pub fn interface(r: *Reader) *Io.Reader {
1972 return &r.file_reader.interface;1989 return &r.file_reader.interface;
1973 }1990 }
19741991
...@@ -1996,7 +2013,7 @@ pub const Stream = struct {...@@ -1996,7 +2013,7 @@ pub const Stream = struct {
1996 pub const Writer = switch (native_os) {2013 pub const Writer = switch (native_os) {
1997 .windows => struct {2014 .windows => struct {
1998 /// This field is present on all systems.2015 /// This field is present on all systems.
1999 interface: io.Writer,2016 interface: Io.Writer,
2000 /// Use `getStream` for cross-platform support.2017 /// Use `getStream` for cross-platform support.
2001 stream: Stream,2018 stream: Stream,
2002 /// This field is present on all systems.2019 /// This field is present on all systems.
...@@ -2034,7 +2051,7 @@ pub const Stream = struct {...@@ -2034,7 +2051,7 @@ pub const Stream = struct {
2034 }2051 }
2035 }2052 }
20362053
2037 fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize {2054 fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
2038 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));2055 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
2039 const buffered = io_w.buffered();2056 const buffered = io_w.buffered();
2040 comptime assert(native_os == .windows);2057 comptime assert(native_os == .windows);
...@@ -2106,7 +2123,7 @@ pub const Stream = struct {...@@ -2106,7 +2123,7 @@ pub const Stream = struct {
2106 },2123 },
2107 else => struct {2124 else => struct {
2108 /// This field is present on all systems.2125 /// This field is present on all systems.
2109 interface: io.Writer,2126 interface: Io.Writer,
21102127
2111 err: ?Error = null,2128 err: ?Error = null,
2112 file_writer: File.Writer,2129 file_writer: File.Writer,
...@@ -2138,7 +2155,7 @@ pub const Stream = struct {...@@ -2138,7 +2155,7 @@ pub const Stream = struct {
2138 i.* += 1;2155 i.* += 1;
2139 }2156 }
21402157
2141 fn drain(io_w: *io.Writer, data: []const []const u8, splat: usize) io.Writer.Error!usize {2158 fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
2142 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));2159 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
2143 const buffered = io_w.buffered();2160 const buffered = io_w.buffered();
2144 var iovecs: [max_buffers_len]posix.iovec_const = undefined;2161 var iovecs: [max_buffers_len]posix.iovec_const = undefined;
...@@ -2190,7 +2207,7 @@ pub const Stream = struct {...@@ -2190,7 +2207,7 @@ pub const Stream = struct {
2190 });2207 });
2191 }2208 }
21922209
2193 fn sendFile(io_w: *io.Writer, file_reader: *File.Reader, limit: io.Limit) io.Writer.FileError!usize {2210 fn sendFile(io_w: *Io.Writer, file_reader: *File.Reader, limit: Io.Limit) Io.Writer.FileError!usize {
2194 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));2211 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
2195 const n = try w.file_writer.interface.sendFileHeader(io_w.buffered(), file_reader, limit);2212 const n = try w.file_writer.interface.sendFileHeader(io_w.buffered(), file_reader, limit);
2196 return io_w.consume(n);2213 return io_w.consume(n);
lib/std/posix.zig+3-1
...@@ -204,6 +204,7 @@ pub const ACCMODE = switch (native_os) {...@@ -204,6 +204,7 @@ pub const ACCMODE = switch (native_os) {
204 // implements this suggestion.204 // implements this suggestion.
205 // https://github.com/SerenityOS/serenity/blob/4adc51fdf6af7d50679c48b39362e062f5a3b2cb/Kernel/API/POSIX/fcntl.h#L28-L30205 // https://github.com/SerenityOS/serenity/blob/4adc51fdf6af7d50679c48b39362e062f5a3b2cb/Kernel/API/POSIX/fcntl.h#L28-L30
206 .serenity => enum(u2) {206 .serenity => enum(u2) {
207 NONE = 0,
207 RDONLY = 1,208 RDONLY = 1,
208 WRONLY = 2,209 WRONLY = 2,
209 RDWR = 3,210 RDWR = 3,
...@@ -1128,8 +1129,9 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -1128,8 +1129,9 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
1128/// * Windows1129/// * Windows
1129/// On these systems, the read races with concurrent writes to the same file descriptor.1130/// On these systems, the read races with concurrent writes to the same file descriptor.
1130pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {1131pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
1132 // NOTE: serenity does not have preadv but it *does* have pwritev.
1131 const have_pread_but_not_preadv = switch (native_os) {1133 const have_pread_but_not_preadv = switch (native_os) {
1132 .windows, .macos, .ios, .watchos, .tvos, .visionos, .haiku => true,1134 .windows, .macos, .ios, .watchos, .tvos, .visionos, .haiku, .serenity => true,
1133 else => false,1135 else => false,
1134 };1136 };
1135 if (have_pread_but_not_preadv) {1137 if (have_pread_but_not_preadv) {
lib/std/start.zig+1-1
...@@ -626,7 +626,6 @@ pub inline fn callMain() u8 {...@@ -626,7 +626,6 @@ pub inline fn callMain() u8 {
626626
627 const result = root.main() catch |err| {627 const result = root.main() catch |err| {
628 switch (builtin.zig_backend) {628 switch (builtin.zig_backend) {
629 .stage2_aarch64,
630 .stage2_powerpc,629 .stage2_powerpc,
631 .stage2_riscv64,630 .stage2_riscv64,
632 => {631 => {
...@@ -700,6 +699,7 @@ fn maybeIgnoreSigpipe() void {...@@ -700,6 +699,7 @@ fn maybeIgnoreSigpipe() void {
700 .visionos,699 .visionos,
701 .dragonfly,700 .dragonfly,
702 .freebsd,701 .freebsd,
702 .serenity,
703 => true,703 => true,
704704
705 else => false,705 else => false,
lib/std/zig.zig+30-9
...@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {...@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {
321 try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));321 try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));
322 try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));322 try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));
323 }323 }
324
325 pub fn format(id: BuildId, writer: *std.io.Writer) std.io.Writer.Error!void {
326 switch (id) {
327 .none, .fast, .uuid, .sha1, .md5 => {
328 try writer.writeAll(@tagName(id));
329 },
330 .hexstring => |hs| {
331 try writer.print("0x{x}", .{hs.toSlice()});
332 },
333 }
334 }
335
336 test format {
337 try std.testing.expectFmt("none", "{f}", .{@as(BuildId, .none)});
338 try std.testing.expectFmt("fast", "{f}", .{@as(BuildId, .fast)});
339 try std.testing.expectFmt("uuid", "{f}", .{@as(BuildId, .uuid)});
340 try std.testing.expectFmt("sha1", "{f}", .{@as(BuildId, .sha1)});
341 try std.testing.expectFmt("md5", "{f}", .{@as(BuildId, .md5)});
342 try std.testing.expectFmt("0x", "{f}", .{BuildId.initHexString("")});
343 try std.testing.expectFmt("0x1234cdef", "{f}", .{BuildId.initHexString("\x12\x34\xcd\xef")});
344 }
324};345};
325346
326pub const LtoMode = enum { none, full, thin };347pub const LtoMode = enum { none, full, thin };
...@@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![...@@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
364/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.385/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
365///386///
366/// See also `fmtIdFlags`.387/// See also `fmtIdFlags`.
367pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {388pub fn fmtId(bytes: []const u8) FormatId {
368 return .{ .data = .{ .bytes = bytes, .flags = .{} } };389 return .{ .bytes = bytes, .flags = .{} };
369}390}
370391
371/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.392/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
372///393///
373/// See also `fmtId`.394/// See also `fmtId`.
374pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) {395pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) FormatId {
375 return .{ .data = .{ .bytes = bytes, .flags = flags } };396 return .{ .bytes = bytes, .flags = flags };
376}397}
377398
378pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {399pub fn fmtIdPU(bytes: []const u8) FormatId {
379 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } };400 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } };
380}401}
381402
382pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {403pub fn fmtIdP(bytes: []const u8) FormatId {
383 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } };404 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true } };
384}405}
385406
386test fmtId {407test fmtId {
...@@ -426,7 +447,7 @@ pub const FormatId = struct {...@@ -426,7 +447,7 @@ pub const FormatId = struct {
426 };447 };
427448
428 /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed.449 /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed.
429 fn render(ctx: FormatId, writer: *Writer) Writer.Error!void {450 pub fn format(ctx: FormatId, writer: *Writer) Writer.Error!void {
430 const bytes = ctx.bytes;451 const bytes = ctx.bytes;
431 if (isValidId(bytes) and452 if (isValidId(bytes) and
432 (ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and453 (ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and
lib/std/zig/Ast.zig+2-2
...@@ -3361,7 +3361,7 @@ pub const Node = struct {...@@ -3361,7 +3361,7 @@ pub const Node = struct {
3361 /// The `main_token` might be a ** token, which is shared with a3361 /// The `main_token` might be a ** token, which is shared with a
3362 /// parent/child pointer type and may require special handling.3362 /// parent/child pointer type and may require special handling.
3363 ptr_type_sentinel,3363 ptr_type_sentinel,
3364 /// The `data` field is a `.opt_node_and_node`:3364 /// The `data` field is a `.extra_and_node`:
3365 /// 1. a `ExtraIndex` to `PtrType`.3365 /// 1. a `ExtraIndex` to `PtrType`.
3366 /// 2. a `Node.Index` to the element type expression.3366 /// 2. a `Node.Index` to the element type expression.
3367 ///3367 ///
...@@ -3370,7 +3370,7 @@ pub const Node = struct {...@@ -3370,7 +3370,7 @@ pub const Node = struct {
3370 /// The `main_token` might be a ** token, which is shared with a3370 /// The `main_token` might be a ** token, which is shared with a
3371 /// parent/child pointer type and may require special handling.3371 /// parent/child pointer type and may require special handling.
3372 ptr_type,3372 ptr_type,
3373 /// The `data` field is a `.opt_node_and_node`:3373 /// The `data` field is a `.extra_and_node`:
3374 /// 1. a `ExtraIndex` to `PtrTypeBitRange`.3374 /// 1. a `ExtraIndex` to `PtrTypeBitRange`.
3375 /// 2. a `Node.Index` to the element type expression.3375 /// 2. a `Node.Index` to the element type expression.
3376 ///3376 ///
lib/std/zip.zig+45-43
...@@ -7,8 +7,9 @@ const builtin = @import("builtin");...@@ -7,8 +7,9 @@ const builtin = @import("builtin");
7const std = @import("std");7const std = @import("std");
8const File = std.fs.File;8const File = std.fs.File;
9const is_le = builtin.target.cpu.arch.endian() == .little;9const is_le = builtin.target.cpu.arch.endian() == .little;
10const Writer = std.io.Writer;10const Writer = std.Io.Writer;
11const Reader = std.io.Reader;11const Reader = std.Io.Reader;
12const flate = std.compress.flate;
1213
13pub const CompressionMethod = enum(u16) {14pub const CompressionMethod = enum(u16) {
14 store = 0,15 store = 0,
...@@ -117,6 +118,7 @@ pub const EndRecord = extern struct {...@@ -117,6 +118,7 @@ pub const EndRecord = extern struct {
117 pub const FindFileError = File.GetEndPosError || File.SeekError || File.ReadError || error{118 pub const FindFileError = File.GetEndPosError || File.SeekError || File.ReadError || error{
118 ZipNoEndRecord,119 ZipNoEndRecord,
119 EndOfStream,120 EndOfStream,
121 ReadFailed,
120 };122 };
121123
122 pub fn findFile(fr: *File.Reader) FindFileError!EndRecord {124 pub fn findFile(fr: *File.Reader) FindFileError!EndRecord {
...@@ -137,8 +139,7 @@ pub const EndRecord = extern struct {...@@ -137,8 +139,7 @@ pub const EndRecord = extern struct {
137139
138 try fr.seekTo(end_pos - @as(u64, new_loaded_len));140 try fr.seekTo(end_pos - @as(u64, new_loaded_len));
139 const read_buf: []u8 = buf[buf.len - new_loaded_len ..][0..read_len];141 const read_buf: []u8 = buf[buf.len - new_loaded_len ..][0..read_len];
140 var br = fr.interface().unbuffered();142 fr.interface.readSliceAll(read_buf) catch |err| switch (err) {
141 br.readSlice(read_buf) catch |err| switch (err) {
142 error.ReadFailed => return fr.err.?,143 error.ReadFailed => return fr.err.?,
143 error.EndOfStream => return error.EndOfStream,144 error.EndOfStream => return error.EndOfStream,
144 };145 };
...@@ -164,7 +165,7 @@ pub const EndRecord = extern struct {...@@ -164,7 +165,7 @@ pub const EndRecord = extern struct {
164pub const Decompress = struct {165pub const Decompress = struct {
165 interface: Reader,166 interface: Reader,
166 state: union {167 state: union {
167 inflate: std.compress.flate.Decompress,168 inflate: flate.Decompress,
168 store: *Reader,169 store: *Reader,
169 },170 },
170171
...@@ -201,7 +202,7 @@ pub const Decompress = struct {...@@ -201,7 +202,7 @@ pub const Decompress = struct {
201202
202 fn streamDeflate(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {203 fn streamDeflate(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {
203 const d: *Decompress = @fieldParentPtr("interface", r);204 const d: *Decompress = @fieldParentPtr("interface", r);
204 return std.compress.flate.Decompress.read(&d.inflate, w, limit);205 return flate.Decompress.read(&d.inflate, w, limit);
205 }206 }
206};207};
207208
...@@ -305,7 +306,7 @@ pub const Iterator = struct {...@@ -305,7 +306,7 @@ pub const Iterator = struct {
305 if (locator_end_offset > stream_len)306 if (locator_end_offset > stream_len)
306 return error.ZipTruncated;307 return error.ZipTruncated;
307 try input.seekTo(stream_len - locator_end_offset);308 try input.seekTo(stream_len - locator_end_offset);
308 const locator = input.interface.takeStructEndian(EndLocator64, .little) catch |err| switch (err) {309 const locator = input.interface.takeStruct(EndLocator64, .little) catch |err| switch (err) {
309 error.ReadFailed => return input.err.?,310 error.ReadFailed => return input.err.?,
310 error.EndOfStream => return error.EndOfStream,311 error.EndOfStream => return error.EndOfStream,
311 };312 };
...@@ -318,7 +319,7 @@ pub const Iterator = struct {...@@ -318,7 +319,7 @@ pub const Iterator = struct {
318319
319 try input.seekTo(locator.record_file_offset);320 try input.seekTo(locator.record_file_offset);
320321
321 const record64 = input.interface.takeStructEndian(EndRecord64, .little) catch |err| switch (err) {322 const record64 = input.interface.takeStruct(EndRecord64, .little) catch |err| switch (err) {
322 error.ReadFailed => return input.err.?,323 error.ReadFailed => return input.err.?,
323 error.EndOfStream => return error.EndOfStream,324 error.EndOfStream => return error.EndOfStream,
324 };325 };
...@@ -374,7 +375,7 @@ pub const Iterator = struct {...@@ -374,7 +375,7 @@ pub const Iterator = struct {
374 const header_zip_offset = self.cd_zip_offset + self.cd_record_offset;375 const header_zip_offset = self.cd_zip_offset + self.cd_record_offset;
375 const input = self.input;376 const input = self.input;
376 try input.seekTo(header_zip_offset);377 try input.seekTo(header_zip_offset);
377 const header = input.interface.takeStructEndian(CentralDirectoryFileHeader, .little) catch |err| switch (err) {378 const header = input.interface.takeStruct(CentralDirectoryFileHeader, .little) catch |err| switch (err) {
378 error.ReadFailed => return input.err.?,379 error.ReadFailed => return input.err.?,
379 error.EndOfStream => return error.EndOfStream,380 error.EndOfStream => return error.EndOfStream,
380 };381 };
...@@ -405,7 +406,7 @@ pub const Iterator = struct {...@@ -405,7 +406,7 @@ pub const Iterator = struct {
405 const extra = extra_buf[0..header.extra_len];406 const extra = extra_buf[0..header.extra_len];
406407
407 try input.seekTo(header_zip_offset + @sizeOf(CentralDirectoryFileHeader) + header.filename_len);408 try input.seekTo(header_zip_offset + @sizeOf(CentralDirectoryFileHeader) + header.filename_len);
408 input.interface.readSlice(extra) catch |err| switch (err) {409 input.interface.readSliceAll(extra) catch |err| switch (err) {
409 error.ReadFailed => return input.err.?,410 error.ReadFailed => return input.err.?,
410 error.EndOfStream => return error.EndOfStream,411 error.EndOfStream => return error.EndOfStream,
411 };412 };
...@@ -460,7 +461,7 @@ pub const Iterator = struct {...@@ -460,7 +461,7 @@ pub const Iterator = struct {
460 options: ExtractOptions,461 options: ExtractOptions,
461 filename_buf: []u8,462 filename_buf: []u8,
462 dest: std.fs.Dir,463 dest: std.fs.Dir,
463 ) !u32 {464 ) !void {
464 if (filename_buf.len < self.filename_len)465 if (filename_buf.len < self.filename_len)
465 return error.ZipInsufficientBuffer;466 return error.ZipInsufficientBuffer;
466 switch (self.compression_method) {467 switch (self.compression_method) {
...@@ -470,13 +471,13 @@ pub const Iterator = struct {...@@ -470,13 +471,13 @@ pub const Iterator = struct {
470 const filename = filename_buf[0..self.filename_len];471 const filename = filename_buf[0..self.filename_len];
471 {472 {
472 try stream.seekTo(self.header_zip_offset + @sizeOf(CentralDirectoryFileHeader));473 try stream.seekTo(self.header_zip_offset + @sizeOf(CentralDirectoryFileHeader));
473 try stream.interface.readSlice(filename);474 try stream.interface.readSliceAll(filename);
474 }475 }
475476
476 const local_data_header_offset: u64 = local_data_header_offset: {477 const local_data_header_offset: u64 = local_data_header_offset: {
477 const local_header = blk: {478 const local_header = blk: {
478 try stream.seekTo(self.file_offset);479 try stream.seekTo(self.file_offset);
479 break :blk try stream.interface.takeStructEndian(LocalFileHeader, .little);480 break :blk try stream.interface.takeStruct(LocalFileHeader, .little);
480 };481 };
481 if (!std.mem.eql(u8, &local_header.signature, &local_file_header_sig))482 if (!std.mem.eql(u8, &local_header.signature, &local_file_header_sig))
482 return error.ZipBadFileOffset;483 return error.ZipBadFileOffset;
...@@ -502,7 +503,7 @@ pub const Iterator = struct {...@@ -502,7 +503,7 @@ pub const Iterator = struct {
502503
503 {504 {
504 try stream.seekTo(self.file_offset + @sizeOf(LocalFileHeader) + local_header.filename_len);505 try stream.seekTo(self.file_offset + @sizeOf(LocalFileHeader) + local_header.filename_len);
505 try stream.interface.readSlice(extra);506 try stream.interface.readSliceAll(extra);
506 }507 }
507508
508 var extra_offset: usize = 0;509 var extra_offset: usize = 0;
...@@ -550,7 +551,7 @@ pub const Iterator = struct {...@@ -550,7 +551,7 @@ pub const Iterator = struct {
550 if (self.uncompressed_size != 0)551 if (self.uncompressed_size != 0)
551 return error.ZipBadDirectorySize;552 return error.ZipBadDirectorySize;
552 try dest.makePath(filename[0 .. filename.len - 1]);553 try dest.makePath(filename[0 .. filename.len - 1]);
553 return std.hash.Crc32.hash(&.{});554 return;
554 }555 }
555556
556 const out_file = blk: {557 const out_file = blk: {
...@@ -564,31 +565,36 @@ pub const Iterator = struct {...@@ -564,31 +565,36 @@ pub const Iterator = struct {
564 break :blk try dest.createFile(filename, .{ .exclusive = true });565 break :blk try dest.createFile(filename, .{ .exclusive = true });
565 };566 };
566 defer out_file.close();567 defer out_file.close();
567 var file_writer = out_file.writer();568 var out_file_buffer: [1024]u8 = undefined;
568 var file_bw = file_writer.writer(&.{});569 var file_writer = out_file.writer(&out_file_buffer);
569 const local_data_file_offset: u64 =570 const local_data_file_offset: u64 =
570 @as(u64, self.file_offset) +571 @as(u64, self.file_offset) +
571 @as(u64, @sizeOf(LocalFileHeader)) +572 @as(u64, @sizeOf(LocalFileHeader)) +
572 local_data_header_offset;573 local_data_header_offset;
573 try stream.seekTo(local_data_file_offset);574 try stream.seekTo(local_data_file_offset);
574 var limited_file_reader = stream.interface.limited(.limited(self.compressed_size));575
575 var file_read_buffer: [1000]u8 = undefined;576 // TODO limit based on self.compressed_size
576 var decompress_read_buffer: [1000]u8 = undefined;577
577 var limited_br = limited_file_reader.reader().buffered(&file_read_buffer);578 switch (self.compression_method) {
578 var decompress: Decompress = undefined;579 .store => {
579 var decompress_br = decompress.readable(&limited_br, self.compression_method, &decompress_read_buffer);580 stream.interface.streamExact64(&file_writer.interface, self.uncompressed_size) catch |err| switch (err) {
580 const start_out = file_bw.count;581 error.ReadFailed => return stream.err.?,
581 var hash_writer = file_bw.hashed(std.hash.Crc32.init());582 error.WriteFailed => return file_writer.err.?,
582 var hash_bw = hash_writer.writer(&.{});583 error.EndOfStream => return error.ZipDecompressTruncated,
583 decompress_br.readAll(&hash_bw, .limited(self.uncompressed_size)) catch |err| switch (err) {584 };
584 error.ReadFailed => return stream.err.?,585 },
585 error.WriteFailed => return file_writer.err.?,586 .deflate => {
586 error.EndOfStream => return error.ZipDecompressTruncated,587 var flate_buffer: [flate.max_window_len]u8 = undefined;
587 };588 var decompress: flate.Decompress = .init(&stream.interface, .raw, &flate_buffer);
588 if (limited_file_reader.remaining.nonzero()) return error.ZipDecompressTruncated;589 decompress.reader.streamExact64(&file_writer.interface, self.uncompressed_size) catch |err| switch (err) {
589 const written = file_bw.count - start_out;590 error.ReadFailed => return stream.err.?,
590 if (written != self.uncompressed_size) return error.ZipUncompressSizeMismatch;591 error.WriteFailed => return file_writer.err orelse decompress.err.?,
591 return hash_writer.hasher.final();592 error.EndOfStream => return error.ZipDecompressTruncated,
593 };
594 },
595 else => return error.UnsupportedCompressionMethod,
596 }
597 try file_writer.end();
592 }598 }
593 };599 };
594};600};
...@@ -636,25 +642,21 @@ pub const ExtractOptions = struct {...@@ -636,25 +642,21 @@ pub const ExtractOptions = struct {
636 /// Allow filenames within the zip to use backslashes. Back slashes are normalized642 /// Allow filenames within the zip to use backslashes. Back slashes are normalized
637 /// to forward slashes before forwarding them to platform APIs.643 /// to forward slashes before forwarding them to platform APIs.
638 allow_backslashes: bool = false,644 allow_backslashes: bool = false,
639
640 diagnostics: ?*Diagnostics = null,645 diagnostics: ?*Diagnostics = null,
646 verify_checksums: bool = false,
641};647};
642648
643/// Extract the zipped files to the given `dest` directory.649/// Extract the zipped files to the given `dest` directory.
644pub fn extract(dest: std.fs.Dir, fr: *File.Reader, options: ExtractOptions) !void {650pub fn extract(dest: std.fs.Dir, fr: *File.Reader, options: ExtractOptions) !void {
651 if (options.verify_checksums) @panic("TODO unimplemented");
652
645 var iter = try Iterator.init(fr);653 var iter = try Iterator.init(fr);
646654
647 var filename_buf: [std.fs.max_path_bytes]u8 = undefined;655 var filename_buf: [std.fs.max_path_bytes]u8 = undefined;
648 while (try iter.next()) |entry| {656 while (try iter.next()) |entry| {
649 const crc32 = try entry.extract(fr, options, &filename_buf, dest);657 try entry.extract(fr, options, &filename_buf, dest);
650 if (crc32 != entry.crc32)
651 return error.ZipCrcMismatch;
652 if (options.diagnostics) |d| {658 if (options.diagnostics) |d| {
653 try d.nextFilename(filename_buf[0..entry.filename_len]);659 try d.nextFilename(filename_buf[0..entry.filename_len]);
654 }660 }
655 }661 }
656}662}
657
658test {
659 _ = @import("zip/test.zig");
660}
lib/std/zip/test.zig deleted-515
...@@ -1,515 +0,0 @@
1const std = @import("std");
2const testing = std.testing;
3const zip = @import("../zip.zig");
4const maxInt = std.math.maxInt;
5const assert = std.debug.assert;
6const Writer = std.io.Writer;
7
8const File = struct {
9 name: []const u8,
10 content: []const u8,
11 compression: zip.CompressionMethod,
12};
13
14fn expectFiles(
15 test_files: []const File,
16 dir: std.fs.Dir,
17 opt: struct {
18 strip_prefix: ?[]const u8 = null,
19 },
20) !void {
21 for (test_files) |test_file| {
22 var normalized_sub_path_buf: [std.fs.max_path_bytes]u8 = undefined;
23
24 const name = blk: {
25 if (opt.strip_prefix) |strip_prefix| {
26 try testing.expect(test_file.name.len >= strip_prefix.len);
27 try testing.expectEqualStrings(strip_prefix, test_file.name[0..strip_prefix.len]);
28 break :blk test_file.name[strip_prefix.len..];
29 }
30 break :blk test_file.name;
31 };
32 const normalized_sub_path = normalized_sub_path_buf[0..name.len];
33 @memcpy(normalized_sub_path, name);
34 std.mem.replaceScalar(u8, normalized_sub_path, '\\', '/');
35 var file = try dir.openFile(normalized_sub_path, .{});
36 defer file.close();
37 var content_buf: [4096]u8 = undefined;
38 var file_reader = file.reader(&content_buf);
39 const n = try file_reader.interface.readSliceShort(&content_buf);
40 try testing.expectEqualStrings(test_file.content, content_buf[0..n]);
41 }
42}
43
44// Used to store any data from writing a file to the zip archive that's needed
45// when writing the corresponding central directory record.
46const FileStore = struct {
47 compression: zip.CompressionMethod,
48 file_offset: u64,
49 crc32: u32,
50 compressed_size: u32,
51 uncompressed_size: usize,
52};
53
54fn makeZip(file_writer: *std.fs.File.Writer, files: []const File, options: WriteZipOptions) !void {
55 const store = try std.testing.allocator.alloc(FileStore, files.len);
56 defer std.testing.allocator.free(store);
57 try makeZipWithStore(file_writer, files, options, store);
58}
59
60fn makeZipWithStore(
61 file_writer: *std.fs.File.Writer,
62 files: []const File,
63 options: WriteZipOptions,
64 store: []FileStore,
65) !void {
66 try writeZip(&file_writer.interface, files, store, options);
67}
68
69const WriteZipOptions = struct {
70 end: ?EndRecordOptions = null,
71 local_header: ?LocalHeaderOptions = null,
72};
73const LocalHeaderOptions = struct {
74 zip64: ?LocalHeaderZip64Options = null,
75 compressed_size: ?u32 = null,
76 uncompressed_size: ?u32 = null,
77 extra_len: ?u16 = null,
78};
79const LocalHeaderZip64Options = struct {
80 data_size: ?u16 = null,
81};
82const EndRecordOptions = struct {
83 zip64: ?Zip64Options = null,
84 sig: ?[4]u8 = null,
85 disk_number: ?u16 = null,
86 central_directory_disk_number: ?u16 = null,
87 record_count_disk: ?u16 = null,
88 record_count_total: ?u16 = null,
89 central_directory_size: ?u32 = null,
90 central_directory_offset: ?u32 = null,
91 comment_len: ?u16 = null,
92 comment: ?[]const u8 = null,
93};
94const Zip64Options = struct {
95 locator_sig: ?[4]u8 = null,
96 locator_zip64_disk_count: ?u32 = null,
97 locator_record_file_offset: ?u64 = null,
98 locator_total_disk_count: ?u32 = null,
99 //record_size: ?u64 = null,
100 central_directory_size: ?u64 = null,
101};
102
103fn writeZip(
104 writer: *Writer,
105 files: []const File,
106 store: []FileStore,
107 options: WriteZipOptions,
108) !void {
109 if (store.len < files.len) return error.FileStoreTooSmall;
110 var zipper: Zipper = .init(writer);
111 for (files, 0..) |file, i| {
112 store[i] = try zipper.writeFile(.{
113 .name = file.name,
114 .content = file.content,
115 .compression = file.compression,
116 .write_options = options,
117 });
118 }
119 for (files, 0..) |file, i| {
120 try zipper.writeCentralRecord(store[i], .{
121 .name = file.name,
122 });
123 }
124 try zipper.writeEndRecord(if (options.end) |e| e else .{});
125}
126
127/// Provides methods to format and write the contents of a zip archive
128/// to the underlying Writer.
129const Zipper = struct {
130 writer: *Writer,
131 init_count: u64,
132 central_count: u64 = 0,
133 first_central_offset: ?u64 = null,
134 last_central_limit: ?u64 = null,
135
136 fn init(writer: *Writer) Zipper {
137 return .{ .writer = writer, .init_count = writer.count };
138 }
139
140 fn writeFile(
141 self: *Zipper,
142 opt: struct {
143 name: []const u8,
144 content: []const u8,
145 compression: zip.CompressionMethod,
146 write_options: WriteZipOptions,
147 },
148 ) !FileStore {
149 const writer = self.writer;
150
151 const file_offset: u64 = writer.count - self.init_count;
152 const crc32 = std.hash.Crc32.hash(opt.content);
153
154 const header_options = opt.write_options.local_header;
155 {
156 var compressed_size: u32 = 0;
157 var uncompressed_size: u32 = 0;
158 var extra_len: u16 = 0;
159 if (header_options) |hdr_options| {
160 compressed_size = if (hdr_options.compressed_size) |size| size else 0;
161 uncompressed_size = if (hdr_options.uncompressed_size) |size| size else @intCast(opt.content.len);
162 extra_len = if (hdr_options.extra_len) |len| len else 0;
163 }
164 const hdr: zip.LocalFileHeader = .{
165 .signature = zip.local_file_header_sig,
166 .version_needed_to_extract = 10,
167 .flags = .{ .encrypted = false, ._ = 0 },
168 .compression_method = opt.compression,
169 .last_modification_time = 0,
170 .last_modification_date = 0,
171 .crc32 = crc32,
172 .compressed_size = compressed_size,
173 .uncompressed_size = uncompressed_size,
174 .filename_len = @intCast(opt.name.len),
175 .extra_len = extra_len,
176 };
177 try writer.writeStructEndian(hdr, .little);
178 }
179 try writer.writeAll(opt.name);
180
181 if (header_options) |hdr| {
182 if (hdr.zip64) |options| {
183 try writer.writeInt(u16, 0x0001, .little);
184 const data_size = if (options.data_size) |size| size else 8;
185 try writer.writeInt(u16, data_size, .little);
186 try writer.writeInt(u64, 0, .little);
187 try writer.writeInt(u64, @intCast(opt.content.len), .little);
188 }
189 }
190
191 var compressed_size: u32 = undefined;
192 switch (opt.compression) {
193 .store => {
194 try writer.writeAll(opt.content);
195 compressed_size = @intCast(opt.content.len);
196 },
197 .deflate => {
198 const offset = writer.count;
199 var br: std.io.Reader = .fixed(opt.content);
200 var compress: std.compress.flate.Compress = .init(&br, .{});
201 var compress_br = compress.reader(&.{});
202 const n = try compress_br.streamRemaining(writer);
203 assert(br.seek == opt.content.len);
204 try testing.expectEqual(n, writer.count - offset);
205 compressed_size = @intCast(n);
206 },
207 else => unreachable,
208 }
209 return .{
210 .compression = opt.compression,
211 .file_offset = file_offset,
212 .crc32 = crc32,
213 .compressed_size = compressed_size,
214 .uncompressed_size = opt.content.len,
215 };
216 }
217
218 fn writeCentralRecord(
219 self: *Zipper,
220 store: FileStore,
221 opt: struct {
222 name: []const u8,
223 version_needed_to_extract: u16 = 10,
224 },
225 ) !void {
226 if (self.first_central_offset == null) {
227 self.first_central_offset = self.writer.count - self.init_count;
228 }
229 self.central_count += 1;
230
231 const hdr: zip.CentralDirectoryFileHeader = .{
232 .signature = zip.central_file_header_sig,
233 .version_made_by = 0,
234 .version_needed_to_extract = opt.version_needed_to_extract,
235 .flags = .{ .encrypted = false, ._ = 0 },
236 .compression_method = store.compression,
237 .last_modification_time = 0,
238 .last_modification_date = 0,
239 .crc32 = store.crc32,
240 .compressed_size = store.compressed_size,
241 .uncompressed_size = @intCast(store.uncompressed_size),
242 .filename_len = @intCast(opt.name.len),
243 .extra_len = 0,
244 .comment_len = 0,
245 .disk_number = 0,
246 .internal_file_attributes = 0,
247 .external_file_attributes = 0,
248 .local_file_header_offset = @intCast(store.file_offset),
249 };
250 try self.writer.writeStructEndian(hdr, .little);
251 try self.writer.writeAll(opt.name);
252 self.last_central_limit = self.writer.count - self.init_count;
253 }
254
255 fn writeEndRecord(self: *Zipper, opt: EndRecordOptions) !void {
256 const cd_offset = self.first_central_offset orelse 0;
257 const cd_end = self.last_central_limit orelse 0;
258
259 if (opt.zip64) |zip64| {
260 const end64_off = cd_end;
261 const fixed: zip.EndRecord64 = .{
262 .signature = zip.end_record64_sig,
263 .end_record_size = @sizeOf(zip.EndRecord64) - 12,
264 .version_made_by = 0,
265 .version_needed_to_extract = 45,
266 .disk_number = 0,
267 .central_directory_disk_number = 0,
268 .record_count_disk = @intCast(self.central_count),
269 .record_count_total = @intCast(self.central_count),
270 .central_directory_size = @intCast(cd_end - cd_offset),
271 .central_directory_offset = @intCast(cd_offset),
272 };
273 try self.writer.writeStructEndian(fixed, .little);
274 const locator: zip.EndLocator64 = .{
275 .signature = if (zip64.locator_sig) |s| s else zip.end_locator64_sig,
276 .zip64_disk_count = if (zip64.locator_zip64_disk_count) |c| c else 0,
277 .record_file_offset = if (zip64.locator_record_file_offset) |o| o else @intCast(end64_off),
278 .total_disk_count = if (zip64.locator_total_disk_count) |c| c else 1,
279 };
280 try self.writer.writeStructEndian(locator, .little);
281 }
282 const hdr: zip.EndRecord = .{
283 .signature = if (opt.sig) |s| s else zip.end_record_sig,
284 .disk_number = if (opt.disk_number) |n| n else 0,
285 .central_directory_disk_number = if (opt.central_directory_disk_number) |n| n else 0,
286 .record_count_disk = if (opt.record_count_disk) |c| c else @intCast(self.central_count),
287 .record_count_total = if (opt.record_count_total) |c| c else @intCast(self.central_count),
288 .central_directory_size = if (opt.central_directory_size) |s| s else @intCast(cd_end - cd_offset),
289 .central_directory_offset = if (opt.central_directory_offset) |o| o else @intCast(cd_offset),
290 .comment_len = if (opt.comment_len) |l| l else (if (opt.comment) |c| @as(u16, @intCast(c.len)) else 0),
291 };
292 try self.writer.writeStructEndian(hdr, .little);
293 if (opt.comment) |c|
294 try self.writer.writeAll(c);
295 }
296};
297
298fn testZip(options: zip.ExtractOptions, comptime files: []const File, write_opt: WriteZipOptions) !void {
299 var store: [files.len]FileStore = undefined;
300 try testZipWithStore(options, files, write_opt, &store);
301}
302fn testZipWithStore(
303 options: zip.ExtractOptions,
304 test_files: []const File,
305 write_opt: WriteZipOptions,
306 store: []FileStore,
307) !void {
308 var tmp = testing.tmpDir(.{ .no_follow = true });
309 defer tmp.cleanup();
310
311 var file = tmp.createFile();
312 defer file.close();
313 var buffer: [100]u8 = undefined;
314 var file_writer = file.writer(&buffer);
315 try makeZipWithStore(&file_writer, test_files, write_opt, store);
316 var file_reader = file_writer.moveToReader();
317 try zip.extract(tmp.dir, &file_reader, options);
318 try expectFiles(test_files, tmp.dir, .{});
319}
320fn testZipError(expected_error: anyerror, file: File, options: zip.ExtractOptions) !void {
321 var tmp = testing.tmpDir(.{ .no_follow = true });
322 defer tmp.cleanup();
323 const tmp_file = tmp.createFile();
324 defer tmp_file.close();
325 var buffer: [100]u8 = undefined;
326 var file_writer = tmp_file.writer(&buffer);
327 var store: [1]FileStore = undefined;
328 try makeZipWithStore(&file_writer, &[_]File{file}, .{}, &store);
329 var file_reader = file_writer.moveToReader();
330 try testing.expectError(expected_error, zip.extract(tmp.dir, &file_reader, options));
331}
332
333test "zip one file" {
334 try testZip(.{}, &[_]File{
335 .{ .name = "onefile.txt", .content = "Just a single file\n", .compression = .store },
336 }, .{});
337}
338test "zip multiple files" {
339 try testZip(.{ .allow_backslashes = true }, &[_]File{
340 .{ .name = "foo", .content = "a foo file\n", .compression = .store },
341 .{ .name = "subdir/bar", .content = "bar is this right?\nanother newline\n", .compression = .store },
342 .{ .name = "subdir\\whoa", .content = "you can do backslashes", .compression = .store },
343 .{ .name = "subdir/another/baz", .content = "bazzy mc bazzerson", .compression = .store },
344 }, .{});
345}
346test "zip deflated" {
347 try testZip(.{}, &[_]File{
348 .{ .name = "deflateme", .content = "This is a deflated file.\nIt should be smaller in the Zip file1\n", .compression = .deflate },
349 // TODO: re-enable this if/when we add support for deflate64
350 //.{ .name = "deflateme64", .content = "The 64k version of deflate!\n", .compression = .deflate64 },
351 .{ .name = "raw", .content = "Not all files need to be deflated in the same Zip.\n", .compression = .store },
352 }, .{});
353}
354test "zip verify filenames" {
355 // no empty filenames
356 try testZipError(error.ZipBadFilename, .{ .name = "", .content = "", .compression = .store }, .{});
357 // no absolute paths
358 try testZipError(error.ZipBadFilename, .{ .name = "/", .content = "", .compression = .store }, .{});
359 try testZipError(error.ZipBadFilename, .{ .name = "/foo", .content = "", .compression = .store }, .{});
360 try testZipError(error.ZipBadFilename, .{ .name = "/foo/bar", .content = "", .compression = .store }, .{});
361 // no '..' components
362 try testZipError(error.ZipBadFilename, .{ .name = "..", .content = "", .compression = .store }, .{});
363 try testZipError(error.ZipBadFilename, .{ .name = "foo/..", .content = "", .compression = .store }, .{});
364 try testZipError(error.ZipBadFilename, .{ .name = "foo/bar/..", .content = "", .compression = .store }, .{});
365 try testZipError(error.ZipBadFilename, .{ .name = "foo/bar/../", .content = "", .compression = .store }, .{});
366 // no backslashes
367 try testZipError(error.ZipFilenameHasBackslash, .{ .name = "foo\\bar", .content = "", .compression = .store }, .{});
368}
369
370test "zip64" {
371 const test_files = [_]File{
372 .{ .name = "fram", .content = "fram foo fro fraba", .compression = .store },
373 .{ .name = "subdir/barro", .content = "aljdk;jal;jfd;lajkf", .compression = .store },
374 };
375
376 try testZip(.{}, &test_files, .{
377 .end = .{
378 .zip64 = .{},
379 .record_count_disk = std.math.maxInt(u16), // trigger zip64
380 },
381 });
382 try testZip(.{}, &test_files, .{
383 .end = .{
384 .zip64 = .{},
385 .record_count_total = std.math.maxInt(u16), // trigger zip64
386 },
387 });
388 try testZip(.{}, &test_files, .{
389 .end = .{
390 .zip64 = .{},
391 .record_count_disk = std.math.maxInt(u16), // trigger zip64
392 .record_count_total = std.math.maxInt(u16), // trigger zip64
393 },
394 });
395 try testZip(.{}, &test_files, .{
396 .end = .{
397 .zip64 = .{},
398 .central_directory_size = std.math.maxInt(u32), // trigger zip64
399 },
400 });
401 try testZip(.{}, &test_files, .{
402 .end = .{
403 .zip64 = .{},
404 .central_directory_offset = std.math.maxInt(u32), // trigger zip64
405 },
406 });
407 try testZip(.{}, &test_files, .{
408 .end = .{
409 .zip64 = .{},
410 .central_directory_offset = std.math.maxInt(u32), // trigger zip64
411 },
412 .local_header = .{
413 .zip64 = .{ // trigger local header zip64
414 .data_size = 16,
415 },
416 .compressed_size = std.math.maxInt(u32),
417 .uncompressed_size = std.math.maxInt(u32),
418 .extra_len = 20,
419 },
420 });
421}
422
423test "bad zip files" {
424 var tmp = testing.tmpDir(.{ .no_follow = true });
425 defer tmp.cleanup();
426 var buffer: [4096]u8 = undefined;
427
428 const file_a = [_]File{.{ .name = "a", .content = "", .compression = .store }};
429
430 {
431 const tmp_file = tmp.createFile();
432 defer tmp_file.close();
433 var file_writer = tmp_file.writer(&buffer);
434 try makeZip(&file_writer, &.{}, .{ .end = .{ .sig = [_]u8{ 1, 2, 3, 4 } } });
435 var file_reader = file_writer.moveToReader();
436 try testing.expectError(error.ZipNoEndRecord, zip.extract(tmp.dir, &file_reader, .{}));
437 }
438 {
439 const tmp_file = tmp.createFile();
440 defer tmp_file.close();
441 var file_writer = tmp_file.writer(&buffer);
442 try makeZip(&file_writer, &.{}, .{ .end = .{ .comment_len = 1 } });
443 var file_reader = file_writer.moveToReader();
444 try testing.expectError(error.ZipNoEndRecord, zip.extract(tmp.dir, &file_reader, .{}));
445 }
446 {
447 const tmp_file = tmp.createFile();
448 defer tmp_file.close();
449 var file_writer = tmp_file.writer(&buffer);
450 try makeZip(&file_writer, &.{}, .{ .end = .{ .comment = "a", .comment_len = 0 } });
451 var file_reader = file_writer.moveToReader();
452 try testing.expectError(error.ZipNoEndRecord, zip.extract(tmp.dir, &file_reader, .{}));
453 }
454 {
455 const tmp_file = tmp.createFile();
456 defer tmp_file.close();
457 var file_writer = tmp_file.writer(&buffer);
458 try makeZip(&file_writer, &.{}, .{ .end = .{ .disk_number = 1 } });
459 var file_reader = file_writer.moveToReader();
460 try testing.expectError(error.ZipMultiDiskUnsupported, zip.extract(tmp.dir, &file_reader, .{}));
461 }
462 {
463 const tmp_file = tmp.createFile();
464 defer tmp_file.close();
465 var file_writer = tmp_file.writer(&buffer);
466 try makeZip(&file_writer, &.{}, .{ .end = .{ .central_directory_disk_number = 1 } });
467 var file_reader = file_writer.moveToReader();
468 try testing.expectError(error.ZipMultiDiskUnsupported, zip.extract(tmp.dir, &file_reader, .{}));
469 }
470 {
471 const tmp_file = tmp.createFile();
472 defer tmp_file.close();
473 var file_writer = tmp_file.writer(&buffer);
474 try makeZip(&file_writer, &.{}, .{ .end = .{ .record_count_disk = 1 } });
475 var file_reader = file_writer.moveToReader();
476 try testing.expectError(error.ZipDiskRecordCountTooLarge, zip.extract(tmp.dir, &file_reader, .{}));
477 }
478 {
479 const tmp_file = tmp.createFile();
480 defer tmp_file.close();
481 var file_writer = tmp_file.writer(&buffer);
482 try makeZip(&file_writer, &.{}, .{ .end = .{ .central_directory_size = 1 } });
483 var file_reader = file_writer.moveToReader();
484 try testing.expectError(error.ZipCdOversized, zip.extract(tmp.dir, &file_reader, .{}));
485 }
486 {
487 const tmp_file = tmp.createFile();
488 defer tmp_file.close();
489 var file_writer = tmp_file.writer(&buffer);
490 try makeZip(&file_writer, &file_a, .{ .end = .{ .central_directory_size = 0 } });
491 var file_reader = file_writer.moveToReader();
492 try testing.expectError(error.ZipCdUndersized, zip.extract(tmp.dir, &file_reader, .{}));
493 }
494 {
495 const tmp_file = tmp.createFile();
496 defer tmp_file.close();
497 var file_writer = tmp_file.writer(&buffer);
498 try makeZip(&file_writer, &file_a, .{ .end = .{ .central_directory_offset = 0 } });
499 var file_reader = file_writer.moveToReader();
500 try testing.expectError(error.ZipBadCdOffset, zip.extract(tmp.dir, &file_reader, .{}));
501 }
502 {
503 const tmp_file = tmp.createFile();
504 defer tmp_file.close();
505 var file_writer = tmp_file.writer(&buffer);
506 try makeZip(&file_writer, &file_a, .{
507 .end = .{
508 .zip64 = .{ .locator_sig = [_]u8{ 1, 2, 3, 4 } },
509 .central_directory_size = std.math.maxInt(u32), // trigger 64
510 },
511 });
512 var file_reader = file_writer.moveToReader();
513 try testing.expectError(error.ZipBadLocatorSig, zip.extract(tmp.dir, &file_reader, .{}));
514 }
515}
lib/std/zon/parse.zig+3-3
...@@ -2774,11 +2774,11 @@ test "std.zon parse float" {...@@ -2774,11 +2774,11 @@ test "std.zon parse float" {
27742774
2775 // Test big integers2775 // Test big integers
2776 try std.testing.expectEqual(2776 try std.testing.expectEqual(
2777 @as(f32, 36893488147419103231),2777 @as(f32, 36893488147419103231.0),
2778 try fromSlice(f32, gpa, "36893488147419103231", null, .{}),2778 try fromSlice(f32, gpa, "36893488147419103231", null, .{}),
2779 );2779 );
2780 try std.testing.expectEqual(2780 try std.testing.expectEqual(
2781 @as(f32, -36893488147419103231),2781 @as(f32, -36893488147419103231.0),
2782 try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),2782 try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),
2783 );2783 );
2784 try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(2784 try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(
...@@ -2788,7 +2788,7 @@ test "std.zon parse float" {...@@ -2788,7 +2788,7 @@ test "std.zon parse float" {
2788 null,2788 null,
2789 .{},2789 .{},
2790 ));2790 ));
2791 try std.testing.expectEqual(@as(f32, 0x1ffffffffffffffff), try fromSlice(2791 try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSlice(
2792 f32,2792 f32,
2793 gpa,2793 gpa,
2794 "0x1ffffffffffffffff",2794 "0x1ffffffffffffffff",
src/Compilation.zig+6-4
...@@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1816 if (options.skip_linker_dependencies) break :s .none;1816 if (options.skip_linker_dependencies) break :s .none;
1817 const want = options.want_compiler_rt orelse is_exe_or_dyn_lib;1817 const want = options.want_compiler_rt orelse is_exe_or_dyn_lib;
1818 if (!want) break :s .none;1818 if (!want) break :s .none;
1819 if (have_zcu) {1819 if (have_zcu and target_util.canBuildLibCompilerRt(target, use_llvm, build_options.have_llvm and use_llvm)) {
1820 if (output_mode == .Obj) break :s .zcu;1820 if (output_mode == .Obj) break :s .zcu;
1821 if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64)1821 if (switch (target_util.zigBackend(target, use_llvm)) {
1822 break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;1822 else => false,
1823 .stage2_aarch64, .stage2_x86_64 => target.ofmt == .coff,
1824 }) break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
1823 }1825 }
1824 if (is_exe_or_dyn_lib) break :s .lib;1826 if (is_exe_or_dyn_lib) break :s .lib;
1825 break :s .obj;1827 break :s .obj;
...@@ -1854,7 +1856,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1854,7 +1856,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1854 const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib);1856 const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib);
1855 if (!want_ubsan_rt) break :s .none;1857 if (!want_ubsan_rt) break :s .none;
1856 if (options.skip_linker_dependencies) break :s .none;1858 if (options.skip_linker_dependencies) break :s .none;
1857 if (have_zcu) break :s .zcu;1859 if (have_zcu and target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm and use_llvm)) break :s .zcu;
1858 if (is_exe_or_dyn_lib) break :s .lib;1860 if (is_exe_or_dyn_lib) break :s .lib;
1859 break :s .obj;1861 break :s .obj;
1860 };1862 };
src/Package/Fetch.zig+20-81
...@@ -1203,12 +1203,11 @@ fn unpackResource(...@@ -1203,12 +1203,11 @@ fn unpackResource(
1203 return unpackTarball(f, tmp_directory.handle, &adapter.new_interface);1203 return unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1204 },1204 },
1205 .@"tar.gz" => {1205 .@"tar.gz" => {
1206 const reader = resource.reader();1206 var adapter_buffer: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
1207 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);1207 var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
1208 var dcp = std.compress.gzip.decompressor(br.reader());1208 var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
1209 var adapter_buffer: [1024]u8 = undefined;1209 var decompress: std.compress.flate.Decompress = .init(&adapter.new_interface, .gzip, &flate_buffer);
1210 var adapter = dcp.reader().adaptToNewApi(&adapter_buffer);1210 return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
1211 return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1212 },1211 },
1213 .@"tar.xz" => {1212 .@"tar.xz" => {
1214 const gpa = f.arena.child_allocator;1213 const gpa = f.arena.child_allocator;
...@@ -1352,7 +1351,10 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {...@@ -1352,7 +1351,10 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {
1352 ));1351 ));
1353 defer zip_file.close();1352 defer zip_file.close();
13541353
1355 std.zip.extract(out_dir, zip_file.seekableStream(), .{1354 var zip_file_buffer: [1024]u8 = undefined;
1355 var zip_file_reader = zip_file.reader(&zip_file_buffer);
1356
1357 std.zip.extract(out_dir, &zip_file_reader, .{
1356 .allow_backslashes = true,1358 .allow_backslashes = true,
1357 .diagnostics = &diagnostics,1359 .diagnostics = &diagnostics,
1358 }) catch |err| return f.fail(f.location_tok, try eb.printString(1360 }) 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...@@ -1384,25 +1386,28 @@ fn unpackGitPack(f: *Fetch, out_dir: fs.Dir, resource: *Resource.Git) anyerror!U
1384 defer pack_dir.close();1386 defer pack_dir.close();
1385 var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });1387 var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });
1386 defer pack_file.close();1388 defer pack_file.close();
1387 _ = try resource.fetch_stream.reader().readRemaining(pack_file.writer());1389 var pack_file_buffer: [4096]u8 = undefined;
1388 try pack_file.sync();1390 var fifo = std.fifo.LinearFifo(u8, .{ .Slice = {} }).init(&pack_file_buffer);
1391 try fifo.pump(resource.fetch_stream.reader(), pack_file.deprecatedWriter());
1392
1393 var pack_file_reader = pack_file.reader(&pack_file_buffer);
13891394
1390 var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });1395 var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });
1391 defer index_file.close();1396 defer index_file.close();
1397 var index_file_buffer: [2000]u8 = undefined;
1398 var index_file_writer = index_file.writer(&index_file_buffer);
1392 {1399 {
1393 const index_prog_node = f.prog_node.start("Index pack", 0);1400 const index_prog_node = f.prog_node.start("Index pack", 0);
1394 defer index_prog_node.end();1401 defer index_prog_node.end();
1395 var buffer: [4096]u8 = undefined;1402 try git.indexPack(gpa, object_format, &pack_file_reader, &index_file_writer);
1396 var index_file_writer = index_file.writer(&buffer);
1397 try git.indexPack(gpa, object_format, pack_file, &index_file_writer.interface);
1398 try index_file_writer.flush();
1399 try index_file.sync();
1400 }1403 }
14011404
1402 {1405 {
1406 var index_file_reader = index_file.reader(&index_file_buffer);
1403 const checkout_prog_node = f.prog_node.start("Checkout", 0);1407 const checkout_prog_node = f.prog_node.start("Checkout", 0);
1404 defer checkout_prog_node.end();1408 defer checkout_prog_node.end();
1405 var repository = try git.Repository.init(gpa, object_format, pack_file, index_file);1409 var repository: git.Repository = undefined;
1410 try repository.init(gpa, object_format, &pack_file_reader, &index_file_reader);
1406 defer repository.deinit();1411 defer repository.deinit();
1407 var diagnostics: git.Diagnostics = .{ .allocator = arena };1412 var diagnostics: git.Diagnostics = .{ .allocator = arena };
1408 try repository.checkout(out_dir, resource.want_oid, &diagnostics);1413 try repository.checkout(out_dir, resource.want_oid, &diagnostics);
...@@ -2069,72 +2074,6 @@ const UnpackResult = struct {...@@ -2069,72 +2074,6 @@ const UnpackResult = struct {
2069 }2074 }
2070};2075};
20712076
2072test "zip" {
2073 const gpa = std.testing.allocator;
2074 var tmp = std.testing.tmpDir(.{});
2075 defer tmp.cleanup();
2076
2077 const test_files = [_]std.zip.testutil.File{
2078 .{ .name = "foo", .content = "this is just foo\n", .compression = .store },
2079 .{ .name = "bar", .content = "another file\n", .compression = .deflate },
2080 };
2081 {
2082 var zip_file = try tmp.dir.createFile("test.zip", .{});
2083 defer zip_file.close();
2084 var bw = std.io.bufferedWriter(zip_file.deprecatedWriter());
2085 var store: [test_files.len]std.zip.testutil.FileStore = undefined;
2086 try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{});
2087 try bw.flush();
2088 }
2089
2090 const zip_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/test.zip", .{tmp.sub_path});
2091 defer gpa.free(zip_path);
2092
2093 var fb: TestFetchBuilder = undefined;
2094 var fetch = try fb.build(gpa, tmp.dir, zip_path);
2095 defer fb.deinit();
2096
2097 try fetch.run();
2098
2099 var out = try fb.packageDir();
2100 defer out.close();
2101
2102 try std.zip.testutil.expectFiles(&test_files, out, .{});
2103}
2104
2105test "zip with one root folder" {
2106 const gpa = std.testing.allocator;
2107 var tmp = std.testing.tmpDir(.{});
2108 defer tmp.cleanup();
2109
2110 const test_files = [_]std.zip.testutil.File{
2111 .{ .name = "the_root_folder/foo.zig", .content = "// this is foo.zig\n", .compression = .store },
2112 .{ .name = "the_root_folder/README.md", .content = "# The foo.zig README\n", .compression = .store },
2113 };
2114 {
2115 var zip_file = try tmp.dir.createFile("test.zip", .{});
2116 defer zip_file.close();
2117 var bw = std.io.bufferedWriter(zip_file.deprecatedWriter());
2118 var store: [test_files.len]std.zip.testutil.FileStore = undefined;
2119 try std.zip.testutil.writeZip(bw.writer(), &test_files, &store, .{});
2120 try bw.flush();
2121 }
2122
2123 const zip_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/test.zip", .{tmp.sub_path});
2124 defer gpa.free(zip_path);
2125
2126 var fb: TestFetchBuilder = undefined;
2127 var fetch = try fb.build(gpa, tmp.dir, zip_path);
2128 defer fb.deinit();
2129
2130 try fetch.run();
2131
2132 var out = try fb.packageDir();
2133 defer out.close();
2134
2135 try std.zip.testutil.expectFiles(&test_files, out, .{ .strip_prefix = "the_root_folder/" });
2136}
2137
2138test "tarball with duplicate paths" {2077test "tarball with duplicate paths" {
2139 // This tarball has duplicate path 'dir1/file1' to simulate case sensitve2078 // This tarball has duplicate path 'dir1/file1' to simulate case sensitve
2140 // file system on any file sytstem.2079 // file system on any file sytstem.
src/Package/Fetch/git.zig+463-10
...@@ -73,6 +73,33 @@ pub const Oid = union(Format) {...@@ -73,6 +73,33 @@ pub const Oid = union(Format) {
73 }73 }
74 };74 };
7575
76 const Hashing = union(Format) {
77 sha1: std.Io.Writer.Hashing(Sha1),
78 sha256: std.Io.Writer.Hashing(Sha256),
79
80 fn init(oid_format: Format, buffer: []u8) Hashing {
81 return switch (oid_format) {
82 .sha1 => .{ .sha1 = .init(buffer) },
83 .sha256 => .{ .sha256 = .init(buffer) },
84 };
85 }
86
87 fn writer(h: *@This()) *std.Io.Writer {
88 return switch (h.*) {
89 inline else => |*inner| &inner.writer,
90 };
91 }
92
93 fn final(h: *@This()) Oid {
94 switch (h.*) {
95 inline else => |*inner, tag| {
96 inner.writer.flush() catch unreachable; // hashers cannot fail
97 return @unionInit(Oid, @tagName(tag), inner.hasher.finalResult());
98 },
99 }
100 }
101 };
102
76 pub fn fromBytes(oid_format: Format, bytes: []const u8) Oid {103 pub fn fromBytes(oid_format: Format, bytes: []const u8) Oid {
77 assert(bytes.len == oid_format.byteLength());104 assert(bytes.len == oid_format.byteLength());
78 return switch (oid_format) {105 return switch (oid_format) {
...@@ -80,8 +107,15 @@ pub const Oid = union(Format) {...@@ -80,8 +107,15 @@ pub const Oid = union(Format) {
80 };107 };
81 }108 }
82109
110<<<<<<< HEAD
83 pub fn readBytes(oid_format: Format, reader: *std.io.Reader) std.io.Reader.Error!Oid {111 pub fn readBytes(oid_format: Format, reader: *std.io.Reader) std.io.Reader.Error!Oid {
112||||||| 733b208256
113 pub fn readBytes(oid_format: Format, reader: anytype) @TypeOf(reader).NoEofError!Oid {
114=======
115 pub fn readBytes(oid_format: Format, reader: *std.Io.Reader) !Oid {
116>>>>>>> origin/flate
84 return switch (oid_format) {117 return switch (oid_format) {
118<<<<<<< HEAD
85 .sha1 => {119 .sha1 => {
86 var result: Oid = .{ .sha1 = undefined };120 var result: Oid = .{ .sha1 = undefined };
87 try reader.readSlice(&result.sha1);121 try reader.readSlice(&result.sha1);
...@@ -92,6 +126,11 @@ pub const Oid = union(Format) {...@@ -92,6 +126,11 @@ pub const Oid = union(Format) {
92 try reader.readSlice(&result.sha256);126 try reader.readSlice(&result.sha256);
93 return result;127 return result;
94 },128 },
129||||||| 733b208256
130 inline else => |tag| @unionInit(Oid, @tagName(tag), try reader.readBytesNoEof(tag.byteLength())),
131=======
132 inline else => |tag| @unionInit(Oid, @tagName(tag), (try reader.takeArray(tag.byteLength())).*),
133>>>>>>> origin/flate
95 };134 };
96 }135 }
97136
...@@ -261,7 +300,6 @@ pub const Repository = struct {...@@ -261,7 +300,6 @@ pub const Repository = struct {
261 };300 };
262 defer file.close();301 defer file.close();
263 try file.writeAll(file_object.data);302 try file.writeAll(file_object.data);
264 try file.sync();
265 },303 },
266 .symlink => {304 .symlink => {
267 try repository.odb.seekOid(entry.oid);305 try repository.odb.seekOid(entry.oid);
...@@ -392,15 +430,27 @@ const Odb = struct {...@@ -392,15 +430,27 @@ const Odb = struct {
392430
393 /// Reads the object at the current position in the database.431 /// Reads the object at the current position in the database.
394 fn readObject(odb: *Odb) !Object {432 fn readObject(odb: *Odb) !Object {
433<<<<<<< HEAD
395 var base_offset = odb.pack_file.pos;434 var base_offset = odb.pack_file.pos;
396 const pack_br = &odb.pack_file.interface;435 const pack_br = &odb.pack_file.interface;
436||||||| 733b208256
437 var base_offset = try odb.pack_file.getPos();
438=======
439 var base_offset = odb.pack_file.logicalPos();
440>>>>>>> origin/flate
397 var base_header: EntryHeader = undefined;441 var base_header: EntryHeader = undefined;
398 var delta_offsets: std.ArrayListUnmanaged(u64) = .empty;442 var delta_offsets: std.ArrayListUnmanaged(u64) = .empty;
399 defer delta_offsets.deinit(odb.allocator);443 defer delta_offsets.deinit(odb.allocator);
400 const base_object = while (true) {444 const base_object = while (true) {
401 if (odb.cache.get(base_offset)) |base_object| break base_object;445 if (odb.cache.get(base_offset)) |base_object| break base_object;
402446
447<<<<<<< HEAD
403 base_header = try EntryHeader.read(odb.format, pack_br);448 base_header = try EntryHeader.read(odb.format, pack_br);
449||||||| 733b208256
450 base_header = try EntryHeader.read(odb.format, odb.pack_file.deprecatedReader());
451=======
452 base_header = try EntryHeader.read(odb.format, &odb.pack_file.interface);
453>>>>>>> origin/flate
404 switch (base_header) {454 switch (base_header) {
405 .ofs_delta => |ofs_delta| {455 .ofs_delta => |ofs_delta| {
406 try delta_offsets.append(odb.allocator, base_offset);456 try delta_offsets.append(odb.allocator, base_offset);
...@@ -410,10 +460,22 @@ const Odb = struct {...@@ -410,10 +460,22 @@ const Odb = struct {
410 .ref_delta => |ref_delta| {460 .ref_delta => |ref_delta| {
411 try delta_offsets.append(odb.allocator, base_offset);461 try delta_offsets.append(odb.allocator, base_offset);
412 try odb.seekOid(ref_delta.base_object);462 try odb.seekOid(ref_delta.base_object);
463<<<<<<< HEAD
413 base_offset = odb.pack_file.pos - pack_br.bufferedLen();464 base_offset = odb.pack_file.pos - pack_br.bufferedLen();
465||||||| 733b208256
466 base_offset = try odb.pack_file.getPos();
467=======
468 base_offset = odb.pack_file.logicalPos();
469>>>>>>> origin/flate
414 },470 },
415 else => {471 else => {
472<<<<<<< HEAD
416 const base_data = try readObjectRaw(odb.allocator, pack_br, base_header.uncompressedLength());473 const base_data = try readObjectRaw(odb.allocator, pack_br, base_header.uncompressedLength());
474||||||| 733b208256
475 const base_data = try readObjectRaw(odb.allocator, odb.pack_file.deprecatedReader(), base_header.uncompressedLength());
476=======
477 const base_data = try readObjectRaw(odb.allocator, &odb.pack_file.interface, base_header.uncompressedLength());
478>>>>>>> origin/flate
417 errdefer odb.allocator.free(base_data);479 errdefer odb.allocator.free(base_data);
418 const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };480 const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
419 try odb.cache.put(odb.allocator, base_offset, base_object);481 try odb.cache.put(odb.allocator, base_offset, base_object);
...@@ -443,8 +505,14 @@ const Odb = struct {...@@ -443,8 +505,14 @@ const Odb = struct {
443 const found_index = while (start_index < end_index) {505 const found_index = while (start_index < end_index) {
444 const mid_index = start_index + (end_index - start_index) / 2;506 const mid_index = start_index + (end_index - start_index) / 2;
445 try odb.index_file.seekTo(IndexHeader.size + mid_index * oid_length);507 try odb.index_file.seekTo(IndexHeader.size + mid_index * oid_length);
508<<<<<<< HEAD
446 var br = odb.index_file.interface().unbuffered();509 var br = odb.index_file.interface().unbuffered();
447 const mid_oid = try Oid.readBytes(odb.format, &br);510 const mid_oid = try Oid.readBytes(odb.format, &br);
511||||||| 733b208256
512 const mid_oid = try Oid.readBytes(odb.format, odb.index_file.deprecatedReader());
513=======
514 const mid_oid = try Oid.readBytes(odb.format, &odb.index_file.interface);
515>>>>>>> origin/flate
448 switch (mem.order(u8, mid_oid.slice(), oid.slice())) {516 switch (mem.order(u8, mid_oid.slice(), oid.slice())) {
449 .lt => start_index = mid_index + 1,517 .lt => start_index = mid_index + 1,
450 .gt => end_index = mid_index,518 .gt => end_index = mid_index,
...@@ -456,14 +524,26 @@ const Odb = struct {...@@ -456,14 +524,26 @@ const Odb = struct {
456 const offset_values_start = IndexHeader.size + n_objects * (oid_length + 4);524 const offset_values_start = IndexHeader.size + n_objects * (oid_length + 4);
457 var buffer: [8]u8 = undefined;525 var buffer: [8]u8 = undefined;
458 try odb.index_file.seekTo(offset_values_start + found_index * 4);526 try odb.index_file.seekTo(offset_values_start + found_index * 4);
527<<<<<<< HEAD
459 var br = odb.index_file.interface().buffered(&buffer);528 var br = odb.index_file.interface().buffered(&buffer);
460 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try br.takeInt(u32, .big));529 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try br.takeInt(u32, .big));
530||||||| 733b208256
531 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.deprecatedReader().readInt(u32, .big));
532=======
533 const l1_offset: packed struct { value: u31, big: bool } = @bitCast(try odb.index_file.interface.takeInt(u32, .big));
534>>>>>>> origin/flate
461 const pack_offset = pack_offset: {535 const pack_offset = pack_offset: {
462 if (l1_offset.big) {536 if (l1_offset.big) {
463 const l2_offset_values_start = offset_values_start + n_objects * 4;537 const l2_offset_values_start = offset_values_start + n_objects * 4;
464 try odb.index_file.seekTo(l2_offset_values_start + l1_offset.value * 4);538 try odb.index_file.seekTo(l2_offset_values_start + l1_offset.value * 4);
539<<<<<<< HEAD
465 br = odb.index_file.interface().buffered(&buffer);540 br = odb.index_file.interface().buffered(&buffer);
466 break :pack_offset try br.takeInt(u64, .big);541 break :pack_offset try br.takeInt(u64, .big);
542||||||| 733b208256
543 break :pack_offset try odb.index_file.deprecatedReader().readInt(u64, .big);
544=======
545 break :pack_offset try odb.index_file.interface.takeInt(u64, .big);
546>>>>>>> origin/flate
467 } else {547 } else {
468 break :pack_offset l1_offset.value;548 break :pack_offset l1_offset.value;
469 }549 }
...@@ -1119,12 +1199,48 @@ const PackHeader = struct {...@@ -1119,12 +1199,48 @@ const PackHeader = struct {
1119 const signature = "PACK";1199 const signature = "PACK";
1120 const supported_version = 2;1200 const supported_version = 2;
11211201
1202<<<<<<< HEAD
1122 fn read(reader: *std.io.Reader) !PackHeader {1203 fn read(reader: *std.io.Reader) !PackHeader {
1123 const actual_signature = try reader.take(4);1204 const actual_signature = try reader.take(4);
1124 if (!mem.eql(u8, actual_signature, signature)) return error.InvalidHeader;1205 if (!mem.eql(u8, actual_signature, signature)) return error.InvalidHeader;
1125 const version = try reader.takeInt(u32, .big);1206 const version = try reader.takeInt(u32, .big);
1207||||||| 733b208256
1208 fn read(reader: anytype) !PackHeader {
1209 const actual_signature = reader.readBytesNoEof(4) catch |e| switch (e) {
1210 error.EndOfStream => return error.InvalidHeader,
1211 else => |other| return other,
1212 };
1213 if (!mem.eql(u8, &actual_signature, signature)) return error.InvalidHeader;
1214 const version = reader.readInt(u32, .big) catch |e| switch (e) {
1215 error.EndOfStream => return error.InvalidHeader,
1216 else => |other| return other,
1217 };
1218=======
1219 fn read(reader: *std.Io.Reader) !PackHeader {
1220 const actual_signature = reader.take(4) catch |e| switch (e) {
1221 error.EndOfStream => return error.InvalidHeader,
1222 else => |other| return other,
1223 };
1224 if (!mem.eql(u8, actual_signature, signature)) return error.InvalidHeader;
1225 const version = reader.takeInt(u32, .big) catch |e| switch (e) {
1226 error.EndOfStream => return error.InvalidHeader,
1227 else => |other| return other,
1228 };
1229>>>>>>> origin/flate
1126 if (version != supported_version) return error.UnsupportedVersion;1230 if (version != supported_version) return error.UnsupportedVersion;
1231<<<<<<< HEAD
1127 const total_objects = try reader.takeInt(u32, .big);1232 const total_objects = try reader.takeInt(u32, .big);
1233||||||| 733b208256
1234 const total_objects = reader.readInt(u32, .big) catch |e| switch (e) {
1235 error.EndOfStream => return error.InvalidHeader,
1236 else => |other| return other,
1237 };
1238=======
1239 const total_objects = reader.takeInt(u32, .big) catch |e| switch (e) {
1240 error.EndOfStream => return error.InvalidHeader,
1241 else => |other| return other,
1242 };
1243>>>>>>> origin/flate
1128 return .{ .total_objects = total_objects };1244 return .{ .total_objects = total_objects };
1129 }1245 }
1130};1246};
...@@ -1173,10 +1289,30 @@ const EntryHeader = union(Type) {...@@ -1173,10 +1289,30 @@ const EntryHeader = union(Type) {
1173 };1289 };
1174 }1290 }
11751291
1292<<<<<<< HEAD
1176 fn read(format: Oid.Format, reader: *std.io.Reader) !EntryHeader {1293 fn read(format: Oid.Format, reader: *std.io.Reader) !EntryHeader {
1294||||||| 733b208256
1295 fn read(format: Oid.Format, reader: anytype) !EntryHeader {
1296=======
1297 fn read(format: Oid.Format, reader: *std.Io.Reader) !EntryHeader {
1298>>>>>>> origin/flate
1177 const InitialByte = packed struct { len: u4, type: u3, has_next: bool };1299 const InitialByte = packed struct { len: u4, type: u3, has_next: bool };
1300<<<<<<< HEAD
1178 const initial: InitialByte = @bitCast(try reader.takeByte());1301 const initial: InitialByte = @bitCast(try reader.takeByte());
1179 const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;1302 const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;
1303||||||| 733b208256
1304 const initial: InitialByte = @bitCast(reader.readByte() catch |e| switch (e) {
1305 error.EndOfStream => return error.InvalidFormat,
1306 else => |other| return other,
1307 });
1308 const rest_len = if (initial.has_next) try readSizeVarInt(reader) else 0;
1309=======
1310 const initial: InitialByte = @bitCast(reader.takeByte() catch |e| switch (e) {
1311 error.EndOfStream => return error.InvalidFormat,
1312 else => |other| return other,
1313 });
1314 const rest_len = if (initial.has_next) try reader.takeLeb128(u64) else 0;
1315>>>>>>> origin/flate
1180 var uncompressed_length: u64 = initial.len;1316 var uncompressed_length: u64 = initial.len;
1181 uncompressed_length |= std.math.shlExact(u64, rest_len, 4) catch return error.InvalidFormat;1317 uncompressed_length |= std.math.shlExact(u64, rest_len, 4) catch return error.InvalidFormat;
1182 const @"type" = std.enums.fromInt(EntryHeader.Type, initial.type) orelse return error.InvalidFormat;1318 const @"type" = std.enums.fromInt(EntryHeader.Type, initial.type) orelse return error.InvalidFormat;
...@@ -1199,8 +1335,15 @@ const EntryHeader = union(Type) {...@@ -1199,8 +1335,15 @@ const EntryHeader = union(Type) {
1199 }1335 }
1200};1336};
12011337
1338<<<<<<< HEAD
1202fn readSizeVarInt(r: *std.io.Reader) !u64 {1339fn readSizeVarInt(r: *std.io.Reader) !u64 {
1340||||||| 733b208256
1341fn readSizeVarInt(r: anytype) !u64 {
1342=======
1343fn readOffsetVarInt(r: *std.Io.Reader) !u64 {
1344>>>>>>> origin/flate
1203 const Byte = packed struct { value: u7, has_next: bool };1345 const Byte = packed struct { value: u7, has_next: bool };
1346<<<<<<< HEAD
1204 var b: Byte = @bitCast(try r.takeByte());1347 var b: Byte = @bitCast(try r.takeByte());
1205 var value: u64 = b.value;1348 var value: u64 = b.value;
1206 var shift: u6 = 0;1349 var shift: u6 = 0;
...@@ -1215,6 +1358,24 @@ fn readSizeVarInt(r: *std.io.Reader) !u64 {...@@ -1215,6 +1358,24 @@ fn readSizeVarInt(r: *std.io.Reader) !u64 {
1215fn readOffsetVarInt(r: *std.io.Reader) !u64 {1358fn readOffsetVarInt(r: *std.io.Reader) !u64 {
1216 const Byte = packed struct { value: u7, has_next: bool };1359 const Byte = packed struct { value: u7, has_next: bool };
1217 var b: Byte = @bitCast(try r.takeByte());1360 var b: Byte = @bitCast(try r.takeByte());
1361||||||| 733b208256
1362 var b: Byte = @bitCast(try r.readByte());
1363 var value: u64 = b.value;
1364 var shift: u6 = 0;
1365 while (b.has_next) {
1366 b = @bitCast(try r.readByte());
1367 shift = std.math.add(u6, shift, 7) catch return error.InvalidFormat;
1368 value |= @as(u64, b.value) << shift;
1369 }
1370 return value;
1371}
1372
1373fn readOffsetVarInt(r: anytype) !u64 {
1374 const Byte = packed struct { value: u7, has_next: bool };
1375 var b: Byte = @bitCast(try r.readByte());
1376=======
1377 var b: Byte = @bitCast(try r.takeByte());
1378>>>>>>> origin/flate
1218 var value: u64 = b.value;1379 var value: u64 = b.value;
1219 while (b.has_next) {1380 while (b.has_next) {
1220 b = @bitCast(try r.takeByte());1381 b = @bitCast(try r.takeByte());
...@@ -1231,12 +1392,37 @@ const IndexHeader = struct {...@@ -1231,12 +1392,37 @@ const IndexHeader = struct {
1231 const supported_version = 2;1392 const supported_version = 2;
1232 const size = 4 + 4 + @sizeOf([256]u32);1393 const size = 4 + 4 + @sizeOf([256]u32);
12331394
1395<<<<<<< HEAD
1234 fn read(index_header: *IndexHeader, br: *std.io.Reader) !void {1396 fn read(index_header: *IndexHeader, br: *std.io.Reader) !void {
1235 const sig = try br.take(4);1397 const sig = try br.take(4);
1236 if (!mem.eql(u8, sig, signature)) return error.InvalidHeader;1398 if (!mem.eql(u8, sig, signature)) return error.InvalidHeader;
1237 const version = try br.takeInt(u32, .big);1399 const version = try br.takeInt(u32, .big);
1400||||||| 733b208256
1401 fn read(reader: anytype) !IndexHeader {
1402 var header_bytes = try reader.readBytesNoEof(size);
1403 if (!mem.eql(u8, header_bytes[0..4], signature)) return error.InvalidHeader;
1404 const version = mem.readInt(u32, header_bytes[4..8], .big);
1405=======
1406 fn read(index_header: *IndexHeader, reader: *std.Io.Reader) !void {
1407 const sig = try reader.take(4);
1408 if (!mem.eql(u8, sig, signature)) return error.InvalidHeader;
1409 const version = try reader.takeInt(u32, .big);
1410>>>>>>> origin/flate
1238 if (version != supported_version) return error.UnsupportedVersion;1411 if (version != supported_version) return error.UnsupportedVersion;
1412<<<<<<< HEAD
1239 try br.readSliceEndian(u32, &index_header.fan_out_table, .big);1413 try br.readSliceEndian(u32, &index_header.fan_out_table, .big);
1414||||||| 733b208256
1415
1416 var fan_out_table: [256]u32 = undefined;
1417 var fan_out_table_stream = std.io.fixedBufferStream(header_bytes[8..]);
1418 const fan_out_table_reader = fan_out_table_stream.reader();
1419 for (&fan_out_table) |*entry| {
1420 entry.* = fan_out_table_reader.readInt(u32, .big) catch unreachable;
1421 }
1422 return .{ .fan_out_table = fan_out_table };
1423=======
1424 try reader.readSliceEndian(u32, &index_header.fan_out_table, .big);
1425>>>>>>> origin/flate
1240 }1426 }
1241};1427};
12421428
...@@ -1305,10 +1491,18 @@ pub fn indexPack(...@@ -1305,10 +1491,18 @@ pub fn indexPack(
1305 }1491 }
1306 @memset(fan_out_table[fan_out_index..], count);1492 @memset(fan_out_table[fan_out_index..], count);
13071493
1494<<<<<<< HEAD
1308 var index_writer_bw = index_writer.writer(&.{});1495 var index_writer_bw = index_writer.writer(&.{});
1309 var index_hashed_writer = index_writer_bw.hashed(Oid.Hasher.init(format));1496 var index_hashed_writer = index_writer_bw.hashed(Oid.Hasher.init(format));
1310 var write_buffer: [256]u8 = undefined;1497 var write_buffer: [256]u8 = undefined;
1311 var writer = index_hashed_writer.writer(&write_buffer);1498 var writer = index_hashed_writer.writer(&write_buffer);
1499||||||| 733b208256
1500 var index_hashed_writer = hashedWriter(index_writer, Oid.Hasher.init(format));
1501 const writer = index_hashed_writer.writer();
1502=======
1503 var index_hashed_writer = std.Io.Writer.hashed(&index_writer.interface, Oid.Hasher.init(format), &.{});
1504 const writer = &index_hashed_writer.writer;
1505>>>>>>> origin/flate
1312 try writer.writeAll(IndexHeader.signature);1506 try writer.writeAll(IndexHeader.signature);
1313 try writer.writeInt(u32, IndexHeader.supported_version, .big);1507 try writer.writeInt(u32, IndexHeader.supported_version, .big);
1314 for (fan_out_table) |fan_out_entry| {1508 for (fan_out_table) |fan_out_entry| {
...@@ -1342,7 +1536,14 @@ pub fn indexPack(...@@ -1342,7 +1536,14 @@ pub fn indexPack(
1342 try writer.writeAll(pack_checksum.slice());1536 try writer.writeAll(pack_checksum.slice());
1343 try writer.flush();1537 try writer.flush();
1344 const index_checksum = index_hashed_writer.hasher.finalResult();1538 const index_checksum = index_hashed_writer.hasher.finalResult();
1539<<<<<<< HEAD
1345 try index_writer_bw.writeAll(index_checksum.slice());1540 try index_writer_bw.writeAll(index_checksum.slice());
1541||||||| 733b208256
1542 try index_writer.writeAll(index_checksum.slice());
1543=======
1544 try index_writer.interface.writeAll(index_checksum.slice());
1545 try index_writer.end();
1546>>>>>>> origin/flate
1346}1547}
13471548
1348/// Performs the first pass over the packfile data for index construction.1549/// Performs the first pass over the packfile data for index construction.
...@@ -1356,11 +1557,29 @@ fn indexPackFirstPass(...@@ -1356,11 +1557,29 @@ fn indexPackFirstPass(
1356 index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),1557 index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),
1357 pending_deltas: *std.ArrayListUnmanaged(IndexEntry),1558 pending_deltas: *std.ArrayListUnmanaged(IndexEntry),
1358) !Oid {1559) !Oid {
1560<<<<<<< HEAD
1561 var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
1562 var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);
1563||||||| 733b208256
1564 var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());
1565 var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());
1566 var pack_hashed_reader = hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format));
1567 const pack_reader = pack_hashed_reader.reader();
1568=======
1569 var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
1359 var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.1570 var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
1360 var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);1571 var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);
1572>>>>>>> origin/flate
13611573
1574<<<<<<< HEAD
1362 const pack_header = try PackHeader.read(&pack_hashed.interface);1575 const pack_header = try PackHeader.read(&pack_hashed.interface);
1576||||||| 733b208256
1577 const pack_header = try PackHeader.read(pack_reader);
1578=======
1579 const pack_header = try PackHeader.read(&pack_hashed.reader);
1580>>>>>>> origin/flate
13631581
1582<<<<<<< HEAD
1364 for (0..pack_header.total_objects) |_| {1583 for (0..pack_header.total_objects) |_| {
1365 const entry_offset = pack.pos - pack_hashed.interface.buffered().len;1584 const entry_offset = pack.pos - pack_hashed.interface.buffered().len;
1366 var entry_buffer: [64]u8 = undefined; // Buffer only needed for loading EntryHeader.1585 var entry_buffer: [64]u8 = undefined; // Buffer only needed for loading EntryHeader.
...@@ -1370,40 +1589,111 @@ fn indexPackFirstPass(...@@ -1370,40 +1589,111 @@ fn indexPackFirstPass(
1370 var entry_decompress_stream: zlib.Decompressor = .init(&entry_crc32_br);1589 var entry_decompress_stream: zlib.Decompressor = .init(&entry_crc32_br);
1371 // Decompress uses large output buffer; no input buffer needed.1590 // Decompress uses large output buffer; no input buffer needed.
1372 var entry_decompress_br = entry_decompress_stream.reader(&.{});1591 var entry_decompress_br = entry_decompress_stream.reader(&.{});
1592||||||| 733b208256
1593 var current_entry: u32 = 0;
1594 while (current_entry < pack_header.total_objects) : (current_entry += 1) {
1595 const entry_offset = pack_counting_reader.bytes_read;
1596 var entry_crc32_reader = hashedReader(pack_reader, std.hash.Crc32.init());
1597 const entry_header = try EntryHeader.read(format, entry_crc32_reader.reader());
1598=======
1599 for (0..pack_header.total_objects) |_| {
1600 const entry_offset = pack.logicalPos() - pack_hashed.reader.bufferedLen();
1601 const entry_header = try EntryHeader.read(format, &pack_hashed.reader);
1602>>>>>>> origin/flate
1373 switch (entry_header) {1603 switch (entry_header) {
1374 .commit, .tree, .blob, .tag => |object| {1604 .commit, .tree, .blob, .tag => |object| {
1605<<<<<<< HEAD
1375 var oid_hasher = Oid.Hasher.init(format);1606 var oid_hasher = Oid.Hasher.init(format);
1376 var oid_hasher_buffer: [zlib.max_window_len]u8 = undefined;1607 var oid_hasher_buffer: [zlib.max_window_len]u8 = undefined;
1377 var oid_hasher_bw = oid_hasher.writer(&oid_hasher_buffer);1608 var oid_hasher_bw = oid_hasher.writer(&oid_hasher_buffer);
1609||||||| 733b208256
1610 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
1611 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
1612 var entry_hashed_writer = hashedWriter(std.io.null_writer, Oid.Hasher.init(format));
1613 const entry_writer = entry_hashed_writer.writer();
1614=======
1615 var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &.{});
1616 var oid_hasher: Oid.Hashing = .init(format, &flate_buffer);
1617 const oid_hasher_w = oid_hasher.writer();
1618>>>>>>> origin/flate
1378 // The object header is not included in the pack data but is1619 // The object header is not included in the pack data but is
1620<<<<<<< HEAD
1379 // part of the object's ID.1621 // part of the object's ID.
1380 try oid_hasher_bw.print("{s} {d}\x00", .{ @tagName(entry_header), object.uncompressed_length });1622 try oid_hasher_bw.print("{s} {d}\x00", .{ @tagName(entry_header), object.uncompressed_length });
1381 const n = try entry_decompress_br.readRemaining(&oid_hasher_bw);1623 const n = try entry_decompress_br.readRemaining(&oid_hasher_bw);
1382 if (n != object.uncompressed_length) return error.InvalidObject;1624 if (n != object.uncompressed_length) return error.InvalidObject;
1383 try oid_hasher_bw.flush();1625 try oid_hasher_bw.flush();
1384 const oid = oid_hasher.finalResult();1626 const oid = oid_hasher.finalResult();
1627||||||| 733b208256
1628 // part of the object's ID
1629 try entry_writer.print("{s} {}\x00", .{ @tagName(entry_header), object.uncompressed_length });
1630 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1631 try fifo.pump(entry_counting_reader.reader(), entry_writer);
1632 if (entry_counting_reader.bytes_read != object.uncompressed_length) {
1633 return error.InvalidObject;
1634 }
1635 const oid = entry_hashed_writer.hasher.finalResult();
1636=======
1637 // part of the object's ID
1638 try oid_hasher_w.print("{t} {d}\x00", .{ entry_header, object.uncompressed_length });
1639 const n = try entry_decompress.reader.streamRemaining(oid_hasher_w);
1640 if (n != object.uncompressed_length) return error.InvalidObject;
1641 const oid = oid_hasher.final();
1642 if (!skip_checksums) @compileError("TODO");
1643>>>>>>> origin/flate
1385 try index_entries.put(allocator, oid, .{1644 try index_entries.put(allocator, oid, .{
1386 .offset = entry_offset,1645 .offset = entry_offset,
1387 .crc32 = entry_crc32_reader.hasher.final(),1646 .crc32 = 0,
1388 });1647 });
1389 },1648 },
1390 inline .ofs_delta, .ref_delta => |delta| {1649 inline .ofs_delta, .ref_delta => |delta| {
1650<<<<<<< HEAD
1391 const n = try entry_decompress_br.discardRemaining();1651 const n = try entry_decompress_br.discardRemaining();
1392 if (n != delta.uncompressed_length) return error.InvalidObject;1652 if (n != delta.uncompressed_length) return error.InvalidObject;
1653||||||| 733b208256
1654 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
1655 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
1656 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1657 try fifo.pump(entry_counting_reader.reader(), std.io.null_writer);
1658 if (entry_counting_reader.bytes_read != delta.uncompressed_length) {
1659 return error.InvalidObject;
1660 }
1661=======
1662 var entry_decompress: std.compress.flate.Decompress = .init(&pack_hashed.reader, .zlib, &flate_buffer);
1663 const n = try entry_decompress.reader.discardRemaining();
1664 if (n != delta.uncompressed_length) return error.InvalidObject;
1665 if (!skip_checksums) @compileError("TODO");
1666>>>>>>> origin/flate
1393 try pending_deltas.append(allocator, .{1667 try pending_deltas.append(allocator, .{
1394 .offset = entry_offset,1668 .offset = entry_offset,
1395 .crc32 = entry_crc32_reader.hasher.final(),1669 .crc32 = 0,
1396 });1670 });
1397 },1671 },
1398 }1672 }
1399 }1673 }
14001674
1675<<<<<<< HEAD
1401 const pack_checksum = pack_hashed.hasher.finalResult();1676 const pack_checksum = pack_hashed.hasher.finalResult();
1402 const recorded_checksum = try Oid.readBytes(format, &pack.interface);1677 const recorded_checksum = try Oid.readBytes(format, &pack.interface);
1403 if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {1678 if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {
1404 return error.CorruptedPack;1679 return error.CorruptedPack;
1405 }1680 }
1406 return pack_checksum;1681 return pack_checksum;
1682||||||| 733b208256
1683 const pack_checksum = pack_hashed_reader.hasher.finalResult();
1684 const recorded_checksum = try Oid.readBytes(format, pack_buffered_reader.reader());
1685 if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {
1686 return error.CorruptedPack;
1687 }
1688 _ = pack_reader.readByte() catch |e| switch (e) {
1689 error.EndOfStream => return pack_checksum,
1690 else => |other| return other,
1691 };
1692 return error.InvalidFormat;
1693=======
1694 if (!skip_checksums) @compileError("TODO");
1695 return pack_hashed.hasher.finalResult();
1696>>>>>>> origin/flate
1407}1697}
14081698
1409/// Attempts to determine the final object ID of the given deltified object.1699/// Attempts to determine the final object ID of the given deltified object.
...@@ -1448,6 +1738,7 @@ fn indexPackHashDelta(...@@ -1448,6 +1738,7 @@ fn indexPackHashDelta(
14481738
1449 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);1739 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
14501740
1741<<<<<<< HEAD
1451 var entry_hasher: Oid.Hasher = .init(format);1742 var entry_hasher: Oid.Hasher = .init(format);
1452 var entry_hasher_buffer: [64]u8 = undefined;1743 var entry_hasher_buffer: [64]u8 = undefined;
1453 var entry_hasher_bw = entry_hasher.writer(&entry_hasher_buffer);1744 var entry_hasher_bw = entry_hasher.writer(&entry_hasher_buffer);
...@@ -1456,6 +1747,21 @@ fn indexPackHashDelta(...@@ -1456,6 +1747,21 @@ fn indexPackHashDelta(
1456 entry_hasher_bw.writeAll(base_data) catch unreachable;1747 entry_hasher_bw.writeAll(base_data) catch unreachable;
1457 entry_hasher_bw.flush() catch unreachable;1748 entry_hasher_bw.flush() catch unreachable;
1458 return entry_hasher.finalResult();1749 return entry_hasher.finalResult();
1750||||||| 733b208256
1751 var entry_hasher: Oid.Hasher = .init(format);
1752 var entry_hashed_writer = hashedWriter(std.io.null_writer, &entry_hasher);
1753 try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });
1754 entry_hasher.update(base_data);
1755 return entry_hasher.finalResult();
1756=======
1757 var entry_hasher_buffer: [64]u8 = undefined;
1758 var entry_hasher: Oid.Hashing = .init(format, &entry_hasher_buffer);
1759 const entry_hasher_w = entry_hasher.writer();
1760 // Writes to hashers cannot fail.
1761 entry_hasher_w.print("{t} {d}\x00", .{ base_object.type, base_data.len }) catch unreachable;
1762 entry_hasher_w.writeAll(base_data) catch unreachable;
1763 return entry_hasher.final();
1764>>>>>>> origin/flate
1459}1765}
14601766
1461/// Resolves a chain of deltas, returning the final base object data. `pack` is1767/// Resolves a chain of deltas, returning the final base object data. `pack` is
...@@ -1477,6 +1783,7 @@ fn resolveDeltaChain(...@@ -1477,6 +1783,7 @@ fn resolveDeltaChain(
14771783
1478 const delta_offset = delta_offsets[i];1784 const delta_offset = delta_offsets[i];
1479 try pack.seekTo(delta_offset);1785 try pack.seekTo(delta_offset);
1786<<<<<<< HEAD
1480 const delta_header = try EntryHeader.read(format, &pack.interface);1787 const delta_header = try EntryHeader.read(format, &pack.interface);
1481 _ = delta_header;1788 _ = delta_header;
1482 var delta_decompress: zlib.Decompressor = .init(&pack.interface);1789 var delta_decompress: zlib.Decompressor = .init(&pack.interface);
...@@ -1484,12 +1791,41 @@ fn resolveDeltaChain(...@@ -1484,12 +1791,41 @@ fn resolveDeltaChain(
1484 var delta_reader = delta_decompress.reader(&delta_decompress_buffer);1791 var delta_reader = delta_decompress.reader(&delta_decompress_buffer);
1485 _ = try readSizeVarInt(&delta_reader); // base object size1792 _ = try readSizeVarInt(&delta_reader); // base object size
1486 const expanded_size = try readSizeVarInt(&delta_reader);1793 const expanded_size = try readSizeVarInt(&delta_reader);
1794||||||| 733b208256
1795 const delta_header = try EntryHeader.read(format, pack.deprecatedReader());
1796 const delta_data = try readObjectRaw(allocator, pack.deprecatedReader(), delta_header.uncompressedLength());
1797 defer allocator.free(delta_data);
1798 var delta_stream = std.io.fixedBufferStream(delta_data);
1799 const delta_reader = delta_stream.reader();
1800 _ = try readSizeVarInt(delta_reader); // base object size
1801 const expanded_size = try readSizeVarInt(delta_reader);
1802
1803=======
1804 const delta_header = try EntryHeader.read(format, &pack.interface);
1805 const delta_data = try readObjectRaw(allocator, &pack.interface, delta_header.uncompressedLength());
1806 defer allocator.free(delta_data);
1807 var delta_reader: std.Io.Reader = .fixed(delta_data);
1808 _ = try delta_reader.takeLeb128(u64); // base object size
1809 const expanded_size = try delta_reader.takeLeb128(u64);
1810
1811>>>>>>> origin/flate
1487 const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge;1812 const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge;
1488 const expanded_data = try allocator.alloc(u8, expanded_alloc_size);1813 const expanded_data = try allocator.alloc(u8, expanded_alloc_size);
1489 errdefer allocator.free(expanded_data);1814 errdefer allocator.free(expanded_data);
1815<<<<<<< HEAD
1490 var expanded_delta_stream: Writer = .fixed(expanded_data);1816 var expanded_delta_stream: Writer = .fixed(expanded_data);
1491 try expandDelta(base_data, &delta_reader, &expanded_delta_stream);1817 try expandDelta(base_data, &delta_reader, &expanded_delta_stream);
1492 if (expanded_delta_stream.end != expanded_size) return error.InvalidObject;1818 if (expanded_delta_stream.end != expanded_size) return error.InvalidObject;
1819||||||| 733b208256
1820 var expanded_delta_stream = std.io.fixedBufferStream(expanded_data);
1821 var base_stream = std.io.fixedBufferStream(base_data);
1822 try expandDelta(&base_stream, delta_reader, expanded_delta_stream.writer());
1823 if (expanded_delta_stream.pos != expanded_size) return error.InvalidObject;
1824=======
1825 var expanded_delta_stream: std.Io.Writer = .fixed(expanded_data);
1826 try expandDelta(base_data, &delta_reader, &expanded_delta_stream);
1827 if (expanded_delta_stream.end != expanded_size) return error.InvalidObject;
1828>>>>>>> origin/flate
14931829
1494 try cache.put(allocator, delta_offset, .{ .type = base_object.type, .data = expanded_data });1830 try cache.put(allocator, delta_offset, .{ .type = base_object.type, .data = expanded_data });
1495 base_data = expanded_data;1831 base_data = expanded_data;
...@@ -1497,21 +1833,68 @@ fn resolveDeltaChain(...@@ -1497,21 +1833,68 @@ fn resolveDeltaChain(
1497 return base_data;1833 return base_data;
1498}1834}
14991835
1836<<<<<<< HEAD
1500/// Reads the complete contents of an object from `reader`.1837/// Reads the complete contents of an object from `reader`.
1501fn readObjectRaw(gpa: Allocator, reader: *std.io.Reader, size: u64) ![]u8 {1838fn readObjectRaw(gpa: Allocator, reader: *std.io.Reader, size: u64) ![]u8 {
1839||||||| 733b208256
1840/// Reads the complete contents of an object from `reader`. This function may
1841/// read more bytes than required from `reader`, so the reader position after
1842/// returning is not reliable.
1843fn readObjectRaw(allocator: Allocator, reader: anytype, size: u64) ![]u8 {
1844=======
1845/// Reads the complete contents of an object from `reader`. This function may
1846/// read more bytes than required from `reader`, so the reader position after
1847/// returning is not reliable.
1848fn readObjectRaw(allocator: Allocator, reader: *std.Io.Reader, size: u64) ![]u8 {
1849>>>>>>> origin/flate
1502 const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge;1850 const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge;
1851<<<<<<< HEAD
1503 var decompress: zlib.Decompressor = .init(reader);1852 var decompress: zlib.Decompressor = .init(reader);
1504 var buffer: std.ArrayListUnmanaged(u8) = .empty;1853 var buffer: std.ArrayListUnmanaged(u8) = .empty;
1505 defer buffer.deinit(gpa);1854 defer buffer.deinit(gpa);
1506 try decompress.reader().readRemainingArrayList(gpa, null, &buffer, .limited(alloc_size), zlib.max_window_len);1855 try decompress.reader().readRemainingArrayList(gpa, null, &buffer, .limited(alloc_size), zlib.max_window_len);
1507 if (buffer.items.len < size) return error.EndOfStream;1856 if (buffer.items.len < size) return error.EndOfStream;
1508 return buffer.toOwnedSlice(gpa);1857 return buffer.toOwnedSlice(gpa);
1858||||||| 733b208256
1859 var buffered_reader = std.io.bufferedReader(reader);
1860 var decompress_stream = std.compress.zlib.decompressor(buffered_reader.reader());
1861 const data = try allocator.alloc(u8, alloc_size);
1862 errdefer allocator.free(data);
1863 try decompress_stream.reader().readNoEof(data);
1864 _ = decompress_stream.reader().readByte() catch |e| switch (e) {
1865 error.EndOfStream => return data,
1866 else => |other| return other,
1867 };
1868 return error.InvalidFormat;
1869=======
1870 var aw: std.Io.Writer.Allocating = .init(allocator);
1871 try aw.ensureTotalCapacity(alloc_size + std.compress.flate.max_window_len);
1872 defer aw.deinit();
1873 var decompress: std.compress.flate.Decompress = .init(reader, .zlib, &.{});
1874 try decompress.reader.streamExact(&aw.writer, alloc_size);
1875 return aw.toOwnedSlice();
1876>>>>>>> origin/flate
1509}1877}
15101878
1879<<<<<<< HEAD
1880||||||| 733b208256
1881/// Expands delta data from `delta_reader` to `writer`. `base_object` must
1882/// support `reader` and `seekTo` (such as a `std.io.FixedBufferStream`).
1883///
1884=======
1885/// Expands delta data from `delta_reader` to `writer`.
1886///
1887>>>>>>> origin/flate
1511/// The format of the delta data is documented in1888/// The format of the delta data is documented in
1512/// [pack-format](https://git-scm.com/docs/pack-format).1889/// [pack-format](https://git-scm.com/docs/pack-format).
1890<<<<<<< HEAD
1513fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *Writer) !void {1891fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *Writer) !void {
1514 var base_offset: u32 = 0;1892 var base_offset: u32 = 0;
1893||||||| 733b208256
1894fn expandDelta(base_object: anytype, delta_reader: anytype, writer: anytype) !void {
1895=======
1896fn expandDelta(base_object: []const u8, delta_reader: *std.Io.Reader, writer: *std.Io.Writer) !void {
1897>>>>>>> origin/flate
1515 while (true) {1898 while (true) {
1516 const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) {1899 const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) {
1517 error.EndOfStream => return,1900 error.EndOfStream => return,
...@@ -1533,7 +1916,13 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *W...@@ -1533,7 +1916,13 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *W
1533 .offset3 = if (available.offset3) try delta_reader.takeByte() else 0,1916 .offset3 = if (available.offset3) try delta_reader.takeByte() else 0,
1534 .offset4 = if (available.offset4) try delta_reader.takeByte() else 0,1917 .offset4 = if (available.offset4) try delta_reader.takeByte() else 0,
1535 };1918 };
1919<<<<<<< HEAD
1536 base_offset = @bitCast(offset_parts);1920 base_offset = @bitCast(offset_parts);
1921||||||| 733b208256
1922 const offset: u32 = @bitCast(offset_parts);
1923=======
1924 const base_offset: u32 = @bitCast(offset_parts);
1925>>>>>>> origin/flate
1537 const size_parts: packed struct { size1: u8, size2: u8, size3: u8 } = .{1926 const size_parts: packed struct { size1: u8, size2: u8, size3: u8 } = .{
1538 .size1 = if (available.size1) try delta_reader.takeByte() else 0,1927 .size1 = if (available.size1) try delta_reader.takeByte() else 0,
1539 .size2 = if (available.size2) try delta_reader.takeByte() else 0,1928 .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...@@ -1541,11 +1930,28 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *W
1541 };1930 };
1542 var size: u24 = @bitCast(size_parts);1931 var size: u24 = @bitCast(size_parts);
1543 if (size == 0) size = 0x10000;1932 if (size == 0) size = 0x10000;
1933<<<<<<< HEAD
15441934
1545 try writer.writeAll(base_object[base_offset..][0..size]);1935 try writer.writeAll(base_object[base_offset..][0..size]);
1546 base_offset += size;1936 base_offset += size;
1937||||||| 733b208256
1938 try base_object.seekTo(offset);
1939 var copy_reader = std.io.limitedReader(base_object.reader(), size);
1940 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1941 try fifo.pump(copy_reader.reader(), writer);
1942=======
1943 try writer.writeAll(base_object[base_offset..][0..size]);
1944>>>>>>> origin/flate
1547 } else if (inst.value != 0) {1945 } else if (inst.value != 0) {
1946<<<<<<< HEAD
1548 try delta_reader.readAll(writer, .limited(inst.value));1947 try delta_reader.readAll(writer, .limited(inst.value));
1948||||||| 733b208256
1949 var data_reader = std.io.limitedReader(delta_reader, inst.value);
1950 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1951 try fifo.pump(data_reader.reader(), writer);
1952=======
1953 try delta_reader.streamExact(writer, inst.value);
1954>>>>>>> origin/flate
1549 } else {1955 } else {
1550 return error.InvalidDeltaInstruction;1956 return error.InvalidDeltaInstruction;
1551 }1957 }
...@@ -1575,25 +1981,46 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void...@@ -1575,25 +1981,46 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
1575 defer pack_file.close();1981 defer pack_file.close();
1576 try pack_file.writeAll(testrepo_pack);1982 try pack_file.writeAll(testrepo_pack);
15771983
1984 var pack_file_buffer: [2000]u8 = undefined;
1985 var pack_file_reader = pack_file.reader(&pack_file_buffer);
1986
1578 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });1987 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });
1579 defer index_file.close();1988 defer index_file.close();
1989<<<<<<< HEAD
1580 var index_file_writer = index_file.writer();1990 var index_file_writer = index_file.writer();
1581 try indexPack(testing.allocator, format, pack_file, &index_file_writer);1991 try indexPack(testing.allocator, format, pack_file, &index_file_writer);
1992||||||| 733b208256
1993 try indexPack(testing.allocator, format, pack_file, index_file.deprecatedWriter());
1994=======
1995 var index_file_buffer: [2000]u8 = undefined;
1996 var index_file_writer = index_file.writer(&index_file_buffer);
1997 try indexPack(testing.allocator, format, &pack_file_reader, &index_file_writer);
1998>>>>>>> origin/flate
15821999
1583 // Arbitrary size limit on files read while checking the repository contents2000 // Arbitrary size limit on files read while checking the repository contents
1584 // (all files in the test repo are known to be smaller than this)2001 // (all files in the test repo are known to be smaller than this)
1585 const max_file_size = 8192;2002 const max_file_size = 8192;
15862003
1587 const index_file_data = try git_dir.dir.readFileAlloc(testing.allocator, "testrepo.idx", max_file_size);2004 if (!skip_checksums) {
1588 defer testing.allocator.free(index_file_data);2005 const index_file_data = try git_dir.dir.readFileAlloc(testing.allocator, "testrepo.idx", max_file_size);
1589 // testrepo.idx is generated by Git. The index created by this file should2006 defer testing.allocator.free(index_file_data);
1590 // match it exactly. Running `git verify-pack -v testrepo.pack` can verify2007 // testrepo.idx is generated by Git. The index created by this file should
1591 // this.2008 // match it exactly. Running `git verify-pack -v testrepo.pack` can verify
1592 const testrepo_idx = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".idx");2009 // this.
1593 try testing.expectEqualSlices(u8, testrepo_idx, index_file_data);2010 const testrepo_idx = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".idx");
2011 try testing.expectEqualSlices(u8, testrepo_idx, index_file_data);
2012 }
15942013
2014<<<<<<< HEAD
1595 var index_file_reader = index_file_writer.moveToReader();2015 var index_file_reader = index_file_writer.moveToReader();
1596 var repository = try Repository.init(testing.allocator, format, pack_file, &index_file_reader);2016 var repository = try Repository.init(testing.allocator, format, pack_file, &index_file_reader);
2017||||||| 733b208256
2018 var repository = try Repository.init(testing.allocator, format, pack_file, index_file);
2019=======
2020 var index_file_reader = index_file.reader(&index_file_buffer);
2021 var repository: Repository = undefined;
2022 try repository.init(testing.allocator, format, &pack_file_reader, &index_file_reader);
2023>>>>>>> origin/flate
1597 defer repository.deinit();2024 defer repository.deinit();
15982025
1599 var worktree = testing.tmpDir(.{ .iterate = true });2026 var worktree = testing.tmpDir(.{ .iterate = true });
...@@ -1663,6 +2090,12 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void...@@ -1663,6 +2090,12 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
1663 try testing.expectEqualStrings(expected_file_contents, actual_file_contents);2090 try testing.expectEqualStrings(expected_file_contents, actual_file_contents);
1664}2091}
16652092
2093/// Checksum calculation is useful for troubleshooting and debugging, but it's
2094/// redundant since the package manager already does content hashing at the
2095/// end. Let's save time by not doing that work, but, I left a cookie crumb
2096/// trail here if you want to restore the functionality for tinkering purposes.
2097const skip_checksums = true;
2098
1666test "SHA-1 packfile indexing and checkout" {2099test "SHA-1 packfile indexing and checkout" {
1667 try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb");2100 try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb");
1668}2101}
...@@ -1688,6 +2121,9 @@ pub fn main() !void {...@@ -1688,6 +2121,9 @@ pub fn main() !void {
16882121
1689 var pack_file = try std.fs.cwd().openFile(args[2], .{});2122 var pack_file = try std.fs.cwd().openFile(args[2], .{});
1690 defer pack_file.close();2123 defer pack_file.close();
2124 var pack_file_buffer: [4096]u8 = undefined;
2125 var pack_file_reader = pack_file.reader(&pack_file_buffer);
2126
1691 const commit = try Oid.parse(format, args[3]);2127 const commit = try Oid.parse(format, args[3]);
1692 var worktree = try std.fs.cwd().makeOpenPath(args[4], .{});2128 var worktree = try std.fs.cwd().makeOpenPath(args[4], .{});
1693 defer worktree.close();2129 defer worktree.close();
...@@ -1698,15 +2134,32 @@ pub fn main() !void {...@@ -1698,15 +2134,32 @@ pub fn main() !void {
1698 std.debug.print("Starting index...\n", .{});2134 std.debug.print("Starting index...\n", .{});
1699 var index_file = try git_dir.createFile("idx", .{ .read = true });2135 var index_file = try git_dir.createFile("idx", .{ .read = true });
1700 defer index_file.close();2136 defer index_file.close();
2137<<<<<<< HEAD
1701 var index_file_writer = index_file.writer();2138 var index_file_writer = index_file.writer();
1702 var pack_file_reader = pack_file.reader();2139 var pack_file_reader = pack_file.reader();
1703 try indexPack(gpa, format, &pack_file_reader, &index_file_writer);2140 try indexPack(gpa, format, &pack_file_reader, &index_file_writer);
1704 try index_file.sync();2141 try index_file.sync();
2142||||||| 733b208256
2143 var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter());
2144 try indexPack(allocator, format, pack_file, index_buffered_writer.writer());
2145 try index_buffered_writer.flush();
2146 try index_file.sync();
2147=======
2148 var index_buffered_writer = std.io.bufferedWriter(index_file.deprecatedWriter());
2149 try indexPack(allocator, format, &pack_file_reader, index_buffered_writer.writer());
2150 try index_buffered_writer.flush();
2151>>>>>>> origin/flate
17052152
1706 std.debug.print("Starting checkout...\n", .{});2153 std.debug.print("Starting checkout...\n", .{});
2154<<<<<<< HEAD
1707 var index_file_reader = index_file_writer.moveToReader();2155 var index_file_reader = index_file_writer.moveToReader();
1708 var repository: Repository = undefined;2156 var repository: Repository = undefined;
1709 try repository.init(gpa, format, &pack_file_reader, &index_file_reader);2157 try repository.init(gpa, format, &pack_file_reader, &index_file_reader);
2158||||||| 733b208256
2159 var repository = try Repository.init(allocator, format, pack_file, index_file);
2160=======
2161 var repository = try Repository.init(allocator, format, &pack_file_reader, index_file);
2162>>>>>>> origin/flate
1710 defer repository.deinit();2163 defer repository.deinit();
1711 var diagnostics: Diagnostics = .{ .allocator = gpa };2164 var diagnostics: Diagnostics = .{ .allocator = gpa };
1712 defer diagnostics.deinit();2165 defer diagnostics.deinit();
src/Package/Module.zig+1-1
...@@ -250,7 +250,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -250,7 +250,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
250 };250 };
251251
252 const stack_check = b: {252 const stack_check = b: {
253 if (!target_util.supportsStackProbing(target)) {253 if (!target_util.supportsStackProbing(target, zig_backend)) {
254 if (options.inherited.stack_check == true)254 if (options.inherited.stack_check == true)
255 return error.StackCheckUnsupportedByTarget;255 return error.StackCheckUnsupportedByTarget;
256 break :b false;256 break :b false;
src/Sema.zig+223-603
...@@ -1905,8 +1905,12 @@ fn analyzeBodyInner(...@@ -1905,8 +1905,12 @@ fn analyzeBodyInner(
1905 const err_union = try sema.resolveInst(extra.data.operand);1905 const err_union = try sema.resolveInst(extra.data.operand);
1906 const err_union_ty = sema.typeOf(err_union);1906 const err_union_ty = sema.typeOf(err_union);
1907 if (err_union_ty.zigTypeTag(zcu) != .error_union) {1907 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
1908 return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{1908 return sema.failWithOwnedErrorMsg(block, msg: {
1909 err_union_ty.fmt(pt),1909 const msg = try sema.errMsg(operand_src, "expected error union type, found '{f}'", .{err_union_ty.fmt(pt)});
1910 errdefer msg.destroy(sema.gpa);
1911 try sema.addDeclaredHereNote(msg, err_union_ty);
1912 try sema.errNote(operand_src, msg, "consider omitting 'try'", .{});
1913 break :msg msg;
1910 });1914 });
1911 }1915 }
1912 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);1916 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,...@@ -3922,7 +3926,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
3922 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));3926 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
3923 const ptr_to_map = switch (store_inst.tag) {3927 const ptr_to_map = switch (store_inst.tag) {
3924 .store, .store_safe => store_inst.data.bin_op.lhs.toIndex().?, // Map the pointer being stored to.3928 .store, .store_safe => store_inst.data.bin_op.lhs.toIndex().?, // Map the pointer being stored to.
3925 .set_union_tag => continue, // We can completely ignore these: we'll do it implicitly when we get the field pointer.3929 .set_union_tag => continue, // Ignore for now; handled after we map pointers
3926 .optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself.3930 .optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself.
3927 else => unreachable,3931 else => unreachable,
3928 };3932 };
...@@ -4055,19 +4059,33 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4055,19 +4059,33 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4055 }4059 }
40564060
4057 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.4061 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.
4058 // Any implicit stores performed by `optional_payload_ptr_set`, `errunion_payload_ptr_set`, or4062 // Any implicit stores performed by `optional_payload_ptr_set` or `errunion_payload_ptr_set`
4059 // `set_union_tag` instructions were already done above.4063 // instructions were already done above.
40604064
4061 for (stores) |store_inst_idx| {4065 for (stores) |store_inst_idx| {
4062 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));4066 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
4063 switch (store_inst.tag) {4067 switch (store_inst.tag) {
4064 .set_union_tag => {}, // Handled implicitly by field pointers above
4065 .optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above4068 .optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above
4069 .set_union_tag => {
4070 // Usually, we can ignore these, because the creation of the field pointer above
4071 // already did it for us. However, if the field is OPV, this is relevant, because
4072 // there is not going to be a store to the field. So we must initialize the union
4073 // tag if the field is OPV.
4074 const union_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
4075 const union_ptr_val: Value = .fromInterned(ptr_mapping.get(union_ptr_inst).?);
4076 const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?);
4077 const union_ty = union_ptr_val.typeOf(zcu).childType(zcu);
4078 const field_ty = union_ty.unionFieldType(tag_val, zcu).?;
4079 if (try sema.typeHasOnePossibleValue(field_ty)) |payload_val| {
4080 const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val);
4081 try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty);
4082 }
4083 },
4066 .store, .store_safe => {4084 .store, .store_safe => {
4067 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;4085 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
4068 const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;4086 const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;
4069 const new_ptr = ptr_mapping.get(air_ptr_inst).?;4087 const new_ptr = ptr_mapping.get(air_ptr_inst).?;
4070 try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(new_ptr), store_val, .fromInterned(zcu.intern_pool.typeOf(store_val.toIntern())));4088 try sema.storePtrVal(block, .unneeded, .fromInterned(new_ptr), store_val, store_val.typeOf(zcu));
4071 },4089 },
4072 else => unreachable,4090 else => unreachable,
4073 }4091 }
...@@ -4099,14 +4117,13 @@ fn finishResolveComptimeKnownAllocPtr(...@@ -4099,14 +4117,13 @@ fn finishResolveComptimeKnownAllocPtr(
4099 // We're almost done - we have the resolved comptime value. We just need to4117 // We're almost done - we have the resolved comptime value. We just need to
4100 // eliminate the now-dead runtime instructions.4118 // eliminate the now-dead runtime instructions.
41014119
4102 // We will rewrite the AIR to eliminate the alloc and all stores to it.4120 // This instruction has type `alloc_ty`, meaning we can rewrite the `alloc` AIR instruction to
4103 // This will cause instructions deriving field pointers etc of the alloc to4121 // this one to drop the side effect. We also need to rewrite the stores; we'll turn them to this
4104 // become invalid, however, since we are removing all stores to those pointers,4122 // too because it doesn't really matter what they become.
4105 // they will be eliminated by Liveness before they reach codegen.4123 const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{
41064124 .ty = .fromIntern(alloc_ty.toIntern()),
4107 // The specifics of this instruction aren't really important: we just want4125 .operand = .zero_usize,
4108 // Liveness to elide it.4126 } } };
4109 const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ .ty = .u8_type, .operand = .zero_u8 } } };
41104127
4111 sema.air_instructions.set(@intFromEnum(alloc_inst), nop_inst);4128 sema.air_instructions.set(@intFromEnum(alloc_inst), nop_inst);
4112 for (comptime_info.stores.items(.inst)) |store_inst| {4129 for (comptime_info.stores.items(.inst)) |store_inst| {
...@@ -4829,13 +4846,13 @@ fn zirValidatePtrStructInit(...@@ -4829,13 +4846,13 @@ fn zirValidatePtrStructInit(
4829 agg_ty,4846 agg_ty,
4830 init_src,4847 init_src,
4831 instrs,4848 instrs,
4849 object_ptr,
4832 ),4850 ),
4833 .@"union" => return sema.validateUnionInit(4851 .@"union" => return sema.validateUnionInit(
4834 block,4852 block,
4835 agg_ty,4853 agg_ty,
4836 init_src,4854 init_src,
4837 instrs,4855 instrs,
4838 object_ptr,
4839 ),4856 ),
4840 else => unreachable,4857 else => unreachable,
4841 }4858 }
...@@ -4847,164 +4864,28 @@ fn validateUnionInit(...@@ -4847,164 +4864,28 @@ fn validateUnionInit(
4847 union_ty: Type,4864 union_ty: Type,
4848 init_src: LazySrcLoc,4865 init_src: LazySrcLoc,
4849 instrs: []const Zir.Inst.Index,4866 instrs: []const Zir.Inst.Index,
4850 union_ptr: Air.Inst.Ref,
4851) CompileError!void {4867) CompileError!void {
4852 const pt = sema.pt;4868 if (instrs.len == 1) {
4853 const zcu = pt.zcu;4869 // Trvial validation done, and the union tag was already set by machinery in `unionFieldPtr`.
4854 const gpa = sema.gpa;
4855
4856 if (instrs.len != 1) {
4857 const msg = msg: {
4858 const msg = try sema.errMsg(
4859 init_src,
4860 "cannot initialize multiple union fields at once; unions can only have one active field",
4861 .{},
4862 );
4863 errdefer msg.destroy(gpa);
4864
4865 for (instrs[1..]) |inst| {
4866 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
4867 const inst_src = block.src(.{ .node_offset_initializer = inst_data.src_node });
4868 try sema.errNote(inst_src, msg, "additional initializer here", .{});
4869 }
4870 try sema.addDeclaredHereNote(msg, union_ty);
4871 break :msg msg;
4872 };
4873 return sema.failWithOwnedErrorMsg(block, msg);
4874 }
4875
4876 if (block.isComptime() and
4877 (try sema.resolveDefinedValue(block, init_src, union_ptr)) != null)
4878 {
4879 // In this case, comptime machinery already did everything. No work to do here.
4880 return;4870 return;
4881 }4871 }
4872 const msg = msg: {
4873 const msg = try sema.errMsg(
4874 init_src,
4875 "cannot initialize multiple union fields at once; unions can only have one active field",
4876 .{},
4877 );
4878 errdefer msg.destroy(sema.gpa);
48824879
4883 const field_ptr = instrs[0];4880 for (instrs[1..]) |inst| {
4884 const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;4881 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
4885 const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node });4882 const inst_src = block.src(.{ .node_offset_initializer = inst_data.src_node });
4886 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;4883 try sema.errNote(inst_src, msg, "additional initializer here", .{});
4887 const field_name = try zcu.intern_pool.getOrPutString(
4888 gpa,
4889 pt.tid,
4890 sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
4891 .no_embedded_nulls,
4892 );
4893 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
4894 const air_tags = sema.air_instructions.items(.tag);
4895 const air_datas = sema.air_instructions.items(.data);
4896 const field_ptr_ref = sema.inst_map.get(field_ptr).?;
4897
4898 // Our task here is to determine if the union is comptime-known. In such case,
4899 // we erase the runtime AIR instructions for initializing the union, and replace
4900 // the mapping with the comptime value. Either way, we will need to populate the tag.
4901
4902 // We expect to see something like this in the current block AIR:
4903 // %a = alloc(*const U)
4904 // %b = bitcast(*U, %a)
4905 // %c = field_ptr(..., %b)
4906 // %e!= store(%c!, %d!)
4907 // If %d is a comptime operand, the union is comptime.
4908 // If the union is comptime, we want `first_block_index`
4909 // to point at %c so that the bitcast becomes the last instruction in the block.
4910 //
4911 // Store instruction may be missing; if field type has only one possible value, this case is handled below.
4912 //
4913 // In the case of a comptime-known pointer to a union, the
4914 // the field_ptr instruction is missing, so we have to pattern-match
4915 // based only on the store instructions.
4916 // `first_block_index` needs to point to the `field_ptr` if it exists;
4917 // the `store` otherwise.
4918 var first_block_index = block.instructions.items.len;
4919 var block_index = block.instructions.items.len - 1;
4920 var init_val: ?Value = null;
4921 var init_ref: ?Air.Inst.Ref = null;
4922 while (block_index > 0) : (block_index -= 1) {
4923 const store_inst = block.instructions.items[block_index];
4924 if (store_inst.toRef() == field_ptr_ref) {
4925 first_block_index = block_index;
4926 break;
4927 }4884 }
4928 switch (air_tags[@intFromEnum(store_inst)]) {4885 try sema.addDeclaredHereNote(msg, union_ty);
4929 .store, .store_safe => {},4886 break :msg msg;
4930 else => continue,4887 };
4931 }4888 return sema.failWithOwnedErrorMsg(block, msg);
4932 const bin_op = air_datas[@intFromEnum(store_inst)].bin_op;
4933 var ptr_ref = bin_op.lhs;
4934 if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
4935 ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
4936 };
4937 if (ptr_ref != field_ptr_ref) continue;
4938 first_block_index = @min(if (field_ptr_ref.toIndex()) |field_ptr_inst|
4939 std.mem.lastIndexOfScalar(
4940 Air.Inst.Index,
4941 block.instructions.items[0..block_index],
4942 field_ptr_inst,
4943 ).?
4944 else
4945 block_index, first_block_index);
4946 init_ref = bin_op.rhs;
4947 init_val = try sema.resolveValue(bin_op.rhs);
4948 break;
4949 }
4950
4951 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
4952 const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
4953 const field_type = union_ty.unionFieldType(tag_val, zcu).?;
4954
4955 if (try sema.typeHasOnePossibleValue(field_type)) |field_only_value| {
4956 init_val = field_only_value;
4957 }
4958
4959 if (init_val) |val| {
4960 // Our task is to delete all the `field_ptr` and `store` instructions, and insert
4961 // instead a single `store` to the result ptr with a comptime union value.
4962 block_index = first_block_index;
4963 for (block.instructions.items[first_block_index..]) |cur_inst| {
4964 switch (air_tags[@intFromEnum(cur_inst)]) {
4965 .struct_field_ptr,
4966 .struct_field_ptr_index_0,
4967 .struct_field_ptr_index_1,
4968 .struct_field_ptr_index_2,
4969 .struct_field_ptr_index_3,
4970 => if (cur_inst.toRef() == field_ptr_ref) continue,
4971 .bitcast => if (air_datas[@intFromEnum(cur_inst)].ty_op.operand == field_ptr_ref) continue,
4972 .store, .store_safe => {
4973 var ptr_ref = air_datas[@intFromEnum(cur_inst)].bin_op.lhs;
4974 if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
4975 ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
4976 };
4977 if (ptr_ref == field_ptr_ref) continue;
4978 },
4979 else => {},
4980 }
4981 block.instructions.items[block_index] = cur_inst;
4982 block_index += 1;
4983 }
4984 block.instructions.shrinkRetainingCapacity(block_index);
4985
4986 const union_val = try pt.internUnion(.{
4987 .ty = union_ty.toIntern(),
4988 .tag = tag_val.toIntern(),
4989 .val = val.toIntern(),
4990 });
4991 const union_init = Air.internedToRef(union_val);
4992 try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
4993 return;
4994 } else if (try union_ty.comptimeOnlySema(pt)) {
4995 const src = block.nodeOffset(field_ptr_data.src_node);
4996 return sema.failWithNeededComptime(block, src, .{ .comptime_only = .{
4997 .ty = union_ty,
4998 .msg = .union_init,
4999 } });
5000 }
5001 if (init_ref) |v| try sema.validateRuntimeValue(block, block.nodeOffset(field_ptr_data.src_node), v);
5002
5003 if ((try sema.typeHasOnePossibleValue(tag_ty)) == null) {
5004 const new_tag = Air.internedToRef(tag_val.toIntern());
5005 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, new_tag);
5006 try sema.checkComptimeKnownStore(block, set_tag_inst, LazySrcLoc.unneeded); // `unneeded` since this isn't a "proper" store
5007 }
5008}4889}
50094890
5010fn validateStructInit(4891fn validateStructInit(
...@@ -5013,187 +4894,62 @@ fn validateStructInit(...@@ -5013,187 +4894,62 @@ fn validateStructInit(
5013 struct_ty: Type,4894 struct_ty: Type,
5014 init_src: LazySrcLoc,4895 init_src: LazySrcLoc,
5015 instrs: []const Zir.Inst.Index,4896 instrs: []const Zir.Inst.Index,
4897 struct_ptr: Air.Inst.Ref,
5016) CompileError!void {4898) CompileError!void {
5017 const pt = sema.pt;4899 const pt = sema.pt;
5018 const zcu = pt.zcu;4900 const zcu = pt.zcu;
5019 const gpa = sema.gpa;4901 const gpa = sema.gpa;
5020 const ip = &zcu.intern_pool;4902 const ip = &zcu.intern_pool;
50214903
5022 const field_indices = try gpa.alloc(u32, instrs.len);4904 // Tracks whether each field was explicitly initialized.
5023 defer gpa.free(field_indices);4905 const found_fields = try gpa.alloc(bool, struct_ty.structFieldCount(zcu));
5024
5025 // Maps field index to field_ptr index of where it was already initialized.
5026 const found_fields = try gpa.alloc(Zir.Inst.OptionalIndex, struct_ty.structFieldCount(zcu));
5027 defer gpa.free(found_fields);4906 defer gpa.free(found_fields);
5028 @memset(found_fields, .none);4907 @memset(found_fields, false);
5029
5030 var struct_ptr_zir_ref: Zir.Inst.Ref = undefined;
50314908
5032 for (instrs, field_indices) |field_ptr, *field_index| {4909 for (instrs) |field_ptr| {
5033 const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;4910 const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
5034 const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node });4911 const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node });
5035 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;4912 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
5036 struct_ptr_zir_ref = field_ptr_extra.lhs;
5037 const field_name = try ip.getOrPutString(4913 const field_name = try ip.getOrPutString(
5038 gpa,4914 gpa,
5039 pt.tid,4915 pt.tid,
5040 sema.code.nullTerminatedString(field_ptr_extra.field_name_start),4916 sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
5041 .no_embedded_nulls,4917 .no_embedded_nulls,
5042 );4918 );
5043 field_index.* = if (struct_ty.isTuple(zcu))4919 const field_index = if (struct_ty.isTuple(zcu))
5044 try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)4920 try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
5045 else4921 else
5046 try sema.structFieldIndex(block, struct_ty, field_name, field_src);4922 try sema.structFieldIndex(block, struct_ty, field_name, field_src);
5047 assert(found_fields[field_index.*] == .none);4923 assert(found_fields[field_index] == false);
5048 found_fields[field_index.*] = field_ptr.toOptional();4924 found_fields[field_index] = true;
5049 }4925 }
50504926
5051 var root_msg: ?*Zcu.ErrorMsg = null;4927 // Our job is simply to deal with default field values. Specifically, any field which was not
5052 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);4928 // explicitly initialized must have its default value stored to the field pointer, or, if the
50534929 // field has no default value, a compile error must be emitted instead.
5054 const struct_ptr = try sema.resolveInst(struct_ptr_zir_ref);
5055 if (block.isComptime() and
5056 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
5057 {
5058 try struct_ty.resolveLayout(pt);
5059 // In this case the only thing we need to do is evaluate the implicit
5060 // store instructions for default field values, and report any missing fields.
5061 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
5062 for (found_fields, 0..) |field_ptr, i_usize| {
5063 const i: u32 = @intCast(i_usize);
5064 if (field_ptr != .none) continue;
5065
5066 try struct_ty.resolveStructFieldInits(pt);
5067 const default_val = struct_ty.structFieldDefaultValue(i, zcu);
5068 if (default_val.toIntern() == .unreachable_value) {
5069 const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {
5070 const template = "missing tuple field with index {d}";
5071 if (root_msg) |msg| {
5072 try sema.errNote(init_src, msg, template, .{i});
5073 } else {
5074 root_msg = try sema.errMsg(init_src, template, .{i});
5075 }
5076 continue;
5077 };
5078 const template = "missing struct field: {f}";
5079 const args = .{field_name.fmt(ip)};
5080 if (root_msg) |msg| {
5081 try sema.errNote(init_src, msg, template, args);
5082 } else {
5083 root_msg = try sema.errMsg(init_src, template, args);
5084 }
5085 continue;
5086 }
5087
5088 const field_src = init_src; // TODO better source location
5089 const default_field_ptr = if (struct_ty.isTuple(zcu))
5090 try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(i), true)
5091 else
5092 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);
5093 const init = Air.internedToRef(default_val.toIntern());
5094 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
5095 }
5096
5097 if (root_msg) |msg| {
5098 try sema.addDeclaredHereNote(msg, struct_ty);
5099 root_msg = null;
5100 return sema.failWithOwnedErrorMsg(block, msg);
5101 }
5102
5103 return;
5104 }
5105
5106 var fields_allow_runtime = true;
5107
5108 var struct_is_comptime = true;
5109 var first_block_index = block.instructions.items.len;
5110
5111 const require_comptime = try struct_ty.comptimeOnlySema(pt);
5112 const air_tags = sema.air_instructions.items(.tag);
5113 const air_datas = sema.air_instructions.items(.data);
51144930
5115 try struct_ty.resolveStructFieldInits(pt);4931 // In the past, this code had other responsibilities, which involved some nasty AIR rewrites. However,
4932 // that work was actually all redundant:
4933 //
4934 // * If the struct value is comptime-known, field stores remain a perfectly valid way of initializing
4935 // the struct through RLS; there is no need to turn the field stores into one store. Comptime-known
4936 // consts are handled correctly either way thanks to `maybe_comptime_allocs` and friends.
4937 //
4938 // * If the struct type is comptime-only, we need to make sure all of the fields were comptime-known.
4939 // But the comptime-only type means that `struct_ptr` must be a comptime-mutable pointer, so the
4940 // field stores were to comptime-mutable pointers, so have already errored if not comptime-known.
4941 //
4942 // * If the value is runtime-known, then comptime-known fields must be validated as runtime values.
4943 // But this was already handled for every field store by the machinery in `checkComptimeKnownStore`.
51164944
5117 // We collect the comptime field values in case the struct initialization4945 var root_msg: ?*Zcu.ErrorMsg = null;
5118 // ends up being comptime-known.4946 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
5119 const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(zcu));
51204947
5121 field: for (found_fields, 0..) |opt_field_ptr, i_usize| {4948 for (found_fields, 0..) |explicit, i_usize| {
4949 if (explicit) continue;
5122 const i: u32 = @intCast(i_usize);4950 const i: u32 = @intCast(i_usize);
5123 if (opt_field_ptr.unwrap()) |field_ptr| {
5124 // Determine whether the value stored to this pointer is comptime-known.
5125 const field_ty = struct_ty.fieldType(i, zcu);
5126 if (try sema.typeHasOnePossibleValue(field_ty)) |opv| {
5127 field_values[i] = opv.toIntern();
5128 continue;
5129 }
5130
5131 const field_ptr_ref = sema.inst_map.get(field_ptr).?;
5132
5133 //std.debug.print("validateStructInit (field_ptr_ref=%{d}):\n", .{field_ptr_ref});
5134 //for (block.instructions.items) |item| {
5135 // std.debug.print(" %{d} = {s}\n", .{item, @tagName(air_tags[@intFromEnum(item)])});
5136 //}
5137
5138 // We expect to see something like this in the current block AIR:
5139 // %a = field_ptr(...)
5140 // store(%a, %b)
5141 // With an optional bitcast between the store and the field_ptr.
5142 // If %b is a comptime operand, this field is comptime.
5143 //
5144 // However, in the case of a comptime-known pointer to a struct, the
5145 // the field_ptr instruction is missing, so we have to pattern-match
5146 // based only on the store instructions.
5147 // `first_block_index` needs to point to the `field_ptr` if it exists;
5148 // the `store` otherwise.
5149
5150 // Possible performance enhancement: save the `block_index` between iterations
5151 // of the for loop.
5152 var block_index = block.instructions.items.len;
5153 while (block_index > 0) {
5154 block_index -= 1;
5155 const store_inst = block.instructions.items[block_index];
5156 if (store_inst.toRef() == field_ptr_ref) {
5157 struct_is_comptime = false;
5158 continue :field;
5159 }
5160 switch (air_tags[@intFromEnum(store_inst)]) {
5161 .store, .store_safe => {},
5162 else => continue,
5163 }
5164 const bin_op = air_datas[@intFromEnum(store_inst)].bin_op;
5165 var ptr_ref = bin_op.lhs;
5166 if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
5167 ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
5168 };
5169 if (ptr_ref != field_ptr_ref) continue;
5170 first_block_index = @min(if (field_ptr_ref.toIndex()) |field_ptr_inst|
5171 std.mem.lastIndexOfScalar(
5172 Air.Inst.Index,
5173 block.instructions.items[0..block_index],
5174 field_ptr_inst,
5175 ).?
5176 else
5177 block_index, first_block_index);
5178 if (!sema.checkRuntimeValue(bin_op.rhs)) fields_allow_runtime = false;
5179 if (try sema.resolveValue(bin_op.rhs)) |val| {
5180 field_values[i] = val.toIntern();
5181 } else if (require_comptime) {
5182 const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
5183 const src = block.nodeOffset(field_ptr_data.src_node);
5184 return sema.failWithNeededComptime(block, src, .{ .comptime_only = .{
5185 .ty = struct_ty,
5186 .msg = .struct_init,
5187 } });
5188 } else {
5189 struct_is_comptime = false;
5190 }
5191 continue :field;
5192 }
5193 struct_is_comptime = false;
5194 continue :field;
5195 }
51964951
4952 try struct_ty.resolveStructFieldInits(pt);
5197 const default_val = struct_ty.structFieldDefaultValue(i, zcu);4953 const default_val = struct_ty.structFieldDefaultValue(i, zcu);
5198 if (default_val.toIntern() == .unreachable_value) {4954 if (default_val.toIntern() == .unreachable_value) {
5199 const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {4955 const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {
...@@ -5214,70 +4970,6 @@ fn validateStructInit(...@@ -5214,70 +4970,6 @@ fn validateStructInit(
5214 }4970 }
5215 continue;4971 continue;
5216 }4972 }
5217 field_values[i] = default_val.toIntern();
5218 }
5219
5220 if (!struct_is_comptime and !fields_allow_runtime and root_msg == null) {
5221 root_msg = try sema.errMsg(init_src, "runtime value contains reference to comptime var", .{});
5222 try sema.errNote(init_src, root_msg.?, "comptime var pointers are not available at runtime", .{});
5223 }
5224
5225 if (root_msg) |msg| {
5226 try sema.addDeclaredHereNote(msg, struct_ty);
5227 root_msg = null;
5228 return sema.failWithOwnedErrorMsg(block, msg);
5229 }
5230
5231 if (struct_is_comptime) {
5232 // Our task is to delete all the `field_ptr` and `store` instructions, and insert
5233 // instead a single `store` to the struct_ptr with a comptime struct value.
5234 var init_index: usize = 0;
5235 var field_ptr_ref = Air.Inst.Ref.none;
5236 var block_index = first_block_index;
5237 for (block.instructions.items[first_block_index..]) |cur_inst| {
5238 while (field_ptr_ref == .none and init_index < instrs.len) : (init_index += 1) {
5239 const field_ty = struct_ty.fieldType(field_indices[init_index], zcu);
5240 if (try field_ty.onePossibleValue(pt)) |_| continue;
5241 field_ptr_ref = sema.inst_map.get(instrs[init_index]).?;
5242 }
5243 switch (air_tags[@intFromEnum(cur_inst)]) {
5244 .struct_field_ptr,
5245 .struct_field_ptr_index_0,
5246 .struct_field_ptr_index_1,
5247 .struct_field_ptr_index_2,
5248 .struct_field_ptr_index_3,
5249 => if (cur_inst.toRef() == field_ptr_ref) continue,
5250 .bitcast => if (air_datas[@intFromEnum(cur_inst)].ty_op.operand == field_ptr_ref) continue,
5251 .store, .store_safe => {
5252 var ptr_ref = air_datas[@intFromEnum(cur_inst)].bin_op.lhs;
5253 if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
5254 ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
5255 };
5256 if (ptr_ref == field_ptr_ref) {
5257 field_ptr_ref = .none;
5258 continue;
5259 }
5260 },
5261 else => {},
5262 }
5263 block.instructions.items[block_index] = cur_inst;
5264 block_index += 1;
5265 }
5266 block.instructions.shrinkRetainingCapacity(block_index);
5267
5268 const struct_val = try pt.intern(.{ .aggregate = .{
5269 .ty = struct_ty.toIntern(),
5270 .storage = .{ .elems = field_values },
5271 } });
5272 const struct_init = Air.internedToRef(struct_val);
5273 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
5274 return;
5275 }
5276 try struct_ty.resolveLayout(pt);
5277
5278 // Our task is to insert `store` instructions for all the default field values.
5279 for (found_fields, 0..) |field_ptr, i| {
5280 if (field_ptr != .none) continue;
52814973
5282 const field_src = init_src; // TODO better source location4974 const field_src = init_src; // TODO better source location
5283 const default_field_ptr = if (struct_ty.isTuple(zcu))4975 const default_field_ptr = if (struct_ty.isTuple(zcu))
...@@ -5285,8 +4977,13 @@ fn validateStructInit(...@@ -5285,8 +4977,13 @@ fn validateStructInit(
5285 else4977 else
5286 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);4978 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);
5287 try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr);4979 try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr);
5288 const init = Air.internedToRef(field_values[i]);4980 try sema.storePtr2(block, init_src, default_field_ptr, init_src, .fromValue(default_val), field_src, .store);
5289 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);4981 }
4982
4983 if (root_msg) |msg| {
4984 try sema.addDeclaredHereNote(msg, struct_ty);
4985 root_msg = null;
4986 return sema.failWithOwnedErrorMsg(block, msg);
5290 }4987 }
5291}4988}
52924989
...@@ -5307,15 +5004,14 @@ fn zirValidatePtrArrayInit(...@@ -5307,15 +5004,14 @@ fn zirValidatePtrArrayInit(
5307 const array_ty = sema.typeOf(array_ptr).childType(zcu).optEuBaseType(zcu);5004 const array_ty = sema.typeOf(array_ptr).childType(zcu).optEuBaseType(zcu);
5308 const array_len = array_ty.arrayLen(zcu);5005 const array_len = array_ty.arrayLen(zcu);
53095006
5310 // Collect the comptime element values in case the array literal ends up5007 // Analagously to `validateStructInit`, our job is to handle default fields; either emitting AIR
5311 // being comptime-known.5008 // to initialize them, or emitting a compile error if an unspecified field has no default. For
5312 const element_vals = try sema.arena.alloc(5009 // tuples, there are literally default field values, although they're guaranteed to be comptime
5313 InternPool.Index,5010 // fields so we don't need to initialize them. For arrays, we may have a sentinel, which is never
5314 try sema.usizeCast(block, init_src, array_len),5011 // specified so we always need to initialize here. For vectors, there's no such thing.
5315 );
53165012
5317 if (instrs.len != array_len) switch (array_ty.zigTypeTag(zcu)) {5013 switch (array_ty.zigTypeTag(zcu)) {
5318 .@"struct" => {5014 .@"struct" => if (instrs.len != array_len) {
5319 var root_msg: ?*Zcu.ErrorMsg = null;5015 var root_msg: ?*Zcu.ErrorMsg = null;
5320 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);5016 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
53215017
...@@ -5332,8 +5028,6 @@ fn zirValidatePtrArrayInit(...@@ -5332,8 +5028,6 @@ fn zirValidatePtrArrayInit(
5332 }5028 }
5333 continue;5029 continue;
5334 }5030 }
5335
5336 element_vals[i] = default_val;
5337 }5031 }
53385032
5339 if (root_msg) |msg| {5033 if (root_msg) |msg| {
...@@ -5341,162 +5035,25 @@ fn zirValidatePtrArrayInit(...@@ -5341,162 +5035,25 @@ fn zirValidatePtrArrayInit(
5341 return sema.failWithOwnedErrorMsg(block, msg);5035 return sema.failWithOwnedErrorMsg(block, msg);
5342 }5036 }
5343 },5037 },
5344 .array => {5038
5039 .array => if (instrs.len != array_len) {
5345 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{5040 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
5346 array_len, instrs.len,5041 array_len, instrs.len,
5347 });5042 });
5043 } else if (array_ty.sentinel(zcu)) |sentinel| {
5044 const array_len_ref = try pt.intRef(.usize, array_len);
5045 const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true);
5046 try sema.checkKnownAllocPtr(block, array_ptr, sentinel_ptr);
5047 try sema.storePtr2(block, init_src, sentinel_ptr, init_src, .fromValue(sentinel), init_src, .store);
5348 },5048 },
5349 .vector => {5049
5050 .vector => if (instrs.len != array_len) {
5350 return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{5051 return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{
5351 array_len, instrs.len,5052 array_len, instrs.len,
5352 });5053 });
5353 },5054 },
5354 else => unreachable,
5355 };
5356
5357 if (block.isComptime() and
5358 (try sema.resolveDefinedValue(block, init_src, array_ptr)) != null)
5359 {
5360 // In this case the comptime machinery will have evaluated the store instructions
5361 // at comptime so we have almost nothing to do here. However, in case of a
5362 // sentinel-terminated array, the sentinel will not have been populated by
5363 // any ZIR instructions at comptime; we need to do that here.
5364 if (array_ty.sentinel(zcu)) |sentinel_val| {
5365 const array_len_ref = try pt.intRef(.usize, array_len);
5366 const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true);
5367 const sentinel = Air.internedToRef(sentinel_val.toIntern());
5368 try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);
5369 }
5370 return;
5371 }
5372
5373 // If the array has one possible value, the value is always comptime-known.
5374 if (try sema.typeHasOnePossibleValue(array_ty)) |array_opv| {
5375 const array_init = Air.internedToRef(array_opv.toIntern());
5376 try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
5377 return;
5378 }
5379
5380 var array_is_comptime = true;
5381 var first_block_index = block.instructions.items.len;
5382
5383 const air_tags = sema.air_instructions.items(.tag);
5384 const air_datas = sema.air_instructions.items(.data);
5385
5386 outer: for (instrs, 0..) |elem_ptr, i| {
5387 // Determine whether the value stored to this pointer is comptime-known.
5388
5389 if (array_ty.isTuple(zcu)) {
5390 if (array_ty.structFieldIsComptime(i, zcu))
5391 try array_ty.resolveStructFieldInits(pt);
5392 if (try array_ty.structFieldValueComptime(pt, i)) |opv| {
5393 element_vals[i] = opv.toIntern();
5394 continue;
5395 }
5396 }
5397
5398 const elem_ptr_ref = sema.inst_map.get(elem_ptr).?;
5399
5400 // We expect to see something like this in the current block AIR:
5401 // %a = elem_ptr(...)
5402 // store(%a, %b)
5403 // With an optional bitcast between the store and the elem_ptr.
5404 // If %b is a comptime operand, this element is comptime.
5405 //
5406 // However, in the case of a comptime-known pointer to an array, the
5407 // the elem_ptr instruction is missing, so we have to pattern-match
5408 // based only on the store instructions.
5409 // `first_block_index` needs to point to the `elem_ptr` if it exists;
5410 // the `store` otherwise.
5411 //
5412 // This is nearly identical to similar logic in `validateStructInit`.
5413
5414 // Possible performance enhancement: save the `block_index` between iterations
5415 // of the for loop.
5416 var block_index = block.instructions.items.len;
5417 while (block_index > 0) {
5418 block_index -= 1;
5419 const store_inst = block.instructions.items[block_index];
5420 if (store_inst.toRef() == elem_ptr_ref) {
5421 array_is_comptime = false;
5422 continue :outer;
5423 }
5424 switch (air_tags[@intFromEnum(store_inst)]) {
5425 .store, .store_safe => {},
5426 else => continue,
5427 }
5428 const bin_op = air_datas[@intFromEnum(store_inst)].bin_op;
5429 var ptr_ref = bin_op.lhs;
5430 if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
5431 ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
5432 };
5433 if (ptr_ref != elem_ptr_ref) continue;
5434 first_block_index = @min(if (elem_ptr_ref.toIndex()) |elem_ptr_inst|
5435 std.mem.lastIndexOfScalar(
5436 Air.Inst.Index,
5437 block.instructions.items[0..block_index],
5438 elem_ptr_inst,
5439 ).?
5440 else
5441 block_index, first_block_index);
5442 if (try sema.resolveValue(bin_op.rhs)) |val| {
5443 element_vals[i] = val.toIntern();
5444 } else {
5445 array_is_comptime = false;
5446 }
5447 continue :outer;
5448 }
5449 array_is_comptime = false;
5450 continue :outer;
5451 }
5452
5453 if (array_is_comptime) {
5454 if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {
5455 switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) {
5456 .ptr => |ptr| switch (ptr.base_addr) {
5457 .comptime_field => return, // This store was validated by the individual elem ptrs.
5458 else => {},
5459 },
5460 else => {},
5461 }
5462 }
5463
5464 // Our task is to delete all the `elem_ptr` and `store` instructions, and insert
5465 // instead a single `store` to the array_ptr with a comptime struct value.
5466 var elem_index: usize = 0;
5467 var elem_ptr_ref = Air.Inst.Ref.none;
5468 var block_index = first_block_index;
5469 for (block.instructions.items[first_block_index..]) |cur_inst| {
5470 while (elem_ptr_ref == .none and elem_index < instrs.len) : (elem_index += 1) {
5471 if (array_ty.isTuple(zcu) and array_ty.structFieldIsComptime(elem_index, zcu)) continue;
5472 elem_ptr_ref = sema.inst_map.get(instrs[elem_index]).?;
5473 }
5474 switch (air_tags[@intFromEnum(cur_inst)]) {
5475 .ptr_elem_ptr => if (cur_inst.toRef() == elem_ptr_ref) continue,
5476 .bitcast => if (air_datas[@intFromEnum(cur_inst)].ty_op.operand == elem_ptr_ref) continue,
5477 .store, .store_safe => {
5478 var ptr_ref = air_datas[@intFromEnum(cur_inst)].bin_op.lhs;
5479 if (ptr_ref.toIndex()) |ptr_inst| if (air_tags[@intFromEnum(ptr_inst)] == .bitcast) {
5480 ptr_ref = air_datas[@intFromEnum(ptr_inst)].ty_op.operand;
5481 };
5482 if (ptr_ref == elem_ptr_ref) {
5483 elem_ptr_ref = .none;
5484 continue;
5485 }
5486 },
5487 else => {},
5488 }
5489 block.instructions.items[block_index] = cur_inst;
5490 block_index += 1;
5491 }
5492 block.instructions.shrinkRetainingCapacity(block_index);
54935055
5494 const array_val = try pt.intern(.{ .aggregate = .{5056 else => unreachable,
5495 .ty = array_ty.toIntern(),
5496 .storage = .{ .elems = element_vals },
5497 } });
5498 const array_init = Air.internedToRef(array_val);
5499 try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
5500 }5057 }
5501}5058}
55025059
...@@ -5774,8 +5331,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v...@@ -5774,8 +5331,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
5774 const tracy = trace(@src());5331 const tracy = trace(@src());
5775 defer tracy.end();5332 defer tracy.end();
57765333
5777 const pt = sema.pt;
5778 const zcu = pt.zcu;
5779 const zir_tags = sema.code.instructions.items(.tag);5334 const zir_tags = sema.code.instructions.items(.tag);
5780 const zir_datas = sema.code.instructions.items(.data);5335 const zir_datas = sema.code.instructions.items(.data);
5781 const inst_data = zir_datas[@intFromEnum(inst)].pl_node;5336 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...@@ -5789,16 +5344,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
5789 else5344 else
5790 false;5345 false;
57915346
5792 // Check for the possibility of this pattern:
5793 // %a = ret_ptr
5794 // %b = store(%a, %c)
5795 // Where %c is an error union or error set. In such case we need to add
5796 // to the current function's inferred error set, if any.
5797 if (is_ret and sema.fn_ret_ty_ies != null) switch (sema.typeOf(operand).zigTypeTag(zcu)) {
5798 .error_union, .error_set => try sema.addToInferredErrorSet(operand),
5799 else => {},
5800 };
5801
5802 const ptr_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });5347 const ptr_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
5803 const operand_src = block.src(.{ .node_offset_store_operand = inst_data.src_node });5348 const operand_src = block.src(.{ .node_offset_store_operand = inst_data.src_node });
5804 const air_tag: Air.Inst.Tag = if (is_ret)5349 const air_tag: Air.Inst.Tag = if (is_ret)
...@@ -14136,7 +13681,7 @@ fn zirShl(...@@ -14136,7 +13681,7 @@ fn zirShl(
14136 try sema.requireRuntimeBlock(block, src, runtime_src);13681 try sema.requireRuntimeBlock(block, src, runtime_src);
14137 if (block.wantSafety()) {13682 if (block.wantSafety()) {
14138 const bit_count = scalar_ty.intInfo(zcu).bits;13683 const bit_count = scalar_ty.intInfo(zcu).bits;
14139 if (!std.math.isPowerOfTwo(bit_count)) {13684 if (air_tag != .shl_sat and !std.math.isPowerOfTwo(bit_count)) {
14140 const bit_count_val = try pt.intValue(scalar_rhs_ty, bit_count);13685 const bit_count_val = try pt.intValue(scalar_rhs_ty, bit_count);
14141 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {13686 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {
14142 const bit_count_inst = Air.internedToRef((try sema.splat(rhs_ty, bit_count_val)).toIntern());13687 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!...@@ -18634,8 +18179,12 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
18634 const pt = sema.pt;18179 const pt = sema.pt;
18635 const zcu = pt.zcu;18180 const zcu = pt.zcu;
18636 if (err_union_ty.zigTypeTag(zcu) != .error_union) {18181 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
18637 return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{18182 return sema.failWithOwnedErrorMsg(parent_block, msg: {
18638 err_union_ty.fmt(pt),18183 const msg = try sema.errMsg(operand_src, "expected error union type, found '{f}'", .{err_union_ty.fmt(pt)});
18184 errdefer msg.destroy(sema.gpa);
18185 try sema.addDeclaredHereNote(msg, err_union_ty);
18186 try sema.errNote(operand_src, msg, "consider omitting 'try'", .{});
18187 break :msg msg;
18639 });18188 });
18640 }18189 }
18641 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);18190 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...@@ -18694,8 +18243,12 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
18694 const pt = sema.pt;18243 const pt = sema.pt;
18695 const zcu = pt.zcu;18244 const zcu = pt.zcu;
18696 if (err_union_ty.zigTypeTag(zcu) != .error_union) {18245 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
18697 return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{18246 return sema.failWithOwnedErrorMsg(parent_block, msg: {
18698 err_union_ty.fmt(pt),18247 const msg = try sema.errMsg(operand_src, "expected error union type, found '{f}'", .{err_union_ty.fmt(pt)});
18248 errdefer msg.destroy(sema.gpa);
18249 try sema.addDeclaredHereNote(msg, err_union_ty);
18250 try sema.errNote(operand_src, msg, "consider omitting 'try'", .{});
18251 break :msg msg;
18699 });18252 });
18700 }18253 }
18701 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);18254 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
...@@ -20019,7 +19572,7 @@ fn structInitAnon(...@@ -20019,7 +19572,7 @@ fn structInitAnon(
20019 try sema.declareDependency(.{ .interned = struct_ty });19572 try sema.declareDependency(.{ .interned = struct_ty });
20020 try sema.addTypeReferenceEntry(src, struct_ty);19573 try sema.addTypeReferenceEntry(src, struct_ty);
2002119574
20022 const runtime_index = opt_runtime_index orelse {19575 _ = opt_runtime_index orelse {
20023 const struct_val = try pt.intern(.{ .aggregate = .{19576 const struct_val = try pt.intern(.{ .aggregate = .{
20024 .ty = struct_ty,19577 .ty = struct_ty,
20025 .storage = .{ .elems = values },19578 .storage = .{ .elems = values },
...@@ -20027,11 +19580,6 @@ fn structInitAnon(...@@ -20027,11 +19580,6 @@ fn structInitAnon(
20027 return sema.addConstantMaybeRef(struct_val, is_ref);19580 return sema.addConstantMaybeRef(struct_val, is_ref);
20028 };19581 };
2002919582
20030 try sema.requireRuntimeBlock(block, LazySrcLoc.unneeded, block.src(.{ .init_elem = .{
20031 .init_node_offset = src.offset.node_offset.x,
20032 .elem_index = @intCast(runtime_index),
20033 } }));
20034
20035 if (is_ref) {19583 if (is_ref) {
20036 const target = zcu.getTarget();19584 const target = zcu.getTarget();
20037 const alloc_ty = try pt.ptrTypeSema(.{19585 const alloc_ty = try pt.ptrTypeSema(.{
...@@ -20160,7 +19708,7 @@ fn zirArrayInit(...@@ -20160,7 +19708,7 @@ fn zirArrayInit(
20160 if (!comptime_known) break @intCast(i);19708 if (!comptime_known) break @intCast(i);
20161 } else null;19709 } else null;
2016219710
20163 const runtime_index = opt_runtime_index orelse {19711 _ = opt_runtime_index orelse {
20164 const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len);19712 const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len);
20165 for (elem_vals, resolved_args) |*val, arg| {19713 for (elem_vals, resolved_args) |*val, arg| {
20166 // We checked that all args are comptime above.19714 // We checked that all args are comptime above.
...@@ -20175,11 +19723,6 @@ fn zirArrayInit(...@@ -20175,11 +19723,6 @@ fn zirArrayInit(
20175 return sema.addConstantMaybeRef(result_val.toIntern(), is_ref);19723 return sema.addConstantMaybeRef(result_val.toIntern(), is_ref);
20176 };19724 };
2017719725
20178 try sema.requireRuntimeBlock(block, LazySrcLoc.unneeded, block.src(.{ .init_elem = .{
20179 .init_node_offset = src.offset.node_offset.x,
20180 .elem_index = runtime_index,
20181 } }));
20182
20183 if (is_ref) {19726 if (is_ref) {
20184 const target = zcu.getTarget();19727 const target = zcu.getTarget();
20185 const alloc_ty = try pt.ptrTypeSema(.{19728 const alloc_ty = try pt.ptrTypeSema(.{
...@@ -21089,6 +20632,16 @@ fn zirReify(...@@ -21089,6 +20632,16 @@ fn zirReify(
21089 }20632 }
21090 const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);20633 const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
2109120634
20635 const has_tag = tag_type_val.optionalValue(zcu) != null;
20636
20637 if (has_tag) {
20638 switch (layout) {
20639 .@"extern" => return sema.fail(block, src, "extern union does not support enum tag type", .{}),
20640 .@"packed" => return sema.fail(block, src, "packed union does not support enum tag type", .{}),
20641 .auto => {},
20642 }
20643 }
20644
21092 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });20645 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });
2109320646
21094 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);20647 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
...@@ -22483,11 +22036,18 @@ fn ptrCastFull(...@@ -22483,11 +22036,18 @@ fn ptrCastFull(
22483 .slice => {},22036 .slice => {},
22484 .many, .c, .one => break :len null,22037 .many, .c, .one => break :len null,
22485 }22038 }
22486 // `null` means the operand is a runtime-known slice (so the length is runtime-known).22039 // A `null` length means the operand is a runtime-known slice (so the length is runtime-known).
22487 const opt_src_len: ?u64 = switch (src_info.flags.size) {22040 // `src_elem_type` is different from `src_info.child` if the latter is an array, to ensure we ignore sentinels.
22488 .one => 1,22041 const src_elem_ty: Type, const opt_src_len: ?u64 = switch (src_info.flags.size) {
22489 .slice => src_len: {22042 .one => src: {
22490 const operand_val = try sema.resolveValue(operand) orelse break :src_len null;22043 const true_child: Type = .fromInterned(src_info.child);
22044 break :src switch (true_child.zigTypeTag(zcu)) {
22045 .array => .{ true_child.childType(zcu), true_child.arrayLen(zcu) },
22046 else => .{ true_child, 1 },
22047 };
22048 },
22049 .slice => src: {
22050 const operand_val = try sema.resolveValue(operand) orelse break :src .{ .fromInterned(src_info.child), null };
22491 if (operand_val.isUndef(zcu)) break :len .undef;22051 if (operand_val.isUndef(zcu)) break :len .undef;
22492 const slice_val = switch (operand_ty.zigTypeTag(zcu)) {22052 const slice_val = switch (operand_ty.zigTypeTag(zcu)) {
22493 .optional => operand_val.optionalValue(zcu) orelse break :len .undef,22053 .optional => operand_val.optionalValue(zcu) orelse break :len .undef,
...@@ -22496,14 +22056,13 @@ fn ptrCastFull(...@@ -22496,14 +22056,13 @@ fn ptrCastFull(
22496 };22056 };
22497 const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));22057 const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));
22498 if (slice_len_resolved.isUndef(zcu)) break :len .undef;22058 if (slice_len_resolved.isUndef(zcu)) break :len .undef;
22499 break :src_len slice_len_resolved.toUnsignedInt(zcu);22059 break :src .{ .fromInterned(src_info.child), slice_len_resolved.toUnsignedInt(zcu) };
22500 },22060 },
22501 .many, .c => {22061 .many, .c => {
22502 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});22062 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});
22503 },22063 },
22504 };22064 };
22505 const dest_elem_ty: Type = .fromInterned(dest_info.child);22065 const dest_elem_ty: Type = .fromInterned(dest_info.child);
22506 const src_elem_ty: Type = .fromInterned(src_info.child);
22507 if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) {22066 if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) {
22508 break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice;22067 break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice;
22509 }22068 }
...@@ -22519,7 +22078,7 @@ fn ptrCastFull(...@@ -22519,7 +22078,7 @@ fn ptrCastFull(
22519 const bytes = src_len * src_elem_size;22078 const bytes = src_len * src_elem_size;
22520 const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {22079 const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {
22521 .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}),22080 .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}),
22522 .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}),22081 .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{Type.fromInterned(src_info.child).fmt(pt)}),
22523 else => unreachable,22082 else => unreachable,
22524 };22083 };
22525 break :len .{ .constant = dest_len };22084 break :len .{ .constant = dest_len };
...@@ -25052,6 +24611,7 @@ fn analyzeMinMax(...@@ -25052,6 +24611,7 @@ fn analyzeMinMax(
25052 } else {24611 } else {
25053 for (operands[1..], operand_srcs[1..]) |operand, operand_src| {24612 for (operands[1..], operand_srcs[1..]) |operand, operand_src| {
25054 const operand_ty = sema.typeOf(operand);24613 const operand_ty = sema.typeOf(operand);
24614 try sema.checkNumericType(block, operand_src, operand_ty);
25055 if (operand_ty.zigTypeTag(zcu) == .vector) {24615 if (operand_ty.zigTypeTag(zcu) == .vector) {
25056 return sema.failWithOwnedErrorMsg(block, msg: {24616 return sema.failWithOwnedErrorMsg(block, msg: {
25057 const msg = try sema.errMsg(operand_srcs[0], "expected vector, found '{f}'", .{first_operand_ty.fmt(pt)});24617 const msg = try sema.errMsg(operand_srcs[0], "expected vector, found '{f}'", .{first_operand_ty.fmt(pt)});
...@@ -28009,15 +27569,24 @@ fn unionFieldPtr(...@@ -28009,15 +27569,24 @@ fn unionFieldPtr(
28009 return Air.internedToRef(field_ptr_val.toIntern());27569 return Air.internedToRef(field_ptr_val.toIntern());
28010 }27570 }
2801127571
28012 if (!initializing and union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and27572 // If the union has a tag, we must either set or or safety check it depending on `initializing`.
28013 union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)27573 tag: {
28014 {27574 if (union_ty.containerLayout(zcu) != .auto) break :tag;
28015 const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);27575 const tag_ty: Type = .fromInterned(union_obj.enum_tag_ty);
28016 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());27576 if (try sema.typeHasOnePossibleValue(tag_ty) != null) break :tag;
28017 // TODO would it be better if get_union_tag supported pointers to unions?27577 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
28018 const union_val = try block.addTyOp(.load, union_ty, union_ptr);27578 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
28019 const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_ty), union_val);27579 const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
28020 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag);27580 if (initializing) {
27581 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));
27582 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
27583 } else if (block.wantSafety() and union_obj.hasTag(ip)) {
27584 // The tag exists at runtime (safety tag), so emit a safety check.
27585 // TODO would it be better if get_union_tag supported pointers to unions?
27586 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
27587 const active_tag = try block.addTyOp(.get_union_tag, tag_ty, union_val);
27588 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, .fromValue(want_tag));
27589 }
28021 }27590 }
28022 if (field_ty.zigTypeTag(zcu) == .noreturn) {27591 if (field_ty.zigTypeTag(zcu) == .noreturn) {
28023 _ = try block.addNoOp(.unreach);27592 _ = try block.addNoOp(.unreach);
...@@ -29166,17 +28735,36 @@ fn coerceExtra(...@@ -29166,17 +28735,36 @@ fn coerceExtra(
29166 break :int;28735 break :int;
29167 };28736 };
29168 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);28737 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);
29169 // TODO implement this compile error28738 const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {
29170 //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty);28739 else => unreachable,
29171 //if (!int_again_val.eql(val, inst_ty, zcu)) {28740 .undef => true,
29172 // return sema.fail(28741 .float => |float| fits: {
29173 // block,28742 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
29174 // inst_src,28743 const operand_big_int = val.toBigInt(&buffer, zcu);
29175 // "type '{f}' cannot represent integer value '{f}'",28744 switch (float.storage) {
29176 // .{ dest_ty.fmt(pt), val },28745 inline else => |x| {
29177 // );28746 if (!std.math.isFinite(x)) break :fits false;
29178 //}28747 var result_big_int: std.math.big.int.Mutable = .{
29179 return Air.internedToRef(result_val.toIntern());28748 .limbs = try sema.arena.alloc(std.math.big.Limb, std.math.big.int.calcLimbLen(x)),
28749 .len = undefined,
28750 .positive = undefined,
28751 };
28752 switch (result_big_int.setFloat(x, .nearest_even)) {
28753 .inexact => break :fits false,
28754 .exact => {},
28755 }
28756 break :fits result_big_int.toConst().eql(operand_big_int);
28757 },
28758 }
28759 },
28760 };
28761 if (!fits) return sema.fail(
28762 block,
28763 inst_src,
28764 "type '{f}' cannot represent integer value '{f}'",
28765 .{ dest_ty.fmt(pt), val.fmtValue(pt) },
28766 );
28767 return .fromValue(result_val);
29180 },28768 },
29181 else => {},28769 else => {},
29182 },28770 },
...@@ -32309,6 +31897,38 @@ fn analyzeSlice(...@@ -32309,6 +31897,38 @@ fn analyzeSlice(
32309 break :e try sema.coerce(block, .usize, uncasted_end, end_src);31897 break :e try sema.coerce(block, .usize, uncasted_end, end_src);
32310 } else break :e try sema.coerce(block, .usize, uncasted_end_opt, end_src);31898 } else break :e try sema.coerce(block, .usize, uncasted_end_opt, end_src);
32311 }31899 }
31900
31901 // when slicing a many-item pointer, if a sentinel `S` is provided as in `ptr[a.. :S]`, it
31902 // must match the sentinel of `@TypeOf(ptr)`.
31903 sentinel_check: {
31904 if (sentinel_opt == .none) break :sentinel_check;
31905 const provided = provided: {
31906 const casted = try sema.coerce(block, elem_ty, sentinel_opt, sentinel_src);
31907 try checkSentinelType(sema, block, sentinel_src, elem_ty);
31908 break :provided try sema.resolveConstDefinedValue(
31909 block,
31910 sentinel_src,
31911 casted,
31912 .{ .simple = .slice_sentinel },
31913 );
31914 };
31915
31916 if (ptr_sentinel) |current| {
31917 if (provided.toIntern() == current.toIntern()) break :sentinel_check;
31918 }
31919
31920 return sema.failWithOwnedErrorMsg(block, msg: {
31921 const msg = try sema.errMsg(sentinel_src, "sentinel-terminated slicing of many-item pointer must match existing sentinel", .{});
31922 errdefer msg.destroy(sema.gpa);
31923 if (ptr_sentinel) |current| {
31924 try sema.errNote(sentinel_src, msg, "expected sentinel '{f}', found '{f}'", .{ current.fmtValue(pt), provided.fmtValue(pt) });
31925 } else {
31926 try sema.errNote(ptr_src, msg, "type '{f}' does not have a sentinel", .{slice_ty.fmt(pt)});
31927 }
31928 try sema.errNote(src, msg, "use @ptrCast to cast pointer sentinel", .{});
31929 break :msg msg;
31930 });
31931 }
32312 return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);31932 return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
32313 };31933 };
3231431934
src/Zcu.zig+6-1
...@@ -3859,7 +3859,12 @@ pub fn atomicPtrAlignment(...@@ -3859,7 +3859,12 @@ pub fn atomicPtrAlignment(
3859 }3859 }
3860 return .none;3860 return .none;
3861 }3861 }
3862 if (ty.isAbiInt(zcu)) {3862 if (switch (ty.zigTypeTag(zcu)) {
3863 .int, .@"enum" => true,
3864 .@"struct" => ty.containerLayout(zcu) == .@"packed",
3865 else => false,
3866 }) {
3867 assert(ty.isAbiInt(zcu));
3863 const bit_count = ty.intInfo(zcu).bits;3868 const bit_count = ty.intInfo(zcu).bits;
3864 if (bit_count > max_atomic_bits) {3869 if (bit_count > max_atomic_bits) {
3865 diags.* = .{3870 diags.* = .{
src/arch/x86_64/CodeGen.zig+33-24
...@@ -1103,11 +1103,7 @@ const FormatAirData = struct {...@@ -1103,11 +1103,7 @@ const FormatAirData = struct {
1103 inst: Air.Inst.Index,1103 inst: Air.Inst.Index,
1104};1104};
1105fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {1105fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {
1106 // not acceptable implementation because it ignores `w`:1106 data.self.air.writeInst(w, data.inst, data.self.pt, data.self.liveness);
1107 //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1108 _ = data;
1109 _ = w;
1110 @panic("TODO: unimplemented");
1111}1107}
1112fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {1108fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {
1113 return .{ .data = .{ .self = self, .inst = inst } };1109 return .{ .data = .{ .self = self, .inst = inst } };
...@@ -168141,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -168141,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168141 .unused,168137 .unused,
168142 .unused,168138 .unused,
168143 },168139 },
168144 .dst_temps = .{ .{ .cc = .b }, .unused },168140 .dst_temps = .{ .{ .cc = .be }, .unused },
168145 .clobbers = .{ .eflags = true },168141 .clobbers = .{ .eflags = true },
168146 .each = .{ .once = &.{168142 .each = .{ .once = &.{
168147 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },168143 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
...@@ -168165,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -168165,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168165 .unused,168161 .unused,
168166 .unused,168162 .unused,
168167 },168163 },
168168 .dst_temps = .{ .{ .cc = .b }, .unused },168164 .dst_temps = .{ .{ .cc = .be }, .unused },
168169 .clobbers = .{ .eflags = true },168165 .clobbers = .{ .eflags = true },
168170 .each = .{ .once = &.{168166 .each = .{ .once = &.{
168171 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },168167 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
...@@ -168189,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -168189,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168189 .unused,168185 .unused,
168190 .unused,168186 .unused,
168191 },168187 },
168192 .dst_temps = .{ .{ .cc = .b }, .unused },168188 .dst_temps = .{ .{ .cc = .be }, .unused },
168193 .clobbers = .{ .eflags = true },168189 .clobbers = .{ .eflags = true },
168194 .each = .{ .once = &.{168190 .each = .{ .once = &.{
168195 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },168191 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
...@@ -179300,10 +179296,13 @@ fn lowerSwitchBr(...@@ -179300,10 +179296,13 @@ fn lowerSwitchBr(
179300 } else undefined;179296 } else undefined;
179301 const table_start: u31 = @intCast(cg.mir_table.items.len);179297 const table_start: u31 = @intCast(cg.mir_table.items.len);
179302 {179298 {
179303 const condition_index_reg = if (condition_index.isRegister())179299 const condition_index_reg = condition_index_reg: {
179304 condition_index.getReg().?179300 if (condition_index.isRegister()) {
179305 else179301 const condition_index_reg = condition_index.getReg().?;
179306 try cg.copyToTmpRegister(.usize, condition_index);179302 if (condition_index_reg.isClass(.general_purpose)) break :condition_index_reg condition_index_reg;
179303 }
179304 break :condition_index_reg try cg.copyToTmpRegister(.usize, condition_index);
179305 };
179307 const condition_index_lock = cg.register_manager.lockReg(condition_index_reg);179306 const condition_index_lock = cg.register_manager.lockReg(condition_index_reg);
179308 defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock);179307 defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock);
179309 try cg.truncateRegister(condition_ty, condition_index_reg);179308 try cg.truncateRegister(condition_ty, condition_index_reg);
...@@ -191921,18 +191920,15 @@ const Select = struct {...@@ -191921,18 +191920,15 @@ const Select = struct {
191921 error.InvalidInstruction => {191920 error.InvalidInstruction => {
191922 const fixes = @tagName(mir_tag[0]);191921 const fixes = @tagName(mir_tag[0]);
191923 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;191922 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
191924 return s.cg.fail(191923 return s.cg.fail("invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", .{
191925 "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'",191924 fixes[0..fixes_blank],
191926 .{191925 @tagName(mir_tag[1]),
191927 fixes[0..fixes_blank],191926 fixes[fixes_blank + 1 ..],
191928 @tagName(mir_tag[1]),191927 @tagName(mir_ops[0]),
191929 fixes[fixes_blank + 1 ..],191928 @tagName(mir_ops[1]),
191930 @tagName(mir_ops[0]),191929 @tagName(mir_ops[2]),
191931 @tagName(mir_ops[1]),191930 @tagName(mir_ops[3]),
191932 @tagName(mir_ops[2]),191931 });
191933 @tagName(mir_ops[3]),
191934 },
191935 );
191936 },191932 },
191937 else => |e| return e,191933 else => |e| return e,
191938 };191934 };
...@@ -194424,6 +194420,18 @@ fn select(...@@ -194424,6 +194420,18 @@ fn select(
194424 while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {194420 while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {
194425 if (try src_pattern.convert(src_temp, cg)) break;194421 if (try src_pattern.convert(src_temp, cg)) break;
194426 } else break;194422 } else break;
194423 var src_locks: [s_src_temps.len][2]?RegisterLock = @splat(@splat(null));
194424 for (src_locks[0..src_temps.len], src_temps) |*locks, src_temp| {
194425 const regs: [2]Register = switch (src_temp.tracking(cg).short) {
194426 else => continue,
194427 .register => |reg| .{ reg, .none },
194428 .register_pair => |regs| regs,
194429 };
194430 for (regs, locks) |reg, *lock| {
194431 if (reg == .none) continue;
194432 lock.* = cg.register_manager.lockRegIndex(RegisterManager.indexOfRegIntoTracked(reg) orelse continue);
194433 }
194434 }
194427 @memcpy(s_src_temps[0..src_temps.len], src_temps);194435 @memcpy(s_src_temps[0..src_temps.len], src_temps);
194428 std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]);194436 std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]);
194429194437
...@@ -194442,6 +194450,7 @@ fn select(...@@ -194442,6 +194450,7 @@ fn select(
194442 }194450 }
194443 assert(s.top == 0);194451 assert(s.top == 0);
194444194452
194453 for (src_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194445 for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);194454 for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194446 for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);194455 for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194447 caller_preserved: {194456 caller_preserved: {
src/arch/x86_64/Emit.zig+6-5
...@@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void {
168 else if (emit.bin_file.cast(.macho)) |macho_file|168 else if (emit.bin_file.cast(.macho)) |macho_file|
169 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|169 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
170 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})170 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
171 else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: {171 else if (emit.bin_file.cast(.coff)) |coff_file|
172 const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|172 if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom|
173 return emit.fail("{s} creating lazy symbol", .{@errorName(err)});173 coff_file.getAtom(atom).getSymbolIndex().?
174 break :sym_index coff_file.getAtom(atom).getSymbolIndex().?;174 else |err|
175 } else if (emit.bin_file.cast(.plan9)) |p9_file|175 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
176 else if (emit.bin_file.cast(.plan9)) |p9_file|
176 p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|177 p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
177 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})178 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
178 else179 else
src/codegen/aarch64.zig+36-23
...@@ -19,8 +19,12 @@ pub fn generate(...@@ -19,8 +19,12 @@ pub fn generate(
19) !Mir {19) !Mir {
20 const zcu = pt.zcu;20 const zcu = pt.zcu;
21 const gpa = zcu.gpa;21 const gpa = zcu.gpa;
22 const ip = &zcu.intern_pool;
22 const func = zcu.funcInfo(func_index);23 const func = zcu.funcInfo(func_index);
23 const func_type = zcu.intern_pool.indexToKey(func.ty).func_type;24 const func_zir = func.zir_body_inst.resolveFull(ip).?;
25 const file = zcu.fileByIndex(func_zir.file);
26 const named_params_len = file.zir.?.getParamBody(func_zir.inst).len;
27 const func_type = ip.indexToKey(func.ty).func_type;
24 assert(liveness.* == null);28 assert(liveness.* == null);
2529
26 const mod = zcu.navFileScope(func.owner_nav).mod.?;30 const mod = zcu.navFileScope(func.owner_nav).mod.?;
...@@ -47,6 +51,7 @@ pub fn generate(...@@ -47,6 +51,7 @@ pub fn generate(
47 .literals = .empty,51 .literals = .empty,
48 .nav_relocs = .empty,52 .nav_relocs = .empty,
49 .uav_relocs = .empty,53 .uav_relocs = .empty,
54 .lazy_relocs = .empty,
50 .global_relocs = .empty,55 .global_relocs = .empty,
51 .literal_relocs = .empty,56 .literal_relocs = .empty,
5257
...@@ -60,23 +65,32 @@ pub fn generate(...@@ -60,23 +65,32 @@ pub fn generate(
60 .values = .empty,65 .values = .empty,
61 };66 };
62 defer isel.deinit();67 defer isel.deinit();
68 const is_sysv = !isel.target.os.tag.isDarwin() and isel.target.os.tag != .windows;
69 const is_sysv_var_args = is_sysv and func_type.is_var_args;
6370
64 const air_main_body = air.getMainBody();71 const air_main_body = air.getMainBody();
65 var param_it: Select.CallAbiIterator = .init;72 var param_it: Select.CallAbiIterator = .init;
66 const air_args = for (air_main_body, 0..) |air_inst_index, body_index| {73 const air_args = for (air_main_body, 0..) |air_inst_index, body_index| {
67 if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index];74 if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index];
68 const param_ty = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg.ty.toType();75 const arg = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg;
69 const param_vi = try param_it.param(&isel, param_ty);76 const param_ty = arg.ty.toType();
77 const param_vi = param_vi: {
78 if (arg.zir_param_index >= named_params_len) {
79 assert(func_type.is_var_args);
80 if (!is_sysv) break :param_vi try param_it.nonSysvVarArg(&isel, param_ty);
81 }
82 break :param_vi try param_it.param(&isel, param_ty);
83 };
70 tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) });84 tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) });
71 try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?);85 try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?);
72 } else unreachable;86 } else unreachable;
7387
74 const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start;88 const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start;
75 const saved_gra_end = if (func_type.is_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn;89 const saved_gra_end = if (is_sysv_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn;
76 const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start);90 const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start);
7791
78 const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start;92 const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start;
79 const saved_vra_end = if (func_type.is_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn;93 const saved_vra_end = if (is_sysv_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn;
80 const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start);94 const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start);
8195
82 const frame_record = 2;96 const frame_record = 2;
...@@ -84,11 +98,16 @@ pub fn generate(...@@ -84,11 +98,16 @@ pub fn generate(
84 .base = .fp,98 .base = .fp,
85 .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2),99 .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2),
86 };100 };
87 isel.va_list = .{101 const stack_var_args = named_stack_args.withOffset(param_it.nsaa);
88 .__stack = named_stack_args.withOffset(param_it.nsaa),102 const gr_top = named_stack_args;
89 .__gr_top = named_stack_args,103 const vr_top: Select.Value.Indirect = .{ .base = .fp, .offset = 0 };
90 .__vr_top = .{ .base = .fp, .offset = 0 },104 isel.va_list = if (is_sysv) .{ .sysv = .{
91 };105 .__stack = stack_var_args,
106 .__gr_top = gr_top,
107 .__vr_top = vr_top,
108 .__gr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.ngrn_end) - @intFromEnum(param_it.ngrn)) * -8,
109 .__vr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.nsrn_end) - @intFromEnum(param_it.nsrn)) * -16,
110 } } else .{ .other = stack_var_args };
92111
93 // translate arg locations from caller-based to callee-based112 // translate arg locations from caller-based to callee-based
94 for (air_args) |air_inst_index| {113 for (air_args) |air_inst_index| {
...@@ -101,15 +120,13 @@ pub fn generate(...@@ -101,15 +120,13 @@ pub fn generate(
101 };120 };
102 switch (passed_vi.parent(&isel)) {121 switch (passed_vi.parent(&isel)) {
103 .unallocated => if (!mod.strip) {122 .unallocated => if (!mod.strip) {
104 var part_it = arg_vi.parts(&isel);123 var part_it = passed_vi.parts(&isel);
105 const first_passed_part_vi = part_it.next() orelse passed_vi;124 const first_passed_part_vi = part_it.next().?;
106 const hint_ra = first_passed_part_vi.hint(&isel).?;125 const hint_ra = first_passed_part_vi.hint(&isel).?;
107 passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())126 passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())
108 isel.va_list.__vr_top.withOffset(@as(i8, -16) *127 vr_top.withOffset(@as(i8, -16) * (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
109 (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
110 else128 else
111 isel.va_list.__gr_top.withOffset(@as(i8, -8) *129 gr_top.withOffset(@as(i8, -8) * (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
112 (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
113 },130 },
114 .stack_slot => |stack_slot| {131 .stack_slot => |stack_slot| {
115 assert(stack_slot.base == .sp);132 assert(stack_slot.base == .sp);
...@@ -151,13 +168,7 @@ pub fn generate(...@@ -151,13 +168,7 @@ pub fn generate(
151 isel.verify(true);168 isel.verify(true);
152169
153 const prologue = isel.instructions.items.len;170 const prologue = isel.instructions.items.len;
154 const epilogue = try isel.layout(171 const epilogue = try isel.layout(param_it, is_sysv_var_args, saved_gra_len, saved_vra_len, mod);
155 param_it,
156 func_type.is_var_args,
157 saved_gra_len,
158 saved_vra_len,
159 mod,
160 );
161172
162 const instructions = try isel.instructions.toOwnedSlice(gpa);173 const instructions = try isel.instructions.toOwnedSlice(gpa);
163 var mir: Mir = .{174 var mir: Mir = .{
...@@ -167,6 +178,7 @@ pub fn generate(...@@ -167,6 +178,7 @@ pub fn generate(
167 .literals = &.{},178 .literals = &.{},
168 .nav_relocs = &.{},179 .nav_relocs = &.{},
169 .uav_relocs = &.{},180 .uav_relocs = &.{},
181 .lazy_relocs = &.{},
170 .global_relocs = &.{},182 .global_relocs = &.{},
171 .literal_relocs = &.{},183 .literal_relocs = &.{},
172 };184 };
...@@ -174,6 +186,7 @@ pub fn generate(...@@ -174,6 +186,7 @@ pub fn generate(
174 mir.literals = try isel.literals.toOwnedSlice(gpa);186 mir.literals = try isel.literals.toOwnedSlice(gpa);
175 mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);187 mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);
176 mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);188 mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);
189 mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa);
177 mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);190 mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);
178 mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);191 mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);
179 return mir;192 return mir;
src/codegen/aarch64/Assemble.zig+26-6
...@@ -6,14 +6,19 @@ pub const Operand = union(enum) {...@@ -6,14 +6,19 @@ pub const Operand = union(enum) {
6};6};
77
8pub fn nextInstruction(as: *Assemble) !?Instruction {8pub fn nextInstruction(as: *Assemble) !?Instruction {
9 @setEvalBranchQuota(37_000);9 @setEvalBranchQuota(42_000);
10 comptime var ct_token_buf: [token_buf_len]u8 = undefined;10 comptime var ct_token_buf: [token_buf_len]u8 = undefined;
11 var token_buf: [token_buf_len]u8 = undefined;11 var token_buf: [token_buf_len]u8 = undefined;
12 const original_source = while (true) {12 const original_source = while (true) {
13 const original_source = as.source;13 const original_source = as.source;
14 const source_token = try as.nextToken(&token_buf, .{});14 const source_token = try as.nextToken(&token_buf, .{});
15 if (source_token.len == 0) return null;15 switch (source_token.len) {
16 if (source_token[0] != '\n') break original_source;16 0 => return null,
17 else => switch (source_token[0]) {
18 else => break original_source,
19 '\n', ';' => {},
20 },
21 }
17 };22 };
18 log.debug(23 log.debug(
19 \\.24 \\.
...@@ -52,7 +57,13 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {...@@ -52,7 +57,13 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
52 std.zig.fmtString(source_token),57 std.zig.fmtString(source_token),
53 });58 });
54 if (pattern_token.len == 0) {59 if (pattern_token.len == 0) {
55 if (source_token.len > 0 and source_token[0] != '\n') break :next_pattern;60 switch (source_token.len) {
61 0 => {},
62 else => switch (source_token[0]) {
63 else => break :next_pattern,
64 '\n', ';' => {},
65 },
66 }
56 const encode = @field(Instruction, @tagName(instruction.encode[0]));67 const encode = @field(Instruction, @tagName(instruction.encode[0]));
57 const Encode = @TypeOf(encode);68 const Encode = @TypeOf(encode);
58 var args: std.meta.ArgsTuple(Encode) = undefined;69 var args: std.meta.ArgsTuple(Encode) = undefined;
...@@ -65,7 +76,7 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {...@@ -65,7 +76,7 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
65 const symbol = &@field(symbols, symbol_name);76 const symbol = &@field(symbols, symbol_name);
66 symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;77 symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;
67 log.debug("{s} = {any}", .{ symbol_name, symbol.* });78 log.debug("{s} = {any}", .{ symbol_name, symbol.* });
68 } else if (!std.ascii.eqlIgnoreCase(pattern_token, source_token)) break :next_pattern;79 } else if (!toUpperEqlAssertUpper(source_token, pattern_token)) break :next_pattern;
69 }80 }
70 }81 }
71 log.debug("'{s}' not matched...", .{instruction.pattern});82 log.debug("'{s}' not matched...", .{instruction.pattern});
...@@ -125,6 +136,15 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {...@@ -125,6 +136,15 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
125 }136 }
126}137}
127138
139fn toUpperEqlAssertUpper(lhs: []const u8, rhs: []const u8) bool {
140 if (lhs.len != rhs.len) return false;
141 for (lhs, rhs) |l, r| {
142 assert(!std.ascii.isLower(r));
143 if (std.ascii.toUpper(l) != r) return false;
144 }
145 return true;
146}
147
128const token_buf_len = "v31.b[15]".len;148const token_buf_len = "v31.b[15]".len;
129fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {149fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
130 operands: bool = false,150 operands: bool = false,
...@@ -134,7 +154,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {...@@ -134,7 +154,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
134 while (true) c: switch (as.source[0]) {154 while (true) c: switch (as.source[0]) {
135 0 => return as.source[0..0],155 0 => return as.source[0..0],
136 '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..],156 '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..],
137 '\n', '!', '#', ',', '[', ']' => {157 '\n', '!', '#', ',', ';', '[', ']' => {
138 defer as.source = as.source[1..];158 defer as.source = as.source[1..];
139 return as.source[0..1];159 return as.source[0..1];
140 },160 },
src/codegen/aarch64/Mir.zig+106-33
...@@ -4,6 +4,7 @@ epilogue: []const Instruction,...@@ -4,6 +4,7 @@ epilogue: []const Instruction,
4literals: []const u32,4literals: []const u32,
5nav_relocs: []const Reloc.Nav,5nav_relocs: []const Reloc.Nav,
6uav_relocs: []const Reloc.Uav,6uav_relocs: []const Reloc.Uav,
7lazy_relocs: []const Reloc.Lazy,
7global_relocs: []const Reloc.Global,8global_relocs: []const Reloc.Global,
8literal_relocs: []const Reloc.Literal,9literal_relocs: []const Reloc.Literal,
910
...@@ -21,8 +22,13 @@ pub const Reloc = struct {...@@ -21,8 +22,13 @@ pub const Reloc = struct {
21 reloc: Reloc,22 reloc: Reloc,
22 };23 };
2324
25 pub const Lazy = struct {
26 symbol: link.File.LazySymbol,
27 reloc: Reloc,
28 };
29
24 pub const Global = struct {30 pub const Global = struct {
25 global: [*:0]const u8,31 name: [*:0]const u8,
26 reloc: Reloc,32 reloc: Reloc,
27 };33 };
2834
...@@ -38,6 +44,7 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {...@@ -38,6 +44,7 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
38 gpa.free(mir.literals);44 gpa.free(mir.literals);
39 gpa.free(mir.nav_relocs);45 gpa.free(mir.nav_relocs);
40 gpa.free(mir.uav_relocs);46 gpa.free(mir.uav_relocs);
47 gpa.free(mir.lazy_relocs);
41 gpa.free(mir.global_relocs);48 gpa.free(mir.global_relocs);
42 gpa.free(mir.literal_relocs);49 gpa.free(mir.literal_relocs);
43 mir.* = undefined;50 mir.* = undefined;
...@@ -119,16 +126,37 @@ pub fn emit(...@@ -119,16 +126,37 @@ pub fn emit(
119 body_end - Instruction.size * (1 + uav_reloc.reloc.label),126 body_end - Instruction.size * (1 + uav_reloc.reloc.label),
120 uav_reloc.reloc.addend,127 uav_reloc.reloc.addend,
121 );128 );
129 for (mir.lazy_relocs) |lazy_reloc| try emitReloc(
130 lf,
131 zcu,
132 func.owner_nav,
133 if (lf.cast(.elf)) |ef|
134 ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
135 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
136 else if (lf.cast(.macho)) |mf|
137 mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
138 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
139 else if (lf.cast(.coff)) |cf|
140 if (cf.getOrCreateAtomForLazySymbol(pt, lazy_reloc.symbol)) |atom|
141 cf.getAtom(atom).getSymbolIndex().?
142 else |err|
143 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
144 else
145 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
146 mir.body[lazy_reloc.reloc.label],
147 body_end - Instruction.size * (1 + lazy_reloc.reloc.label),
148 lazy_reloc.reloc.addend,
149 );
122 for (mir.global_relocs) |global_reloc| try emitReloc(150 for (mir.global_relocs) |global_reloc| try emitReloc(
123 lf,151 lf,
124 zcu,152 zcu,
125 func.owner_nav,153 func.owner_nav,
126 if (lf.cast(.elf)) |ef|154 if (lf.cast(.elf)) |ef|
127 try ef.getGlobalSymbol(std.mem.span(global_reloc.global), null)155 try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)
128 else if (lf.cast(.macho)) |mf|156 else if (lf.cast(.macho)) |mf|
129 try mf.getGlobalSymbol(std.mem.span(global_reloc.global), null)157 try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)
130 else if (lf.cast(.coff)) |cf|158 else if (lf.cast(.coff)) |cf|
131 try cf.getGlobalSymbol(std.mem.span(global_reloc.global), "compiler_rt")159 try cf.getGlobalSymbol(std.mem.span(global_reloc.name), "compiler_rt")
132 else160 else
133 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),161 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
134 mir.body[global_reloc.reloc.label],162 mir.body[global_reloc.reloc.label],
...@@ -172,35 +200,6 @@ fn emitReloc(...@@ -172,35 +200,6 @@ fn emitReloc(
172 const gpa = zcu.gpa;200 const gpa = zcu.gpa;
173 switch (instruction.decode()) {201 switch (instruction.decode()) {
174 else => unreachable,202 else => unreachable,
175 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
176 const zo = ef.zigObjectPtr().?;
177 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
178 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
179 .b => .JUMP26,
180 .bl => .CALL26,
181 };
182 try atom.addReloc(gpa, .{
183 .r_offset = offset,
184 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
185 .r_addend = @bitCast(addend),
186 }, zo);
187 } else if (lf.cast(.macho)) |mf| {
188 const zo = mf.getZigObject().?;
189 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
190 try atom.addReloc(mf, .{
191 .tag = .@"extern",
192 .offset = offset,
193 .target = sym_index,
194 .addend = @bitCast(addend),
195 .type = .branch,
196 .meta = .{
197 .pcrel = true,
198 .has_subtractor = false,
199 .length = 2,
200 .symbolnum = @intCast(sym_index),
201 },
202 });
203 },
204 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {203 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
205 const zo = ef.zigObjectPtr().?;204 const zo = ef.zigObjectPtr().?;
206 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;205 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
...@@ -259,6 +258,80 @@ fn emitReloc(...@@ -259,6 +258,80 @@ fn emitReloc(
259 },258 },
260 }259 }
261 },260 },
261 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
262 const zo = ef.zigObjectPtr().?;
263 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
264 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
265 .b => .JUMP26,
266 .bl => .CALL26,
267 };
268 try atom.addReloc(gpa, .{
269 .r_offset = offset,
270 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
271 .r_addend = @bitCast(addend),
272 }, zo);
273 } else if (lf.cast(.macho)) |mf| {
274 const zo = mf.getZigObject().?;
275 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
276 try atom.addReloc(mf, .{
277 .tag = .@"extern",
278 .offset = offset,
279 .target = sym_index,
280 .addend = @bitCast(addend),
281 .type = .branch,
282 .meta = .{
283 .pcrel = true,
284 .has_subtractor = false,
285 .length = 2,
286 .symbolnum = @intCast(sym_index),
287 },
288 });
289 },
290 .load_store => |decoded| if (lf.cast(.elf)) |ef| {
291 const zo = ef.zigObjectPtr().?;
292 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
293 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
294 .integer => |integer| switch (integer.decode()) {
295 .unallocated, .prfm => unreachable,
296 .strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC,
297 .strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC,
298 .ldrsw => .LDST32_ABS_LO12_NC,
299 inline .str, .ldr => |encoded| switch (encoded.sf) {
300 .word => .LDST32_ABS_LO12_NC,
301 .doubleword => .LDST64_ABS_LO12_NC,
302 },
303 },
304 .vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) {
305 .byte => .LDST8_ABS_LO12_NC,
306 .half => .LDST16_ABS_LO12_NC,
307 .single => .LDST32_ABS_LO12_NC,
308 .double => .LDST64_ABS_LO12_NC,
309 .quad => .LDST128_ABS_LO12_NC,
310 .scalable, .predicate => unreachable,
311 },
312 };
313 try atom.addReloc(gpa, .{
314 .r_offset = offset,
315 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
316 .r_addend = @bitCast(addend),
317 }, zo);
318 } else if (lf.cast(.macho)) |mf| {
319 const zo = mf.getZigObject().?;
320 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
321 try atom.addReloc(mf, .{
322 .tag = .@"extern",
323 .offset = offset,
324 .target = sym_index,
325 .addend = @bitCast(addend),
326 .type = .pageoff,
327 .meta = .{
328 .pcrel = false,
329 .has_subtractor = false,
330 .length = 2,
331 .symbolnum = @intCast(sym_index),
332 },
333 });
334 },
262 }335 }
263}336}
264337
src/codegen/aarch64/Select.zig+2031-547
...@@ -22,15 +22,21 @@ instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction),...@@ -22,15 +22,21 @@ instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction),
22literals: std.ArrayListUnmanaged(u32),22literals: std.ArrayListUnmanaged(u32),
23nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav),23nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav),
24uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav),24uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav),
25lazy_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Lazy),
25global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global),26global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global),
26literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal),27literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal),
2728
28// Stack Frame29// Stack Frame
29returns: bool,30returns: bool,
30va_list: struct {31va_list: union(enum) {
31 __stack: Value.Indirect,32 other: Value.Indirect,
32 __gr_top: Value.Indirect,33 sysv: struct {
33 __vr_top: Value.Indirect,34 __stack: Value.Indirect,
35 __gr_top: Value.Indirect,
36 __vr_top: Value.Indirect,
37 __gr_offs: i32,
38 __vr_offs: i32,
39 },
34},40},
35stack_size: u24,41stack_size: u24,
36stack_align: InternPool.Alignment,42stack_align: InternPool.Alignment,
...@@ -50,11 +56,11 @@ pub const Block = struct {...@@ -50,11 +56,11 @@ pub const Block = struct {
50 std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),56 std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),
51 );57 );
5258
53 fn branch(block: *const Block, isel: *Select) !void {59 fn branch(target_block: *const Block, isel: *Select) !void {
54 if (isel.instructions.items.len > block.target_label) {60 if (isel.instructions.items.len > target_block.target_label) {
55 try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - block.target_label) << 2)));61 try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - target_block.target_label) << 2)));
56 }62 }
57 try isel.merge(&block.live_registers, .{});63 try isel.merge(&target_block.live_registers, .{});
58 }64 }
59};65};
6066
...@@ -84,12 +90,12 @@ pub const Loop = struct {...@@ -84,12 +90,12 @@ pub const Loop = struct {
8490
85 pub const empty_list: u32 = std.math.maxInt(u32);91 pub const empty_list: u32 = std.math.maxInt(u32);
8692
87 fn branch(loop: *Loop, isel: *Select) !void {93 fn branch(target_loop: *Loop, isel: *Select) !void {
88 try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1);94 try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1);
89 const repeat_list_tail = loop.repeat_list;95 const repeat_list_tail = target_loop.repeat_list;
90 loop.repeat_list = @intCast(isel.instructions.items.len);96 target_loop.repeat_list = @intCast(isel.instructions.items.len);
91 isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail));97 isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail));
92 try isel.merge(&loop.live_registers, .{});98 try isel.merge(&target_loop.live_registers, .{});
93 }99 }
94};100};
95101
...@@ -108,6 +114,7 @@ pub fn deinit(isel: *Select) void {...@@ -108,6 +114,7 @@ pub fn deinit(isel: *Select) void {
108 isel.literals.deinit(gpa);114 isel.literals.deinit(gpa);
109 isel.nav_relocs.deinit(gpa);115 isel.nav_relocs.deinit(gpa);
110 isel.uav_relocs.deinit(gpa);116 isel.uav_relocs.deinit(gpa);
117 isel.lazy_relocs.deinit(gpa);
111 isel.global_relocs.deinit(gpa);118 isel.global_relocs.deinit(gpa);
112 isel.literal_relocs.deinit(gpa);119 isel.literal_relocs.deinit(gpa);
113120
...@@ -406,13 +413,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -406,13 +413,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
406413
407 air_body_index += 1;414 air_body_index += 1;
408 },415 },
409 .breakpoint,416 .breakpoint, .dbg_stmt, .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, .c_va_end => {
410 .dbg_stmt,
411 .dbg_empty_stmt,
412 .dbg_var_ptr,
413 .dbg_var_val,
414 .dbg_arg_inline,
415 => {
416 air_body_index += 1;417 air_body_index += 1;
417 air_inst_index = air_body[air_body_index];418 air_inst_index = air_body[air_body_index];
418 continue :air_tag air_tags[@intFromEnum(air_inst_index)];419 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 {...@@ -426,23 +427,43 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
426 const extra = isel.air.extraData(Air.Call, pl_op.payload);427 const extra = isel.air.extraData(Air.Call, pl_op.payload);
427 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);428 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
428 isel.saved_registers.insert(.lr);429 isel.saved_registers.insert(.lr);
430 const callee_ty = isel.air.typeOf(pl_op.operand, ip);
431 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
432 else => unreachable,
433 .func_type => |func_type| func_type,
434 .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,
435 };
429436
430 try isel.analyzeUse(pl_op.operand);437 try isel.analyzeUse(pl_op.operand);
431 var param_it: CallAbiIterator = .init;438 var param_it: CallAbiIterator = .init;
432 for (args) |arg| {439 for (args, 0..) |arg, arg_index| {
433 const restore_values_len = isel.values.items.len;440 const restore_values_len = isel.values.items.len;
434 defer isel.values.shrinkRetainingCapacity(restore_values_len);441 defer isel.values.shrinkRetainingCapacity(restore_values_len);
435 const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;442 const param_vi = param_vi: {
436 const param_parent = param_vi.parent(isel);443 const param_ty = isel.air.typeOf(arg, ip);
437 switch (switch (param_parent) {444 if (arg_index >= func_info.param_types.len) {
438 .unallocated, .stack_slot => param_parent,445 assert(func_info.is_var_args);
446 switch (isel.va_list) {
447 .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty),
448 .sysv => {},
449 }
450 }
451 break :param_vi try param_it.param(isel, param_ty);
452 } orelse continue;
453 defer param_vi.deref(isel);
454 const passed_vi = switch (param_vi.parent(isel)) {
455 .unallocated, .stack_slot => param_vi,
439 .value, .constant => unreachable,456 .value, .constant => unreachable,
440 .address => |address_vi| address_vi.parent(isel),457 .address => |address_vi| address_vi,
441 }) {458 };
459 switch (passed_vi.parent(isel)) {
442 .unallocated => {},460 .unallocated => {},
443 .stack_slot => |stack_slot| {461 .stack_slot => |stack_slot| {
444 assert(stack_slot.base == .sp);462 assert(stack_slot.base == .sp);
445 isel.stack_size = @max(isel.stack_size, stack_slot.offset);463 isel.stack_size = @max(
464 isel.stack_size,
465 stack_slot.offset + @as(u24, @intCast(passed_vi.size(isel))),
466 );
446 },467 },
447 .value, .constant, .address => unreachable,468 .value, .constant, .address => unreachable,
448 }469 }
...@@ -582,7 +603,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -582,7 +603,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
582603
583 air_body_index += 1;604 air_body_index += 1;
584 },605 },
585 .@"try", .try_cold, .try_ptr, .try_ptr_cold => {606 .@"try", .try_cold => {
586 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;607 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
587 const extra = isel.air.extraData(Air.Try, pl_op.payload);608 const extra = isel.air.extraData(Air.Try, pl_op.payload);
588609
...@@ -594,6 +615,18 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -594,6 +615,18 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
594 air_inst_index = air_body[air_body_index];615 air_inst_index = air_body[air_body_index];
595 continue :air_tag air_tags[@intFromEnum(air_inst_index)];616 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
596 },617 },
618 .try_ptr, .try_ptr_cold => {
619 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
620 const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);
621
622 try isel.analyzeUse(extra.data.ptr);
623 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
624 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
625
626 air_body_index += 1;
627 air_inst_index = air_body[air_body_index];
628 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
629 },
597 .ret, .ret_safe, .ret_load => {630 .ret, .ret_safe, .ret_load => {
598 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;631 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
599 isel.returns = true;632 isel.returns = true;
...@@ -788,7 +821,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -788,7 +821,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
788 air_inst_index = air_body[air_body_index];821 air_inst_index = air_body[air_body_index];
789 continue :air_tag air_tags[@intFromEnum(air_inst_index)];822 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
790 },823 },
791 .set_err_return_trace, .c_va_end => {824 .set_err_return_trace => {
792 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;825 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
793826
794 try isel.analyzeUse(un_op);827 try isel.analyzeUse(un_op);
...@@ -864,7 +897,7 @@ pub fn finishAnalysis(isel: *Select) !void {...@@ -864,7 +897,7 @@ pub fn finishAnalysis(isel: *Select) !void {
864 }897 }
865}898}
866899
867pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {900pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void {
868 const zcu = isel.pt.zcu;901 const zcu = isel.pt.zcu;
869 const ip = &zcu.intern_pool;902 const ip = &zcu.intern_pool;
870 const gpa = zcu.gpa;903 const gpa = zcu.gpa;
...@@ -946,7 +979,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -946,7 +979,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
946 }979 }
947 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;980 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
948 },981 },
949 .add, .add_optimized, .add_wrap, .sub, .sub_optimized, .sub_wrap => |air_tag| {982 .add, .add_safe, .add_optimized, .add_wrap, .sub, .sub_safe, .sub_optimized, .sub_wrap => |air_tag| {
950 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {983 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
951 defer res_vi.value.deref(isel);984 defer res_vi.value.deref(isel);
952985
...@@ -954,13 +987,16 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -954,13 +987,16 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
954 const ty = isel.air.typeOf(bin_op.lhs, ip);987 const ty = isel.air.typeOf(bin_op.lhs, ip);
955 if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) {988 if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) {
956 else => unreachable,989 else => unreachable,
957 .add, .add_wrap => .add,990 .add, .add_safe, .add_wrap => .add,
958 .sub, .sub_wrap => .sub,991 .sub, .sub_safe, .sub_wrap => .sub,
959 }, try isel.use(bin_op.rhs), .{ .wrap = switch (air_tag) {992 }, try isel.use(bin_op.rhs), .{
960 else => unreachable,993 .overflow = switch (air_tag) {
961 .add, .sub => false,994 else => unreachable,
962 .add_wrap, .sub_wrap => true,995 .add, .sub => .@"unreachable",
963 } }) else switch (ty.floatBits(isel.target)) {996 .add_safe, .sub_safe => .{ .panic = .integer_overflow },
997 .add_wrap, .sub_wrap => .wrap,
998 },
999 }) else switch (ty.floatBits(isel.target)) {
964 else => unreachable,1000 else => unreachable,
965 16, 32, 64 => |bits| {1001 16, 32, 64 => |bits| {
966 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;1002 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 {...@@ -1021,7 +1057,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
10211057
1022 try call.prepareCallee(isel);1058 try call.prepareCallee(isel);
1023 try isel.global_relocs.append(gpa, .{1059 try isel.global_relocs.append(gpa, .{
1024 .global = switch (air_tag) {1060 .name = switch (air_tag) {
1025 else => unreachable,1061 else => unreachable,
1026 .add, .add_optimized => switch (bits) {1062 .add, .add_optimized => switch (bits) {
1027 else => unreachable,1063 else => unreachable,
...@@ -1336,7 +1372,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1336,7 +1372,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
13361372
1337 try call.prepareCallee(isel);1373 try call.prepareCallee(isel);
1338 try isel.global_relocs.append(gpa, .{1374 try isel.global_relocs.append(gpa, .{
1339 .global = switch (bits) {1375 .name = switch (bits) {
1340 else => unreachable,1376 else => unreachable,
1341 16 => "__mulhf3",1377 16 => "__mulhf3",
1342 32 => "__mulsf3",1378 32 => "__mulsf3",
...@@ -1379,6 +1415,143 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1379,6 +1415,143 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
1379 }1415 }
1380 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;1416 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1381 },1417 },
1418 .mul_safe => |air_tag| {
1419 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1420 defer res_vi.value.deref(isel);
1421
1422 const bin_op = air.data(air.inst_index).bin_op;
1423 const ty = isel.air.typeOf(bin_op.lhs, ip);
1424 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1425 const int_info = ty.intInfo(zcu);
1426 switch (int_info.signedness) {
1427 .signed => switch (int_info.bits) {
1428 0 => unreachable,
1429 1 => {
1430 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1431 const lhs_vi = try isel.use(bin_op.lhs);
1432 const rhs_vi = try isel.use(bin_op.rhs);
1433 const lhs_mat = try lhs_vi.matReg(isel);
1434 const rhs_mat = try rhs_vi.matReg(isel);
1435 try isel.emit(.orr(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1436 const skip_label = isel.instructions.items.len;
1437 try isel.emitPanic(.integer_overflow);
1438 try isel.emit(.@"b."(
1439 .invert(.ne),
1440 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1441 ));
1442 try isel.emit(.ands(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1443 try rhs_mat.finish(isel);
1444 try lhs_mat.finish(isel);
1445 },
1446 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1447 },
1448 .unsigned => switch (int_info.bits) {
1449 0 => unreachable,
1450 1 => {
1451 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1452 const lhs_vi = try isel.use(bin_op.lhs);
1453 const rhs_vi = try isel.use(bin_op.rhs);
1454 const lhs_mat = try lhs_vi.matReg(isel);
1455 const rhs_mat = try rhs_vi.matReg(isel);
1456 try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1457 try rhs_mat.finish(isel);
1458 try lhs_mat.finish(isel);
1459 },
1460 2...16 => |bits| {
1461 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1462 const lhs_vi = try isel.use(bin_op.lhs);
1463 const rhs_vi = try isel.use(bin_op.rhs);
1464 const lhs_mat = try lhs_vi.matReg(isel);
1465 const rhs_mat = try rhs_vi.matReg(isel);
1466 const skip_label = isel.instructions.items.len;
1467 try isel.emitPanic(.integer_overflow);
1468 try isel.emit(.@"b."(
1469 .eq,
1470 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1471 ));
1472 try isel.emit(.ands(.wzr, res_ra.w(), .{ .immediate = .{
1473 .N = .word,
1474 .immr = @intCast(32 - bits),
1475 .imms = @intCast(32 - bits - 1),
1476 } }));
1477 try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr));
1478 try rhs_mat.finish(isel);
1479 try lhs_mat.finish(isel);
1480 },
1481 17...32 => |bits| {
1482 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1483 const lhs_vi = try isel.use(bin_op.lhs);
1484 const rhs_vi = try isel.use(bin_op.rhs);
1485 const lhs_mat = try lhs_vi.matReg(isel);
1486 const rhs_mat = try rhs_vi.matReg(isel);
1487 const skip_label = isel.instructions.items.len;
1488 try isel.emitPanic(.integer_overflow);
1489 try isel.emit(.@"b."(
1490 .eq,
1491 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1492 ));
1493 try isel.emit(.ands(.xzr, res_ra.x(), .{ .immediate = .{
1494 .N = .doubleword,
1495 .immr = @intCast(64 - bits),
1496 .imms = @intCast(64 - bits - 1),
1497 } }));
1498 try isel.emit(.umaddl(res_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr));
1499 try rhs_mat.finish(isel);
1500 try lhs_mat.finish(isel);
1501 },
1502 33...63 => |bits| {
1503 const lo64_ra = try res_vi.value.defReg(isel) orelse break :unused;
1504 const lhs_vi = try isel.use(bin_op.lhs);
1505 const rhs_vi = try isel.use(bin_op.rhs);
1506 const lhs_mat = try lhs_vi.matReg(isel);
1507 const rhs_mat = try rhs_vi.matReg(isel);
1508 const hi64_ra = hi64_ra: {
1509 const lo64_lock = isel.tryLockReg(lo64_ra);
1510 defer lo64_lock.unlock(isel);
1511 break :hi64_ra try isel.allocIntReg();
1512 };
1513 defer isel.freeReg(hi64_ra);
1514 const skip_label = isel.instructions.items.len;
1515 try isel.emitPanic(.integer_overflow);
1516 try isel.emit(.cbz(
1517 hi64_ra.x(),
1518 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1519 ));
1520 try isel.emit(.orr(hi64_ra.x(), hi64_ra.x(), .{ .shifted_register = .{
1521 .register = lo64_ra.x(),
1522 .shift = .{ .lsr = @intCast(bits) },
1523 } }));
1524 try isel.emit(.madd(lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1525 try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1526 try rhs_mat.finish(isel);
1527 try lhs_mat.finish(isel);
1528 },
1529 64 => {
1530 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1531 const lhs_vi = try isel.use(bin_op.lhs);
1532 const rhs_vi = try isel.use(bin_op.rhs);
1533 const lhs_mat = try lhs_vi.matReg(isel);
1534 const rhs_mat = try rhs_vi.matReg(isel);
1535 try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1536 const hi64_ra = try isel.allocIntReg();
1537 defer isel.freeReg(hi64_ra);
1538 const skip_label = isel.instructions.items.len;
1539 try isel.emitPanic(.integer_overflow);
1540 try isel.emit(.cbz(
1541 hi64_ra.x(),
1542 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1543 ));
1544 try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1545 try rhs_mat.finish(isel);
1546 try lhs_mat.finish(isel);
1547 },
1548 65...128 => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1549 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1550 },
1551 }
1552 }
1553 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1554 },
1382 .mul_sat => |air_tag| {1555 .mul_sat => |air_tag| {
1383 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {1556 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1384 defer res_vi.value.deref(isel);1557 defer res_vi.value.deref(isel);
...@@ -1674,7 +1847,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1674,7 +1847,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
16741847
1675 try call.prepareCallee(isel);1848 try call.prepareCallee(isel);
1676 try isel.global_relocs.append(gpa, .{1849 try isel.global_relocs.append(gpa, .{
1677 .global = switch (bits) {1850 .name = switch (bits) {
1678 else => unreachable,1851 else => unreachable,
1679 16 => "__divhf3",1852 16 => "__divhf3",
1680 32 => "__divsf3",1853 32 => "__divsf3",
...@@ -1746,8 +1919,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1746,8 +1919,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
1746 switch (bits) {1919 switch (bits) {
1747 else => unreachable,1920 else => unreachable,
1748 1...32 => {1921 1...32 => {
1749 try isel.emit(.sub(res_ra.w(), div_ra.w(), .{ .register = rem_ra.w() }));1922 try isel.emit(.csel(res_ra.w(), div_ra.w(), rem_ra.w(), .pl));
1750 try isel.emit(.csinc(rem_ra.w(), .wzr, .wzr, .ge));1923 try isel.emit(.sub(rem_ra.w(), div_ra.w(), .{ .immediate = 1 }));
1751 try isel.emit(.ccmp(1924 try isel.emit(.ccmp(
1752 rem_ra.w(),1925 rem_ra.w(),
1753 .{ .immediate = 0 },1926 .{ .immediate = 0 },
...@@ -1759,8 +1932,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1759,8 +1932,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
1759 try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));1932 try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
1760 },1933 },
1761 33...64 => {1934 33...64 => {
1762 try isel.emit(.sub(res_ra.x(), div_ra.x(), .{ .register = rem_ra.x() }));1935 try isel.emit(.csel(res_ra.x(), div_ra.x(), rem_ra.x(), .pl));
1763 try isel.emit(.csinc(rem_ra.x(), .xzr, .xzr, .ge));1936 try isel.emit(.sub(rem_ra.x(), div_ra.x(), .{ .immediate = 1 }));
1764 try isel.emit(.ccmp(1937 try isel.emit(.ccmp(
1765 rem_ra.x(),1938 rem_ra.x(),
1766 .{ .immediate = 0 },1939 .{ .immediate = 0 },
...@@ -1813,7 +1986,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1813,7 +1986,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
18131986
1814 try call.prepareCallee(isel);1987 try call.prepareCallee(isel);
1815 try isel.global_relocs.append(gpa, .{1988 try isel.global_relocs.append(gpa, .{
1816 .global = switch (int_info.signedness) {1989 .name = switch (int_info.signedness) {
1817 .signed => "__divti3",1990 .signed => "__divti3",
1818 .unsigned => "__udivti3",1991 .unsigned => "__udivti3",
1819 },1992 },
...@@ -1917,7 +2090,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1917,7 +2090,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
1917 else => unreachable,2090 else => unreachable,
1918 .div_trunc, .div_trunc_optimized => {2091 .div_trunc, .div_trunc_optimized => {
1919 try isel.global_relocs.append(gpa, .{2092 try isel.global_relocs.append(gpa, .{
1920 .global = switch (bits) {2093 .name = switch (bits) {
1921 else => unreachable,2094 else => unreachable,
1922 16 => "__trunch",2095 16 => "__trunch",
1923 32 => "truncf",2096 32 => "truncf",
...@@ -1931,7 +2104,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1931,7 +2104,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
1931 },2104 },
1932 .div_floor, .div_floor_optimized => {2105 .div_floor, .div_floor_optimized => {
1933 try isel.global_relocs.append(gpa, .{2106 try isel.global_relocs.append(gpa, .{
1934 .global = switch (bits) {2107 .name = switch (bits) {
1935 else => unreachable,2108 else => unreachable,
1936 16 => "__floorh",2109 16 => "__floorh",
1937 32 => "floorf",2110 32 => "floorf",
...@@ -1946,7 +2119,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1946,7 +2119,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
1946 .div_exact, .div_exact_optimized => {},2119 .div_exact, .div_exact_optimized => {},
1947 }2120 }
1948 try isel.global_relocs.append(gpa, .{2121 try isel.global_relocs.append(gpa, .{
1949 .global = switch (bits) {2122 .name = switch (bits) {
1950 else => unreachable,2123 else => unreachable,
1951 16 => "__divhf3",2124 16 => "__divhf3",
1952 32 => "__divsf3",2125 32 => "__divsf3",
...@@ -1989,7 +2162,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -1989,7 +2162,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
1989 }2162 }
1990 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;2163 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1991 },2164 },
1992 .rem => |air_tag| {2165 .rem, .rem_optimized, .mod, .mod_optimized => |air_tag| {
1993 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {2166 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1994 defer res_vi.value.deref(isel);2167 defer res_vi.value.deref(isel);
19952168
...@@ -2007,17 +2180,57 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -2007,17 +2180,57 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
2007 const rhs_mat = try rhs_vi.matReg(isel);2180 const rhs_mat = try rhs_vi.matReg(isel);
2008 const div_ra = try isel.allocIntReg();2181 const div_ra = try isel.allocIntReg();
2009 defer isel.freeReg(div_ra);2182 defer isel.freeReg(div_ra);
2183 const rem_ra = rem_ra: switch (air_tag) {
2184 else => unreachable,
2185 .rem => res_ra,
2186 .mod => switch (int_info.signedness) {
2187 .signed => {
2188 const rem_ra = try isel.allocIntReg();
2189 errdefer isel.freeReg(rem_ra);
2190 switch (int_info.bits) {
2191 else => unreachable,
2192 1...32 => {
2193 try isel.emit(.csel(res_ra.w(), rem_ra.w(), div_ra.w(), .pl));
2194 try isel.emit(.add(div_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() }));
2195 try isel.emit(.ccmp(
2196 div_ra.w(),
2197 .{ .immediate = 0 },
2198 .{ .n = false, .z = false, .c = false, .v = false },
2199 .ne,
2200 ));
2201 try isel.emit(.eor(div_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() }));
2202 try isel.emit(.subs(.wzr, rem_ra.w(), .{ .immediate = 0 }));
2203 },
2204 33...64 => {
2205 try isel.emit(.csel(res_ra.x(), rem_ra.x(), div_ra.x(), .pl));
2206 try isel.emit(.add(div_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() }));
2207 try isel.emit(.ccmp(
2208 div_ra.x(),
2209 .{ .immediate = 0 },
2210 .{ .n = false, .z = false, .c = false, .v = false },
2211 .ne,
2212 ));
2213 try isel.emit(.eor(div_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() }));
2214 try isel.emit(.subs(.xzr, rem_ra.x(), .{ .immediate = 0 }));
2215 },
2216 }
2217 break :rem_ra rem_ra;
2218 },
2219 .unsigned => res_ra,
2220 },
2221 };
2222 defer if (rem_ra != res_ra) isel.freeReg(rem_ra);
2010 switch (int_info.bits) {2223 switch (int_info.bits) {
2011 else => unreachable,2224 else => unreachable,
2012 1...32 => {2225 1...32 => {
2013 try isel.emit(.msub(res_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));2226 try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
2014 try isel.emit(switch (int_info.signedness) {2227 try isel.emit(switch (int_info.signedness) {
2015 .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),2228 .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2016 .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),2229 .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2017 });2230 });
2018 },2231 },
2019 33...64 => {2232 33...64 => {
2020 try isel.emit(.msub(res_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));2233 try isel.emit(.msub(rem_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));
2021 try isel.emit(switch (int_info.signedness) {2234 try isel.emit(switch (int_info.signedness) {
2022 .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),2235 .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2023 .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),2236 .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 {...@@ -2028,25 +2241,188 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
2028 try lhs_mat.finish(isel);2241 try lhs_mat.finish(isel);
2029 } else {2242 } else {
2030 const bits = ty.floatBits(isel.target);2243 const bits = ty.floatBits(isel.target);
20312244 switch (air_tag) {
2032 try call.prepareReturn(isel);
2033 switch (bits) {
2034 else => unreachable,2245 else => unreachable,
2035 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),2246 .rem, .rem_optimized => {
2036 80 => {2247 if (!res_vi.value.isUsed(isel)) break :unused;
2037 var res_hi16_it = res_vi.value.field(ty, 8, 8);2248 try call.prepareReturn(isel);
2038 const res_hi16_vi = try res_hi16_it.only(isel);2249 switch (bits) {
2039 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);2250 else => unreachable,
2040 var res_lo64_it = res_vi.value.field(ty, 0, 8);2251 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2041 const res_lo64_vi = try res_lo64_it.only(isel);2252 80 => {
2042 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);2253 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2254 const res_hi16_vi = try res_hi16_it.only(isel);
2255 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2256 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2257 const res_lo64_vi = try res_lo64_it.only(isel);
2258 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2259 },
2260 }
2261 try call.finishReturn(isel);
2262 },
2263 .mod, .mod_optimized => switch (bits) {
2264 else => unreachable,
2265 16, 32, 64 => {
2266 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2267 try call.prepareReturn(isel);
2268 const rem_ra: Register.Alias = .v0;
2269 const temp1_ra: Register.Alias = .v1;
2270 const temp2_ra: Register.Alias = switch (res_ra) {
2271 rem_ra, temp1_ra => .v2,
2272 else => res_ra,
2273 };
2274 const need_fcvt = switch (bits) {
2275 else => unreachable,
2276 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
2277 32, 64 => false,
2278 };
2279 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
2280 try isel.emit(switch (res_ra) {
2281 rem_ra => .bif(res_ra.@"8b"(), temp2_ra.@"8b"(), temp1_ra.@"8b"()),
2282 temp1_ra => .bsl(res_ra.@"8b"(), rem_ra.@"8b"(), temp2_ra.@"8b"()),
2283 else => .bit(res_ra.@"8b"(), rem_ra.@"8b"(), temp1_ra.@"8b"()),
2284 });
2285 const rhs_vi = try isel.use(bin_op.rhs);
2286 const rhs_mat = try rhs_vi.matReg(isel);
2287 try isel.emit(bits: switch (bits) {
2288 else => unreachable,
2289 16 => if (need_fcvt)
2290 continue :bits 32
2291 else
2292 .fadd(temp2_ra.h(), rem_ra.h(), rhs_mat.ra.h()),
2293 32 => .fadd(temp2_ra.s(), rem_ra.s(), rhs_mat.ra.s()),
2294 64 => .fadd(temp2_ra.d(), rem_ra.d(), rhs_mat.ra.d()),
2295 });
2296 if (need_fcvt) {
2297 try isel.emit(.fcvt(rhs_mat.ra.s(), rhs_mat.ra.h()));
2298 try isel.emit(.fcvt(rem_ra.s(), rem_ra.h()));
2299 }
2300 try isel.emit(.orr(temp1_ra.@"8b"(), temp1_ra.@"8b"(), .{
2301 .register = temp2_ra.@"8b"(),
2302 }));
2303 try isel.emit(switch (bits) {
2304 else => unreachable,
2305 16 => .cmge(temp1_ra.@"4h"(), temp1_ra.@"4h"(), .zero),
2306 32 => .cmge(temp1_ra.@"2s"(), temp1_ra.@"2s"(), .zero),
2307 64 => .cmge(temp1_ra.d(), temp1_ra.d(), .zero),
2308 });
2309 try isel.emit(switch (bits) {
2310 else => unreachable,
2311 16 => .fcmeq(temp2_ra.h(), rem_ra.h(), .zero),
2312 32 => .fcmeq(temp2_ra.s(), rem_ra.s(), .zero),
2313 64 => .fcmeq(temp2_ra.d(), rem_ra.d(), .zero),
2314 });
2315 try isel.emit(.eor(temp1_ra.@"8b"(), rem_ra.@"8b"(), .{
2316 .register = rhs_mat.ra.@"8b"(),
2317 }));
2318 try rhs_mat.finish(isel);
2319 try call.finishReturn(isel);
2320 },
2321 80, 128 => {
2322 if (!res_vi.value.isUsed(isel)) break :unused;
2323 try call.prepareReturn(isel);
2324 switch (bits) {
2325 else => unreachable,
2326 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2327 80 => {
2328 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2329 const res_hi16_vi = try res_hi16_it.only(isel);
2330 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2331 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2332 const res_lo64_vi = try res_lo64_it.only(isel);
2333 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2334 },
2335 }
2336 const skip_label = isel.instructions.items.len;
2337 try isel.global_relocs.append(gpa, .{
2338 .name = switch (bits) {
2339 else => unreachable,
2340 16 => "__addhf3",
2341 32 => "__addsf3",
2342 64 => "__adddf3",
2343 80 => "__addxf3",
2344 128 => "__addtf3",
2345 },
2346 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2347 });
2348 try isel.emit(.bl(0));
2349 const rhs_vi = try isel.use(bin_op.rhs);
2350 switch (bits) {
2351 else => unreachable,
2352 80 => {
2353 const lhs_lo64_ra: Register.Alias = .r0;
2354 const lhs_hi16_ra: Register.Alias = .r1;
2355 const rhs_lo64_ra: Register.Alias = .r2;
2356 const rhs_hi16_ra: Register.Alias = .r3;
2357 const temp_ra: Register.Alias = .r4;
2358 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
2359 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
2360 try call.paramLiveOut(isel, rhs_hi16_vi.?, rhs_hi16_ra);
2361 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
2362 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
2363 try call.paramLiveOut(isel, rhs_lo64_vi.?, rhs_lo64_ra);
2364 try isel.emit(.cbz(
2365 temp_ra.x(),
2366 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
2367 ));
2368 try isel.emit(.orr(temp_ra.x(), lhs_lo64_ra.x(), .{ .shifted_register = .{
2369 .register = lhs_hi16_ra.x(),
2370 .shift = .{ .lsl = 64 - 15 },
2371 } }));
2372 try isel.emit(.tbz(
2373 temp_ra.w(),
2374 15,
2375 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
2376 ));
2377 try isel.emit(.eor(temp_ra.w(), lhs_hi16_ra.w(), .{
2378 .register = rhs_hi16_ra.w(),
2379 }));
2380 },
2381 128 => {
2382 const lhs_ra: Register.Alias = .v0;
2383 const rhs_ra: Register.Alias = .v1;
2384 const temp1_ra: Register.Alias = .r0;
2385 const temp2_ra: Register.Alias = .r1;
2386 try call.paramLiveOut(isel, rhs_vi, rhs_ra);
2387 try isel.emit(.@"b."(
2388 .pl,
2389 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
2390 ));
2391 try isel.emit(.cbz(
2392 temp1_ra.x(),
2393 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
2394 ));
2395 try isel.emit(.orr(temp1_ra.x(), temp1_ra.x(), .{ .shifted_register = .{
2396 .register = temp2_ra.x(),
2397 .shift = .{ .lsl = 1 },
2398 } }));
2399 try isel.emit(.fmov(temp1_ra.x(), .{
2400 .register = rhs_ra.d(),
2401 }));
2402 try isel.emit(.tbz(
2403 temp1_ra.x(),
2404 63,
2405 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
2406 ));
2407 try isel.emit(.eor(temp1_ra.x(), temp1_ra.x(), .{
2408 .register = temp2_ra.x(),
2409 }));
2410 try isel.emit(.fmov(temp2_ra.x(), .{
2411 .register = rhs_ra.@"d[]"(1),
2412 }));
2413 try isel.emit(.fmov(temp1_ra.x(), .{
2414 .register = lhs_ra.@"d[]"(1),
2415 }));
2416 },
2417 }
2418 try call.finishReturn(isel);
2419 },
2043 },2420 },
2044 }2421 }
2045 try call.finishReturn(isel);
20462422
2047 try call.prepareCallee(isel);2423 try call.prepareCallee(isel);
2048 try isel.global_relocs.append(gpa, .{2424 try isel.global_relocs.append(gpa, .{
2049 .global = switch (bits) {2425 .name = switch (bits) {
2050 else => unreachable,2426 else => unreachable,
2051 16 => "__fmodh",2427 16 => "__fmodh",
2052 32 => "fmodf",2428 32 => "fmodf",
...@@ -2212,7 +2588,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -2212,7 +2588,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
22122588
2213 try call.prepareCallee(isel);2589 try call.prepareCallee(isel);
2214 try isel.global_relocs.append(gpa, .{2590 try isel.global_relocs.append(gpa, .{
2215 .global = switch (air_tag) {2591 .name = switch (air_tag) {
2216 else => unreachable,2592 else => unreachable,
2217 .max => switch (bits) {2593 .max => switch (bits) {
2218 else => unreachable,2594 else => unreachable,
...@@ -2284,7 +2660,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -2284,7 +2660,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
2284 else => unreachable,2660 else => unreachable,
2285 .add_with_overflow => .add,2661 .add_with_overflow => .add,
2286 .sub_with_overflow => .sub,2662 .sub_with_overflow => .sub,
2287 }, rhs_vi, .{ .wrap = true, .overflow_ra = try overflow_vi.?.defReg(isel) orelse .zr });2663 }, rhs_vi, .{
2664 .overflow = if (try overflow_vi.?.defReg(isel)) |overflow_ra| .{ .ra = overflow_ra } else .wrap,
2665 });
2288 }2666 }
2289 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;2667 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2290 },2668 },
...@@ -2318,6 +2696,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -2318,6 +2696,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
2318 }2696 }
2319 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;2697 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2320 },2698 },
2699 .inferred_alloc, .inferred_alloc_comptime => unreachable,
2321 .assembly => {2700 .assembly => {
2322 const ty_pl = air.data(air.inst_index).ty_pl;2701 const ty_pl = air.data(air.inst_index).ty_pl;
2323 const extra = isel.air.extraData(Air.Asm, ty_pl.payload);2702 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 {...@@ -3085,14 +3464,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3085 assert(dst_int_info.bits == src_child_int_info.bits * src_len);3464 assert(dst_int_info.bits == src_child_int_info.bits * src_len);
3086 const src_child_size = src_ty.childType(zcu).abiSize(zcu);3465 const src_child_size = src_ty.childType(zcu).abiSize(zcu);
3087 if (8 * src_child_size == src_child_int_info.bits) {3466 if (8 * src_child_size == src_child_int_info.bits) {
3088 try dst_vi.value.defAddr(isel, dst_ty, dst_int_info, comptime &.initFill(.free)) orelse break :unused;3467 try dst_vi.value.defAddr(isel, dst_ty, .{ .wrap = dst_int_info }) orelse break :unused;
30893468
3090 try call.prepareReturn(isel);3469 try call.prepareReturn(isel);
3091 try call.finishReturn(isel);3470 try call.finishReturn(isel);
30923471
3093 try call.prepareCallee(isel);3472 try call.prepareCallee(isel);
3094 try isel.global_relocs.append(gpa, .{3473 try isel.global_relocs.append(gpa, .{
3095 .global = "memcpy",3474 .name = "memcpy",
3096 .reloc = .{ .label = @intCast(isel.instructions.items.len) },3475 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3097 });3476 });
3098 try isel.emit(.bl(0));3477 try isel.emit(.bl(0));
...@@ -3112,14 +3491,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3112,14 +3491,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3112 assert(dst_child_int_info.bits * dst_len == src_int_info.bits);3491 assert(dst_child_int_info.bits * dst_len == src_int_info.bits);
3113 const dst_child_size = dst_ty.childType(zcu).abiSize(zcu);3492 const dst_child_size = dst_ty.childType(zcu).abiSize(zcu);
3114 if (8 * dst_child_size == dst_child_int_info.bits) {3493 if (8 * dst_child_size == dst_child_int_info.bits) {
3115 try dst_vi.value.defAddr(isel, dst_ty, null, comptime &.initFill(.free)) orelse break :unused;3494 try dst_vi.value.defAddr(isel, dst_ty, .{}) orelse break :unused;
31163495
3117 try call.prepareReturn(isel);3496 try call.prepareReturn(isel);
3118 try call.finishReturn(isel);3497 try call.finishReturn(isel);
31193498
3120 try call.prepareCallee(isel);3499 try call.prepareCallee(isel);
3121 try isel.global_relocs.append(gpa, .{3500 try isel.global_relocs.append(gpa, .{
3122 .global = "memcpy",3501 .name = "memcpy",
3123 .reloc = .{ .label = @intCast(isel.instructions.items.len) },3502 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3124 });3503 });
3125 try isel.emit(.bl(0));3504 try isel.emit(.bl(0));
...@@ -3139,19 +3518,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3139,19 +3518,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3139 .block => {3518 .block => {
3140 const ty_pl = air.data(air.inst_index).ty_pl;3519 const ty_pl = air.data(air.inst_index).ty_pl;
3141 const extra = isel.air.extraData(Air.Block, ty_pl.payload);3520 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
31423521 try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
3143 if (ty_pl.ty != .noreturn_type) {3522 isel.air.extra.items[extra.end..][0..extra.data.body_len],
3144 isel.blocks.putAssumeCapacityNoClobber(air.inst_index, .{3523 ));
3145 .live_registers = isel.live_registers,
3146 .target_label = @intCast(isel.instructions.items.len),
3147 });
3148 }
3149 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
3150 if (ty_pl.ty != .noreturn_type) {
3151 const block_entry = isel.blocks.pop().?;
3152 assert(block_entry.key == air.inst_index);
3153 if (isel.live_values.fetchRemove(air.inst_index)) |result_vi| result_vi.value.deref(isel);
3154 }
3155 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3524 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3156 },3525 },
3157 .loop => {3526 .loop => {
...@@ -3175,11 +3544,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3175,11 +3544,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3175 }3544 }
31763545
3177 // IT'S DOM TIME!!!3546 // IT'S DOM TIME!!!
3178 for (isel.blocks.values(), 0..) |*block, dom_index| {3547 for (isel.blocks.values(), 0..) |*dom_block, dom_index| {
3179 if (@as(u1, @truncate(isel.dom.items[3548 if (@as(u1, @truncate(isel.dom.items[
3180 loop.dom + dom_index / @bitSizeOf(DomInt)3549 loop.dom + dom_index / @bitSizeOf(DomInt)
3181 ] >> @truncate(dom_index))) == 0) continue;3550 ] >> @truncate(dom_index))) == 0) continue;
3182 var live_reg_it = block.live_registers.iterator();3551 var live_reg_it = dom_block.live_registers.iterator();
3183 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {3552 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
3184 _ => |live_vi| try live_vi.mat(isel),3553 _ => |live_vi| try live_vi.mat(isel),
3185 .allocating => unreachable,3554 .allocating => unreachable,
...@@ -3211,8 +3580,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3211,8 +3580,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3211 },3580 },
3212 .br => {3581 .br => {
3213 const br = air.data(air.inst_index).br;3582 const br = air.data(air.inst_index).br;
3214 const block = isel.blocks.getPtr(br.block_inst).?;3583 try isel.blocks.getPtr(br.block_inst).?.branch(isel);
3215 try block.branch(isel);
3216 if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand);3584 if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand);
3217 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3585 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3218 },3586 },
...@@ -3224,10 +3592,32 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3224,10 +3592,32 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3224 try isel.emit(.brk(0xf000));3592 try isel.emit(.brk(0xf000));
3225 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;3593 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3226 },3594 },
3595 .ret_addr => {
3596 if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: {
3597 defer addr_vi.value.deref(isel);
3598 const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused;
3599 try isel.emit(.ldr(addr_ra.x(), .{ .unsigned_offset = .{ .base = .fp, .offset = 8 } }));
3600 }
3601 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3602 },
3603 .frame_addr => {
3604 if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: {
3605 defer addr_vi.value.deref(isel);
3606 const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused;
3607 try isel.emit(.orr(addr_ra.x(), .xzr, .{ .register = .fp }));
3608 }
3609 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3610 },
3227 .call => {3611 .call => {
3228 const pl_op = air.data(air.inst_index).pl_op;3612 const pl_op = air.data(air.inst_index).pl_op;
3229 const extra = isel.air.extraData(Air.Call, pl_op.payload);3613 const extra = isel.air.extraData(Air.Call, pl_op.payload);
3230 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);3614 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
3615 const callee_ty = isel.air.typeOf(pl_op.operand, ip);
3616 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
3617 else => unreachable,
3618 .func_type => |func_type| func_type,
3619 .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,
3620 };
32313621
3232 try call.prepareReturn(isel);3622 try call.prepareReturn(isel);
3233 const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index);3623 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 {...@@ -3251,12 +3641,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3251 .value, .constant => unreachable,3641 .value, .constant => unreachable,
3252 .address => |address_vi| {3642 .address => |address_vi| {
3253 maybe_ret_addr_vi = address_vi;3643 maybe_ret_addr_vi = address_vi;
3254 _ = try def_ret_vi.value.defAddr(3644 _ = try def_ret_vi.value.defAddr(isel, isel.air.typeOfIndex(air.inst_index, ip), .{
3255 isel,3645 .expected_live_registers = &call.caller_saved_regs,
3256 isel.air.typeOfIndex(air.inst_index, ip),3646 });
3257 null,
3258 &call.caller_saved_regs,
3259 );
3260 },3647 },
3261 }3648 }
3262 }3649 }
...@@ -3294,41 +3681,50 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3294,41 +3681,50 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
3294 ret_addr_vi.hint(isel).?,3681 ret_addr_vi.hint(isel).?,
3295 );3682 );
3296 var param_it: CallAbiIterator = .init;3683 var param_it: CallAbiIterator = .init;
3297 for (args) |arg| {3684 for (args, 0..) |arg, arg_index| {
3298 const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;3685 const param_ty = isel.air.typeOf(arg, ip);
3686 const param_vi = param_vi: {
3687 if (arg_index >= func_info.param_types.len) {
3688 assert(func_info.is_var_args);
3689 switch (isel.va_list) {
3690 .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty),
3691 .sysv => {},
3692 }
3693 }
3694 break :param_vi try param_it.param(isel, param_ty);
3695 } orelse continue;
3299 defer param_vi.deref(isel);3696 defer param_vi.deref(isel);
3300 const arg_vi = try isel.use(arg);3697 const arg_vi = try isel.use(arg);
3301 const passed_vi = switch (param_vi.parent(isel)) {3698 switch (param_vi.parent(isel)) {
3302 .unallocated, .stack_slot => param_vi,3699 .unallocated => if (param_vi.hint(isel)) |param_ra| {
3303 .value, .constant => unreachable,3700 try call.paramLiveOut(isel, arg_vi, param_ra);
3304 .address => |address_vi| {3701 } else {
3305 try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?);3702 var param_part_it = param_vi.parts(isel);
3306 continue;3703 var arg_part_it = arg_vi.parts(isel);
3704 if (arg_part_it.only()) |_| {
3705 try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining);
3706 arg_vi.setParts(isel, param_part_it.remaining);
3707 while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart(
3708 isel,
3709 param_part_vi.get(isel).offset_from_parent,
3710 param_part_vi.size(isel),
3711 );
3712 param_part_it = param_vi.parts(isel);
3713 arg_part_it = arg_vi.parts(isel);
3714 }
3715 while (param_part_it.next()) |param_part_vi| {
3716 const arg_part_vi = arg_part_it.next().?;
3717 assert(arg_part_vi.get(isel).offset_from_parent ==
3718 param_part_vi.get(isel).offset_from_parent);
3719 assert(arg_part_vi.size(isel) == param_part_vi.size(isel));
3720 try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?);
3721 }
3307 },3722 },
3308 };3723 .stack_slot => |stack_slot| try arg_vi.store(isel, param_ty, stack_slot.base, .{
3309 if (passed_vi.hint(isel)) |param_ra| {3724 .offset = @intCast(stack_slot.offset),
3310 try call.paramLiveOut(isel, arg_vi, param_ra);3725 }),
3311 } else {3726 .value, .constant => unreachable,
3312 var param_part_it = passed_vi.parts(isel);3727 .address => |address_vi| try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?),
3313 var arg_part_it = arg_vi.parts(isel);
3314 if (arg_part_it.only()) |_| {
3315 try isel.values.ensureUnusedCapacity(isel.pt.zcu.gpa, param_part_it.remaining);
3316 arg_vi.setParts(isel, param_part_it.remaining);
3317 while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart(
3318 isel,
3319 param_part_vi.get(isel).offset_from_parent,
3320 param_part_vi.size(isel),
3321 );
3322 param_part_it = passed_vi.parts(isel);
3323 arg_part_it = arg_vi.parts(isel);
3324 }
3325 while (param_part_it.next()) |param_part_vi| {
3326 const arg_part_vi = arg_part_it.next().?;
3327 assert(arg_part_vi.get(isel).offset_from_parent ==
3328 param_part_vi.get(isel).offset_from_parent);
3329 assert(arg_part_vi.size(isel) == param_part_vi.size(isel));
3330 try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?);
3331 }
3332 }3728 }
3333 }3729 }
3334 try call.finishParams(isel);3730 try call.finishParams(isel);
...@@ -3659,7 +4055,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3659,7 +4055,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
36594055
3660 try call.prepareCallee(isel);4056 try call.prepareCallee(isel);
3661 try isel.global_relocs.append(gpa, .{4057 try isel.global_relocs.append(gpa, .{
3662 .global = switch (air_tag) {4058 .name = switch (air_tag) {
3663 else => unreachable,4059 else => unreachable,
3664 .sqrt => switch (bits) {4060 .sqrt => switch (bits) {
3665 else => unreachable,4061 else => unreachable,
...@@ -3751,7 +4147,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -3751,7 +4147,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
37514147
3752 try call.prepareCallee(isel);4148 try call.prepareCallee(isel);
3753 try isel.global_relocs.append(gpa, .{4149 try isel.global_relocs.append(gpa, .{
3754 .global = switch (air_tag) {4150 .name = switch (air_tag) {
3755 else => unreachable,4151 else => unreachable,
3756 .sin => switch (bits) {4152 .sin => switch (bits) {
3757 else => unreachable,4153 else => unreachable,
...@@ -4239,7 +4635,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4239,7 +4635,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
42394635
4240 try call.prepareCallee(isel);4636 try call.prepareCallee(isel);
4241 try isel.global_relocs.append(gpa, .{4637 try isel.global_relocs.append(gpa, .{
4242 .global = switch (bits) {4638 .name = switch (bits) {
4243 else => unreachable,4639 else => unreachable,
4244 16 => "__cmphf2",4640 16 => "__cmphf2",
4245 32 => "__cmpsf2",4641 32 => "__cmpsf2",
...@@ -4328,7 +4724,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4328,7 +4724,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4328 };4724 };
4329 var cond_mat: ?Value.Materialize = null;4725 var cond_mat: ?Value.Materialize = null;
4330 var cond_reg: Register = undefined;4726 var cond_reg: Register = undefined;
4331 var temp_reg: Register = undefined;
4332 var cases_it = switch_br.iterateCases();4727 var cases_it = switch_br.iterateCases();
4333 while (cases_it.next()) |case| {4728 while (cases_it.next()) |case| {
4334 const next_label = isel.instructions.items.len;4729 const next_label = isel.instructions.items.len;
...@@ -4342,11 +4737,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4342,11 +4737,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4342 if (cond_mat == null) {4737 if (cond_mat == null) {
4343 var cond_vi = try isel.use(switch_br.operand);4738 var cond_vi = try isel.use(switch_br.operand);
4344 cond_mat = try cond_vi.matReg(isel);4739 cond_mat = try cond_vi.matReg(isel);
4345 const temp_ra = try isel.allocIntReg();4740 cond_reg = switch (cond_int_info.bits) {
4346 cond_reg, temp_reg = switch (cond_int_info.bits) {
4347 else => unreachable,4741 else => unreachable,
4348 1...32 => .{ cond_mat.?.ra.w(), temp_ra.w() },4742 1...32 => cond_mat.?.ra.w(),
4349 33...64 => .{ cond_mat.?.ra.x(), temp_ra.x() },4743 33...64 => cond_mat.?.ra.x(),
4350 };4744 };
4351 }4745 }
4352 if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned(4746 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 {...@@ -4387,17 +4781,45 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4387 ) else high_bigint.toInt(i64) catch4781 ) else high_bigint.toInt(i64) catch
4388 return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)});4782 return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)});
43894783
4784 const adjusted_ra = switch (low_int) {
4785 0 => cond_mat.?.ra,
4786 else => try isel.allocIntReg(),
4787 };
4788 defer if (adjusted_ra != cond_mat.?.ra) isel.freeReg(adjusted_ra);
4789 const adjusted_reg = switch (cond_int_info.bits) {
4790 else => unreachable,
4791 1...32 => adjusted_ra.w(),
4792 33...64 => adjusted_ra.x(),
4793 };
4390 const delta_int = high_int -% low_int;4794 const delta_int = high_int -% low_int;
4391 if (case_range_index > 0) {4795 if (case_range_index | case.items.len > 0) {
4392 return isel.fail("case range", .{});4796 if (std.math.cast(u5, delta_int)) |pos_imm| try isel.emit(.ccmp(
4393 } else if (case.items.len > 0) {4797 adjusted_reg,
4394 return isel.fail("case range", .{});4798 .{ .immediate = pos_imm },
4799 .{ .n = false, .z = true, .c = false, .v = false },
4800 if (case_range_index > 0) .hi else .ne,
4801 )) else if (std.math.cast(u5, -delta_int)) |neg_imm| try isel.emit(.ccmn(
4802 adjusted_reg,
4803 .{ .immediate = neg_imm },
4804 .{ .n = false, .z = true, .c = false, .v = false },
4805 if (case_range_index > 0) .hi else .ne,
4806 )) else {
4807 const imm_ra = try isel.allocIntReg();
4808 defer isel.freeReg(imm_ra);
4809 const imm_reg = switch (cond_int_info.bits) {
4810 else => unreachable,
4811 1...32 => imm_ra.w(),
4812 33...64 => imm_ra.x(),
4813 };
4814 try isel.emit(.ccmp(
4815 cond_reg,
4816 .{ .register = imm_reg },
4817 .{ .n = false, .z = true, .c = false, .v = false },
4818 if (case_range_index > 0) .hi else .ne,
4819 ));
4820 try isel.movImmediate(imm_reg, @bitCast(delta_int));
4821 }
4395 } else {4822 } else {
4396 const adjusted_reg = switch (low_int) {
4397 0 => cond_reg,
4398 else => temp_reg,
4399 };
4400
4401 if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs(4823 if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs(
4402 zero_reg,4824 zero_reg,
4403 adjusted_reg,4825 adjusted_reg,
...@@ -4421,41 +4843,55 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4421,41 +4843,55 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4421 adjusted_reg,4843 adjusted_reg,
4422 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },4844 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4423 )) else {4845 )) else {
4424 try isel.movImmediate(temp_reg, @bitCast(delta_int));4846 const imm_ra = try isel.allocIntReg();
4425 try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = temp_reg }));4847 defer isel.freeReg(imm_ra);
4848 const imm_reg = switch (cond_int_info.bits) {
4849 else => unreachable,
4850 1...32 => imm_ra.w(),
4851 33...64 => imm_ra.x(),
4852 };
4853 try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = imm_reg }));
4854 try isel.movImmediate(imm_reg, @bitCast(delta_int));
4426 }4855 }
4856 }
44274857
4428 switch (low_int) {4858 switch (low_int) {
4429 0 => {},4859 0 => {},
4430 else => {4860 else => {
4431 if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(4861 if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
4432 adjusted_reg,4862 adjusted_reg,
4433 cond_reg,4863 cond_reg,
4434 .{ .immediate = pos_imm },4864 .{ .immediate = pos_imm },
4435 )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(4865 )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
4436 adjusted_reg,4866 adjusted_reg,
4437 cond_reg,4867 cond_reg,
4438 .{ .immediate = neg_imm },4868 .{ .immediate = neg_imm },
4439 )) else if (if (@as(i12, @truncate(low_int)) == 0)4869 )) else if (if (@as(i12, @truncate(low_int)) == 0)
4440 std.math.cast(u12, low_int >> 12)4870 std.math.cast(u12, low_int >> 12)
4441 else4871 else
4442 null) |pos_imm_lsr_12| try isel.emit(.sub(4872 null) |pos_imm_lsr_12| try isel.emit(.sub(
4443 adjusted_reg,4873 adjusted_reg,
4444 cond_reg,4874 cond_reg,
4445 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },4875 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4446 )) else if (if (@as(i12, @truncate(-low_int)) == 0)4876 )) else if (if (@as(i12, @truncate(-low_int)) == 0)
4447 std.math.cast(u12, -low_int >> 12)4877 std.math.cast(u12, -low_int >> 12)
4448 else4878 else
4449 null) |neg_imm_lsr_12| try isel.emit(.add(4879 null) |neg_imm_lsr_12| try isel.emit(.add(
4450 adjusted_reg,4880 adjusted_reg,
4451 cond_reg,4881 cond_reg,
4452 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },4882 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4453 )) else {4883 )) else {
4454 try isel.movImmediate(temp_reg, @bitCast(low_int));4884 const imm_ra = try isel.allocIntReg();
4455 try isel.emit(.subs(adjusted_reg, cond_reg, .{ .register = temp_reg }));4885 defer isel.freeReg(imm_ra);
4456 }4886 const imm_reg = switch (cond_int_info.bits) {
4457 },4887 else => unreachable,
4458 }4888 1...32 => imm_ra.w(),
4889 33...64 => imm_ra.x(),
4890 };
4891 try isel.emit(.sub(adjusted_reg, cond_reg, .{ .register = imm_reg }));
4892 try isel.movImmediate(imm_reg, @bitCast(low_int));
4893 }
4894 },
4459 }4895 }
4460 }4896 }
4461 var case_item_index = case.items.len;4897 var case_item_index = case.items.len;
...@@ -4483,13 +4919,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4483,13 +4919,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4483 .{ .n = false, .z = true, .c = false, .v = false },4919 .{ .n = false, .z = true, .c = false, .v = false },
4484 .ne,4920 .ne,
4485 )) else {4921 )) else {
4486 try isel.movImmediate(temp_reg, @bitCast(item_int));4922 const imm_ra = try isel.allocIntReg();
4923 defer isel.freeReg(imm_ra);
4924 const imm_reg = switch (cond_int_info.bits) {
4925 else => unreachable,
4926 1...32 => imm_ra.w(),
4927 33...64 => imm_ra.x(),
4928 };
4487 try isel.emit(.ccmp(4929 try isel.emit(.ccmp(
4488 cond_reg,4930 cond_reg,
4489 .{ .register = temp_reg },4931 .{ .register = imm_reg },
4490 .{ .n = false, .z = true, .c = false, .v = false },4932 .{ .n = false, .z = true, .c = false, .v = false },
4491 .ne,4933 .ne,
4492 ));4934 ));
4935 try isel.movImmediate(imm_reg, @bitCast(item_int));
4493 }4936 }
4494 } else {4937 } else {
4495 if (std.math.cast(u12, item_int)) |pos_imm| try isel.emit(.subs(4938 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 {...@@ -4515,16 +4958,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4515 cond_reg,4958 cond_reg,
4516 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },4959 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4517 )) else {4960 )) else {
4518 try isel.movImmediate(temp_reg, @bitCast(item_int));4961 const imm_ra = try isel.allocIntReg();
4519 try isel.emit(.subs(zero_reg, cond_reg, .{ .register = temp_reg }));4962 defer isel.freeReg(imm_ra);
4520 }4963 const imm_reg = switch (cond_int_info.bits) {
4964 else => unreachable,
4965 1...32 => imm_ra.w(),
4966 33...64 => imm_ra.x(),
4967 };
4968 try isel.emit(.subs(zero_reg, cond_reg, .{ .register = imm_reg }));
4969 try isel.movImmediate(imm_reg, @bitCast(item_int));
4970 }
4521 }4971 }
4522 }4972 }
4523 }4973 }
4524 if (cond_mat) |mat| {4974 if (cond_mat) |mat| try mat.finish(isel);
4525 try mat.finish(isel);
4526 isel.freeReg(temp_reg.alias);
4527 }
4528 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;4975 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4529 },4976 },
4530 .@"try", .try_cold => {4977 .@"try", .try_cold => {
...@@ -4560,24 +5007,75 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4560,24 +5007,75 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4560 const error_set_part_vi = try error_set_part_it.only(isel);5007 const error_set_part_vi = try error_set_part_it.only(isel);
4561 const error_set_part_mat = try error_set_part_vi.?.matReg(isel);5008 const error_set_part_mat = try error_set_part_vi.?.matReg(isel);
4562 try isel.emit(.cbz(5009 try isel.emit(.cbz(
4563 switch (error_set_part_vi.?.size(isel)) {5010 error_set_part_mat.ra.w(),
4564 else => unreachable,
4565 1...4 => error_set_part_mat.ra.w(),
4566 5...8 => error_set_part_mat.ra.x(),
4567 },
4568 @intCast((isel.instructions.items.len + 1 - cont_label) << 2),5011 @intCast((isel.instructions.items.len + 1 - cont_label) << 2),
4569 ));5012 ));
4570 try error_set_part_mat.finish(isel);5013 try error_set_part_mat.finish(isel);
45715014
4572 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5015 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4573 },5016 },
4574 .dbg_stmt => {5017 .try_ptr, .try_ptr_cold => {
5018 const ty_pl = air.data(air.inst_index).ty_pl;
5019 const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);
5020 const error_union_ty = isel.air.typeOf(extra.data.ptr, ip).childType(zcu);
5021 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
5022 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
5023
5024 const error_union_ptr_vi = try isel.use(extra.data.ptr);
5025 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5026 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
5027 defer payload_ptr_vi.value.deref(isel);
5028 switch (codegen.errUnionPayloadOffset(ty_pl.ty.toType().childType(zcu), zcu)) {
5029 0 => try payload_ptr_vi.value.move(isel, extra.data.ptr),
5030 else => |payload_offset| {
5031 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
5032 const lo12: u12 = @truncate(payload_offset >> 0);
5033 const hi12: u12 = @intCast(payload_offset >> 12);
5034 if (hi12 > 0) try isel.emit(.add(
5035 payload_ptr_ra.x(),
5036 if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5037 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5038 ));
5039 if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5040 },
5041 }
5042 }
5043
5044 const cont_label = isel.instructions.items.len;
5045 const cont_live_registers = isel.live_registers;
5046 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
5047 try isel.merge(&cont_live_registers, .{});
5048
5049 const error_set_ra = try isel.allocIntReg();
5050 defer isel.freeReg(error_set_ra);
5051 try isel.loadReg(
5052 error_set_ra,
5053 ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu),
5054 .unsigned,
5055 error_union_ptr_mat.ra,
5056 codegen.errUnionErrorOffset(payload_ty, zcu),
5057 );
5058 try error_union_ptr_mat.finish(isel);
5059 try isel.emit(.cbz(
5060 error_set_ra.w(),
5061 @intCast((isel.instructions.items.len + 1 - cont_label) << 2),
5062 ));
5063
4575 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5064 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4576 },5065 },
5066 .dbg_stmt => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
4577 .dbg_empty_stmt => {5067 .dbg_empty_stmt => {
4578 try isel.emit(.nop());5068 try isel.emit(.nop());
4579 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5069 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4580 },5070 },
5071 .dbg_inline_block => {
5072 const ty_pl = air.data(air.inst_index).ty_pl;
5073 const extra = isel.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
5074 try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
5075 isel.air.extra.items[extra.end..][0..extra.data.body_len],
5076 ));
5077 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5078 },
4581 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {5079 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {
4582 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5080 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4583 },5081 },
...@@ -4655,37 +5153,34 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4655,37 +5153,34 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4655 if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef());5153 if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef());
4656 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {5154 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
4657 defer dst_vi.value.deref(isel);5155 defer dst_vi.value.deref(isel);
4658 switch (dst_vi.value.size(isel)) {5156 const size = dst_vi.value.size(isel);
4659 0 => unreachable,5157 if (size <= Value.max_parts and ip.zigTypeTag(ptr_info.child) != .@"union") {
4660 1...Value.max_parts => {5158 const ptr_vi = try isel.use(ty_op.operand);
4661 const ptr_vi = try isel.use(ty_op.operand);5159 const ptr_mat = try ptr_vi.matReg(isel);
4662 const ptr_mat = try ptr_vi.matReg(isel);5160 _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{
4663 _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{5161 .@"volatile" = ptr_info.flags.is_volatile,
4664 .@"volatile" = ptr_info.flags.is_volatile,5162 });
4665 });5163 try ptr_mat.finish(isel);
4666 try ptr_mat.finish(isel);5164 } else {
4667 },5165 try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), .{}) orelse break :unused;
4668 else => |size| {
4669 try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), null, comptime &.initFill(.free)) orelse break :unused;
46705166
4671 try call.prepareReturn(isel);5167 try call.prepareReturn(isel);
4672 try call.finishReturn(isel);5168 try call.finishReturn(isel);
46735169
4674 try call.prepareCallee(isel);5170 try call.prepareCallee(isel);
4675 try isel.global_relocs.append(gpa, .{5171 try isel.global_relocs.append(gpa, .{
4676 .global = "memcpy",5172 .name = "memcpy",
4677 .reloc = .{ .label = @intCast(isel.instructions.items.len) },5173 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4678 });5174 });
4679 try isel.emit(.bl(0));5175 try isel.emit(.bl(0));
4680 try call.finishCallee(isel);5176 try call.finishCallee(isel);
46815177
4682 try call.prepareParams(isel);5178 try call.prepareParams(isel);
4683 const ptr_vi = try isel.use(ty_op.operand);5179 const ptr_vi = try isel.use(ty_op.operand);
4684 try isel.movImmediate(.x2, size);5180 try isel.movImmediate(.x2, size);
4685 try call.paramLiveOut(isel, ptr_vi, .r1);5181 try call.paramLiveOut(isel, ptr_vi, .r1);
4686 try call.paramAddress(isel, dst_vi.value, .r0);5182 try call.paramAddress(isel, dst_vi.value, .r0);
4687 try call.finishParams(isel);5183 try call.finishParams(isel);
4688 },
4689 }5184 }
4690 }5185 }
46915186
...@@ -4765,10 +5260,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4765,10 +5260,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4765 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);5260 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
4766 const ptr_info = ptr_ty.ptrInfo(zcu);5261 const ptr_info = ptr_ty.ptrInfo(zcu);
4767 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{});5262 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{});
4768 if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val)) {5263 if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val))
4769 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5264 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4770 break :air_tag;
4771 };
47725265
4773 const src_vi = try isel.use(bin_op.rhs);5266 const src_vi = try isel.use(bin_op.rhs);
4774 const size = src_vi.size(isel);5267 const size = src_vi.size(isel);
...@@ -4782,8 +5275,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4782,8 +5275,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
4782 });5275 });
4783 try ptr_mat.finish(isel);5276 try ptr_mat.finish(isel);
47845277
4785 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5278 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4786 break :air_tag;
4787 },5279 },
4788 else => {},5280 else => {},
4789 };5281 };
...@@ -4792,7 +5284,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4792,7 +5284,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
47925284
4793 try call.prepareCallee(isel);5285 try call.prepareCallee(isel);
4794 try isel.global_relocs.append(gpa, .{5286 try isel.global_relocs.append(gpa, .{
4795 .global = "memcpy",5287 .name = "memcpy",
4796 .reloc = .{ .label = @intCast(isel.instructions.items.len) },5288 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4797 });5289 });
4798 try isel.emit(.bl(0));5290 try isel.emit(.bl(0));
...@@ -4855,7 +5347,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -4855,7 +5347,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
48555347
4856 try call.prepareCallee(isel);5348 try call.prepareCallee(isel);
4857 try isel.global_relocs.append(gpa, .{5349 try isel.global_relocs.append(gpa, .{
4858 .global = switch (dst_bits) {5350 .name = switch (dst_bits) {
4859 else => unreachable,5351 else => unreachable,
4860 16 => switch (src_bits) {5352 16 => switch (src_bits) {
4861 else => unreachable,5353 else => unreachable,
...@@ -5009,6 +5501,108 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5009,6 +5501,108 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5009 }5501 }
5010 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5502 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5011 },5503 },
5504 .intcast_safe => |air_tag| {
5505 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5506 defer dst_vi.value.deref(isel);
5507
5508 const ty_op = air.data(air.inst_index).ty_op;
5509 const dst_ty = ty_op.ty.toType();
5510 const dst_int_info = dst_ty.intInfo(zcu);
5511 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5512 const src_int_info = src_ty.intInfo(zcu);
5513 const can_be_negative = dst_int_info.signedness == .signed and
5514 src_int_info.signedness == .signed;
5515 const panic_id: Zcu.SimplePanicId = panic_id: switch (dst_ty.zigTypeTag(zcu)) {
5516 else => unreachable,
5517 .int => .integer_out_of_bounds,
5518 .@"enum" => {
5519 if (!dst_ty.isNonexhaustiveEnum(zcu)) {
5520 return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5521 }
5522 break :panic_id .invalid_enum_value;
5523 },
5524 };
5525 if (dst_ty.toIntern() == src_ty.toIntern()) {
5526 try dst_vi.value.move(isel, ty_op.operand);
5527 } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 64) {
5528 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5529 const src_vi = try isel.use(ty_op.operand);
5530 const dst_active_bits = dst_int_info.bits - @intFromBool(dst_int_info.signedness == .signed);
5531 const src_active_bits = src_int_info.bits - @intFromBool(src_int_info.signedness == .signed);
5532 if ((dst_int_info.signedness != .unsigned or src_int_info.signedness != .signed) and dst_active_bits >= src_active_bits) {
5533 const src_mat = try src_vi.matReg(isel);
5534 try isel.emit(if (can_be_negative and dst_active_bits > 32 and src_active_bits <= 32)
5535 .sbfm(dst_ra.x(), src_mat.ra.x(), .{
5536 .N = .doubleword,
5537 .immr = 0,
5538 .imms = @intCast(src_int_info.bits - 1),
5539 })
5540 else switch (src_int_info.bits) {
5541 else => unreachable,
5542 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }),
5543 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }),
5544 });
5545 try src_mat.finish(isel);
5546 } else {
5547 const skip_label = isel.instructions.items.len;
5548 try isel.emitPanic(panic_id);
5549 try isel.emit(.@"b."(
5550 .eq,
5551 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
5552 ));
5553 if (can_be_negative) {
5554 const src_mat = src_mat: {
5555 const dst_lock = isel.lockReg(dst_ra);
5556 defer dst_lock.unlock(isel);
5557 break :src_mat try src_vi.matReg(isel);
5558 };
5559 try isel.emit(switch (src_int_info.bits) {
5560 else => unreachable,
5561 1...32 => .subs(.wzr, dst_ra.w(), .{ .register = src_mat.ra.w() }),
5562 33...64 => .subs(.xzr, dst_ra.x(), .{ .register = src_mat.ra.x() }),
5563 });
5564 try isel.emit(switch (@max(dst_int_info.bits, src_int_info.bits)) {
5565 else => unreachable,
5566 1...32 => .sbfm(dst_ra.w(), src_mat.ra.w(), .{
5567 .N = .word,
5568 .immr = 0,
5569 .imms = @intCast(dst_int_info.bits - 1),
5570 }),
5571 33...64 => .sbfm(dst_ra.x(), src_mat.ra.x(), .{
5572 .N = .doubleword,
5573 .immr = 0,
5574 .imms = @intCast(dst_int_info.bits - 1),
5575 }),
5576 });
5577 try src_mat.finish(isel);
5578 } else {
5579 const src_mat = try src_vi.matReg(isel);
5580 try isel.emit(switch (@min(dst_int_info.bits, src_int_info.bits)) {
5581 else => unreachable,
5582 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }),
5583 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }),
5584 });
5585 const active_bits = @min(dst_active_bits, src_active_bits);
5586 try isel.emit(switch (src_int_info.bits) {
5587 else => unreachable,
5588 1...32 => .ands(.wzr, src_mat.ra.w(), .{ .immediate = .{
5589 .N = .word,
5590 .immr = @intCast(32 - active_bits),
5591 .imms = @intCast(32 - active_bits - 1),
5592 } }),
5593 33...64 => .ands(.xzr, src_mat.ra.x(), .{ .immediate = .{
5594 .N = .doubleword,
5595 .immr = @intCast(64 - active_bits),
5596 .imms = @intCast(64 - active_bits - 1),
5597 } }),
5598 });
5599 try src_mat.finish(isel);
5600 }
5601 }
5602 } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5603 }
5604 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5605 },
5012 .trunc => |air_tag| {5606 .trunc => |air_tag| {
5013 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {5607 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5014 defer dst_vi.value.deref(isel);5608 defer dst_vi.value.deref(isel);
...@@ -5096,14 +5690,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5096,14 +5690,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5096 }5690 }
5097 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5691 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5098 },5692 },
5099 .optional_payload_ptr => {
5100 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
5101 defer dst_vi.value.deref(isel);
5102 const ty_op = air.data(air.inst_index).ty_op;
5103 try dst_vi.value.move(isel, ty_op.operand);
5104 }
5105 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5106 },
5107 .optional_payload => {5693 .optional_payload => {
5108 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: {5694 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: {
5109 defer payload_vi.value.deref(isel);5695 defer payload_vi.value.deref(isel);
...@@ -5122,6 +5708,37 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5122,6 +5708,37 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5122 }5708 }
5123 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5709 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5124 },5710 },
5711 .optional_payload_ptr => {
5712 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| {
5713 defer payload_ptr_vi.value.deref(isel);
5714 const ty_op = air.data(air.inst_index).ty_op;
5715 try payload_ptr_vi.value.move(isel, ty_op.operand);
5716 }
5717 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5718 },
5719 .optional_payload_ptr_set => {
5720 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| {
5721 defer payload_ptr_vi.value.deref(isel);
5722 const ty_op = air.data(air.inst_index).ty_op;
5723 const opt_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu);
5724 if (!opt_ty.optionalReprIsPayload(zcu)) {
5725 const opt_ptr_vi = try isel.use(ty_op.operand);
5726 const opt_ptr_mat = try opt_ptr_vi.matReg(isel);
5727 const has_value_ra = try isel.allocIntReg();
5728 defer isel.freeReg(has_value_ra);
5729 try isel.storeReg(
5730 has_value_ra,
5731 1,
5732 opt_ptr_mat.ra,
5733 opt_ty.optionalChild(zcu).abiSize(zcu),
5734 );
5735 try opt_ptr_mat.finish(isel);
5736 try isel.emit(.movz(has_value_ra.w(), 1, .{ .lsl = .@"0" }));
5737 }
5738 try payload_ptr_vi.value.move(isel, ty_op.operand);
5739 }
5740 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5741 },
5125 .wrap_optional => {5742 .wrap_optional => {
5126 if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: {5743 if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: {
5127 defer opt_vi.value.deref(isel);5744 defer opt_vi.value.deref(isel);
...@@ -5179,6 +5796,93 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5179,6 +5796,93 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5179 }5796 }
5180 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5797 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5181 },5798 },
5799 .unwrap_errunion_payload_ptr => {
5800 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
5801 defer payload_ptr_vi.value.deref(isel);
5802 const ty_op = air.data(air.inst_index).ty_op;
5803 switch (codegen.errUnionPayloadOffset(ty_op.ty.toType().childType(zcu), zcu)) {
5804 0 => try payload_ptr_vi.value.move(isel, ty_op.operand),
5805 else => |payload_offset| {
5806 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
5807 const error_union_ptr_vi = try isel.use(ty_op.operand);
5808 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5809 const lo12: u12 = @truncate(payload_offset >> 0);
5810 const hi12: u12 = @intCast(payload_offset >> 12);
5811 if (hi12 > 0) try isel.emit(.add(
5812 payload_ptr_ra.x(),
5813 if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5814 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5815 ));
5816 if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5817 try error_union_ptr_mat.finish(isel);
5818 },
5819 }
5820 }
5821 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5822 },
5823 .unwrap_errunion_err_ptr => {
5824 if (isel.live_values.fetchRemove(air.inst_index)) |error_ptr_vi| unused: {
5825 defer error_ptr_vi.value.deref(isel);
5826 const ty_op = air.data(air.inst_index).ty_op;
5827 switch (codegen.errUnionErrorOffset(
5828 isel.air.typeOf(ty_op.operand, ip).childType(zcu).errorUnionPayload(zcu),
5829 zcu,
5830 )) {
5831 0 => try error_ptr_vi.value.move(isel, ty_op.operand),
5832 else => |error_offset| {
5833 const error_ptr_ra = try error_ptr_vi.value.defReg(isel) orelse break :unused;
5834 const error_union_ptr_vi = try isel.use(ty_op.operand);
5835 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5836 const lo12: u12 = @truncate(error_offset >> 0);
5837 const hi12: u12 = @intCast(error_offset >> 12);
5838 if (hi12 > 0) try isel.emit(.add(
5839 error_ptr_ra.x(),
5840 if (lo12 > 0) error_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5841 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5842 ));
5843 if (lo12 > 0) try isel.emit(.add(error_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5844 try error_union_ptr_mat.finish(isel);
5845 },
5846 }
5847 }
5848 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5849 },
5850 .errunion_payload_ptr_set => {
5851 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
5852 defer payload_ptr_vi.value.deref(isel);
5853 const ty_op = air.data(air.inst_index).ty_op;
5854 const payload_ty = ty_op.ty.toType().childType(zcu);
5855 const error_union_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu);
5856 const error_set_size = error_union_ty.errorUnionSet(zcu).abiSize(zcu);
5857 const error_union_ptr_vi = try isel.use(ty_op.operand);
5858 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5859 if (error_set_size > 0) try isel.storeReg(
5860 .zr,
5861 error_set_size,
5862 error_union_ptr_mat.ra,
5863 codegen.errUnionErrorOffset(payload_ty, zcu),
5864 );
5865 switch (codegen.errUnionPayloadOffset(payload_ty, zcu)) {
5866 0 => {
5867 try error_union_ptr_mat.finish(isel);
5868 try payload_ptr_vi.value.move(isel, ty_op.operand);
5869 },
5870 else => |payload_offset| {
5871 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
5872 const lo12: u12 = @truncate(payload_offset >> 0);
5873 const hi12: u12 = @intCast(payload_offset >> 12);
5874 if (hi12 > 0) try isel.emit(.add(
5875 payload_ptr_ra.x(),
5876 if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5877 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5878 ));
5879 if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5880 try error_union_ptr_mat.finish(isel);
5881 },
5882 }
5883 }
5884 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5885 },
5182 .wrap_errunion_payload => {5886 .wrap_errunion_payload => {
5183 if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {5887 if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {
5184 defer error_union_vi.value.deref(isel);5888 defer error_union_vi.value.deref(isel);
...@@ -5220,26 +5924,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5220,26 +5924,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5220 const error_set_size = error_set_ty.abiSize(zcu);5924 const error_set_size = error_set_ty.abiSize(zcu);
5221 const payload_size = payload_ty.abiSize(zcu);5925 const payload_size = payload_ty.abiSize(zcu);
52225926
5927 var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size);
5928 const error_set_part_vi = try error_set_part_it.only(isel);
5929 try error_set_part_vi.?.move(isel, ty_op.operand);
5223 if (payload_size > 0) {5930 if (payload_size > 0) {
5224 var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);5931 var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
5225 const payload_part_vi = try payload_part_it.only(isel);5932 const payload_part_vi = try payload_part_it.only(isel);
5226 if (try payload_part_vi.?.defReg(isel)) |payload_part_ra| try isel.emit(switch (payload_size) {5933 try payload_part_vi.?.defUndef(isel, payload_ty, .{});
5227 else => unreachable,
5228 1...4 => .orr(payload_part_ra.w(), .wzr, .{ .immediate = .{
5229 .N = .word,
5230 .immr = 0b000001,
5231 .imms = 0b111100,
5232 } }),
5233 5...8 => .orr(payload_part_ra.x(), .xzr, .{ .immediate = .{
5234 .N = .word,
5235 .immr = 0b000001,
5236 .imms = 0b111100,
5237 } }),
5238 });
5239 }5934 }
5240 var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size);
5241 const error_set_part_vi = try error_set_part_it.only(isel);
5242 try error_set_part_vi.?.move(isel, ty_op.operand);
5243 }5935 }
5244 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;5936 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5245 },5937 },
...@@ -5313,7 +6005,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5313,7 +6005,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5313 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6005 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5314 },6006 },
5315 .struct_field_val => {6007 .struct_field_val => {
5316 if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| {6008 if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| unused: {
5317 defer field_vi.value.deref(isel);6009 defer field_vi.value.deref(isel);
53186010
5319 const ty_pl = air.data(air.inst_index).ty_pl;6011 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 {...@@ -5340,31 +6032,85 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
5340 });6032 });
53416033
5342 const agg_vi = try isel.use(extra.struct_operand);6034 const agg_vi = try isel.use(extra.struct_operand);
5343 var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8));6035 switch (agg_ty.zigTypeTag(zcu)) {
5344 while (try agg_part_it.next(isel)) |agg_part| {6036 else => unreachable,
5345 var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));6037 .@"struct" => {
5346 const field_part_vi = try field_part_it.only(isel);6038 var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8));
5347 if (field_part_vi.? == agg_part.vi) continue;6039 while (try agg_part_it.next(isel)) |agg_part| {
5348 var field_subpart_it = field_part_vi.?.parts(isel);6040 var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));
5349 const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|6041 const field_part_vi = try field_part_it.only(isel);
5350 field_subpart_vi.get(isel).offset_from_parent6042 if (field_part_vi.? == agg_part.vi) continue;
5351 else6043 var field_subpart_it = field_part_vi.?.parts(isel);
5352 0;6044 const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|
5353 while (field_subpart_it.next()) |field_subpart_vi| {6045 field_subpart_vi.get(isel).offset_from_parent
5354 const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;6046 else
5355 const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);6047 0;
5356 var agg_subpart_it = agg_part.vi.field(6048 while (field_subpart_it.next()) |field_subpart_vi| {
5357 field_ty,6049 const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;
5358 agg_part.offset + field_subpart_offset - field_part_offset,6050 const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);
5359 field_subpart_size,6051 var agg_subpart_it = agg_part.vi.field(
5360 );6052 field_ty,
5361 const agg_subpart_vi = try agg_subpart_it.only(isel);6053 agg_part.offset + field_subpart_offset - field_part_offset,
5362 try agg_subpart_vi.?.liveOut(isel, field_subpart_ra);6054 field_subpart_size,
5363 }6055 );
6056 const agg_subpart_vi = try agg_subpart_it.only(isel);
6057 try agg_subpart_vi.?.liveOut(isel, field_subpart_ra);
6058 }
6059 }
6060 },
6061 .@"union" => {
6062 try field_vi.value.defAddr(isel, field_ty, .{}) orelse break :unused;
6063
6064 try call.prepareReturn(isel);
6065 try call.finishReturn(isel);
6066
6067 try call.prepareCallee(isel);
6068 try isel.global_relocs.append(gpa, .{
6069 .name = "memcpy",
6070 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6071 });
6072 try isel.emit(.bl(0));
6073 try call.finishCallee(isel);
6074
6075 try call.prepareParams(isel);
6076 const union_layout = agg_ty.unionGetLayout(zcu);
6077 var payload_it = agg_vi.field(agg_ty, union_layout.payloadOffset(), union_layout.payload_size);
6078 const payload_vi = try payload_it.only(isel);
6079 try isel.movImmediate(.x2, field_vi.value.size(isel));
6080 try call.paramAddress(isel, payload_vi.?, .r1);
6081 try call.paramAddress(isel, field_vi.value, .r0);
6082 try call.finishParams(isel);
6083 },
5364 }6084 }
5365 }6085 }
5366 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6086 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5367 },6087 },
6088 .set_union_tag => {
6089 const bin_op = air.data(air.inst_index).bin_op;
6090 const union_ty = isel.air.typeOf(bin_op.lhs, ip).childType(zcu);
6091 const union_layout = union_ty.unionGetLayout(zcu);
6092 const tag_vi = try isel.use(bin_op.rhs);
6093 const union_ptr_vi = try isel.use(bin_op.lhs);
6094 const union_ptr_mat = try union_ptr_vi.matReg(isel);
6095 try tag_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), union_ptr_mat.ra, .{
6096 .offset = union_layout.tagOffset(),
6097 });
6098 try union_ptr_mat.finish(isel);
6099 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6100 },
6101 .get_union_tag => {
6102 if (isel.live_values.fetchRemove(air.inst_index)) |tag_vi| {
6103 defer tag_vi.value.deref(isel);
6104 const ty_op = air.data(air.inst_index).ty_op;
6105 const union_ty = isel.air.typeOf(ty_op.operand, ip);
6106 const union_layout = union_ty.unionGetLayout(zcu);
6107 const union_vi = try isel.use(ty_op.operand);
6108 var tag_part_it = union_vi.field(union_ty, union_layout.tagOffset(), union_layout.tag_size);
6109 const tag_part_vi = try tag_part_it.only(isel);
6110 try tag_vi.value.copy(isel, ty_op.ty.toType(), tag_part_vi.?);
6111 }
6112 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6113 },
5368 .slice => {6114 .slice => {
5369 if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {6115 if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {
5370 defer slice_vi.value.deref(isel);6116 defer slice_vi.value.deref(isel);
...@@ -5781,7 +6527,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5781,7 +6527,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
57816527
5782 try call.prepareCallee(isel);6528 try call.prepareCallee(isel);
5783 try isel.global_relocs.append(gpa, .{6529 try isel.global_relocs.append(gpa, .{
5784 .global = switch (dst_int_info.bits) {6530 .name = switch (dst_int_info.bits) {
5785 else => unreachable,6531 else => unreachable,
5786 1...32 => switch (dst_int_info.signedness) {6532 1...32 => switch (dst_int_info.signedness) {
5787 .signed => switch (src_bits) {6533 .signed => switch (src_bits) {
...@@ -5921,7 +6667,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -5921,7 +6667,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
59216667
5922 try call.prepareCallee(isel);6668 try call.prepareCallee(isel);
5923 try isel.global_relocs.append(gpa, .{6669 try isel.global_relocs.append(gpa, .{
5924 .global = switch (src_int_info.bits) {6670 .name = switch (src_int_info.bits) {
5925 else => unreachable,6671 else => unreachable,
5926 1...32 => switch (src_int_info.signedness) {6672 1...32 => switch (src_int_info.signedness) {
5927 .signed => switch (dst_bits) {6673 .signed => switch (dst_bits) {
...@@ -6004,14 +6750,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6004,14 +6750,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6004 }6750 }
6005 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6751 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6006 },6752 },
6007 .memset => |air_tag| {6753 .memset, .memset_safe => |air_tag| {
6008 const bin_op = air.data(air.inst_index).bin_op;6754 const bin_op = air.data(air.inst_index).bin_op;
6009 const dst_ty = isel.air.typeOf(bin_op.lhs, ip);6755 const dst_ty = isel.air.typeOf(bin_op.lhs, ip);
6010 const dst_info = dst_ty.ptrInfo(zcu);6756 const dst_info = dst_ty.ptrInfo(zcu);
6011 const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: {6757 const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: {
6012 if (bin_op.rhs.toInterned()) |fill_val|6758 if (bin_op.rhs.toInterned()) |fill_val| {
6759 if (ip.isUndef(fill_val)) switch (air_tag) {
6760 else => unreachable,
6761 .memset => break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
6762 .memset_safe => break :fill_byte .{ .constant = 0xaa },
6763 };
6013 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|6764 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
6014 break :fill_byte .{ .constant = fill_byte };6765 break :fill_byte .{ .constant = fill_byte };
6766 }
6015 switch (dst_ty.elemType2(zcu).abiSize(zcu)) {6767 switch (dst_ty.elemType2(zcu).abiSize(zcu)) {
6016 0 => unreachable,6768 0 => unreachable,
6017 1 => break :fill_byte .{ .value = bin_op.rhs },6769 1 => break :fill_byte .{ .value = bin_op.rhs },
...@@ -6070,8 +6822,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6070,8 +6822,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6070 .c => unreachable,6822 .c => unreachable,
6071 }6823 }
60726824
6073 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6825 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6074 break :air_tag;
6075 },6826 },
6076 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }),6827 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }),
6077 }6828 }
...@@ -6082,7 +6833,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6082,7 +6833,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
60826833
6083 try call.prepareCallee(isel);6834 try call.prepareCallee(isel);
6084 try isel.global_relocs.append(gpa, .{6835 try isel.global_relocs.append(gpa, .{
6085 .global = "memset",6836 .name = "memset",
6086 .reloc = .{ .label = @intCast(isel.instructions.items.len) },6837 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6087 });6838 });
6088 try isel.emit(.bl(0));6839 try isel.emit(.bl(0));
...@@ -6128,7 +6879,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6128,7 +6879,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
61286879
6129 try call.prepareCallee(isel);6880 try call.prepareCallee(isel);
6130 try isel.global_relocs.append(gpa, .{6881 try isel.global_relocs.append(gpa, .{
6131 .global = @tagName(air_tag),6882 .name = @tagName(air_tag),
6132 .reloc = .{ .label = @intCast(isel.instructions.items.len) },6883 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6133 });6884 });
6134 try isel.emit(.bl(0));6885 try isel.emit(.bl(0));
...@@ -6217,6 +6968,72 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6217,6 +6968,72 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
62176968
6218 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;6969 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6219 },6970 },
6971 .error_name => {
6972 if (isel.live_values.fetchRemove(air.inst_index)) |name_vi| unused: {
6973 defer name_vi.value.deref(isel);
6974 var ptr_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 0, 8);
6975 const ptr_part_vi = try ptr_part_it.only(isel);
6976 const ptr_part_ra = try ptr_part_vi.?.defReg(isel);
6977 var len_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 8, 8);
6978 const len_part_vi = try len_part_it.only(isel);
6979 const len_part_ra = try len_part_vi.?.defReg(isel);
6980 if (ptr_part_ra == null and len_part_ra == null) break :unused;
6981
6982 const un_op = air.data(air.inst_index).un_op;
6983 const error_vi = try isel.use(un_op);
6984 const error_mat = try error_vi.matReg(isel);
6985 const ptr_ra = try isel.allocIntReg();
6986 defer isel.freeReg(ptr_ra);
6987 const start_ra, const end_ra = range_ras: {
6988 const name_lock: RegLock = if (len_part_ra != null) if (ptr_part_ra) |name_ptr_ra|
6989 isel.tryLockReg(name_ptr_ra)
6990 else
6991 .empty else .empty;
6992 defer name_lock.unlock(isel);
6993 break :range_ras .{ try isel.allocIntReg(), try isel.allocIntReg() };
6994 };
6995 defer {
6996 isel.freeReg(start_ra);
6997 isel.freeReg(end_ra);
6998 }
6999 if (len_part_ra) |name_len_ra| try isel.emit(.sub(
7000 name_len_ra.w(),
7001 end_ra.w(),
7002 .{ .register = start_ra.w() },
7003 ));
7004 if (ptr_part_ra) |name_ptr_ra| try isel.emit(.add(
7005 name_ptr_ra.x(),
7006 ptr_ra.x(),
7007 .{ .extended_register = .{
7008 .register = start_ra.w(),
7009 .extend = .{ .uxtw = 0 },
7010 } },
7011 ));
7012 if (len_part_ra) |_| try isel.emit(.sub(end_ra.w(), end_ra.w(), .{ .immediate = 1 }));
7013 try isel.emit(.ldp(start_ra.w(), end_ra.w(), .{ .base = start_ra.x() }));
7014 try isel.emit(.add(start_ra.x(), ptr_ra.x(), .{ .extended_register = .{
7015 .register = error_mat.ra.w(),
7016 .extend = switch (zcu.errorSetBits()) {
7017 else => unreachable,
7018 1...8 => .{ .uxtb = 2 },
7019 9...16 => .{ .uxth = 2 },
7020 17...32 => .{ .uxtw = 2 },
7021 },
7022 } }));
7023 try isel.lazy_relocs.append(gpa, .{
7024 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
7025 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7026 });
7027 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
7028 try isel.lazy_relocs.append(gpa, .{
7029 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
7030 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7031 });
7032 try isel.emit(.adrp(ptr_ra.x(), 0));
7033 try error_mat.finish(isel);
7034 }
7035 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7036 },
6220 .aggregate_init => {7037 .aggregate_init => {
6221 if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| {7038 if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| {
6222 defer agg_vi.value.deref(isel);7039 defer agg_vi.value.deref(isel);
...@@ -6295,23 +7112,52 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6295,23 +7112,52 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6295 }7112 }
6296 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;7113 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6297 },7114 },
6298 .union_init => {7115 .union_init => |air_tag| {
6299 if (isel.live_values.fetchRemove(air.inst_index)) |un_vi| unused: {7116 if (isel.live_values.fetchRemove(air.inst_index)) |union_vi| unused: {
6300 defer un_vi.value.deref(isel);7117 defer union_vi.value.deref(isel);
63017118
6302 const ty_pl = air.data(air.inst_index).ty_pl;7119 const ty_pl = air.data(air.inst_index).ty_pl;
6303 const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;7120 const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;
6304 const un_ty = ty_pl.ty.toType();7121 const union_ty = ty_pl.ty.toType();
6305 if (un_ty.containerLayout(zcu) != .@"extern") return isel.fail("bad union init {f}", .{isel.fmtType(un_ty)});7122 const loaded_union = ip.loadUnionType(union_ty.toIntern());
63067123 const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
6307 try un_vi.value.defAddr(isel, un_ty, null, comptime &.initFill(.free)) orelse break :unused;7124
7125 if (union_layout.tag_size > 0) unused_tag: {
7126 const loaded_tag = loaded_union.loadTagType(ip);
7127 var tag_it = union_vi.value.field(union_ty, union_layout.tagOffset(), union_layout.tag_size);
7128 const tag_vi = try tag_it.only(isel);
7129 const tag_ra = try tag_vi.?.defReg(isel) orelse break :unused_tag;
7130 switch (union_layout.tag_size) {
7131 0 => unreachable,
7132 1...4 => try isel.movImmediate(tag_ra.w(), @as(u32, switch (loaded_tag.values.len) {
7133 0 => extra.field_index,
7134 else => switch (ip.indexToKey(loaded_tag.values.get(ip)[extra.field_index]).int.storage) {
7135 .u64 => |imm| @intCast(imm),
7136 .i64 => |imm| @bitCast(@as(i32, @intCast(imm))),
7137 else => unreachable,
7138 },
7139 })),
7140 5...8 => try isel.movImmediate(tag_ra.x(), switch (loaded_tag.values.len) {
7141 0 => extra.field_index,
7142 else => switch (ip.indexToKey(loaded_tag.values.get(ip)[extra.field_index]).int.storage) {
7143 .u64 => |imm| imm,
7144 .i64 => |imm| @bitCast(imm),
7145 else => unreachable,
7146 },
7147 }),
7148 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(union_ty) }),
7149 }
7150 }
7151 var payload_it = union_vi.value.field(union_ty, union_layout.payloadOffset(), union_layout.payload_size);
7152 const payload_vi = try payload_it.only(isel);
7153 try payload_vi.?.defAddr(isel, union_ty, .{ .root_vi = union_vi.value }) orelse break :unused;
63087154
6309 try call.prepareReturn(isel);7155 try call.prepareReturn(isel);
6310 try call.finishReturn(isel);7156 try call.finishReturn(isel);
63117157
6312 try call.prepareCallee(isel);7158 try call.prepareCallee(isel);
6313 try isel.global_relocs.append(gpa, .{7159 try isel.global_relocs.append(gpa, .{
6314 .global = "memcpy",7160 .name = "memcpy",
6315 .reloc = .{ .label = @intCast(isel.instructions.items.len) },7161 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6316 });7162 });
6317 try isel.emit(.bl(0));7163 try isel.emit(.bl(0));
...@@ -6321,7 +7167,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6321,7 +7167,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6321 const init_vi = try isel.use(extra.init);7167 const init_vi = try isel.use(extra.init);
6322 try isel.movImmediate(.x2, init_vi.size(isel));7168 try isel.movImmediate(.x2, init_vi.size(isel));
6323 try call.paramAddress(isel, init_vi, .r1);7169 try call.paramAddress(isel, init_vi, .r1);
6324 try call.paramAddress(isel, un_vi.value, .r0);7170 try call.paramAddress(isel, payload_vi.?, .r0);
6325 try call.finishParams(isel);7171 try call.finishParams(isel);
6326 }7172 }
6327 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;7173 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 {...@@ -6427,7 +7273,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
64277273
6428 try call.prepareCallee(isel);7274 try call.prepareCallee(isel);
6429 try isel.global_relocs.append(gpa, .{7275 try isel.global_relocs.append(gpa, .{
6430 .global = switch (bits) {7276 .name = switch (bits) {
6431 else => unreachable,7277 else => unreachable,
6432 16 => "__fmah",7278 16 => "__fmah",
6433 32 => "fmaf",7279 32 => "fmaf",
...@@ -6508,6 +7354,33 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6508,6 +7354,33 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6508 }7354 }
6509 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;7355 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6510 },7356 },
7357 .wasm_memory_size, .wasm_memory_grow => unreachable,
7358 .cmp_lt_errors_len => {
7359 if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: {
7360 defer is_vi.value.deref(isel);
7361 const is_ra = try is_vi.value.defReg(isel) orelse break :unused;
7362 try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(.ls)));
7363
7364 const un_op = air.data(air.inst_index).un_op;
7365 const error_vi = try isel.use(un_op);
7366 const error_mat = try error_vi.matReg(isel);
7367 const ptr_ra = try isel.allocIntReg();
7368 defer isel.freeReg(ptr_ra);
7369 try isel.emit(.subs(.wzr, error_mat.ra.w(), .{ .register = ptr_ra.w() }));
7370 try isel.lazy_relocs.append(gpa, .{
7371 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
7372 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7373 });
7374 try isel.emit(.ldr(ptr_ra.w(), .{ .base = ptr_ra.x() }));
7375 try isel.lazy_relocs.append(gpa, .{
7376 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
7377 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7378 });
7379 try isel.emit(.adrp(ptr_ra.x(), 0));
7380 try error_mat.finish(isel);
7381 }
7382 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7383 },
6511 .runtime_nav_ptr => {7384 .runtime_nav_ptr => {
6512 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {7385 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
6513 defer ptr_vi.value.deref(isel);7386 defer ptr_vi.value.deref(isel);
...@@ -6516,19 +7389,19 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6516,19 +7389,19 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6516 const ty_nav = air.data(air.inst_index).ty_nav;7389 const ty_nav = air.data(air.inst_index).ty_nav;
6517 if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {7390 if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
6518 false => {7391 false => {
6519 try isel.nav_relocs.append(zcu.gpa, .{7392 try isel.nav_relocs.append(gpa, .{
6520 .nav = ty_nav.nav,7393 .nav = ty_nav.nav,
6521 .reloc = .{ .label = @intCast(isel.instructions.items.len) },7394 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6522 });7395 });
6523 try isel.emit(.adr(ptr_ra.x(), 0));7396 try isel.emit(.adr(ptr_ra.x(), 0));
6524 },7397 },
6525 true => {7398 true => {
6526 try isel.nav_relocs.append(zcu.gpa, .{7399 try isel.nav_relocs.append(gpa, .{
6527 .nav = ty_nav.nav,7400 .nav = ty_nav.nav,
6528 .reloc = .{ .label = @intCast(isel.instructions.items.len) },7401 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6529 });7402 });
6530 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));7403 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
6531 try isel.nav_relocs.append(zcu.gpa, .{7404 try isel.nav_relocs.append(gpa, .{
6532 .nav = ty_nav.nav,7405 .nav = ty_nav.nav,
6533 .reloc = .{ .label = @intCast(isel.instructions.items.len) },7406 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6534 });7407 });
...@@ -6538,19 +7411,266 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -6538,19 +7411,266 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
6538 }7411 }
6539 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;7412 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6540 },7413 },
6541 .add_safe,7414 .c_va_arg => {
6542 .sub_safe,7415 const maybe_arg_vi = isel.live_values.fetchRemove(air.inst_index);
6543 .mul_safe,7416 defer if (maybe_arg_vi) |arg_vi| arg_vi.value.deref(isel);
6544 .inferred_alloc,7417 const ty_op = air.data(air.inst_index).ty_op;
6545 .inferred_alloc_comptime,7418 const ty = ty_op.ty.toType();
6546 .int_from_float_safe,7419 var param_it: CallAbiIterator = .init;
6547 .int_from_float_optimized_safe,7420 const param_vi = try param_it.param(isel, ty);
6548 .wasm_memory_size,7421 defer param_vi.?.deref(isel);
6549 .wasm_memory_grow,7422 const passed_vi = switch (param_vi.?.parent(isel)) {
6550 .work_item_id,7423 .unallocated => param_vi.?,
6551 .work_group_size,7424 .stack_slot, .value, .constant => unreachable,
6552 .work_group_id,7425 .address => |address_vi| address_vi,
6553 => unreachable,7426 };
7427 const passed_size: u5 = @intCast(passed_vi.alignment(isel).forward(passed_vi.size(isel)));
7428 const passed_is_vector = passed_vi.isVector(isel);
7429
7430 const va_list_ptr_vi = try isel.use(ty_op.operand);
7431 const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel);
7432 const offs_ra = try isel.allocIntReg();
7433 defer isel.freeReg(offs_ra);
7434 const stack_ra = try isel.allocIntReg();
7435 defer isel.freeReg(stack_ra);
7436
7437 var part_vis: [2]Value.Index = undefined;
7438 var arg_part_ras: [2]?Register.Alias = @splat(null);
7439 const parts_len = parts_len: {
7440 var parts_len: u2 = 0;
7441 var part_it = passed_vi.parts(isel);
7442 while (part_it.next()) |part_vi| : (parts_len += 1) {
7443 part_vis[parts_len] = part_vi;
7444 const arg_vi = maybe_arg_vi orelse continue;
7445 const part_offset, const part_size = part_vi.position(isel);
7446 var arg_part_it = arg_vi.value.field(ty, part_offset, part_size);
7447 const arg_part_vi = try arg_part_it.only(isel);
7448 arg_part_ras[parts_len] = try arg_part_vi.?.defReg(isel);
7449 }
7450 break :parts_len parts_len;
7451 };
7452
7453 const done_label = isel.instructions.items.len;
7454 try isel.emit(.str(stack_ra.x(), .{ .unsigned_offset = .{
7455 .base = va_list_ptr_mat.ra.x(),
7456 .offset = 0,
7457 } }));
7458 try isel.emit(switch (parts_len) {
7459 else => unreachable,
7460 1 => if (arg_part_ras[0]) |arg_part_ra| switch (part_vis[0].size(isel)) {
7461 else => unreachable,
7462 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .post_index = .{
7463 .base = stack_ra.x(),
7464 .index = passed_size,
7465 } }) else switch (part_vis[0].signedness(isel)) {
7466 .signed => .ldrsb(arg_part_ra.w(), .{ .post_index = .{
7467 .base = stack_ra.x(),
7468 .index = passed_size,
7469 } }),
7470 .unsigned => .ldrb(arg_part_ra.w(), .{ .post_index = .{
7471 .base = stack_ra.x(),
7472 .index = passed_size,
7473 } }),
7474 },
7475 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .post_index = .{
7476 .base = stack_ra.x(),
7477 .index = passed_size,
7478 } }) else switch (part_vis[0].signedness(isel)) {
7479 .signed => .ldrsh(arg_part_ra.w(), .{ .post_index = .{
7480 .base = stack_ra.x(),
7481 .index = passed_size,
7482 } }),
7483 .unsigned => .ldrh(arg_part_ra.w(), .{ .post_index = .{
7484 .base = stack_ra.x(),
7485 .index = passed_size,
7486 } }),
7487 },
7488 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .post_index = .{
7489 .base = stack_ra.x(),
7490 .index = passed_size,
7491 } }),
7492 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .post_index = .{
7493 .base = stack_ra.x(),
7494 .index = passed_size,
7495 } }),
7496 16 => .ldr(arg_part_ra.q(), .{ .post_index = .{
7497 .base = stack_ra.x(),
7498 .index = passed_size,
7499 } }),
7500 } else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }),
7501 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) .ldp(
7502 @as(Register.Alias, arg_part_ras[0] orelse .zr).x(),
7503 @as(Register.Alias, arg_part_ras[1] orelse .zr).x(),
7504 .{ .post_index = .{
7505 .base = stack_ra.x(),
7506 .index = passed_size,
7507 } },
7508 ) else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }),
7509 });
7510 try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{
7511 .base = va_list_ptr_mat.ra.x(),
7512 .offset = 0,
7513 } }));
7514 switch (isel.va_list) {
7515 .other => {},
7516 .sysv => {
7517 const stack_label = isel.instructions.items.len;
7518 try isel.emit(.b(
7519 @intCast((isel.instructions.items.len + 1 - done_label) << 2),
7520 ));
7521 switch (parts_len) {
7522 else => unreachable,
7523 1 => if (arg_part_ras[0]) |arg_part_ra| try isel.emit(switch (part_vis[0].size(isel)) {
7524 else => unreachable,
7525 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .extended_register = .{
7526 .base = stack_ra.x(),
7527 .index = offs_ra.w(),
7528 .extend = .{ .sxtw = 0 },
7529 } }) else switch (part_vis[0].signedness(isel)) {
7530 .signed => .ldrsb(arg_part_ra.w(), .{ .extended_register = .{
7531 .base = stack_ra.x(),
7532 .index = offs_ra.w(),
7533 .extend = .{ .sxtw = 0 },
7534 } }),
7535 .unsigned => .ldrb(arg_part_ra.w(), .{ .extended_register = .{
7536 .base = stack_ra.x(),
7537 .index = offs_ra.w(),
7538 .extend = .{ .sxtw = 0 },
7539 } }),
7540 },
7541 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .extended_register = .{
7542 .base = stack_ra.x(),
7543 .index = offs_ra.w(),
7544 .extend = .{ .sxtw = 0 },
7545 } }) else switch (part_vis[0].signedness(isel)) {
7546 .signed => .ldrsh(arg_part_ra.w(), .{ .extended_register = .{
7547 .base = stack_ra.x(),
7548 .index = offs_ra.w(),
7549 .extend = .{ .sxtw = 0 },
7550 } }),
7551 .unsigned => .ldrh(arg_part_ra.w(), .{ .extended_register = .{
7552 .base = stack_ra.x(),
7553 .index = offs_ra.w(),
7554 .extend = .{ .sxtw = 0 },
7555 } }),
7556 },
7557 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .extended_register = .{
7558 .base = stack_ra.x(),
7559 .index = offs_ra.w(),
7560 .extend = .{ .sxtw = 0 },
7561 } }),
7562 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .extended_register = .{
7563 .base = stack_ra.x(),
7564 .index = offs_ra.w(),
7565 .extend = .{ .sxtw = 0 },
7566 } }),
7567 16 => .ldr(arg_part_ra.q(), .{ .extended_register = .{
7568 .base = stack_ra.x(),
7569 .index = offs_ra.w(),
7570 .extend = .{ .sxtw = 0 },
7571 } }),
7572 }),
7573 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) {
7574 try isel.emit(.ldp(
7575 @as(Register.Alias, arg_part_ras[0] orelse .zr).x(),
7576 @as(Register.Alias, arg_part_ras[1] orelse .zr).x(),
7577 .{ .base = stack_ra.x() },
7578 ));
7579 try isel.emit(.add(stack_ra.x(), stack_ra.x(), .{ .extended_register = .{
7580 .register = offs_ra.w(),
7581 .extend = .{ .sxtw = 0 },
7582 } }));
7583 },
7584 }
7585 try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{
7586 .base = va_list_ptr_mat.ra.x(),
7587 .offset = if (passed_is_vector) 16 else 8,
7588 } }));
7589 try isel.emit(.@"b."(
7590 .gt,
7591 @intCast((isel.instructions.items.len + 1 - stack_label) << 2),
7592 ));
7593 try isel.emit(.str(stack_ra.w(), .{ .unsigned_offset = .{
7594 .base = va_list_ptr_mat.ra.x(),
7595 .offset = if (passed_is_vector) 28 else 24,
7596 } }));
7597 try isel.emit(.adds(stack_ra.w(), offs_ra.w(), .{ .immediate = passed_size }));
7598 try isel.emit(.tbz(
7599 offs_ra.w(),
7600 31,
7601 @intCast((isel.instructions.items.len + 1 - stack_label) << 2),
7602 ));
7603 try isel.emit(.ldr(offs_ra.w(), .{ .unsigned_offset = .{
7604 .base = va_list_ptr_mat.ra.x(),
7605 .offset = if (passed_is_vector) 28 else 24,
7606 } }));
7607 },
7608 }
7609 try va_list_ptr_mat.finish(isel);
7610 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7611 },
7612 .c_va_copy => {
7613 if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| {
7614 defer va_list_vi.value.deref(isel);
7615 const ty_op = air.data(air.inst_index).ty_op;
7616 const va_list_ptr_vi = try isel.use(ty_op.operand);
7617 const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel);
7618 _ = try va_list_vi.value.load(isel, ty_op.ty.toType(), va_list_ptr_mat.ra, .{});
7619 try va_list_ptr_mat.finish(isel);
7620 }
7621 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7622 },
7623 .c_va_end => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
7624 .c_va_start => {
7625 if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| {
7626 defer va_list_vi.value.deref(isel);
7627 const ty = air.data(air.inst_index).ty;
7628 switch (isel.va_list) {
7629 .other => |va_list| if (try va_list_vi.value.defReg(isel)) |va_list_ra| try isel.emit(.add(
7630 va_list_ra.x(),
7631 va_list.base.x(),
7632 .{ .immediate = @intCast(va_list.offset) },
7633 )),
7634 .sysv => |va_list| {
7635 var vr_offs_it = va_list_vi.value.field(ty, 28, 4);
7636 const vr_offs_vi = try vr_offs_it.only(isel);
7637 if (try vr_offs_vi.?.defReg(isel)) |vr_offs_ra| try isel.movImmediate(
7638 vr_offs_ra.w(),
7639 @as(u32, @bitCast(va_list.__vr_offs)),
7640 );
7641 var gr_offs_it = va_list_vi.value.field(ty, 24, 4);
7642 const gr_offs_vi = try gr_offs_it.only(isel);
7643 if (try gr_offs_vi.?.defReg(isel)) |gr_offs_ra| try isel.movImmediate(
7644 gr_offs_ra.w(),
7645 @as(u32, @bitCast(va_list.__gr_offs)),
7646 );
7647 var vr_top_it = va_list_vi.value.field(ty, 16, 8);
7648 const vr_top_vi = try vr_top_it.only(isel);
7649 if (try vr_top_vi.?.defReg(isel)) |vr_top_ra| try isel.emit(.add(
7650 vr_top_ra.x(),
7651 va_list.__vr_top.base.x(),
7652 .{ .immediate = @intCast(va_list.__vr_top.offset) },
7653 ));
7654 var gr_top_it = va_list_vi.value.field(ty, 8, 8);
7655 const gr_top_vi = try gr_top_it.only(isel);
7656 if (try gr_top_vi.?.defReg(isel)) |gr_top_ra| try isel.emit(.add(
7657 gr_top_ra.x(),
7658 va_list.__gr_top.base.x(),
7659 .{ .immediate = @intCast(va_list.__gr_top.offset) },
7660 ));
7661 var stack_it = va_list_vi.value.field(ty, 0, 8);
7662 const stack_vi = try stack_it.only(isel);
7663 if (try stack_vi.?.defReg(isel)) |stack_ra| try isel.emit(.add(
7664 stack_ra.x(),
7665 va_list.__stack.base.x(),
7666 .{ .immediate = @intCast(va_list.__stack.offset) },
7667 ));
7668 },
7669 }
7670 }
7671 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7672 },
7673 .work_item_id, .work_group_size, .work_group_id => unreachable,
6554 }7674 }
6555 assert(air.body_index == 0);7675 assert(air.body_index == 0);
6556}7676}
...@@ -6631,7 +7751,7 @@ pub fn verify(isel: *Select, check_values: bool) void {...@@ -6631,7 +7751,7 @@ pub fn verify(isel: *Select, check_values: bool) void {
6631pub fn layout(7751pub fn layout(
6632 isel: *Select,7752 isel: *Select,
6633 incoming: CallAbiIterator,7753 incoming: CallAbiIterator,
6634 have_va: bool,7754 is_sysv_var_args: bool,
6635 saved_gra_len: u7,7755 saved_gra_len: u7,
6636 saved_vra_len: u7,7756 saved_vra_len: u7,
6637 mod: *const Package.Module,7757 mod: *const Package.Module,
...@@ -6642,8 +7762,6 @@ pub fn layout(...@@ -6642,8 +7762,6 @@ pub fn layout(
6642 wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)});7762 wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)});
66437763
6644 const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size));7764 const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size));
6645 const stack_size_low: u12 = @truncate(stack_size >> 0);
6646 const stack_size_high: u12 = @truncate(stack_size >> 12);
66477765
6648 var saves_buf: [10 + 8 + 8 + 2 + 8]struct {7766 var saves_buf: [10 + 8 + 8 + 2 + 8]struct {
6649 class: enum { integer, vector },7767 class: enum { integer, vector },
...@@ -6721,7 +7839,7 @@ pub fn layout(...@@ -6721,7 +7839,7 @@ pub fn layout(
67217839
6722 // incoming vr arguments7840 // incoming vr arguments
6723 save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start;7841 save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start;
6724 while (save_ra != if (have_va) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {7842 while (save_ra != if (is_sysv_var_args) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
6725 saves_size = std.mem.alignForward(u10, saves_size, 16);7843 saves_size = std.mem.alignForward(u10, saves_size, 16);
6726 saves_buf[saves_len] = .{7844 saves_buf[saves_len] = .{
6727 .class = .vector,7845 .class = .vector,
...@@ -6771,87 +7889,117 @@ pub fn layout(...@@ -6771,87 +7889,117 @@ pub fn layout(
6771 saves_len += 1;7889 saves_len += 1;
6772 saves_size += 8;7890 saves_size += 8;
6773 deferred_gr = null;7891 deferred_gr = null;
7892 } else switch (@as(u1, @truncate(saved_gra_len))) {
7893 0 => {},
7894 1 => saves_size += 8,
6774 }7895 }
6775 save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start;7896 save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start;
6776 while (save_ra != if (have_va) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {7897 while (save_ra != if (is_sysv_var_args) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
6777 saves_size = std.mem.alignForward(u10, saves_size, 8);7898 saves_size = std.mem.alignForward(u10, saves_size, 8);
6778 saves_buf[saves_len] = .{7899 saves_buf[saves_len] = .{
6779 .class = .integer,7900 .class = .integer,
6780 .needs_restore = false,7901 .needs_restore = false,
6781 .register = save_ra.x(),7902 .register = save_ra.x(),
6782 .offset = saves_size,7903 .offset = saves_size,
6783 .size = 8,7904 .size = 8,
6784 };7905 };
6785 saves_len += 1;7906 saves_len += 1;
6786 saves_size += 8;7907 saves_size += 8;
6787 }
6788
6789 assert(InternPool.Alignment.@"16".check(saves_size));
6790 break :saves .{ saves_buf[0..saves_len], saves_size, frame_record_offset };
6791 };
6792
6793 {
6794 wip_mir_log.debug("{f}<prologue>:", .{nav.fqn.fmt(ip)});
6795 var save_index: usize = 0;
6796 while (save_index < saves.len) {
6797 if (save_index + 2 <= saves.len and saves[save_index + 0].class == saves[save_index + 1].class and
6798 saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
6799 {
6800 try isel.emit(.stp(
6801 saves[save_index + 0].register,
6802 saves[save_index + 1].register,
6803 switch (saves[save_index + 0].offset) {
6804 0 => .{ .pre_index = .{
6805 .base = .sp,
6806 .index = @intCast(-@as(i11, saves_size)),
6807 } },
6808 else => |offset| .{ .signed_offset = .{
6809 .base = .sp,
6810 .offset = @intCast(offset),
6811 } },
6812 },
6813 ));
6814 save_index += 2;
6815 } else {
6816 try isel.emit(.str(
6817 saves[save_index].register,
6818 switch (saves[save_index].offset) {
6819 0 => .{ .pre_index = .{
6820 .base = .sp,
6821 .index = @intCast(-@as(i11, saves_size)),
6822 } },
6823 else => |offset| .{ .unsigned_offset = .{
6824 .base = .sp,
6825 .offset = @intCast(offset),
6826 } },
6827 },
6828 ));
6829 save_index += 1;
6830 }
6831 }7908 }
68327909
7910 assert(InternPool.Alignment.@"16".check(saves_size));
7911 break :saves .{ saves_buf[0..saves_len], saves_size, frame_record_offset };
7912 };
7913
7914 {
7915 wip_mir_log.debug("{f}<prologue>:", .{nav.fqn.fmt(ip)});
7916 var save_index: usize = 0;
7917 while (save_index < saves.len) if (save_index + 2 <= saves.len and
7918 saves[save_index + 0].class == saves[save_index + 1].class and
7919 saves[save_index + 0].size == saves[save_index + 1].size and
7920 saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
7921 {
7922 try isel.emit(.stp(
7923 saves[save_index + 0].register,
7924 saves[save_index + 1].register,
7925 switch (saves[save_index + 0].offset) {
7926 0 => .{ .pre_index = .{
7927 .base = .sp,
7928 .index = @intCast(-@as(i11, saves_size)),
7929 } },
7930 else => |offset| .{ .signed_offset = .{
7931 .base = .sp,
7932 .offset = @intCast(offset),
7933 } },
7934 },
7935 ));
7936 save_index += 2;
7937 } else {
7938 try isel.emit(.str(
7939 saves[save_index].register,
7940 switch (saves[save_index].offset) {
7941 0 => .{ .pre_index = .{
7942 .base = .sp,
7943 .index = @intCast(-@as(i11, saves_size)),
7944 } },
7945 else => |offset| .{ .unsigned_offset = .{
7946 .base = .sp,
7947 .offset = @intCast(offset),
7948 } },
7949 },
7950 ));
7951 save_index += 1;
7952 };
7953
7954 try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset }));
6833 const scratch_reg: Register = if (isel.stack_align == .@"16")7955 const scratch_reg: Register = if (isel.stack_align == .@"16")
6834 .sp7956 .sp
6835 else if (stack_size == 0)7957 else if (stack_size == 0 and frame_record_offset == 0)
6836 .fp7958 .fp
6837 else7959 else
6838 .x9;7960 .ip0;
6839 try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset }));7961 const stack_size_lo: u12 = @truncate(stack_size >> 0);
6840 if (stack_size_high > 0) try isel.emit(.sub(scratch_reg, .sp, .{7962 const stack_size_hi: u12 = @truncate(stack_size >> 12);
6841 .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },7963 if (mod.stack_check) {
6842 }));7964 if (stack_size_hi > 2) {
6843 if (stack_size_low > 0) try isel.emit(.sub(7965 try isel.movImmediate(.ip1, stack_size_hi);
6844 scratch_reg,7966 const loop_label = isel.instructions.items.len;
6845 if (stack_size_high > 0) scratch_reg else .sp,7967 try isel.emit(.sub(.sp, .sp, .{
6846 .{ .immediate = stack_size_low },7968 .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" },
6847 ));7969 }));
6848 if (isel.stack_align != .@"16") {7970 try isel.emit(.sub(.ip1, .ip1, .{ .immediate = 1 }));
6849 try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{7971 try isel.emit(.ldr(.xzr, .{ .base = .sp }));
6850 .N = .doubleword,7972 try isel.emit(.cbnz(.ip1, -@as(i21, @intCast(
6851 .immr = -%isel.stack_align.toLog2Units(),7973 (isel.instructions.items.len - loop_label) << 2,
6852 .imms = ~isel.stack_align.toLog2Units(),7974 ))));
6853 } }));7975 } else for (0..stack_size_hi) |_| {
7976 try isel.emit(.sub(.sp, .sp, .{
7977 .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" },
7978 }));
7979 try isel.emit(.ldr(.xzr, .{ .base = .sp }));
7980 }
7981 if (stack_size_lo > 0) try isel.emit(.sub(
7982 scratch_reg,
7983 .sp,
7984 .{ .immediate = stack_size_lo },
7985 )) else if (scratch_reg.alias == Register.Alias.ip0)
7986 try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 }));
7987 } else {
7988 if (stack_size_hi > 0) try isel.emit(.sub(scratch_reg, .sp, .{
7989 .shifted_immediate = .{ .immediate = stack_size_hi, .lsl = .@"12" },
7990 }));
7991 if (stack_size_lo > 0) try isel.emit(.sub(
7992 scratch_reg,
7993 if (stack_size_hi > 0) scratch_reg else .sp,
7994 .{ .immediate = stack_size_lo },
7995 )) else if (scratch_reg.alias == Register.Alias.ip0 and stack_size_hi == 0)
7996 try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 }));
6854 }7997 }
7998 if (isel.stack_align != .@"16") try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{
7999 .N = .doubleword,
8000 .immr = -%isel.stack_align.toLog2Units(),
8001 .imms = ~isel.stack_align.toLog2Units(),
8002 } }));
6855 wip_mir_log.debug("", .{});8003 wip_mir_log.debug("", .{});
6856 }8004 }
68578005
...@@ -6859,6 +8007,7 @@ pub fn layout(...@@ -6859,6 +8007,7 @@ pub fn layout(
6859 if (isel.returns) {8007 if (isel.returns) {
6860 try isel.emit(.ret(.lr));8008 try isel.emit(.ret(.lr));
6861 var save_index: usize = 0;8009 var save_index: usize = 0;
8010 var first_offset: ?u10 = null;
6862 while (save_index < saves.len) {8011 while (save_index < saves.len) {
6863 if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and8012 if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and
6864 saves[save_index + 0].class == saves[save_index + 1].class and8013 saves[save_index + 0].class == saves[save_index + 1].class and
...@@ -6867,46 +8016,51 @@ pub fn layout(...@@ -6867,46 +8016,51 @@ pub fn layout(
6867 try isel.emit(.ldp(8016 try isel.emit(.ldp(
6868 saves[save_index + 0].register,8017 saves[save_index + 0].register,
6869 saves[save_index + 1].register,8018 saves[save_index + 1].register,
6870 switch (saves[save_index + 0].offset) {8019 if (first_offset) |offset| .{ .signed_offset = .{
6871 0 => .{ .post_index = .{8020 .base = .sp,
6872 .base = .sp,8021 .offset = @intCast(saves[save_index + 0].offset - offset),
6873 .index = @intCast(saves_size),8022 } } else form: {
6874 } },8023 first_offset = @intCast(saves[save_index + 0].offset);
6875 else => |offset| .{ .signed_offset = .{8024 break :form .{ .post_index = .{
6876 .base = .sp,8025 .base = .sp,
6877 .offset = @intCast(offset),8026 .index = @intCast(saves_size - first_offset.?),
6878 } },8027 } };
6879 },8028 },
6880 ));8029 ));
6881 save_index += 2;8030 save_index += 2;
6882 } else if (saves[save_index].needs_restore) {8031 } else if (saves[save_index].needs_restore) {
6883 try isel.emit(.ldr(8032 try isel.emit(.ldr(
6884 saves[save_index].register,8033 saves[save_index].register,
6885 switch (saves[save_index].offset) {8034 if (first_offset) |offset| .{ .unsigned_offset = .{
6886 0 => .{ .post_index = .{8035 .base = .sp,
6887 .base = .sp,8036 .offset = saves[save_index + 0].offset - offset,
6888 .index = @intCast(saves_size),8037 } } else form: {
6889 } },8038 const offset = saves[save_index + 0].offset;
6890 else => |offset| .{ .unsigned_offset = .{8039 first_offset = offset;
8040 break :form .{ .post_index = .{
6891 .base = .sp,8041 .base = .sp,
6892 .offset = @intCast(offset),8042 .index = @intCast(saves_size - offset),
6893 } },8043 } };
6894 },8044 },
6895 ));8045 ));
6896 save_index += 1;8046 save_index += 1;
6897 } else save_index += 1;8047 } else save_index += 1;
6898 }8048 }
6899 if (isel.stack_align != .@"16" or (stack_size_low > 0 and stack_size_high > 0)) {8049 const offset = stack_size + first_offset.?;
6900 try isel.emit(switch (frame_record_offset) {8050 const offset_lo: u12 = @truncate(offset >> 0);
6901 0 => .add(.sp, .fp, .{ .immediate = 0 }),8051 const offset_hi: u12 = @truncate(offset >> 12);
6902 else => |offset| .sub(.sp, .fp, .{ .immediate = offset }),8052 if (isel.stack_align != .@"16" or (offset_lo > 0 and offset_hi > 0)) {
6903 });8053 const fp_offset = @as(i11, first_offset.?) - frame_record_offset;
8054 try isel.emit(if (fp_offset >= 0)
8055 .add(.sp, .fp, .{ .immediate = @intCast(fp_offset) })
8056 else
8057 .sub(.sp, .fp, .{ .immediate = @intCast(-fp_offset) }));
6904 } else {8058 } else {
6905 if (stack_size_high > 0) try isel.emit(.add(.sp, .sp, .{8059 if (offset_hi > 0) try isel.emit(.add(.sp, .sp, .{
6906 .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },8060 .shifted_immediate = .{ .immediate = offset_hi, .lsl = .@"12" },
6907 }));8061 }));
6908 if (stack_size_low > 0) try isel.emit(.add(.sp, .sp, .{8062 if (offset_lo > 0) try isel.emit(.add(.sp, .sp, .{
6909 .immediate = stack_size_low,8063 .immediate = offset_lo,
6910 }));8064 }));
6911 }8065 }
6912 wip_mir_log.debug("{f}<epilogue>:\n", .{nav.fqn.fmt(ip)});8066 wip_mir_log.debug("{f}<epilogue>:\n", .{nav.fqn.fmt(ip)});
...@@ -6977,11 +8131,43 @@ fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmt...@@ -6977,11 +8131,43 @@ fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmt
6977 return constant.fmtValue(isel.pt);8131 return constant.fmtValue(isel.pt);
6978}8132}
69798133
8134fn block(
8135 isel: *Select,
8136 air_inst_index: Air.Inst.Index,
8137 res_ty: ZigType,
8138 air_body: []const Air.Inst.Index,
8139) !void {
8140 if (res_ty.toIntern() != .noreturn_type) {
8141 isel.blocks.putAssumeCapacityNoClobber(air_inst_index, .{
8142 .live_registers = isel.live_registers,
8143 .target_label = @intCast(isel.instructions.items.len),
8144 });
8145 }
8146 try isel.body(air_body);
8147 if (res_ty.toIntern() != .noreturn_type) {
8148 const block_entry = isel.blocks.pop().?;
8149 assert(block_entry.key == air_inst_index);
8150 if (isel.live_values.fetchRemove(air_inst_index)) |result_vi| result_vi.value.deref(isel);
8151 }
8152}
8153
6980fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void {8154fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void {
6981 wip_mir_log.debug(" | {f}", .{instruction});8155 wip_mir_log.debug(" | {f}", .{instruction});
6982 try isel.instructions.append(isel.pt.zcu.gpa, instruction);8156 try isel.instructions.append(isel.pt.zcu.gpa, instruction);
6983}8157}
69848158
8159fn emitPanic(isel: *Select, panic_id: Zcu.SimplePanicId) !void {
8160 const zcu = isel.pt.zcu;
8161 try isel.nav_relocs.append(zcu.gpa, .{
8162 .nav = switch (zcu.intern_pool.indexToKey(zcu.builtin_decl_values.get(panic_id.toBuiltin()))) {
8163 else => unreachable,
8164 inline .@"extern", .func => |func| func.owner_nav,
8165 },
8166 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
8167 });
8168 try isel.emit(.bl(0));
8169}
8170
6985fn emitLiteral(isel: *Select, bytes: []const u8) !void {8171fn emitLiteral(isel: *Select, bytes: []const u8) !void {
6986 const words: []align(1) const u32 = @ptrCast(bytes);8172 const words: []align(1) const u32 = @ptrCast(bytes);
6987 const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len);8173 const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len);
...@@ -8000,9 +9186,18 @@ pub const Value = struct {...@@ -8000,9 +9186,18 @@ pub const Value = struct {
8000 var dst_part_it = dst_vi.parts(isel);9186 var dst_part_it = dst_vi.parts(isel);
8001 if (dst_part_it.only()) |dst_part_vi| {9187 if (dst_part_it.only()) |dst_part_vi| {
8002 var src_part_it = src_vi.parts(isel);9188 var src_part_it = src_vi.parts(isel);
8003 if (src_part_it.only()) |src_part_vi| {9189 if (src_part_it.only()) |src_part_vi| only: {
8004 try src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return);9190 const src_part_size = src_part_vi.size(isel);
8005 } else while (src_part_it.next()) |src_part_vi| {9191 if (src_part_size > @as(@TypeOf(src_part_size), if (src_part_vi.isVector(isel)) 16 else 8)) {
9192 var subpart_it = root.src_vi.field(root.ty, root.src_offset, src_part_size - 1);
9193 _ = try subpart_it.next(isel);
9194 src_part_it = src_vi.parts(isel);
9195 assert(src_part_it.only() == null);
9196 break :only;
9197 }
9198 return src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return);
9199 }
9200 while (src_part_it.next()) |src_part_vi| {
8006 const src_part_offset, const src_part_size = src_part_vi.position(isel);9201 const src_part_offset, const src_part_size = src_part_vi.position(isel);
8007 var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size);9202 var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size);
8008 const dst_field_vi = try dst_field_it.only(isel);9203 const dst_field_vi = try dst_field_it.only(isel);
...@@ -8028,6 +9223,32 @@ pub const Value = struct {...@@ -8028,6 +9223,32 @@ pub const Value = struct {
8028 }9223 }
8029 }9224 }
80309225
9226 const AddOrSubtractOptions = struct {
9227 overflow: Overflow,
9228
9229 const Overflow = union(enum) {
9230 @"unreachable",
9231 panic: Zcu.SimplePanicId,
9232 wrap,
9233 ra: Register.Alias,
9234
9235 fn defCond(overflow: Overflow, isel: *Select, cond: codegen.aarch64.encoding.ConditionCode) !void {
9236 switch (overflow) {
9237 .@"unreachable" => unreachable,
9238 .panic => |panic_id| {
9239 const skip_label = isel.instructions.items.len;
9240 try isel.emitPanic(panic_id);
9241 try isel.emit(.@"b."(
9242 cond.invert(),
9243 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
9244 ));
9245 },
9246 .wrap => {},
9247 .ra => |overflow_ra| try isel.emit(.csinc(overflow_ra.w(), .wzr, .wzr, cond.invert())),
9248 }
9249 }
9250 };
9251 };
8031 fn addOrSubtract(9252 fn addOrSubtract(
8032 res_vi: Value.Index,9253 res_vi: Value.Index,
8033 isel: *Select,9254 isel: *Select,
...@@ -8035,19 +9256,21 @@ pub const Value = struct {...@@ -8035,19 +9256,21 @@ pub const Value = struct {
8035 lhs_vi: Value.Index,9256 lhs_vi: Value.Index,
8036 op: codegen.aarch64.encoding.Instruction.AddSubtractOp,9257 op: codegen.aarch64.encoding.Instruction.AddSubtractOp,
8037 rhs_vi: Value.Index,9258 rhs_vi: Value.Index,
8038 opts: struct {9259 opts: AddOrSubtractOptions,
8039 wrap: bool,
8040 overflow_ra: Register.Alias = .zr,
8041 },
8042 ) !void {9260 ) !void {
8043 assert(opts.wrap or opts.overflow_ra == .zr);
8044 const zcu = isel.pt.zcu;9261 const zcu = isel.pt.zcu;
8045 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) });9262 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
8046 const int_info = ty.intInfo(zcu);9263 const int_info = ty.intInfo(zcu);
8047 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) });9264 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
8048 var part_offset = res_vi.size(isel);9265 var part_offset = res_vi.size(isel);
8049 var need_wrap = opts.wrap;9266 var need_wrap = switch (opts.overflow) {
8050 var need_carry = opts.overflow_ra != .zr;9267 .@"unreachable" => false,
9268 .panic, .wrap, .ra => true,
9269 };
9270 var need_carry = switch (opts.overflow) {
9271 .@"unreachable", .wrap => false,
9272 .panic, .ra => true,
9273 };
8051 while (part_offset > 0) : (need_wrap = false) {9274 while (part_offset > 0) : (need_wrap = false) {
8052 const part_size = @min(part_offset, 8);9275 const part_size = @min(part_offset, 8);
8053 part_offset -= part_size;9276 part_offset -= part_size;
...@@ -8057,48 +9280,87 @@ pub const Value = struct {...@@ -8057,48 +9280,87 @@ pub const Value = struct {
8057 const unwrapped_res_part_ra = unwrapped_res_part_ra: {9280 const unwrapped_res_part_ra = unwrapped_res_part_ra: {
8058 if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra;9281 if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra;
8059 if (int_info.bits % 32 == 0) {9282 if (int_info.bits % 32 == 0) {
8060 if (opts.overflow_ra != .zr) try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(switch (int_info.signedness) {9283 try opts.overflow.defCond(isel, switch (int_info.signedness) {
8061 .signed => .vs,9284 .signed => .vs,
8062 .unsigned => switch (op) {9285 .unsigned => switch (op) {
8063 .add => .cs,9286 .add => .cs,
8064 .sub => .cc,9287 .sub => .cc,
8065 },9288 },
8066 })));9289 });
8067 break :unwrapped_res_part_ra wrapped_res_part_ra;9290 break :unwrapped_res_part_ra wrapped_res_part_ra;
8068 }9291 }
8069 const wrapped_part_ra, const unwrapped_part_ra = if (opts.overflow_ra != .zr) part_ra: {9292 need_carry = false;
8070 switch (op) {9293 const wrapped_part_ra, const unwrapped_part_ra = part_ra: switch (opts.overflow) {
8071 .add => {},9294 .@"unreachable" => unreachable,
8072 .sub => switch (int_info.signedness) {9295 .panic, .ra => switch (int_info.signedness) {
8073 .signed => {},9296 .signed => {
8074 .unsigned => {9297 try opts.overflow.defCond(isel, .ne);
8075 try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.cc)));9298 const wrapped_part_ra = switch (wrapped_res_part_ra) {
8076 break :part_ra .{ wrapped_res_part_ra, wrapped_res_part_ra };9299 else => |res_part_ra| res_part_ra,
8077 },9300 .zr => try isel.allocIntReg(),
9301 };
9302 errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
9303 const unwrapped_part_ra = unwrapped_part_ra: {
9304 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
9305 else => |res_part_ra| isel.lockReg(res_part_ra),
9306 .zr => .empty,
9307 };
9308 defer wrapped_res_part_lock.unlock(isel);
9309 break :unwrapped_part_ra try isel.allocIntReg();
9310 };
9311 errdefer isel.freeReg(unwrapped_part_ra);
9312 switch (part_size) {
9313 else => unreachable,
9314 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })),
9315 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })),
9316 }
9317 break :part_ra .{ wrapped_part_ra, unwrapped_part_ra };
8078 },9318 },
8079 }9319 .unsigned => {
8080 try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.ne)));9320 const unwrapped_part_ra = unwrapped_part_ra: {
8081 const wrapped_part_ra = switch (wrapped_res_part_ra) {9321 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
8082 else => |res_part_ra| res_part_ra,9322 else => |res_part_ra| isel.lockReg(res_part_ra),
8083 .zr => try isel.allocIntReg(),9323 .zr => .empty,
8084 };9324 };
8085 errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);9325 defer wrapped_res_part_lock.unlock(isel);
8086 const unwrapped_part_ra = unwrapped_part_ra: {9326 break :unwrapped_part_ra try isel.allocIntReg();
8087 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {9327 };
8088 else => |res_part_ra| isel.lockReg(res_part_ra),9328 errdefer isel.freeReg(unwrapped_part_ra);
8089 .zr => .empty,9329 const bit: u6 = @truncate(int_info.bits);
8090 };9330 switch (opts.overflow) {
8091 defer wrapped_res_part_lock.unlock(isel);9331 .@"unreachable", .wrap => unreachable,
8092 break :unwrapped_part_ra try isel.allocIntReg();9332 .panic => |panic_id| {
8093 };9333 const skip_label = isel.instructions.items.len;
8094 errdefer isel.freeReg(unwrapped_part_ra);9334 try isel.emitPanic(panic_id);
8095 switch (part_size) {9335 try isel.emit(.tbz(
8096 else => unreachable,9336 switch (bit) {
8097 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })),9337 0, 32 => unreachable,
8098 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })),9338 1...31 => unwrapped_part_ra.w(),
8099 }9339 33...63 => unwrapped_part_ra.x(),
8100 break :part_ra .{ wrapped_part_ra, unwrapped_part_ra };9340 },
8101 } else .{ wrapped_res_part_ra, wrapped_res_part_ra };9341 bit,
9342 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
9343 ));
9344 },
9345 .ra => |overflow_ra| try isel.emit(switch (bit) {
9346 0, 32 => unreachable,
9347 1...31 => .ubfm(overflow_ra.w(), unwrapped_part_ra.w(), .{
9348 .N = .word,
9349 .immr = bit,
9350 .imms = bit,
9351 }),
9352 33...63 => .ubfm(overflow_ra.x(), unwrapped_part_ra.x(), .{
9353 .N = .doubleword,
9354 .immr = bit,
9355 .imms = bit,
9356 }),
9357 }),
9358 }
9359 break :part_ra .{ wrapped_res_part_ra, unwrapped_part_ra };
9360 },
9361 },
9362 .wrap => .{ wrapped_res_part_ra, wrapped_res_part_ra },
9363 };
8102 defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);9364 defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
8103 errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra);9365 errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra);
8104 if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) {9366 if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) {
...@@ -8409,9 +9671,12 @@ pub const Value = struct {...@@ -8409,9 +9671,12 @@ pub const Value = struct {
8409 fn defAddr(9671 fn defAddr(
8410 def_vi: Value.Index,9672 def_vi: Value.Index,
8411 isel: *Select,9673 isel: *Select,
8412 def_ty: ZigType,9674 root_ty: ZigType,
8413 wrap: ?std.builtin.Type.Int,9675 opts: struct {
8414 expected_live_registers: *const LiveRegisters,9676 root_vi: Value.Index = .free,
9677 wrap: ?std.builtin.Type.Int = null,
9678 expected_live_registers: *const LiveRegisters = &.initFill(.free),
9679 },
8415 ) !?void {9680 ) !?void {
8416 if (!def_vi.isUsed(isel)) return null;9681 if (!def_vi.isUsed(isel)) return null;
8417 const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel);9682 const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel);
...@@ -8420,11 +9685,12 @@ pub const Value = struct {...@@ -8420,11 +9685,12 @@ pub const Value = struct {
8420 .stack_slot => |stack_slot| .{ stack_slot, false },9685 .stack_slot => |stack_slot| .{ stack_slot, false },
8421 else => unreachable,9686 else => unreachable,
8422 };9687 };
8423 _ = try def_vi.load(isel, def_ty, stack_slot.base, .{9688 _ = try def_vi.load(isel, root_ty, stack_slot.base, .{
9689 .root_vi = opts.root_vi,
8424 .offset = @intCast(stack_slot.offset + offset_from_parent),9690 .offset = @intCast(stack_slot.offset + offset_from_parent),
8425 .split = false,9691 .split = false,
8426 .wrap = wrap,9692 .wrap = opts.wrap,
8427 .expected_live_registers = expected_live_registers,9693 .expected_live_registers = opts.expected_live_registers,
8428 });9694 });
8429 if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot });9695 if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot });
8430 }9696 }
...@@ -8454,12 +9720,12 @@ pub const Value = struct {...@@ -8454,12 +9720,12 @@ pub const Value = struct {
8454 const part_mat = try part_vi.matReg(isel);9720 const part_mat = try part_vi.matReg(isel);
8455 try isel.emit(if (part_vi.isVector(isel)) emit: {9721 try isel.emit(if (part_vi.isVector(isel)) emit: {
8456 assert(part_offset == 0 and part_size == vi_size);9722 assert(part_offset == 0 and part_size == vi_size);
8457 break :emit size: switch (vi_size) {9723 break :emit switch (vi_size) {
8458 else => unreachable,9724 else => unreachable,
8459 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))9725 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
8460 .fmov(ra.h(), .{ .register = part_mat.ra.h() })9726 .fmov(ra.h(), .{ .register = part_mat.ra.h() })
8461 else9727 else
8462 continue :size 4,9728 .dup(ra.h(), part_mat.ra.@"h[]"(0)),
8463 4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }),9729 4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }),
8464 8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }),9730 8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }),
8465 16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }),9731 16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }),
...@@ -8503,6 +9769,53 @@ pub const Value = struct {...@@ -8503,6 +9769,53 @@ pub const Value = struct {
8503 }9769 }
8504 }9770 }
85059771
9772 pub fn defUndef(def_vi: Value.Index, isel: *Select, root_ty: ZigType, opts: struct {
9773 root_vi: Value.Index = .free,
9774 offset: u64 = 0,
9775 split: bool = true,
9776 }) !void {
9777 const root_vi = switch (opts.root_vi) {
9778 _ => |root_vi| root_vi,
9779 .allocating => unreachable,
9780 .free => def_vi,
9781 };
9782 var part_it = def_vi.parts(isel);
9783 if (part_it.only()) |part_vi| only: {
9784 const part_size = part_vi.size(isel);
9785 const part_is_vector = part_vi.isVector(isel);
9786 if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) {
9787 if (!opts.split) return;
9788 var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1);
9789 _ = try subpart_it.next(isel);
9790 part_it = def_vi.parts(isel);
9791 assert(part_it.only() == null);
9792 break :only;
9793 }
9794 return if (try part_vi.defReg(isel)) |part_ra| try isel.emit(if (part_is_vector)
9795 .movi(switch (part_size) {
9796 else => unreachable,
9797 1...8 => part_ra.@"8b"(),
9798 9...16 => part_ra.@"16b"(),
9799 }, 0xaa, .{ .lsl = 0 })
9800 else switch (part_size) {
9801 else => unreachable,
9802 1...4 => .orr(part_ra.w(), .wzr, .{ .immediate = .{
9803 .N = .word,
9804 .immr = 0b000001,
9805 .imms = 0b111100,
9806 } }),
9807 5...8 => .orr(part_ra.x(), .xzr, .{ .immediate = .{
9808 .N = .word,
9809 .immr = 0b000001,
9810 .imms = 0b111100,
9811 } }),
9812 });
9813 }
9814 while (part_it.next()) |part_vi| try part_vi.defUndef(isel, root_ty, .{
9815 .root_vi = root_vi,
9816 });
9817 }
9818
8506 pub fn liveIn(9819 pub fn liveIn(
8507 vi: Value.Index,9820 vi: Value.Index,
8508 isel: *Select,9821 isel: *Select,
...@@ -8532,21 +9845,30 @@ pub const Value = struct {...@@ -8532,21 +9845,30 @@ pub const Value = struct {
8532 },9845 },
8533 true => switch (vi.size(isel)) {9846 true => switch (vi.size(isel)) {
8534 else => unreachable,9847 else => unreachable,
8535 2 => .fmov(dst_ra.w(), .{ .register = src_ra.h() }),9848 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
9849 .fmov(dst_ra.w(), .{ .register = src_ra.h() })
9850 else
9851 .umov(dst_ra.w(), src_ra.@"h[]"(0)),
8536 4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }),9852 4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }),
8537 8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }),9853 8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }),
8538 },9854 },
8539 },9855 },
8540 true => switch (src_ra.isVector()) {9856 true => switch (src_ra.isVector()) {
8541 false => switch (vi.size(isel)) {9857 false => size: switch (vi.size(isel)) {
8542 else => unreachable,9858 else => unreachable,
8543 2 => .fmov(dst_ra.h(), .{ .register = src_ra.w() }),9859 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
9860 .fmov(dst_ra.h(), .{ .register = src_ra.w() })
9861 else
9862 continue :size 4,
8544 4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }),9863 4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }),
8545 8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }),9864 8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }),
8546 },9865 },
8547 true => switch (vi.size(isel)) {9866 true => switch (vi.size(isel)) {
8548 else => unreachable,9867 else => unreachable,
8549 2 => .fmov(dst_ra.h(), .{ .register = src_ra.h() }),9868 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
9869 .fmov(dst_ra.h(), .{ .register = src_ra.h() })
9870 else
9871 .dup(dst_ra.h(), src_ra.@"h[]"(0)),
8550 4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }),9872 4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }),
8551 8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }),9873 8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }),
8552 16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }),9874 16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }),
...@@ -8574,41 +9896,15 @@ pub const Value = struct {...@@ -8574,41 +9896,15 @@ pub const Value = struct {
8574 expected_live_registers: *const LiveRegisters,9896 expected_live_registers: *const LiveRegisters,
8575 ) !void {9897 ) !void {
8576 try vi.liveIn(isel, src_ra, expected_live_registers);9898 try vi.liveIn(isel, src_ra, expected_live_registers);
8577 const offset_from_parent: i65, const parent_vi = vi.valueParent(isel);9899 const offset_from_parent, const parent_vi = vi.valueParent(isel);
8578 switch (parent_vi.parent(isel)) {9900 switch (parent_vi.parent(isel)) {
8579 .unallocated => {},9901 .unallocated => {},
8580 .stack_slot => |stack_slot| {9902 .stack_slot => |stack_slot| if (stack_slot.base != Register.Alias.fp) try isel.storeReg(
8581 const offset = stack_slot.offset + offset_from_parent;9903 src_ra,
8582 try isel.emit(switch (vi.size(isel)) {9904 vi.size(isel),
8583 else => unreachable,9905 stack_slot.base,
8584 1 => if (src_ra.isVector()) .str(src_ra.b(), .{ .unsigned_offset = .{9906 @as(i65, stack_slot.offset) + offset_from_parent,
8585 .base = stack_slot.base.x(),9907 ),
8586 .offset = @intCast(offset),
8587 } }) else .strb(src_ra.w(), .{ .unsigned_offset = .{
8588 .base = stack_slot.base.x(),
8589 .offset = @intCast(offset),
8590 } }),
8591 2 => if (src_ra.isVector()) .str(src_ra.h(), .{ .unsigned_offset = .{
8592 .base = stack_slot.base.x(),
8593 .offset = @intCast(offset),
8594 } }) else .strh(src_ra.w(), .{ .unsigned_offset = .{
8595 .base = stack_slot.base.x(),
8596 .offset = @intCast(offset),
8597 } }),
8598 4 => .str(if (src_ra.isVector()) src_ra.s() else src_ra.w(), .{ .unsigned_offset = .{
8599 .base = stack_slot.base.x(),
8600 .offset = @intCast(offset),
8601 } }),
8602 8 => .str(if (src_ra.isVector()) src_ra.d() else src_ra.x(), .{ .unsigned_offset = .{
8603 .base = stack_slot.base.x(),
8604 .offset = @intCast(offset),
8605 } }),
8606 16 => .str(src_ra.q(), .{ .unsigned_offset = .{
8607 .base = stack_slot.base.x(),
8608 .offset = @intCast(offset),
8609 } }),
8610 });
8611 },
8612 else => unreachable,9908 else => unreachable,
8613 }9909 }
8614 try vi.spillReg(isel, src_ra, 0, expected_live_registers);9910 try vi.spillReg(isel, src_ra, 0, expected_live_registers);
...@@ -8629,9 +9925,12 @@ pub const Value = struct {...@@ -8629,9 +9925,12 @@ pub const Value = struct {
8629 const part_size = part_vi.size(isel);9925 const part_size = part_vi.size(isel);
8630 const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra;9926 const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra;
8631 defer if (part_ra != dst_ra) isel.freeReg(part_ra);9927 defer if (part_ra != dst_ra) isel.freeReg(part_ra);
8632 if (part_ra != dst_ra) try isel.emit(switch (part_size) {9928 if (part_ra != dst_ra) try isel.emit(part_size: switch (part_size) {
8633 else => unreachable,9929 else => unreachable,
8634 2 => .fmov(dst_ra.h(), .{ .register = part_ra.w() }),9930 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
9931 .fmov(dst_ra.h(), .{ .register = part_ra.w() })
9932 else
9933 continue :part_size 4,
8635 4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }),9934 4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }),
8636 8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }),9935 8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }),
8637 });9936 });
...@@ -8798,6 +10097,11 @@ pub const Value = struct {...@@ -8798,6 +10097,11 @@ pub const Value = struct {
8798 return it.vi;10097 return it.vi;
8799 }10098 }
880010099
10100 pub fn peek(it: PartIterator) ?Value.Index {
10101 var it_mut = it;
10102 return it_mut.next();
10103 }
10104
8801 pub fn only(it: PartIterator) ?Value.Index {10105 pub fn only(it: PartIterator) ?Value.Index {
8802 return if (it.remaining == 1) it.vi else null;10106 return if (it.remaining == 1) it.vi else null;
8803 }10107 }
...@@ -8856,24 +10160,31 @@ pub const Value = struct {...@@ -8856,24 +10160,31 @@ pub const Value = struct {
8856 _ = vi.addPart(isel, 8, 8);10160 _ = vi.addPart(isel, 8, 8);
8857 } else unreachable,10161 } else unreachable,
8858 },10162 },
8859 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu))10163 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu)) continue :type_key ip.indexToKey(child_type) else {
8860 continue :type_key ip.indexToKey(child_type)10164 const child_ty: ZigType = .fromInterned(child_type);
8861 else switch (ZigType.fromInterned(child_type).abiSize(zcu)) {10165 const child_size = child_ty.abiSize(zcu);
8862 0...8, 16 => |child_size| if (offset == 0 and size == ty_size) {10166 if (offset == 0 and size == child_size) {
8863 vi.setParts(isel, 2);10167 ty = child_ty;
8864 _ = vi.addPart(isel, 0, child_size);10168 ty_size = child_size;
8865 _ = vi.addPart(isel, child_size, 1);10169 continue :type_key ip.indexToKey(child_type);
8866 } else unreachable,10170 }
8867 9...15 => |child_size| if (offset == 0 and size == ty_size) {10171 switch (child_size) {
8868 vi.setParts(isel, 2);10172 0...8, 16 => if (offset == 0 and size == ty_size) {
8869 _ = vi.addPart(isel, 0, 8);10173 vi.setParts(isel, 2);
8870 _ = vi.addPart(isel, 8, ty_size - 8);10174 _ = vi.addPart(isel, 0, child_size);
8871 } else if (offset == 8 and size == ty_size - 8) {10175 _ = vi.addPart(isel, child_size, 1);
8872 vi.setParts(isel, 2);10176 } else unreachable,
8873 _ = vi.addPart(isel, 0, child_size - 8);10177 9...15 => if (offset == 0 and size == ty_size) {
8874 _ = vi.addPart(isel, child_size - 8, 1);10178 vi.setParts(isel, 2);
8875 } else unreachable,10179 _ = vi.addPart(isel, 0, 8);
8876 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),10180 _ = vi.addPart(isel, 8, ty_size - 8);
10181 } else if (offset == 8 and size == ty_size - 8) {
10182 vi.setParts(isel, 2);
10183 _ = vi.addPart(isel, 0, child_size - 8);
10184 _ = vi.addPart(isel, child_size - 8, 1);
10185 } else unreachable,
10186 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
10187 }
8877 },10188 },
8878 .array_type => |array_type| {10189 .array_type => |array_type| {
8879 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;10190 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 {...@@ -9027,8 +10338,14 @@ pub const Value = struct {
9027 } },10338 } },
9028 },10339 },
9029 .struct_type => {10340 .struct_type => {
9030 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
9031 const loaded_struct = ip.loadStructType(ty.toIntern());10341 const loaded_struct = ip.loadStructType(ty.toIntern());
10342 switch (loaded_struct.layout) {
10343 .auto, .@"extern" => {},
10344 .@"packed" => continue :type_key .{
10345 .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
10346 },
10347 }
10348 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
9032 if (loaded_struct.field_types.len > Value.max_parts and10349 if (loaded_struct.field_types.len > Value.max_parts and
9033 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)10350 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
9034 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});10351 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
...@@ -9136,6 +10453,77 @@ pub const Value = struct {...@@ -9136,6 +10453,77 @@ pub const Value = struct {
9136 if (part.is_vector) subpart_vi.setIsVector(isel);10453 if (part.is_vector) subpart_vi.setIsVector(isel);
9137 }10454 }
9138 },10455 },
10456 .union_type => {
10457 const loaded_union = ip.loadUnionType(ty.toIntern());
10458 switch (loaded_union.flagsUnordered(ip).layout) {
10459 .auto, .@"extern" => {},
10460 .@"packed" => continue :type_key .{ .int_type = .{
10461 .signedness = .unsigned,
10462 .bits = @intCast(ty.bitSize(zcu)),
10463 } },
10464 }
10465 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
10466 if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
10467 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
10468 const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
10469 const alignment = vi.alignment(isel);
10470 const tag_offset = union_layout.tagOffset();
10471 const payload_offset = union_layout.payloadOffset();
10472 const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness };
10473 var parts: [2]Part = undefined;
10474 var parts_len: Value.PartsLen = 0;
10475 var field_end: u64 = 0;
10476 for (0..2) |field_index| {
10477 const field: enum { tag, payload } = switch (field_index) {
10478 0 => if (tag_offset < payload_offset) .tag else .payload,
10479 1 => if (tag_offset < payload_offset) .payload else .tag,
10480 else => unreachable,
10481 };
10482 const field_size, const field_begin = switch (field) {
10483 .tag => .{ union_layout.tag_size, tag_offset },
10484 .payload => .{ union_layout.payload_size, payload_offset },
10485 };
10486 if (field_begin >= offset + size) break;
10487 if (field_size == 0) continue;
10488 field_end = field_begin + field_size;
10489 if (field_end <= offset) continue;
10490 const field_signedness = field_signedness: switch (field) {
10491 .tag => {
10492 if (offset >= field_begin and offset + size <= field_begin + field_size) {
10493 ty = .fromInterned(loaded_union.enum_tag_ty);
10494 ty_size = field_size;
10495 offset -= field_begin;
10496 continue :type_key ip.indexToKey(loaded_union.enum_tag_ty);
10497 }
10498 break :field_signedness ip.indexToKey(loaded_union.loadTagType(ip).tag_ty).int_type.signedness;
10499 },
10500 .payload => null,
10501 };
10502 if (parts_len > 0) combine: {
10503 const prev_part = &parts[parts_len - 1];
10504 const combined_size = field_end - prev_part.offset;
10505 if (combined_size > @as(u64, 1) << @min(
10506 min_part_log2_stride,
10507 alignment.toLog2Units(),
10508 @ctz(prev_part.offset),
10509 )) break :combine;
10510 prev_part.size = combined_size;
10511 prev_part.signedness = null;
10512 continue;
10513 }
10514 parts[parts_len] = .{
10515 .offset = field_begin,
10516 .size = field_size,
10517 .signedness = field_signedness,
10518 };
10519 parts_len += 1;
10520 }
10521 vi.setParts(isel, parts_len);
10522 for (parts[0..parts_len]) |part| {
10523 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
10524 if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
10525 }
10526 },
9139 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },10527 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
9140 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),10528 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
9141 .error_set_type,10529 .error_set_type,
...@@ -9187,7 +10575,10 @@ pub const Value = struct {...@@ -9187,7 +10575,10 @@ pub const Value = struct {
9187 if (vi.register(isel)) |ra| {10575 if (vi.register(isel)) |ra| {
9188 if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) {10576 if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) {
9189 else => unreachable,10577 else => unreachable,
9190 2 => .fmov(mat.ra.h(), .{ .register = ra.h() }),10578 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
10579 .fmov(mat.ra.h(), .{ .register = ra.h() })
10580 else
10581 .dup(mat.ra.h(), ra.@"h[]"(0)),
9191 4 => .fmov(mat.ra.s(), .{ .register = ra.s() }),10582 4 => .fmov(mat.ra.s(), .{ .register = ra.s() }),
9192 8 => .fmov(mat.ra.d(), .{ .register = ra.d() }),10583 8 => .fmov(mat.ra.d(), .{ .register = ra.d() }),
9193 16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }),10584 16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }),
...@@ -9347,11 +10738,12 @@ pub const Value = struct {...@@ -9347,11 +10738,12 @@ pub const Value = struct {
9347 } },10738 } },
9348 .error_union => |error_union| {10739 .error_union => |error_union| {
9349 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;10740 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
10741 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
9350 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);10742 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
9351 if (!ip.isNoReturn(error_union_type.error_set_type) and10743 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
9352 offset == codegen.errUnionErrorOffset(payload_ty, zcu))10744 const error_set_size = error_set_ty.abiSize(zcu);
9353 {10745 if (offset >= error_set_offset and offset + size <= error_set_offset + error_set_size) {
9354 offset = 0;10746 offset -= error_set_offset;
9355 continue :constant_key switch (error_union.val) {10747 continue :constant_key switch (error_union.val) {
9356 .err_name => |err_name| .{ .err = .{10748 .err_name => |err_name| .{ .err = .{
9357 .ty = error_union_type.error_set_type,10749 .ty = error_union_type.error_set_type,
...@@ -9363,15 +10755,18 @@ pub const Value = struct {...@@ -9363,15 +10755,18 @@ pub const Value = struct {
9363 } },10755 } },
9364 };10756 };
9365 }10757 }
9366 assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu));10758 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
9367 offset -= @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));10759 const payload_size = payload_ty.abiSize(zcu);
9368 switch (error_union.val) {10760 if (offset >= payload_offset and offset + size <= payload_offset + payload_size) {
9369 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },10761 offset -= payload_offset;
9370 .payload => |payload| {10762 switch (error_union.val) {
9371 constant = payload;10763 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
9372 constant_key = ip.indexToKey(payload);10764 .payload => |payload| {
9373 continue :constant_key constant_key;10765 constant = payload;
9374 },10766 constant_key = ip.indexToKey(payload);
10767 continue :constant_key constant_key;
10768 },
10769 }
9375 }10770 }
9376 },10771 },
9377 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },10772 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },
...@@ -9555,21 +10950,29 @@ pub const Value = struct {...@@ -9555,21 +10950,29 @@ pub const Value = struct {
9555 var base_ptr = ip.indexToKey(base).ptr;10950 var base_ptr = ip.indexToKey(base).ptr;
9556 const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child;10951 const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child;
9557 const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type;10952 const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type;
9558 base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu);10953 base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu) + ptr.byte_offset;
10954 continue :constant_key .{ .ptr = base_ptr };
10955 },
10956 .opt_payload => |base| {
10957 var base_ptr = ip.indexToKey(base).ptr;
10958 base_ptr.byte_offset += ptr.byte_offset;
9559 continue :constant_key .{ .ptr = base_ptr };10959 continue :constant_key .{ .ptr = base_ptr };
9560 },10960 },
9561 .opt_payload => |base| continue :constant_key .{ .ptr = ip.indexToKey(base).ptr },
9562 .field => |field| {10961 .field => |field| {
9563 var base_ptr = ip.indexToKey(field.base).ptr;10962 var base_ptr = ip.indexToKey(field.base).ptr;
9564 const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);10963 const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
9565 base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu);10964 base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset;
9566 continue :constant_key .{ .ptr = base_ptr };10965 continue :constant_key .{ .ptr = base_ptr };
9567 },10966 },
9568 .comptime_alloc, .comptime_field, .arr_elem => unreachable,10967 .comptime_alloc, .comptime_field, .arr_elem => unreachable,
9569 };10968 };
9570 },10969 },
9571 .slice => |slice| switch (offset) {10970 .slice => |slice| switch (offset) {
9572 0 => continue :constant_key .{ .ptr = ip.indexToKey(slice.ptr).ptr },10971 0 => continue :constant_key switch (ip.indexToKey(slice.ptr)) {
10972 else => unreachable,
10973 .undef => |undef| .{ .undef = undef },
10974 .ptr => |ptr| .{ .ptr = ptr },
10975 },
9573 else => {10976 else => {
9574 assert(offset == @divExact(isel.target.ptrBitWidth(), 8));10977 assert(offset == @divExact(isel.target.ptrBitWidth(), 8));
9575 offset = 0;10978 offset = 0;
...@@ -9900,7 +11303,17 @@ fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8...@@ -9900,7 +11303,17 @@ fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8
9900fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {11303fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {
9901 const zcu = isel.pt.zcu;11304 const zcu = isel.pt.zcu;
9902 const ip = &zcu.intern_pool;11305 const ip = &zcu.intern_pool;
9903 switch (ip.indexToKey(constant.toIntern())) {11306 if (try isel.writeKeyToMemory(ip.indexToKey(constant.toIntern()), buffer)) return true;
11307 constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
11308 error.OutOfMemory => return error.OutOfMemory,
11309 error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
11310 };
11311 return true;
11312}
11313fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) error{OutOfMemory}!bool {
11314 const zcu = isel.pt.zcu;
11315 const ip = &zcu.intern_pool;
11316 switch (constant_key) {
9904 .int_type,11317 .int_type,
9905 .ptr_type,11318 .ptr_type,
9906 .array_type,11319 .array_type,
...@@ -9922,6 +11335,37 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -9922,6 +11335,37 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
9922 .empty_enum_value,11335 .empty_enum_value,
9923 .memoized_call,11336 .memoized_call,
9924 => unreachable, // not a runtime value11337 => unreachable, // not a runtime value
11338 .err => |err| {
11339 const error_int = ip.getErrorValueIfExists(err.name).?;
11340 switch (buffer.len) {
11341 else => unreachable,
11342 inline 1...4 => |size| std.mem.writeInt(
11343 @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * size } }),
11344 buffer[0..size],
11345 @intCast(error_int),
11346 isel.target.cpu.arch.endian(),
11347 ),
11348 }
11349 },
11350 .error_union => |error_union| {
11351 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
11352 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
11353 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
11354 const error_set = buffer[@intCast(codegen.errUnionErrorOffset(payload_ty, zcu))..][0..@intCast(error_set_ty.abiSize(zcu))];
11355 switch (error_union.val) {
11356 .err_name => |err_name| if (!try isel.writeKeyToMemory(.{ .err = .{
11357 .ty = error_set_ty.toIntern(),
11358 .name = err_name,
11359 } }, error_set)) return false,
11360 .payload => |payload| {
11361 if (!try isel.writeToMemory(
11362 .fromInterned(payload),
11363 buffer[@intCast(codegen.errUnionPayloadOffset(payload_ty, zcu))..][0..@intCast(payload_ty.abiSize(zcu))],
11364 )) return false;
11365 @memset(error_set, 0);
11366 },
11367 }
11368 },
9925 .opt => |opt| {11369 .opt => |opt| {
9926 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));11370 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));
9927 switch (opt.val) {11371 switch (opt.val) {
...@@ -9933,7 +11377,6 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -9933,7 +11377,6 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
9933 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);11377 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);
9934 },11378 },
9935 }11379 }
9936 return true;
9937 },11380 },
9938 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {11381 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
9939 else => unreachable,11382 else => unreachable,
...@@ -9952,9 +11395,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -9952,9 +11395,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
9952 elem_offset += elem_size;11395 elem_offset += elem_size;
9953 },11396 },
9954 }11397 }
9955 return true;
9956 },11398 },
9957 .vector_type => {},11399 .vector_type => return false,
9958 .struct_type => {11400 .struct_type => {
9959 const loaded_struct = ip.loadStructType(aggregate.ty);11401 const loaded_struct = ip.loadStructType(aggregate.ty);
9960 switch (loaded_struct.layout) {11402 switch (loaded_struct.layout) {
...@@ -9977,9 +11419,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -9977,9 +11419,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
9977 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;11419 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
9978 field_offset += field_size;11420 field_offset += field_size;
9979 }11421 }
9980 return true;
9981 },11422 },
9982 .@"extern", .@"packed" => {},11423 .@"extern", .@"packed" => return false,
9983 }11424 }
9984 },11425 },
9985 .tuple_type => |tuple_type| {11426 .tuple_type => |tuple_type| {
...@@ -9996,15 +11437,10 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem...@@ -9996,15 +11437,10 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
9996 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;11437 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
9997 field_offset += field_size;11438 field_offset += field_size;
9998 }11439 }
9999 return true;
10000 },11440 },
10001 },11441 },
10002 else => {},11442 else => return false,
10003 }11443 }
10004 constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
10005 error.OutOfMemory => return error.OutOfMemory,
10006 error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
10007 };
10008 return true;11444 return true;
10009}11445}
1001011446
...@@ -10622,16 +12058,14 @@ pub const CallAbiIterator = struct {...@@ -10622,16 +12058,14 @@ pub const CallAbiIterator = struct {
10622 {12058 {
10623 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);12059 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
10624 const offset = codegen.errUnionErrorOffset(payload_ty, zcu);12060 const offset = codegen.errUnionErrorOffset(payload_ty, zcu);
10625 const size = error_set_ty.abiSize(zcu);12061 const end = offset % 8 + error_set_ty.abiSize(zcu);
10626 const end = offset % 8 + size;
10627 const part_index: usize = @intCast(offset / 8);12062 const part_index: usize = @intCast(offset / 8);
10628 sizes[part_index] = @max(sizes[part_index], @min(end, 8));12063 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
10629 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);12064 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
10630 }12065 }
10631 {12066 {
10632 const offset = codegen.errUnionPayloadOffset(payload_ty, zcu);12067 const offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
10633 const size = payload_ty.abiSize(zcu);12068 const end = offset % 8 + payload_ty.abiSize(zcu);
10634 const end = offset % 8 + size;
10635 const part_index: usize = @intCast(offset / 8);12069 const part_index: usize = @intCast(offset / 8);
10636 sizes[part_index] = @max(sizes[part_index], @min(end, 8));12070 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
10637 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);12071 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
...@@ -10675,8 +12109,14 @@ pub const CallAbiIterator = struct {...@@ -10675,8 +12109,14 @@ pub const CallAbiIterator = struct {
10675 => unreachable,12109 => unreachable,
10676 },12110 },
10677 .struct_type => {12111 .struct_type => {
10678 const size = wip_vi.size(isel);
10679 const loaded_struct = ip.loadStructType(ty.toIntern());12112 const loaded_struct = ip.loadStructType(ty.toIntern());
12113 switch (loaded_struct.layout) {
12114 .auto, .@"extern" => {},
12115 .@"packed" => continue :type_key .{
12116 .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
12117 },
12118 }
12119 const size = wip_vi.size(isel);
10680 if (size <= 16 * 4) homogeneous_aggregate: {12120 if (size <= 16 * 4) homogeneous_aggregate: {
10681 const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate;12121 const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate;
10682 const parts_len = @shrExact(size, fdt.log2Size());12122 const parts_len = @shrExact(size, fdt.log2Size());
...@@ -10761,6 +12201,40 @@ pub const CallAbiIterator = struct {...@@ -10761,6 +12201,40 @@ pub const CallAbiIterator = struct {
10761 else => it.indirect(isel, wip_vi),12201 else => it.indirect(isel, wip_vi),
10762 }12202 }
10763 },12203 },
12204 .union_type => {
12205 const loaded_union = ip.loadUnionType(ty.toIntern());
12206 switch (loaded_union.flagsUnordered(ip).layout) {
12207 .auto, .@"extern" => {},
12208 .@"packed" => continue :type_key .{ .int_type = .{
12209 .signedness = .unsigned,
12210 .bits = @intCast(ty.bitSize(zcu)),
12211 } },
12212 }
12213 switch (wip_vi.size(isel)) {
12214 0 => unreachable,
12215 1...8 => it.integer(isel, wip_vi),
12216 9...16 => {
12217 const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
12218 var sizes: [2]u64 = @splat(0);
12219 {
12220 const offset = union_layout.tagOffset();
12221 const end = offset % 8 + union_layout.tag_size;
12222 const part_index: usize = @intCast(offset / 8);
12223 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
12224 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
12225 }
12226 {
12227 const offset = union_layout.payloadOffset();
12228 const end = offset % 8 + union_layout.payload_size;
12229 const part_index: usize = @intCast(offset / 8);
12230 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
12231 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
12232 }
12233 it.integers(isel, wip_vi, sizes);
12234 },
12235 else => it.indirect(isel, wip_vi),
12236 }
12237 },
10764 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },12238 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
10765 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),12239 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
10766 .error_set_type,12240 .error_set_type,
...@@ -10789,6 +12263,16 @@ pub const CallAbiIterator = struct {...@@ -10789,6 +12263,16 @@ pub const CallAbiIterator = struct {
10789 return wip_vi.ref(isel);12263 return wip_vi.ref(isel);
10790 }12264 }
1079112265
12266 pub fn nonSysvVarArg(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
12267 const ngrn = it.ngrn;
12268 defer it.ngrn = ngrn;
12269 it.ngrn = ngrn_end;
12270 const nsrn = it.nsrn;
12271 defer it.nsrn = nsrn;
12272 it.nsrn = nsrn_end;
12273 return it.param(isel, ty);
12274 }
12275
10792 pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {12276 pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
10793 const wip_vi = try it.param(isel, ty) orelse return null;12277 const wip_vi = try it.param(isel, ty) orelse return null;
10794 switch (wip_vi.parent(isel)) {12278 switch (wip_vi.parent(isel)) {
src/codegen/aarch64/encoding.zig+4161-635
...@@ -81,6 +81,14 @@ pub const Register = struct {...@@ -81,6 +81,14 @@ pub const Register = struct {
81 .@"16b", .@"8b" => .byte,81 .@"16b", .@"8b" => .byte,
82 };82 };
83 }83 }
84
85 pub fn elemSz(arrangement: Arrangement) Instruction.DataProcessingVector.Sz {
86 return switch (arrangement) {
87 else => unreachable,
88 .@"2d", .@"1d" => .double,
89 .@"4s", .@"2s" => .single,
90 };
91 }
84 };92 };
8593
86 pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } };94 pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } };
...@@ -151,6 +159,7 @@ pub const Register = struct {...@@ -151,6 +159,7 @@ pub const Register = struct {
151 pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } };159 pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } };
152 pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } };160 pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } };
153161
162 pub const ip = x16;
154 pub const ip0 = x16;163 pub const ip0 = x16;
155 pub const ip1 = x17;164 pub const ip1 = x17;
156 pub const fp = x29;165 pub const fp = x29;
...@@ -774,6 +783,7 @@ pub const Register = struct {...@@ -774,6 +783,7 @@ pub const Register = struct {
774783
775 ffr,784 ffr,
776785
786 pub const ip: Alias = .r16;
777 pub const ip0: Alias = .r16;787 pub const ip0: Alias = .r16;
778 pub const ip1: Alias = .r17;788 pub const ip1: Alias = .r17;
779 pub const fp: Alias = .r29;789 pub const fp: Alias = .r29;
...@@ -6815,7 +6825,7 @@ pub const Instruction = packed union {...@@ -6815,7 +6825,7 @@ pub const Instruction = packed union {
6815 o0: AddSubtractOp = .add,6825 o0: AddSubtractOp = .add,
6816 Rm: Register.Encoded,6826 Rm: Register.Encoded,
6817 op21: u2 = 0b01,6827 op21: u2 = 0b01,
6818 U: bool = false,6828 U: std.builtin.Signedness = .signed,
6819 decoded24: u5 = 0b11011,6829 decoded24: u5 = 0b11011,
6820 op54: u2 = 0b00,6830 op54: u2 = 0b00,
6821 sf: Register.IntegerSize = .doubleword,6831 sf: Register.IntegerSize = .doubleword,
...@@ -6829,7 +6839,7 @@ pub const Instruction = packed union {...@@ -6829,7 +6839,7 @@ pub const Instruction = packed union {
6829 o0: AddSubtractOp = .sub,6839 o0: AddSubtractOp = .sub,
6830 Rm: Register.Encoded,6840 Rm: Register.Encoded,
6831 op21: u2 = 0b01,6841 op21: u2 = 0b01,
6832 U: bool = false,6842 U: std.builtin.Signedness = .signed,
6833 decoded24: u5 = 0b11011,6843 decoded24: u5 = 0b11011,
6834 op54: u2 = 0b00,6844 op54: u2 = 0b00,
6835 sf: Register.IntegerSize = .doubleword,6845 sf: Register.IntegerSize = .doubleword,
...@@ -6843,7 +6853,7 @@ pub const Instruction = packed union {...@@ -6843,7 +6853,7 @@ pub const Instruction = packed union {
6843 o0: AddSubtractOp = .add,6853 o0: AddSubtractOp = .add,
6844 Rm: Register.Encoded,6854 Rm: Register.Encoded,
6845 op21: u2 = 0b10,6855 op21: u2 = 0b10,
6846 U: bool = false,6856 U: std.builtin.Signedness = .signed,
6847 decoded24: u5 = 0b11011,6857 decoded24: u5 = 0b11011,
6848 op54: u2 = 0b00,6858 op54: u2 = 0b00,
6849 sf: Register.IntegerSize = .doubleword,6859 sf: Register.IntegerSize = .doubleword,
...@@ -6857,7 +6867,7 @@ pub const Instruction = packed union {...@@ -6857,7 +6867,7 @@ pub const Instruction = packed union {
6857 o0: AddSubtractOp = .add,6867 o0: AddSubtractOp = .add,
6858 Rm: Register.Encoded,6868 Rm: Register.Encoded,
6859 op21: u2 = 0b01,6869 op21: u2 = 0b01,
6860 U: bool = true,6870 U: std.builtin.Signedness = .unsigned,
6861 decoded24: u5 = 0b11011,6871 decoded24: u5 = 0b11011,
6862 op54: u2 = 0b00,6872 op54: u2 = 0b00,
6863 sf: Register.IntegerSize = .doubleword,6873 sf: Register.IntegerSize = .doubleword,
...@@ -6871,7 +6881,7 @@ pub const Instruction = packed union {...@@ -6871,7 +6881,7 @@ pub const Instruction = packed union {
6871 o0: AddSubtractOp = .sub,6881 o0: AddSubtractOp = .sub,
6872 Rm: Register.Encoded,6882 Rm: Register.Encoded,
6873 op21: u2 = 0b01,6883 op21: u2 = 0b01,
6874 U: bool = true,6884 U: std.builtin.Signedness = .unsigned,
6875 decoded24: u5 = 0b11011,6885 decoded24: u5 = 0b11011,
6876 op54: u2 = 0b00,6886 op54: u2 = 0b00,
6877 sf: Register.IntegerSize = .doubleword,6887 sf: Register.IntegerSize = .doubleword,
...@@ -6885,7 +6895,7 @@ pub const Instruction = packed union {...@@ -6885,7 +6895,7 @@ pub const Instruction = packed union {
6885 o0: AddSubtractOp = .add,6895 o0: AddSubtractOp = .add,
6886 Rm: Register.Encoded,6896 Rm: Register.Encoded,
6887 op21: u2 = 0b10,6897 op21: u2 = 0b10,
6888 U: bool = true,6898 U: std.builtin.Signedness = .unsigned,
6889 decoded24: u5 = 0b11011,6899 decoded24: u5 = 0b11011,
6890 op54: u2 = 0b00,6900 op54: u2 = 0b00,
6891 sf: Register.IntegerSize = .doubleword,6901 sf: Register.IntegerSize = .doubleword,
...@@ -7007,8 +7017,12 @@ pub const Instruction = packed union {...@@ -7007,8 +7017,12 @@ pub const Instruction = packed union {
7007 /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD7017 /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD
7008 pub const DataProcessingVector = packed union {7018 pub const DataProcessingVector = packed union {
7009 group: @This().Group,7019 group: @This().Group,
7020 simd_scalar_copy: SimdScalarCopy,
7021 simd_scalar_two_register_miscellaneous_fp16: SimdScalarTwoRegisterMiscellaneousFp16,
7022 simd_scalar_two_register_miscellaneous: SimdScalarTwoRegisterMiscellaneous,
7010 simd_scalar_pairwise: SimdScalarPairwise,7023 simd_scalar_pairwise: SimdScalarPairwise,
7011 simd_copy: SimdCopy,7024 simd_copy: SimdCopy,
7025 simd_two_register_miscellaneous_fp16: SimdTwoRegisterMiscellaneousFp16,
7012 simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous,7026 simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous,
7013 simd_across_lanes: SimdAcrossLanes,7027 simd_across_lanes: SimdAcrossLanes,
7014 simd_three_same: SimdThreeSame,7028 simd_three_same: SimdThreeSame,
...@@ -7018,6 +7032,7 @@ pub const Instruction = packed union {...@@ -7018,6 +7032,7 @@ pub const Instruction = packed union {
7018 float_compare: FloatCompare,7032 float_compare: FloatCompare,
7019 float_immediate: FloatImmediate,7033 float_immediate: FloatImmediate,
7020 float_data_processing_two_source: FloatDataProcessingTwoSource,7034 float_data_processing_two_source: FloatDataProcessingTwoSource,
7035 float_conditional_select: FloatConditionalSelect,
7021 float_data_processing_three_source: FloatDataProcessingThreeSource,7036 float_data_processing_three_source: FloatDataProcessingThreeSource,
70227037
7023 /// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group7038 /// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group
...@@ -7030,42 +7045,10 @@ pub const Instruction = packed union {...@@ -7030,42 +7045,10 @@ pub const Instruction = packed union {
7030 op0: u4,7045 op0: u4,
7031 };7046 };
70327047
7033 /// Advanced SIMD scalar pairwise7048 /// Advanced SIMD scalar copy
7034 pub const SimdScalarPairwise = packed union {7049 pub const SimdScalarCopy = packed union {
7035 group: @This().Group,
7036 addp: Addp,
7037
7038 pub const Group = packed struct {
7039 Rd: Register.Encoded,
7040 Rn: Register.Encoded,
7041 decoded10: u2 = 0b10,
7042 opcode: u5,
7043 decoded17: u5 = 0b11000,
7044 size: Size,
7045 decoded24: u5 = 0b11110,
7046 U: u1,
7047 decoded30: u2 = 0b01,
7048 };
7049
7050 /// C7.2.4 ADDP (scalar)
7051 pub const Addp = packed struct {
7052 Rd: Register.Encoded,
7053 Rn: Register.Encoded,
7054 decoded10: u2 = 0b10,
7055 opcode: u5 = 0b11011,
7056 decoded17: u5 = 0b11000,
7057 size: Size,
7058 decoded24: u5 = 0b11110,
7059 U: u1 = 0b0,
7060 decoded30: u2 = 0b01,
7061 };
7062 };
7063
7064 /// Advanced SIMD copy
7065 pub const SimdCopy = packed union {
7066 group: @This().Group,7050 group: @This().Group,
7067 smov: Smov,7051 dup: Dup,
7068 umov: Umov,
70697052
7070 pub const Group = packed struct {7053 pub const Group = packed struct {
7071 Rd: Register.Encoded,7054 Rd: Register.Encoded,
...@@ -7074,227 +7057,2423 @@ pub const Instruction = packed union {...@@ -7074,227 +7057,2423 @@ pub const Instruction = packed union {
7074 imm4: u4,7057 imm4: u4,
7075 decoded15: u1 = 0b0,7058 decoded15: u1 = 0b0,
7076 imm5: u5,7059 imm5: u5,
7077 decoded21: u8 = 0b01110000,7060 decoded21: u8 = 0b11110000,
7078 op: u1,7061 op: u1,
7079 Q: Register.IntegerSize,7062 decoded30: u2 = 0b01,
7080 decoded31: u1 = 0b0,
7081 };7063 };
70827064
7083 /// C7.2.279 SMOV7065 /// C7.2.39 DUP (element)
7084 pub const Smov = packed struct {7066 pub const Dup = packed struct {
7085 Rd: Register.Encoded,7067 Rd: Register.Encoded,
7086 Rn: Register.Encoded,7068 Rn: Register.Encoded,
7087 decoded10: u1 = 0b1,7069 decoded10: u1 = 0b1,
7088 decoded11: u1 = 0b1,7070 imm4: u4 = 0b0000,
7089 decoded12: u1 = 0b0,
7090 decoded13: u2 = 0b01,
7091 decoded15: u1 = 0b0,7071 decoded15: u1 = 0b0,
7092 imm5: u5,7072 imm5: u5,
7093 decoded21: u8 = 0b01110000,7073 decoded21: u8 = 0b11110000,
7094 decoded29: u1 = 0b0,7074 op: u1 = 0b0,
7095 Q: Register.IntegerSize,7075 decoded30: u2 = 0b01,
7096 decoded31: u1 = 0b0,
7097 };7076 };
70987077
7099 /// C7.2.371 UMOV7078 pub const Decoded = union(enum) {
7100 pub const Umov = packed struct {7079 unallocated,
7101 Rd: Register.Encoded,7080 dup: Dup,
7102 Rn: Register.Encoded,
7103 decoded10: u1 = 0b1,
7104 decoded11: u1 = 0b1,
7105 decoded12: u1 = 0b1,
7106 decoded13: u2 = 0b01,
7107 decoded15: u1 = 0b0,
7108 imm5: u5,
7109 decoded21: u8 = 0b01110000,
7110 decoded29: u1 = 0b0,
7111 Q: Register.IntegerSize,
7112 decoded31: u1 = 0b0,
7113 };7081 };
7082 pub fn decode(inst: @This()) @This().Decoded {
7083 return switch (inst.group.op) {
7084 0b0 => switch (inst.group.imm4) {
7085 else => .unallocated,
7086 0b0000 => .{ .dup = inst.dup },
7087 },
7088 0b1 => .unallocated,
7089 };
7090 }
7114 };7091 };
71157092
7116 /// Advanced SIMD two-register miscellaneous7093 /// Advanced SIMD scalar two-register miscellaneous FP16
7117 pub const SimdTwoRegisterMiscellaneous = packed union {7094 pub const SimdScalarTwoRegisterMiscellaneousFp16 = packed union {
7118 group: @This().Group,7095 group: @This().Group,
7119 cnt: Cnt,7096 fcvtns: Fcvtns,
7097 fcvtms: Fcvtms,
7098 fcvtas: Fcvtas,
7099 scvtf: Scvtf,
7100 fcmgt: Fcmgt,
7101 fcmeq: Fcmeq,
7102 fcmlt: Fcmlt,
7103 fcvtps: Fcvtps,
7104 fcvtzs: Fcvtzs,
7105 frecpe: Frecpe,
7106 frecpx: Frecpx,
7107 fcvtnu: Fcvtnu,
7108 fcvtmu: Fcvtmu,
7109 fcvtau: Fcvtau,
7110 ucvtf: Ucvtf,
7111 fcmge: Fcmge,
7112 fcmle: Fcmle,
7113 fcvtpu: Fcvtpu,
7114 fcvtzu: Fcvtzu,
7115 frsqrte: Frsqrte,
71207116
7121 pub const Group = packed struct {7117 pub const Group = packed struct {
7122 Rd: Register.Encoded,7118 Rd: Register.Encoded,
7123 Rn: Register.Encoded,7119 Rn: Register.Encoded,
7124 decoded10: u2 = 0b10,7120 decoded10: u2 = 0b10,
7125 opcode: u5,7121 opcode: u5,
7126 decoded17: u5 = 0b10000,7122 decoded17: u6 = 0b111100,
7127 size: Size,7123 a: u1,
7128 decoded24: u5 = 0b01110,7124 decoded24: u5 = 0b11110,
7129 U: u1,7125 U: std.builtin.Signedness,
7130 Q: Q,7126 decoded30: u2 = 0b01,
7131 decoded31: u1 = 0b0,
7132 };7127 };
71337128
7134 /// C7.2.38 CNT7129 /// C7.2.80 FCVTNS (vector)
7135 pub const Cnt = packed struct {7130 pub const Fcvtns = packed struct {
7136 Rd: Register.Encoded,7131 Rd: Register.Encoded,
7137 Rn: Register.Encoded,7132 Rn: Register.Encoded,
7138 decoded10: u2 = 0b10,7133 decoded10: u2 = 0b10,
7139 opcode: u5 = 0b00101,7134 opcode: u5 = 0b11010,
7140 decoded17: u5 = 0b10000,7135 decoded17: u6 = 0b111100,
7141 size: Size,7136 o2: u1 = 0b0,
7142 decoded24: u5 = 0b01110,7137 decoded24: u5 = 0b11110,
7143 U: u1 = 0b0,7138 U: std.builtin.Signedness = .signed,
7144 Q: Q,7139 decoded30: u2 = 0b01,
7145 decoded31: u1 = 0b0,
7146 };7140 };
7147 };
7148
7149 /// Advanced SIMD across lanes
7150 pub const SimdAcrossLanes = packed union {
7151 group: @This().Group,
7152 addv: Addv,
71537141
7154 pub const Group = packed struct {7142 /// C7.2.75 FCVTMS (vector)
7143 pub const Fcvtms = packed struct {
7155 Rd: Register.Encoded,7144 Rd: Register.Encoded,
7156 Rn: Register.Encoded,7145 Rn: Register.Encoded,
7157 decoded10: u2 = 0b10,7146 decoded10: u2 = 0b10,
7158 opcode: u5,7147 opcode: u5 = 0b11011,
7159 decoded17: u5 = 0b11000,7148 decoded17: u6 = 0b111100,
7160 size: Size,7149 o2: u1 = 0b0,
7161 decoded24: u5 = 0b01110,7150 decoded24: u5 = 0b11110,
7162 U: u1,7151 U: std.builtin.Signedness = .signed,
7163 Q: Q,7152 decoded30: u2 = 0b01,
7164 decoded31: u1 = 0b0,
7165 };7153 };
71667154
7167 /// C7.2.6 ADDV7155 /// C7.2.70 FCVTAS (vector)
7168 pub const Addv = packed struct {7156 pub const Fcvtas = packed struct {
7169 Rd: Register.Encoded,7157 Rd: Register.Encoded,
7170 Rn: Register.Encoded,7158 Rn: Register.Encoded,
7171 decoded10: u2 = 0b10,7159 decoded10: u2 = 0b10,
7172 opcode: u5 = 0b11011,7160 opcode: u5 = 0b11100,
7173 decoded17: u5 = 0b11000,7161 decoded17: u6 = 0b111100,
7174 size: Size,7162 o2: u1 = 0b0,
7175 decoded24: u5 = 0b01110,7163 decoded24: u5 = 0b11110,
7176 U: u1 = 0b0,7164 U: std.builtin.Signedness = .signed,
7177 Q: Q,7165 decoded30: u2 = 0b01,
7178 decoded31: u1 = 0b0,
7179 };7166 };
7180 };
71817167
7182 /// Advanced SIMD three same7168 /// C7.2.234 SCVTF (vector, integer)
7183 pub const SimdThreeSame = packed union {7169 pub const Scvtf = packed struct {
7184 group: @This().Group,7170 Rd: Register.Encoded,
7185 addp: Addp,7171 Rn: Register.Encoded,
7186 @"and": And,7172 decoded10: u2 = 0b10,
7187 bic: Bic,7173 opcode: u5 = 0b11101,
7188 orr: Orr,7174 decoded17: u6 = 0b111100,
7189 orn: Orn,7175 o2: u1 = 0b0,
7190 eor: Eor,7176 decoded24: u5 = 0b11110,
7177 U: std.builtin.Signedness = .signed,
7178 decoded30: u2 = 0b01,
7179 };
71917180
7192 pub const Group = packed struct {7181 /// C7.2.61 FCMGT (zero)
7182 pub const Fcmgt = packed struct {
7193 Rd: Register.Encoded,7183 Rd: Register.Encoded,
7194 Rn: Register.Encoded,7184 Rn: Register.Encoded,
7195 decoded10: u1 = 0b1,7185 decoded10: u2 = 0b10,
7196 opcode: u5,7186 opcode: u5 = 0b01100,
7197 Rm: Register.Encoded,7187 decoded17: u6 = 0b111100,
7198 decoded21: u1 = 0b1,7188 o2: u1 = 0b1,
7199 size: Size,7189 decoded24: u5 = 0b11110,
7200 decoded24: u5 = 0b01110,7190 U: std.builtin.Signedness = .signed,
7201 U: u1,7191 decoded30: u2 = 0b01,
7202 Q: Q,
7203 decoded31: u1 = 0b0,
7204 };7192 };
72057193
7206 /// C7.2.5 ADDP (vector)7194 /// C7.2.57 FCMEQ (zero)
7207 pub const Addp = packed struct {7195 pub const Fcmeq = packed struct {
7208 Rd: Register.Encoded,7196 Rd: Register.Encoded,
7209 Rn: Register.Encoded,7197 Rn: Register.Encoded,
7210 decoded10: u1 = 0b1,7198 decoded10: u2 = 0b10,
7211 opcode: u5 = 0b10111,7199 opcode: u5 = 0b01101,
7212 Rm: Register.Encoded,7200 decoded17: u6 = 0b111100,
7213 decoded21: u1 = 0b1,7201 o2: u1 = 0b1,
7214 size: Size,7202 decoded24: u5 = 0b11110,
7215 decoded24: u5 = 0b01110,7203 U: std.builtin.Signedness = .signed,
7216 U: u1 = 0b0,7204 decoded30: u2 = 0b01,
7217 Q: Q,
7218 decoded31: u1 = 0b0,
7219 };7205 };
72207206
7221 /// C7.2.11 AND (vector)7207 /// C7.2.65 FCMLT (zero)
7222 pub const And = packed struct {7208 pub const Fcmlt = packed struct {
7223 Rd: Register.Encoded,7209 Rd: Register.Encoded,
7224 Rn: Register.Encoded,7210 Rn: Register.Encoded,
7225 decoded10: u1 = 0b1,7211 decoded10: u2 = 0b10,
7226 opcode: u5 = 0b00011,7212 opcode: u5 = 0b01110,
7227 Rm: Register.Encoded,7213 decoded17: u6 = 0b111100,
7228 decoded21: u1 = 0b1,7214 o2: u1 = 0b1,
7229 size: Size = .byte,7215 decoded24: u5 = 0b11110,
7230 decoded24: u5 = 0b01110,7216 U: std.builtin.Signedness = .signed,
7231 U: u1 = 0b0,7217 decoded30: u2 = 0b01,
7232 Q: Q,
7233 decoded31: u1 = 0b0,
7234 };7218 };
72357219
7236 /// C7.2.21 BIC (vector, register)7220 /// C7.2.84 FCVTPS (vector)
7237 pub const Bic = packed struct {7221 pub const Fcvtps = packed struct {
7238 Rd: Register.Encoded,7222 Rd: Register.Encoded,
7239 Rn: Register.Encoded,7223 Rn: Register.Encoded,
7240 decoded10: u1 = 0b1,7224 decoded10: u2 = 0b10,
7241 opcode: u5 = 0b00011,7225 opcode: u5 = 0b11010,
7242 Rm: Register.Encoded,7226 decoded17: u6 = 0b111100,
7243 decoded21: u1 = 0b1,7227 o2: u1 = 0b1,
7244 size: Size = .half,7228 decoded24: u5 = 0b11110,
7245 decoded24: u5 = 0b01110,7229 U: std.builtin.Signedness = .signed,
7246 U: u1 = 0b0,7230 decoded30: u2 = 0b01,
7247 Q: Q,
7248 decoded31: u1 = 0b0,
7249 };7231 };
72507232
7251 /// C7.2.213 ORR (vector, register)7233 /// C7.2.90 FCVTZS (vector, integer)
7252 pub const Orr = packed struct {7234 pub const Fcvtzs = packed struct {
7253 Rd: Register.Encoded,7235 Rd: Register.Encoded,
7254 Rn: Register.Encoded,7236 Rn: Register.Encoded,
7255 decoded10: u1 = 0b1,7237 decoded10: u2 = 0b10,
7256 opcode: u5 = 0b00011,7238 opcode: u5 = 0b11011,
7257 Rm: Register.Encoded,7239 decoded17: u6 = 0b111100,
7258 decoded21: u1 = 0b1,7240 o2: u1 = 0b1,
7259 size: Size = .single,7241 decoded24: u5 = 0b11110,
7260 decoded24: u5 = 0b01110,7242 U: std.builtin.Signedness = .signed,
7261 U: u1 = 0b0,7243 decoded30: u2 = 0b01,
7262 Q: Q,
7263 decoded31: u1 = 0b0,
7264 };7244 };
72657245
7266 /// C7.2.211 ORN (vector)7246 /// C7.2.144 FRECPE
7267 pub const Orn = packed struct {7247 pub const Frecpe = packed struct {
7268 Rd: Register.Encoded,7248 Rd: Register.Encoded,
7269 Rn: Register.Encoded,7249 Rn: Register.Encoded,
7270 decoded10: u1 = 0b1,7250 decoded10: u2 = 0b10,
7271 opcode: u5 = 0b00011,7251 opcode: u5 = 0b11101,
7272 Rm: Register.Encoded,7252 decoded17: u6 = 0b111100,
7273 decoded21: u1 = 0b1,7253 o2: u1 = 0b1,
7274 size: Size = .double,7254 decoded24: u5 = 0b11110,
7275 decoded24: u5 = 0b01110,7255 U: std.builtin.Signedness = .signed,
7276 U: u1 = 0b0,7256 decoded30: u2 = 0b01,
7277 Q: Q,
7278 decoded31: u1 = 0b0,
7279 };7257 };
72807258
7281 /// C7.2.41 EOR (vector)7259 /// C7.2.146 FRECPX
7282 pub const Eor = packed struct {7260 pub const Frecpx = packed struct {
7283 Rd: Register.Encoded,7261 Rd: Register.Encoded,
7284 Rn: Register.Encoded,7262 Rn: Register.Encoded,
7285 decoded10: u1 = 0b1,7263 decoded10: u2 = 0b10,
7286 opcode: u5 = 0b00011,7264 opcode: u5 = 0b11111,
7287 Rm: Register.Encoded,7265 decoded17: u6 = 0b111100,
7288 decoded21: u1 = 0b1,7266 o2: u1 = 0b1,
7289 size: Size = .byte,7267 decoded24: u5 = 0b11110,
7290 decoded24: u5 = 0b01110,7268 U: std.builtin.Signedness = .signed,
7291 U: u1 = 0b1,7269 decoded30: u2 = 0b01,
7292 Q: Q,
7293 decoded31: u1 = 0b0,
7294 };7270 };
7295 };
72967271
7297 /// Advanced SIMD modified immediate7272 /// C7.2.82 FCVTNU (vector)
7273 pub const Fcvtnu = packed struct {
7274 Rd: Register.Encoded,
7275 Rn: Register.Encoded,
7276 decoded10: u2 = 0b10,
7277 opcode: u5 = 0b11010,
7278 decoded17: u6 = 0b111100,
7279 o2: u1 = 0b0,
7280 decoded24: u5 = 0b11110,
7281 U: std.builtin.Signedness = .unsigned,
7282 decoded30: u2 = 0b01,
7283 };
7284
7285 /// C7.2.77 FCVTMU (vector)
7286 pub const Fcvtmu = packed struct {
7287 Rd: Register.Encoded,
7288 Rn: Register.Encoded,
7289 decoded10: u2 = 0b10,
7290 opcode: u5 = 0b11011,
7291 decoded17: u6 = 0b111100,
7292 o2: u1 = 0b0,
7293 decoded24: u5 = 0b11110,
7294 U: std.builtin.Signedness = .unsigned,
7295 decoded30: u2 = 0b01,
7296 };
7297
7298 /// C7.2.72 FCVTAU (vector)
7299 pub const Fcvtau = packed struct {
7300 Rd: Register.Encoded,
7301 Rn: Register.Encoded,
7302 decoded10: u2 = 0b10,
7303 opcode: u5 = 0b11100,
7304 decoded17: u6 = 0b111100,
7305 o2: u1 = 0b0,
7306 decoded24: u5 = 0b11110,
7307 U: std.builtin.Signedness = .unsigned,
7308 decoded30: u2 = 0b01,
7309 };
7310
7311 /// C7.2.353 UCVTF (vector, integer)
7312 pub const Ucvtf = packed struct {
7313 Rd: Register.Encoded,
7314 Rn: Register.Encoded,
7315 decoded10: u2 = 0b10,
7316 opcode: u5 = 0b11101,
7317 decoded17: u6 = 0b111100,
7318 o2: u1 = 0b0,
7319 decoded24: u5 = 0b11110,
7320 U: std.builtin.Signedness = .unsigned,
7321 decoded30: u2 = 0b01,
7322 };
7323
7324 /// C7.2.59 FCMGE (zero)
7325 pub const Fcmge = packed struct {
7326 Rd: Register.Encoded,
7327 Rn: Register.Encoded,
7328 decoded10: u2 = 0b10,
7329 opcode: u5 = 0b01100,
7330 decoded17: u6 = 0b111100,
7331 o2: u1 = 0b1,
7332 decoded24: u5 = 0b11110,
7333 U: std.builtin.Signedness = .unsigned,
7334 decoded30: u2 = 0b01,
7335 };
7336
7337 /// C7.2.64 FCMLE (zero)
7338 pub const Fcmle = packed struct {
7339 Rd: Register.Encoded,
7340 Rn: Register.Encoded,
7341 decoded10: u2 = 0b10,
7342 opcode: u5 = 0b01101,
7343 decoded17: u6 = 0b111100,
7344 o2: u1 = 0b1,
7345 decoded24: u5 = 0b11110,
7346 U: std.builtin.Signedness = .unsigned,
7347 decoded30: u2 = 0b01,
7348 };
7349
7350 /// C7.2.86 FCVTPU (vector)
7351 pub const Fcvtpu = packed struct {
7352 Rd: Register.Encoded,
7353 Rn: Register.Encoded,
7354 decoded10: u2 = 0b10,
7355 opcode: u5 = 0b11010,
7356 decoded17: u6 = 0b111100,
7357 o2: u1 = 0b1,
7358 decoded24: u5 = 0b11110,
7359 U: std.builtin.Signedness = .unsigned,
7360 decoded30: u2 = 0b01,
7361 };
7362
7363 /// C7.2.94 FCVTZU (vector, integer)
7364 pub const Fcvtzu = packed struct {
7365 Rd: Register.Encoded,
7366 Rn: Register.Encoded,
7367 decoded10: u2 = 0b10,
7368 opcode: u5 = 0b11011,
7369 decoded17: u6 = 0b111100,
7370 o2: u1 = 0b1,
7371 decoded24: u5 = 0b11110,
7372 U: std.builtin.Signedness = .unsigned,
7373 decoded30: u2 = 0b01,
7374 };
7375
7376 /// C7.2.169 FRSQRTE
7377 pub const Frsqrte = packed struct {
7378 Rd: Register.Encoded,
7379 Rn: Register.Encoded,
7380 decoded10: u2 = 0b10,
7381 opcode: u5 = 0b11101,
7382 decoded17: u6 = 0b111100,
7383 o2: u1 = 0b1,
7384 decoded24: u5 = 0b11110,
7385 U: std.builtin.Signedness = .unsigned,
7386 decoded30: u2 = 0b01,
7387 };
7388 };
7389
7390 /// Advanced SIMD scalar two-register miscellaneous
7391 pub const SimdScalarTwoRegisterMiscellaneous = packed union {
7392 group: @This().Group,
7393 suqadd: Suqadd,
7394 sqabs: Sqabs,
7395 cmgt: Cmgt,
7396 cmeq: Cmeq,
7397 cmlt: Cmlt,
7398 abs: Abs,
7399 sqxtn: Sqxtn,
7400 fcvtns: Fcvtns,
7401 fcvtms: Fcvtms,
7402 fcvtas: Fcvtas,
7403 scvtf: Scvtf,
7404 fcmgt: Fcmgt,
7405 fcmeq: Fcmeq,
7406 fcmlt: Fcmlt,
7407 fcvtps: Fcvtps,
7408 fcvtzs: Fcvtzs,
7409 frecpe: Frecpe,
7410 frecpx: Frecpx,
7411 usqadd: Usqadd,
7412 sqneg: Sqneg,
7413 cmge: Cmge,
7414 cmle: Cmle,
7415 neg: Neg,
7416 sqxtun: Sqxtun,
7417 uqxtn: Uqxtn,
7418 fcvtxn: Fcvtxn,
7419 fcvtnu: Fcvtnu,
7420 fcvtmu: Fcvtmu,
7421 fcvtau: Fcvtau,
7422 ucvtf: Ucvtf,
7423 fcmge: Fcmge,
7424 fcmle: Fcmle,
7425 fcvtpu: Fcvtpu,
7426 fcvtzu: Fcvtzu,
7427 frsqrte: Frsqrte,
7428
7429 pub const Group = packed struct {
7430 Rd: Register.Encoded,
7431 Rn: Register.Encoded,
7432 decoded10: u2 = 0b10,
7433 opcode: u5,
7434 decoded17: u5 = 0b10000,
7435 size: Size,
7436 decoded24: u5 = 0b11110,
7437 U: std.builtin.Signedness,
7438 decoded30: u2 = 0b01,
7439 };
7440
7441 /// C7.2.337 SUQADD
7442 pub const Suqadd = packed struct {
7443 Rd: Register.Encoded,
7444 Rn: Register.Encoded,
7445 decoded10: u2 = 0b10,
7446 opcode: u5 = 0b00011,
7447 decoded17: u5 = 0b10000,
7448 size: Size,
7449 decoded24: u5 = 0b11110,
7450 U: std.builtin.Signedness = .signed,
7451 decoded30: u2 = 0b01,
7452 };
7453
7454 /// C7.2.282 SQABS
7455 pub const Sqabs = packed struct {
7456 Rd: Register.Encoded,
7457 Rn: Register.Encoded,
7458 decoded10: u2 = 0b10,
7459 opcode: u5 = 0b00111,
7460 decoded17: u5 = 0b10000,
7461 size: Size,
7462 decoded24: u5 = 0b11110,
7463 U: std.builtin.Signedness = .signed,
7464 decoded30: u2 = 0b01,
7465 };
7466
7467 /// C7.2.32 CMGT (zero)
7468 pub const Cmgt = packed struct {
7469 Rd: Register.Encoded,
7470 Rn: Register.Encoded,
7471 decoded10: u2 = 0b10,
7472 opcode: u5 = 0b01000,
7473 decoded17: u5 = 0b10000,
7474 size: Size,
7475 decoded24: u5 = 0b11110,
7476 U: std.builtin.Signedness = .signed,
7477 decoded30: u2 = 0b01,
7478 };
7479
7480 /// C7.2.28 CMEQ (zero)
7481 pub const Cmeq = packed struct {
7482 Rd: Register.Encoded,
7483 Rn: Register.Encoded,
7484 decoded10: u2 = 0b10,
7485 opcode: u5 = 0b01001,
7486 decoded17: u5 = 0b10000,
7487 size: Size,
7488 decoded24: u5 = 0b11110,
7489 U: std.builtin.Signedness = .signed,
7490 decoded30: u2 = 0b01,
7491 };
7492
7493 /// C7.2.36 CMLT (zero)
7494 pub const Cmlt = packed struct {
7495 Rd: Register.Encoded,
7496 Rn: Register.Encoded,
7497 decoded10: u2 = 0b10,
7498 opcode: u5 = 0b01010,
7499 decoded17: u5 = 0b10000,
7500 size: Size,
7501 decoded24: u5 = 0b11110,
7502 U: std.builtin.Signedness = .signed,
7503 decoded30: u2 = 0b01,
7504 };
7505
7506 /// C7.2.1 ABS
7507 pub const Abs = packed struct {
7508 Rd: Register.Encoded,
7509 Rn: Register.Encoded,
7510 decoded10: u2 = 0b10,
7511 opcode: u5 = 0b01011,
7512 decoded17: u5 = 0b10000,
7513 size: Size,
7514 decoded24: u5 = 0b11110,
7515 U: std.builtin.Signedness = .signed,
7516 decoded30: u2 = 0b01,
7517 };
7518
7519 /// C7.2.308 SQXTN
7520 pub const Sqxtn = packed struct {
7521 Rd: Register.Encoded,
7522 Rn: Register.Encoded,
7523 decoded10: u2 = 0b10,
7524 opcode: u5 = 0b10100,
7525 decoded17: u5 = 0b10000,
7526 size: Size,
7527 decoded24: u5 = 0b11110,
7528 U: std.builtin.Signedness = .signed,
7529 decoded30: u2 = 0b01,
7530 };
7531
7532 /// C7.2.80 FCVTNS (vector)
7533 pub const Fcvtns = packed struct {
7534 Rd: Register.Encoded,
7535 Rn: Register.Encoded,
7536 decoded10: u2 = 0b10,
7537 opcode: u5 = 0b11010,
7538 decoded17: u5 = 0b10000,
7539 sz: Sz,
7540 o2: u1 = 0b0,
7541 decoded24: u5 = 0b11110,
7542 U: std.builtin.Signedness = .signed,
7543 decoded30: u2 = 0b01,
7544 };
7545
7546 /// C7.2.75 FCVTMS (vector)
7547 pub const Fcvtms = packed struct {
7548 Rd: Register.Encoded,
7549 Rn: Register.Encoded,
7550 decoded10: u2 = 0b10,
7551 opcode: u5 = 0b11011,
7552 decoded17: u5 = 0b10000,
7553 sz: Sz,
7554 o2: u1 = 0b0,
7555 decoded24: u5 = 0b11110,
7556 U: std.builtin.Signedness = .signed,
7557 decoded30: u2 = 0b01,
7558 };
7559
7560 /// C7.2.70 FCVTAS (vector)
7561 pub const Fcvtas = packed struct {
7562 Rd: Register.Encoded,
7563 Rn: Register.Encoded,
7564 decoded10: u2 = 0b10,
7565 opcode: u5 = 0b11100,
7566 decoded17: u5 = 0b10000,
7567 sz: Sz,
7568 o2: u1 = 0b0,
7569 decoded24: u5 = 0b11110,
7570 U: std.builtin.Signedness = .signed,
7571 decoded30: u2 = 0b01,
7572 };
7573
7574 /// C7.2.234 SCVTF (vector, integer)
7575 pub const Scvtf = packed struct {
7576 Rd: Register.Encoded,
7577 Rn: Register.Encoded,
7578 decoded10: u2 = 0b10,
7579 opcode: u5 = 0b11101,
7580 decoded17: u5 = 0b10000,
7581 sz: Sz,
7582 o2: u1 = 0b0,
7583 decoded24: u5 = 0b11110,
7584 U: std.builtin.Signedness = .signed,
7585 decoded30: u2 = 0b01,
7586 };
7587
7588 /// C7.2.61 FCMGT (zero)
7589 pub const Fcmgt = packed struct {
7590 Rd: Register.Encoded,
7591 Rn: Register.Encoded,
7592 decoded10: u2 = 0b10,
7593 opcode: u5 = 0b01100,
7594 decoded17: u5 = 0b10000,
7595 sz: Sz,
7596 o2: u1 = 0b1,
7597 decoded24: u5 = 0b11110,
7598 U: std.builtin.Signedness = .signed,
7599 decoded30: u2 = 0b01,
7600 };
7601
7602 /// C7.2.57 FCMEQ (zero)
7603 pub const Fcmeq = packed struct {
7604 Rd: Register.Encoded,
7605 Rn: Register.Encoded,
7606 decoded10: u2 = 0b10,
7607 opcode: u5 = 0b01101,
7608 decoded17: u5 = 0b10000,
7609 sz: Sz,
7610 o2: u1 = 0b1,
7611 decoded24: u5 = 0b11110,
7612 U: std.builtin.Signedness = .signed,
7613 decoded30: u2 = 0b01,
7614 };
7615
7616 /// C7.2.65 FCMLT (zero)
7617 pub const Fcmlt = packed struct {
7618 Rd: Register.Encoded,
7619 Rn: Register.Encoded,
7620 decoded10: u2 = 0b10,
7621 opcode: u5 = 0b01110,
7622 decoded17: u5 = 0b10000,
7623 sz: Sz,
7624 o2: u1 = 0b1,
7625 decoded24: u5 = 0b11110,
7626 U: std.builtin.Signedness = .signed,
7627 decoded30: u2 = 0b01,
7628 };
7629
7630 /// C7.2.84 FCVTPS (vector)
7631 pub const Fcvtps = packed struct {
7632 Rd: Register.Encoded,
7633 Rn: Register.Encoded,
7634 decoded10: u2 = 0b10,
7635 opcode: u5 = 0b11010,
7636 decoded17: u5 = 0b10000,
7637 sz: Sz,
7638 o2: u1 = 0b1,
7639 decoded24: u5 = 0b11110,
7640 U: std.builtin.Signedness = .signed,
7641 decoded30: u2 = 0b01,
7642 };
7643
7644 /// C7.2.90 FCVTZS (vector, integer)
7645 pub const Fcvtzs = packed struct {
7646 Rd: Register.Encoded,
7647 Rn: Register.Encoded,
7648 decoded10: u2 = 0b10,
7649 opcode: u5 = 0b11011,
7650 decoded17: u5 = 0b10000,
7651 sz: Sz,
7652 o2: u1 = 0b1,
7653 decoded24: u5 = 0b11110,
7654 U: std.builtin.Signedness = .signed,
7655 decoded30: u2 = 0b01,
7656 };
7657
7658 /// C7.2.144 FRECPE
7659 pub const Frecpe = packed struct {
7660 Rd: Register.Encoded,
7661 Rn: Register.Encoded,
7662 decoded10: u2 = 0b10,
7663 opcode: u5 = 0b11101,
7664 decoded17: u5 = 0b10000,
7665 sz: Sz,
7666 o2: u1 = 0b1,
7667 decoded24: u5 = 0b11110,
7668 U: std.builtin.Signedness = .signed,
7669 decoded30: u2 = 0b01,
7670 };
7671
7672 /// C7.2.146 FRECPX
7673 pub const Frecpx = packed struct {
7674 Rd: Register.Encoded,
7675 Rn: Register.Encoded,
7676 decoded10: u2 = 0b10,
7677 opcode: u5 = 0b11111,
7678 decoded17: u5 = 0b10000,
7679 sz: Sz,
7680 o2: u1 = 0b1,
7681 decoded24: u5 = 0b11110,
7682 U: std.builtin.Signedness = .signed,
7683 decoded30: u2 = 0b01,
7684 };
7685
7686 /// C7.2.394 USQADD
7687 pub const Usqadd = packed struct {
7688 Rd: Register.Encoded,
7689 Rn: Register.Encoded,
7690 decoded10: u2 = 0b10,
7691 opcode: u5 = 0b00011,
7692 decoded17: u5 = 0b10000,
7693 size: Size,
7694 decoded24: u5 = 0b11110,
7695 U: std.builtin.Signedness = .unsigned,
7696 decoded30: u2 = 0b01,
7697 };
7698
7699 /// C7.2.292 SQNEG
7700 pub const Sqneg = packed struct {
7701 Rd: Register.Encoded,
7702 Rn: Register.Encoded,
7703 decoded10: u2 = 0b10,
7704 opcode: u5 = 0b00111,
7705 decoded17: u5 = 0b10000,
7706 size: Size,
7707 decoded24: u5 = 0b11110,
7708 U: std.builtin.Signedness = .unsigned,
7709 decoded30: u2 = 0b01,
7710 };
7711
7712 /// C7.2.30 CMGE (zero)
7713 pub const Cmge = packed struct {
7714 Rd: Register.Encoded,
7715 Rn: Register.Encoded,
7716 decoded10: u2 = 0b10,
7717 opcode: u5 = 0b01000,
7718 decoded17: u5 = 0b10000,
7719 size: Size,
7720 decoded24: u5 = 0b11110,
7721 U: std.builtin.Signedness = .unsigned,
7722 decoded30: u2 = 0b01,
7723 };
7724
7725 /// C7.2.35 CMLE (zero)
7726 pub const Cmle = packed struct {
7727 Rd: Register.Encoded,
7728 Rn: Register.Encoded,
7729 decoded10: u2 = 0b10,
7730 opcode: u5 = 0b01001,
7731 decoded17: u5 = 0b10000,
7732 size: Size,
7733 decoded24: u5 = 0b11110,
7734 U: std.builtin.Signedness = .unsigned,
7735 decoded30: u2 = 0b01,
7736 };
7737
7738 /// C7.2.209 NEG (vector)
7739 pub const Neg = packed struct {
7740 Rd: Register.Encoded,
7741 Rn: Register.Encoded,
7742 decoded10: u2 = 0b10,
7743 opcode: u5 = 0b01011,
7744 decoded17: u5 = 0b10000,
7745 size: Size,
7746 decoded24: u5 = 0b11110,
7747 U: std.builtin.Signedness = .unsigned,
7748 decoded30: u2 = 0b01,
7749 };
7750
7751 /// C7.2.309 SQXTUN
7752 pub const Sqxtun = packed struct {
7753 Rd: Register.Encoded,
7754 Rn: Register.Encoded,
7755 decoded10: u2 = 0b10,
7756 opcode: u5 = 0b10010,
7757 decoded17: u5 = 0b10000,
7758 size: Size,
7759 decoded24: u5 = 0b11110,
7760 U: std.builtin.Signedness = .unsigned,
7761 decoded30: u2 = 0b01,
7762 };
7763
7764 /// C7.2.381 UQXTN
7765 pub const Uqxtn = packed struct {
7766 Rd: Register.Encoded,
7767 Rn: Register.Encoded,
7768 decoded10: u2 = 0b10,
7769 opcode: u5 = 0b10100,
7770 decoded17: u5 = 0b10000,
7771 size: Size,
7772 decoded24: u5 = 0b11110,
7773 U: std.builtin.Signedness = .unsigned,
7774 decoded30: u2 = 0b01,
7775 };
7776
7777 /// C7.2.88 FCVTXN
7778 pub const Fcvtxn = packed struct {
7779 Rd: Register.Encoded,
7780 Rn: Register.Encoded,
7781 decoded10: u2 = 0b10,
7782 opcode: u5 = 0b10110,
7783 decoded17: u5 = 0b10000,
7784 sz: Sz,
7785 o2: u1 = 0b0,
7786 decoded24: u5 = 0b11110,
7787 U: std.builtin.Signedness = .unsigned,
7788 decoded30: u2 = 0b01,
7789 };
7790
7791 /// C7.2.82 FCVTNU (vector)
7792 pub const Fcvtnu = packed struct {
7793 Rd: Register.Encoded,
7794 Rn: Register.Encoded,
7795 decoded10: u2 = 0b10,
7796 opcode: u5 = 0b11010,
7797 decoded17: u5 = 0b10000,
7798 sz: Sz,
7799 o2: u1 = 0b0,
7800 decoded24: u5 = 0b11110,
7801 U: std.builtin.Signedness = .unsigned,
7802 decoded30: u2 = 0b01,
7803 };
7804
7805 /// C7.2.77 FCVTMU (vector)
7806 pub const Fcvtmu = packed struct {
7807 Rd: Register.Encoded,
7808 Rn: Register.Encoded,
7809 decoded10: u2 = 0b10,
7810 opcode: u5 = 0b11011,
7811 decoded17: u5 = 0b10000,
7812 sz: Sz,
7813 o2: u1 = 0b0,
7814 decoded24: u5 = 0b11110,
7815 U: std.builtin.Signedness = .unsigned,
7816 decoded30: u2 = 0b01,
7817 };
7818
7819 /// C7.2.72 FCVTAU (vector)
7820 pub const Fcvtau = packed struct {
7821 Rd: Register.Encoded,
7822 Rn: Register.Encoded,
7823 decoded10: u2 = 0b10,
7824 opcode: u5 = 0b11100,
7825 decoded17: u5 = 0b10000,
7826 sz: Sz,
7827 o2: u1 = 0b0,
7828 decoded24: u5 = 0b11110,
7829 U: std.builtin.Signedness = .unsigned,
7830 decoded30: u2 = 0b01,
7831 };
7832
7833 /// C7.2.353 UCVTF (vector, integer)
7834 pub const Ucvtf = packed struct {
7835 Rd: Register.Encoded,
7836 Rn: Register.Encoded,
7837 decoded10: u2 = 0b10,
7838 opcode: u5 = 0b11101,
7839 decoded17: u5 = 0b10000,
7840 sz: Sz,
7841 o2: u1 = 0b0,
7842 decoded24: u5 = 0b11110,
7843 U: std.builtin.Signedness = .unsigned,
7844 decoded30: u2 = 0b01,
7845 };
7846
7847 /// C7.2.59 FCMGE (zero)
7848 pub const Fcmge = packed struct {
7849 Rd: Register.Encoded,
7850 Rn: Register.Encoded,
7851 decoded10: u2 = 0b10,
7852 opcode: u5 = 0b01100,
7853 decoded17: u5 = 0b10000,
7854 sz: Sz,
7855 o2: u1 = 0b1,
7856 decoded24: u5 = 0b11110,
7857 U: std.builtin.Signedness = .unsigned,
7858 decoded30: u2 = 0b01,
7859 };
7860
7861 /// C7.2.64 FCMLE (zero)
7862 pub const Fcmle = packed struct {
7863 Rd: Register.Encoded,
7864 Rn: Register.Encoded,
7865 decoded10: u2 = 0b10,
7866 opcode: u5 = 0b01101,
7867 decoded17: u5 = 0b10000,
7868 sz: Sz,
7869 o2: u1 = 0b1,
7870 decoded24: u5 = 0b11110,
7871 U: std.builtin.Signedness = .unsigned,
7872 decoded30: u2 = 0b01,
7873 };
7874
7875 /// C7.2.86 FCVTPU (vector)
7876 pub const Fcvtpu = packed struct {
7877 Rd: Register.Encoded,
7878 Rn: Register.Encoded,
7879 decoded10: u2 = 0b10,
7880 opcode: u5 = 0b11010,
7881 decoded17: u5 = 0b10000,
7882 sz: Sz,
7883 o2: u1 = 0b1,
7884 decoded24: u5 = 0b11110,
7885 U: std.builtin.Signedness = .unsigned,
7886 decoded30: u2 = 0b01,
7887 };
7888
7889 /// C7.2.94 FCVTZU (vector, integer)
7890 pub const Fcvtzu = packed struct {
7891 Rd: Register.Encoded,
7892 Rn: Register.Encoded,
7893 decoded10: u2 = 0b10,
7894 opcode: u5 = 0b11011,
7895 decoded17: u5 = 0b10000,
7896 sz: Sz,
7897 o2: u1 = 0b1,
7898 decoded24: u5 = 0b11110,
7899 U: std.builtin.Signedness = .unsigned,
7900 decoded30: u2 = 0b01,
7901 };
7902
7903 /// C7.2.169 FRSQRTE
7904 pub const Frsqrte = packed struct {
7905 Rd: Register.Encoded,
7906 Rn: Register.Encoded,
7907 decoded10: u2 = 0b10,
7908 opcode: u5 = 0b11101,
7909 decoded17: u5 = 0b10000,
7910 sz: Sz,
7911 o2: u1 = 0b1,
7912 decoded24: u5 = 0b11110,
7913 U: std.builtin.Signedness = .unsigned,
7914 decoded30: u2 = 0b01,
7915 };
7916 };
7917
7918 /// Advanced SIMD scalar pairwise
7919 pub const SimdScalarPairwise = packed union {
7920 group: @This().Group,
7921 addp: Addp,
7922
7923 pub const Group = packed struct {
7924 Rd: Register.Encoded,
7925 Rn: Register.Encoded,
7926 decoded10: u2 = 0b10,
7927 opcode: u5,
7928 decoded17: u5 = 0b11000,
7929 size: Size,
7930 decoded24: u5 = 0b11110,
7931 U: std.builtin.Signedness,
7932 decoded30: u2 = 0b01,
7933 };
7934
7935 /// C7.2.4 ADDP (scalar)
7936 pub const Addp = packed struct {
7937 Rd: Register.Encoded,
7938 Rn: Register.Encoded,
7939 decoded10: u2 = 0b10,
7940 opcode: u5 = 0b11011,
7941 decoded17: u5 = 0b11000,
7942 size: Size,
7943 decoded24: u5 = 0b11110,
7944 U: std.builtin.Signedness = .signed,
7945 decoded30: u2 = 0b01,
7946 };
7947 };
7948
7949 /// Advanced SIMD copy
7950 pub const SimdCopy = packed union {
7951 group: @This().Group,
7952 dup: Dup,
7953 smov: Smov,
7954 umov: Umov,
7955 ins: Ins,
7956
7957 pub const Group = packed struct {
7958 Rd: Register.Encoded,
7959 Rn: Register.Encoded,
7960 decoded10: u1 = 0b1,
7961 imm4: u4,
7962 decoded15: u1 = 0b0,
7963 imm5: u5,
7964 decoded21: u8 = 0b01110000,
7965 op: u1,
7966 Q: u1,
7967 decoded31: u1 = 0b0,
7968 };
7969
7970 /// C7.2.39 DUP (element)
7971 /// C7.2.40 DUP (general)
7972 pub const Dup = packed struct {
7973 Rd: Register.Encoded,
7974 Rn: Register.Encoded,
7975 decoded10: u1 = 0b1,
7976 imm4: Imm4,
7977 decoded15: u1 = 0b0,
7978 imm5: u5,
7979 decoded21: u8 = 0b01110000,
7980 op: u1 = 0b0,
7981 Q: Q,
7982 decoded31: u1 = 0b0,
7983
7984 pub const Imm4 = enum(u4) {
7985 element = 0b0000,
7986 general = 0b0001,
7987 _,
7988 };
7989 };
7990
7991 /// C7.2.279 SMOV
7992 pub const Smov = packed struct {
7993 Rd: Register.Encoded,
7994 Rn: Register.Encoded,
7995 decoded10: u1 = 0b1,
7996 imm4: u4 = 0b0101,
7997 decoded15: u1 = 0b0,
7998 imm5: u5,
7999 decoded21: u8 = 0b01110000,
8000 op: u1 = 0b0,
8001 Q: Register.IntegerSize,
8002 decoded31: u1 = 0b0,
8003 };
8004
8005 /// C7.2.371 UMOV
8006 pub const Umov = packed struct {
8007 Rd: Register.Encoded,
8008 Rn: Register.Encoded,
8009 decoded10: u1 = 0b1,
8010 imm4: u4 = 0b0111,
8011 decoded15: u1 = 0b0,
8012 imm5: u5,
8013 decoded21: u8 = 0b01110000,
8014 op: u1 = 0b0,
8015 Q: Register.IntegerSize,
8016 decoded31: u1 = 0b0,
8017 };
8018
8019 /// C7.2.175 INS (element)
8020 /// C7.2.176 INS (general)
8021 pub const Ins = packed struct {
8022 Rd: Register.Encoded,
8023 Rn: Register.Encoded,
8024 decoded10: u1 = 0b1,
8025 imm4: Imm4,
8026 decoded15: u1 = 0b0,
8027 imm5: u5,
8028 decoded21: u8 = 0b01110000,
8029 op: Op,
8030 Q: u1 = 0b1,
8031 decoded31: u1 = 0b0,
8032
8033 pub const Imm4 = packed union {
8034 general: General,
8035 element: u4,
8036
8037 pub const General = enum(u4) {
8038 general = 0b0011,
8039 _,
8040 };
8041 };
8042
8043 pub const Op = enum(u1) {
8044 general = 0b0,
8045 element = 0b1,
8046 };
8047 };
8048
8049 pub const Decoded = union(enum) {
8050 unallocated,
8051 dup: Dup,
8052 smov: Smov,
8053 umov: Umov,
8054 ins: Ins,
8055 };
8056 pub fn decode(inst: @This()) @This().Decoded {
8057 return switch (inst.group.op) {
8058 0b0 => switch (inst.group.imm4) {
8059 0b0000, 0b0001 => .{ .dup = inst.dup },
8060 else => .unallocated,
8061 0b0101 => switch (@ctz(inst.group.imm5)) {
8062 0, 1 => .{ .smov = inst.smov },
8063 2 => switch (inst.group.Q) {
8064 0b1 => .{ .smov = inst.smov },
8065 0b0 => .unallocated,
8066 },
8067 else => .unallocated,
8068 },
8069 0b0111 => switch (@ctz(inst.group.imm5)) {
8070 0, 1, 2 => switch (inst.group.Q) {
8071 0b0 => .{ .umov = inst.umov },
8072 0b1 => .unallocated,
8073 },
8074 3 => switch (inst.group.Q) {
8075 0b1 => .{ .umov = inst.umov },
8076 0b0 => .unallocated,
8077 },
8078 else => .unallocated,
8079 },
8080 },
8081 0b1 => switch (inst.group.Q) {
8082 0b0 => .unallocated,
8083 0b1 => .{ .ins = inst.ins },
8084 },
8085 };
8086 }
8087 };
8088
8089 /// Advanced SIMD two-register miscellaneous (FP16)
8090 pub const SimdTwoRegisterMiscellaneousFp16 = packed union {
8091 group: @This().Group,
8092 frintn: Frintn,
8093 frintm: Frintm,
8094 fcvtns: Fcvtns,
8095 fcvtms: Fcvtms,
8096 fcvtas: Fcvtas,
8097 scvtf: Scvtf,
8098 fcmgt: Fcmgt,
8099 fcmeq: Fcmeq,
8100 fcmlt: Fcmlt,
8101 fabs: Fabs,
8102 frintp: Frintp,
8103 frintz: Frintz,
8104 fcvtps: Fcvtps,
8105 fcvtzs: Fcvtzs,
8106 frecpe: Frecpe,
8107 frinta: Frinta,
8108 frintx: Frintx,
8109 fcvtnu: Fcvtnu,
8110 fcvtmu: Fcvtmu,
8111 fcvtau: Fcvtau,
8112 ucvtf: Ucvtf,
8113 fcmge: Fcmge,
8114 fcmle: Fcmle,
8115 fneg: Fneg,
8116 frinti: Frinti,
8117 fcvtpu: Fcvtpu,
8118 fcvtzu: Fcvtzu,
8119 frsqrte: Frsqrte,
8120 fsqrt: Fsqrt,
8121
8122 pub const Group = packed struct {
8123 Rd: Register.Encoded,
8124 Rn: Register.Encoded,
8125 decoded10: u2 = 0b10,
8126 opcode: u5,
8127 decoded17: u6 = 0b111100,
8128 a: u1,
8129 decoded24: u5 = 0b01110,
8130 U: std.builtin.Signedness,
8131 Q: Q,
8132 decoded31: u1 = 0b0,
8133 };
8134
8135 /// C7.2.161 FRINTN (vector)
8136 pub const Frintn = packed struct {
8137 Rd: Register.Encoded,
8138 Rn: Register.Encoded,
8139 decoded10: u2 = 0b10,
8140 opcode: u5 = 0b11000,
8141 decoded17: u6 = 0b111100,
8142 o2: u1 = 0b0,
8143 decoded24: u5 = 0b01110,
8144 U: std.builtin.Signedness = .signed,
8145 Q: Q,
8146 decoded31: u1 = 0b0,
8147 };
8148
8149 /// C7.2.159 FRINTM (vector)
8150 pub const Frintm = packed struct {
8151 Rd: Register.Encoded,
8152 Rn: Register.Encoded,
8153 decoded10: u2 = 0b10,
8154 opcode: u5 = 0b11001,
8155 decoded17: u6 = 0b111100,
8156 o2: u1 = 0b0,
8157 decoded24: u5 = 0b01110,
8158 U: std.builtin.Signedness = .signed,
8159 Q: Q,
8160 decoded31: u1 = 0b0,
8161 };
8162
8163 /// C7.2.80 FCVTNS (vector)
8164 pub const Fcvtns = packed struct {
8165 Rd: Register.Encoded,
8166 Rn: Register.Encoded,
8167 decoded10: u2 = 0b10,
8168 opcode: u5 = 0b11010,
8169 decoded17: u6 = 0b111100,
8170 o2: u1 = 0b0,
8171 decoded24: u5 = 0b01110,
8172 U: std.builtin.Signedness = .signed,
8173 Q: Q,
8174 decoded31: u1 = 0b0,
8175 };
8176
8177 /// C7.2.75 FCVTMS (vector)
8178 pub const Fcvtms = packed struct {
8179 Rd: Register.Encoded,
8180 Rn: Register.Encoded,
8181 decoded10: u2 = 0b10,
8182 opcode: u5 = 0b11011,
8183 decoded17: u6 = 0b111100,
8184 o2: u1 = 0b0,
8185 decoded24: u5 = 0b01110,
8186 U: std.builtin.Signedness = .signed,
8187 Q: Q,
8188 decoded31: u1 = 0b0,
8189 };
8190
8191 /// C7.2.70 FCVTAS (vector)
8192 pub const Fcvtas = packed struct {
8193 Rd: Register.Encoded,
8194 Rn: Register.Encoded,
8195 decoded10: u2 = 0b10,
8196 opcode: u5 = 0b11100,
8197 decoded17: u6 = 0b111100,
8198 o2: u1 = 0b0,
8199 decoded24: u5 = 0b01110,
8200 U: std.builtin.Signedness = .signed,
8201 Q: Q,
8202 decoded31: u1 = 0b0,
8203 };
8204
8205 /// C7.2.234 SCVTF (vector, integer)
8206 pub const Scvtf = packed struct {
8207 Rd: Register.Encoded,
8208 Rn: Register.Encoded,
8209 decoded10: u2 = 0b10,
8210 opcode: u5 = 0b11101,
8211 decoded17: u6 = 0b111100,
8212 o2: u1 = 0b0,
8213 decoded24: u5 = 0b01110,
8214 U: std.builtin.Signedness = .signed,
8215 Q: Q,
8216 decoded31: u1 = 0b0,
8217 };
8218
8219 /// C7.2.61 FCMGT (zero)
8220 pub const Fcmgt = packed struct {
8221 Rd: Register.Encoded,
8222 Rn: Register.Encoded,
8223 decoded10: u2 = 0b10,
8224 opcode: u5 = 0b01100,
8225 decoded17: u6 = 0b111100,
8226 o2: u1 = 0b1,
8227 decoded24: u5 = 0b01110,
8228 U: std.builtin.Signedness = .signed,
8229 Q: Q,
8230 decoded31: u1 = 0b0,
8231 };
8232
8233 /// C7.2.57 FCMEQ (zero)
8234 pub const Fcmeq = packed struct {
8235 Rd: Register.Encoded,
8236 Rn: Register.Encoded,
8237 decoded10: u2 = 0b10,
8238 opcode: u5 = 0b01101,
8239 decoded17: u6 = 0b111100,
8240 o2: u1 = 0b1,
8241 decoded24: u5 = 0b01110,
8242 U: std.builtin.Signedness = .signed,
8243 Q: Q,
8244 decoded31: u1 = 0b0,
8245 };
8246
8247 /// C7.2.65 FCMLT (zero)
8248 pub const Fcmlt = packed struct {
8249 Rd: Register.Encoded,
8250 Rn: Register.Encoded,
8251 decoded10: u2 = 0b10,
8252 opcode: u5 = 0b01110,
8253 decoded17: u6 = 0b111100,
8254 o2: u1 = 0b1,
8255 decoded24: u5 = 0b01110,
8256 U: std.builtin.Signedness = .signed,
8257 Q: Q,
8258 decoded31: u1 = 0b0,
8259 };
8260
8261 /// C7.2.45 FABS (vector)
8262 pub const Fabs = packed struct {
8263 Rd: Register.Encoded,
8264 Rn: Register.Encoded,
8265 decoded10: u2 = 0b10,
8266 opcode: u5 = 0b01111,
8267 decoded17: u6 = 0b111100,
8268 o2: u1 = 0b1,
8269 decoded24: u5 = 0b01110,
8270 U: std.builtin.Signedness = .signed,
8271 Q: Q,
8272 decoded31: u1 = 0b0,
8273 };
8274
8275 /// C7.2.163 FRINTP (vector)
8276 pub const Frintp = packed struct {
8277 Rd: Register.Encoded,
8278 Rn: Register.Encoded,
8279 decoded10: u2 = 0b10,
8280 opcode: u5 = 0b11000,
8281 decoded17: u6 = 0b111100,
8282 o2: u1 = 0b1,
8283 decoded24: u5 = 0b01110,
8284 U: std.builtin.Signedness = .signed,
8285 Q: Q,
8286 decoded31: u1 = 0b0,
8287 };
8288
8289 /// C7.2.167 FRINTZ (vector)
8290 pub const Frintz = packed struct {
8291 Rd: Register.Encoded,
8292 Rn: Register.Encoded,
8293 decoded10: u2 = 0b10,
8294 opcode: u5 = 0b11001,
8295 decoded17: u6 = 0b111100,
8296 o2: u1 = 0b1,
8297 decoded24: u5 = 0b01110,
8298 U: std.builtin.Signedness = .signed,
8299 Q: Q,
8300 decoded31: u1 = 0b0,
8301 };
8302
8303 /// C7.2.84 FCVTPS (vector)
8304 pub const Fcvtps = packed struct {
8305 Rd: Register.Encoded,
8306 Rn: Register.Encoded,
8307 decoded10: u2 = 0b10,
8308 opcode: u5 = 0b11010,
8309 decoded17: u6 = 0b111100,
8310 o2: u1 = 0b1,
8311 decoded24: u5 = 0b01110,
8312 U: std.builtin.Signedness = .signed,
8313 Q: Q,
8314 decoded31: u1 = 0b0,
8315 };
8316
8317 /// C7.2.90 FCVTZS (vector, integer)
8318 pub const Fcvtzs = packed struct {
8319 Rd: Register.Encoded,
8320 Rn: Register.Encoded,
8321 decoded10: u2 = 0b10,
8322 opcode: u5 = 0b11011,
8323 decoded17: u6 = 0b111100,
8324 o2: u1 = 0b1,
8325 decoded24: u5 = 0b01110,
8326 U: std.builtin.Signedness = .signed,
8327 Q: Q,
8328 decoded31: u1 = 0b0,
8329 };
8330
8331 /// C7.2.144 FRECPE
8332 pub const Frecpe = packed struct {
8333 Rd: Register.Encoded,
8334 Rn: Register.Encoded,
8335 decoded10: u2 = 0b10,
8336 opcode: u5 = 0b11101,
8337 decoded17: u6 = 0b111100,
8338 o2: u1 = 0b1,
8339 decoded24: u5 = 0b01110,
8340 U: std.builtin.Signedness = .signed,
8341 Q: Q,
8342 decoded31: u1 = 0b0,
8343 };
8344
8345 /// C7.2.155 FRINTA (vector)
8346 pub const Frinta = packed struct {
8347 Rd: Register.Encoded,
8348 Rn: Register.Encoded,
8349 decoded10: u2 = 0b10,
8350 opcode: u5 = 0b11000,
8351 decoded17: u6 = 0b111100,
8352 o2: u1 = 0b0,
8353 decoded24: u5 = 0b01110,
8354 U: std.builtin.Signedness = .unsigned,
8355 Q: Q,
8356 decoded31: u1 = 0b0,
8357 };
8358
8359 /// C7.2.159 FRINTX (vector)
8360 pub const Frintx = packed struct {
8361 Rd: Register.Encoded,
8362 Rn: Register.Encoded,
8363 decoded10: u2 = 0b10,
8364 opcode: u5 = 0b11001,
8365 decoded17: u6 = 0b111100,
8366 o2: u1 = 0b0,
8367 decoded24: u5 = 0b01110,
8368 U: std.builtin.Signedness = .unsigned,
8369 Q: Q,
8370 decoded31: u1 = 0b0,
8371 };
8372
8373 /// C7.2.82 FCVTNU (vector)
8374 pub const Fcvtnu = packed struct {
8375 Rd: Register.Encoded,
8376 Rn: Register.Encoded,
8377 decoded10: u2 = 0b10,
8378 opcode: u5 = 0b11010,
8379 decoded17: u6 = 0b111100,
8380 o2: u1 = 0b0,
8381 decoded24: u5 = 0b01110,
8382 U: std.builtin.Signedness = .unsigned,
8383 Q: Q,
8384 decoded31: u1 = 0b0,
8385 };
8386
8387 /// C7.2.77 FCVTMU (vector)
8388 pub const Fcvtmu = packed struct {
8389 Rd: Register.Encoded,
8390 Rn: Register.Encoded,
8391 decoded10: u2 = 0b10,
8392 opcode: u5 = 0b11011,
8393 decoded17: u6 = 0b111100,
8394 o2: u1 = 0b0,
8395 decoded24: u5 = 0b01110,
8396 U: std.builtin.Signedness = .unsigned,
8397 Q: Q,
8398 decoded31: u1 = 0b0,
8399 };
8400
8401 /// C7.2.72 FCVTAU (vector)
8402 pub const Fcvtau = packed struct {
8403 Rd: Register.Encoded,
8404 Rn: Register.Encoded,
8405 decoded10: u2 = 0b10,
8406 opcode: u5 = 0b11100,
8407 decoded17: u6 = 0b111100,
8408 o2: u1 = 0b0,
8409 decoded24: u5 = 0b01110,
8410 U: std.builtin.Signedness = .unsigned,
8411 Q: Q,
8412 decoded31: u1 = 0b0,
8413 };
8414
8415 /// C7.2.353 UCVTF (vector, integer)
8416 pub const Ucvtf = packed struct {
8417 Rd: Register.Encoded,
8418 Rn: Register.Encoded,
8419 decoded10: u2 = 0b10,
8420 opcode: u5 = 0b11101,
8421 decoded17: u6 = 0b111100,
8422 o2: u1 = 0b0,
8423 decoded24: u5 = 0b01110,
8424 U: std.builtin.Signedness = .unsigned,
8425 Q: Q,
8426 decoded31: u1 = 0b0,
8427 };
8428
8429 /// C7.2.59 FCMGE (zero)
8430 pub const Fcmge = packed struct {
8431 Rd: Register.Encoded,
8432 Rn: Register.Encoded,
8433 decoded10: u2 = 0b10,
8434 opcode: u5 = 0b01100,
8435 decoded17: u6 = 0b111100,
8436 o2: u1 = 0b1,
8437 decoded24: u5 = 0b01110,
8438 U: std.builtin.Signedness = .unsigned,
8439 Q: Q,
8440 decoded31: u1 = 0b0,
8441 };
8442
8443 /// C7.2.64 FCMLE (zero)
8444 pub const Fcmle = packed struct {
8445 Rd: Register.Encoded,
8446 Rn: Register.Encoded,
8447 decoded10: u2 = 0b10,
8448 opcode: u5 = 0b01101,
8449 decoded17: u6 = 0b111100,
8450 o2: u1 = 0b1,
8451 decoded24: u5 = 0b01110,
8452 U: std.builtin.Signedness = .unsigned,
8453 Q: Q,
8454 decoded31: u1 = 0b0,
8455 };
8456
8457 /// C7.2.139 FNEG (vector)
8458 pub const Fneg = packed struct {
8459 Rd: Register.Encoded,
8460 Rn: Register.Encoded,
8461 decoded10: u2 = 0b10,
8462 opcode: u5 = 0b01111,
8463 decoded17: u6 = 0b111100,
8464 o2: u1 = 0b1,
8465 decoded24: u5 = 0b01110,
8466 U: std.builtin.Signedness = .unsigned,
8467 Q: Q,
8468 decoded31: u1 = 0b0,
8469 };
8470
8471 /// C7.2.157 FRINTI (vector)
8472 pub const Frinti = packed struct {
8473 Rd: Register.Encoded,
8474 Rn: Register.Encoded,
8475 decoded10: u2 = 0b10,
8476 opcode: u5 = 0b11001,
8477 decoded17: u6 = 0b111100,
8478 o2: u1 = 0b1,
8479 decoded24: u5 = 0b01110,
8480 U: std.builtin.Signedness = .unsigned,
8481 Q: Q,
8482 decoded31: u1 = 0b0,
8483 };
8484
8485 /// C7.2.86 FCVTPU (vector)
8486 pub const Fcvtpu = packed struct {
8487 Rd: Register.Encoded,
8488 Rn: Register.Encoded,
8489 decoded10: u2 = 0b10,
8490 opcode: u5 = 0b11010,
8491 decoded17: u6 = 0b111100,
8492 o2: u1 = 0b1,
8493 decoded24: u5 = 0b01110,
8494 U: std.builtin.Signedness = .unsigned,
8495 Q: Q,
8496 decoded31: u1 = 0b0,
8497 };
8498
8499 /// C7.2.94 FCVTZU (vector, integer)
8500 pub const Fcvtzu = packed struct {
8501 Rd: Register.Encoded,
8502 Rn: Register.Encoded,
8503 decoded10: u2 = 0b10,
8504 opcode: u5 = 0b11011,
8505 decoded17: u6 = 0b111100,
8506 o2: u1 = 0b1,
8507 decoded24: u5 = 0b01110,
8508 U: std.builtin.Signedness = .unsigned,
8509 Q: Q,
8510 decoded31: u1 = 0b0,
8511 };
8512
8513 /// C7.2.169 FRSQRTE
8514 pub const Frsqrte = packed struct {
8515 Rd: Register.Encoded,
8516 Rn: Register.Encoded,
8517 decoded10: u2 = 0b10,
8518 opcode: u5 = 0b11101,
8519 decoded17: u6 = 0b111100,
8520 o2: u1 = 0b1,
8521 decoded24: u5 = 0b01110,
8522 U: std.builtin.Signedness = .unsigned,
8523 Q: Q,
8524 decoded31: u1 = 0b0,
8525 };
8526
8527 /// C7.2.171 FSQRT
8528 pub const Fsqrt = packed struct {
8529 Rd: Register.Encoded,
8530 Rn: Register.Encoded,
8531 decoded10: u2 = 0b10,
8532 opcode: u5 = 0b11111,
8533 decoded17: u6 = 0b111100,
8534 o2: u1 = 0b1,
8535 decoded24: u5 = 0b01110,
8536 U: std.builtin.Signedness = .unsigned,
8537 Q: Q,
8538 decoded31: u1 = 0b0,
8539 };
8540 };
8541
8542 /// Advanced SIMD two-register miscellaneous
8543 pub const SimdTwoRegisterMiscellaneous = packed union {
8544 group: @This().Group,
8545 suqadd: Suqadd,
8546 cnt: Cnt,
8547 sqabs: Sqabs,
8548 cmgt: Cmgt,
8549 cmeq: Cmeq,
8550 cmlt: Cmlt,
8551 abs: Abs,
8552 sqxtn: Sqxtn,
8553 frintn: Frintn,
8554 frintm: Frintm,
8555 fcvtns: Fcvtns,
8556 fcvtms: Fcvtms,
8557 fcvtas: Fcvtas,
8558 scvtf: Scvtf,
8559 fcmgt: Fcmgt,
8560 fcmeq: Fcmeq,
8561 fcmlt: Fcmlt,
8562 fabs: Fabs,
8563 frintp: Frintp,
8564 frintz: Frintz,
8565 fcvtps: Fcvtps,
8566 fcvtzs: Fcvtzs,
8567 frecpe: Frecpe,
8568 usqadd: Usqadd,
8569 sqneg: Sqneg,
8570 cmge: Cmge,
8571 cmle: Cmle,
8572 neg: Neg,
8573 sqxtun: Sqxtun,
8574 uqxtn: Uqxtn,
8575 fcvtxn: Fcvtxn,
8576 frinta: Frinta,
8577 frintx: Frintx,
8578 fcvtnu: Fcvtnu,
8579 fcvtmu: Fcvtmu,
8580 fcvtau: Fcvtau,
8581 ucvtf: Ucvtf,
8582 not: Not,
8583 fcmge: Fcmge,
8584 fcmle: Fcmle,
8585 fneg: Fneg,
8586 frinti: Frinti,
8587 fcvtpu: Fcvtpu,
8588 fcvtzu: Fcvtzu,
8589 frsqrte: Frsqrte,
8590 fsqrt: Fsqrt,
8591
8592 pub const Group = packed struct {
8593 Rd: Register.Encoded,
8594 Rn: Register.Encoded,
8595 decoded10: u2 = 0b10,
8596 opcode: u5,
8597 decoded17: u5 = 0b10000,
8598 size: Size,
8599 decoded24: u5 = 0b01110,
8600 U: std.builtin.Signedness,
8601 Q: Q,
8602 decoded31: u1 = 0b0,
8603 };
8604
8605 /// C7.2.337 SUQADD
8606 pub const Suqadd = packed struct {
8607 Rd: Register.Encoded,
8608 Rn: Register.Encoded,
8609 decoded10: u2 = 0b10,
8610 opcode: u5 = 0b00011,
8611 decoded17: u5 = 0b10000,
8612 size: Size,
8613 decoded24: u5 = 0b01110,
8614 U: std.builtin.Signedness = .signed,
8615 Q: Q,
8616 decoded31: u1 = 0b0,
8617 };
8618
8619 /// C7.2.38 CNT
8620 pub const Cnt = packed struct {
8621 Rd: Register.Encoded,
8622 Rn: Register.Encoded,
8623 decoded10: u2 = 0b10,
8624 opcode: u5 = 0b00101,
8625 decoded17: u5 = 0b10000,
8626 size: Size,
8627 decoded24: u5 = 0b01110,
8628 U: std.builtin.Signedness = .signed,
8629 Q: Q,
8630 decoded31: u1 = 0b0,
8631 };
8632
8633 /// C7.2.282 SQABS
8634 pub const Sqabs = packed struct {
8635 Rd: Register.Encoded,
8636 Rn: Register.Encoded,
8637 decoded10: u2 = 0b10,
8638 opcode: u5 = 0b00111,
8639 decoded17: u5 = 0b10000,
8640 size: Size,
8641 decoded24: u5 = 0b01110,
8642 U: std.builtin.Signedness = .signed,
8643 Q: Q,
8644 decoded31: u1 = 0b0,
8645 };
8646
8647 /// C7.2.32 CMGT (zero)
8648 pub const Cmgt = packed struct {
8649 Rd: Register.Encoded,
8650 Rn: Register.Encoded,
8651 decoded10: u2 = 0b10,
8652 opcode: u5 = 0b01000,
8653 decoded17: u5 = 0b10000,
8654 size: Size,
8655 decoded24: u5 = 0b01110,
8656 U: std.builtin.Signedness = .signed,
8657 Q: Q,
8658 decoded31: u1 = 0b0,
8659 };
8660
8661 /// C7.2.28 CMEQ (zero)
8662 pub const Cmeq = packed struct {
8663 Rd: Register.Encoded,
8664 Rn: Register.Encoded,
8665 decoded10: u2 = 0b10,
8666 opcode: u5 = 0b01001,
8667 decoded17: u5 = 0b10000,
8668 size: Size,
8669 decoded24: u5 = 0b01110,
8670 U: std.builtin.Signedness = .signed,
8671 Q: Q,
8672 decoded31: u1 = 0b0,
8673 };
8674
8675 /// C7.2.36 CMLT (zero)
8676 pub const Cmlt = packed struct {
8677 Rd: Register.Encoded,
8678 Rn: Register.Encoded,
8679 decoded10: u2 = 0b10,
8680 opcode: u5 = 0b01010,
8681 decoded17: u5 = 0b10000,
8682 size: Size,
8683 decoded24: u5 = 0b01110,
8684 U: std.builtin.Signedness = .signed,
8685 Q: Q,
8686 decoded31: u1 = 0b0,
8687 };
8688
8689 /// C7.2.1 ABS
8690 pub const Abs = packed struct {
8691 Rd: Register.Encoded,
8692 Rn: Register.Encoded,
8693 decoded10: u2 = 0b10,
8694 opcode: u5 = 0b01011,
8695 decoded17: u5 = 0b10000,
8696 size: Size,
8697 decoded24: u5 = 0b01110,
8698 U: std.builtin.Signedness = .signed,
8699 Q: Q,
8700 decoded31: u1 = 0b0,
8701 };
8702
8703 /// C7.2.308 SQXTN
8704 pub const Sqxtn = packed struct {
8705 Rd: Register.Encoded,
8706 Rn: Register.Encoded,
8707 decoded10: u2 = 0b10,
8708 opcode: u5 = 0b10100,
8709 decoded17: u5 = 0b10000,
8710 size: Size,
8711 decoded24: u5 = 0b01110,
8712 U: std.builtin.Signedness = .signed,
8713 Q: Q,
8714 decoded31: u1 = 0b0,
8715 };
8716
8717 /// C7.2.161 FRINTN (vector)
8718 pub const Frintn = packed struct {
8719 Rd: Register.Encoded,
8720 Rn: Register.Encoded,
8721 decoded10: u2 = 0b10,
8722 opcode: u5 = 0b11000,
8723 decoded17: u5 = 0b10000,
8724 sz: Sz,
8725 o2: u1 = 0b0,
8726 decoded24: u5 = 0b01110,
8727 U: std.builtin.Signedness = .signed,
8728 Q: Q,
8729 decoded31: u1 = 0b0,
8730 };
8731
8732 /// C7.2.159 FRINTM (vector)
8733 pub const Frintm = packed struct {
8734 Rd: Register.Encoded,
8735 Rn: Register.Encoded,
8736 decoded10: u2 = 0b10,
8737 opcode: u5 = 0b11001,
8738 decoded17: u5 = 0b10000,
8739 sz: Sz,
8740 o2: u1 = 0b0,
8741 decoded24: u5 = 0b01110,
8742 U: std.builtin.Signedness = .signed,
8743 Q: Q,
8744 decoded31: u1 = 0b0,
8745 };
8746
8747 /// C7.2.80 FCVTNS (vector)
8748 pub const Fcvtns = packed struct {
8749 Rd: Register.Encoded,
8750 Rn: Register.Encoded,
8751 decoded10: u2 = 0b10,
8752 opcode: u5 = 0b11010,
8753 decoded17: u5 = 0b10000,
8754 sz: Sz,
8755 o2: u1 = 0b0,
8756 decoded24: u5 = 0b01110,
8757 U: std.builtin.Signedness = .signed,
8758 Q: Q,
8759 decoded31: u1 = 0b0,
8760 };
8761
8762 /// C7.2.75 FCVTMS (vector)
8763 pub const Fcvtms = packed struct {
8764 Rd: Register.Encoded,
8765 Rn: Register.Encoded,
8766 decoded10: u2 = 0b10,
8767 opcode: u5 = 0b11011,
8768 decoded17: u5 = 0b10000,
8769 sz: Sz,
8770 o2: u1 = 0b0,
8771 decoded24: u5 = 0b01110,
8772 U: std.builtin.Signedness = .signed,
8773 Q: Q,
8774 decoded31: u1 = 0b0,
8775 };
8776
8777 /// C7.2.70 FCVTAS (vector)
8778 pub const Fcvtas = packed struct {
8779 Rd: Register.Encoded,
8780 Rn: Register.Encoded,
8781 decoded10: u2 = 0b10,
8782 opcode: u5 = 0b11100,
8783 decoded17: u5 = 0b10000,
8784 sz: Sz,
8785 o2: u1 = 0b0,
8786 decoded24: u5 = 0b01110,
8787 U: std.builtin.Signedness = .signed,
8788 Q: Q,
8789 decoded31: u1 = 0b0,
8790 };
8791
8792 /// C7.2.234 SCVTF (vector, integer)
8793 pub const Scvtf = packed struct {
8794 Rd: Register.Encoded,
8795 Rn: Register.Encoded,
8796 decoded10: u2 = 0b10,
8797 opcode: u5 = 0b11101,
8798 decoded17: u5 = 0b10000,
8799 sz: Sz,
8800 o2: u1 = 0b0,
8801 decoded24: u5 = 0b01110,
8802 U: std.builtin.Signedness = .signed,
8803 Q: Q,
8804 decoded31: u1 = 0b0,
8805 };
8806
8807 /// C7.2.61 FCMGT (zero)
8808 pub const Fcmgt = packed struct {
8809 Rd: Register.Encoded,
8810 Rn: Register.Encoded,
8811 decoded10: u2 = 0b10,
8812 opcode: u5 = 0b01100,
8813 decoded17: u5 = 0b10000,
8814 sz: Sz,
8815 o2: u1 = 0b1,
8816 decoded24: u5 = 0b01110,
8817 U: std.builtin.Signedness = .signed,
8818 Q: Q,
8819 decoded31: u1 = 0b0,
8820 };
8821
8822 /// C7.2.57 FCMEQ (zero)
8823 pub const Fcmeq = packed struct {
8824 Rd: Register.Encoded,
8825 Rn: Register.Encoded,
8826 decoded10: u2 = 0b10,
8827 opcode: u5 = 0b01101,
8828 decoded17: u5 = 0b10000,
8829 sz: Sz,
8830 o2: u1 = 0b1,
8831 decoded24: u5 = 0b01110,
8832 U: std.builtin.Signedness = .signed,
8833 Q: Q,
8834 decoded31: u1 = 0b0,
8835 };
8836
8837 /// C7.2.65 FCMLT (zero)
8838 pub const Fcmlt = packed struct {
8839 Rd: Register.Encoded,
8840 Rn: Register.Encoded,
8841 decoded10: u2 = 0b10,
8842 opcode: u5 = 0b01110,
8843 decoded17: u5 = 0b10000,
8844 sz: Sz,
8845 o2: u1 = 0b1,
8846 decoded24: u5 = 0b01110,
8847 U: std.builtin.Signedness = .signed,
8848 Q: Q,
8849 decoded31: u1 = 0b0,
8850 };
8851
8852 /// C7.2.45 FABS (vector)
8853 pub const Fabs = packed struct {
8854 Rd: Register.Encoded,
8855 Rn: Register.Encoded,
8856 decoded10: u2 = 0b10,
8857 opcode: u5 = 0b01111,
8858 decoded17: u5 = 0b10000,
8859 sz: Sz,
8860 o2: u1 = 0b1,
8861 decoded24: u5 = 0b01110,
8862 U: std.builtin.Signedness = .signed,
8863 Q: Q,
8864 decoded31: u1 = 0b0,
8865 };
8866
8867 /// C7.2.163 FRINTP (vector)
8868 pub const Frintp = packed struct {
8869 Rd: Register.Encoded,
8870 Rn: Register.Encoded,
8871 decoded10: u2 = 0b10,
8872 opcode: u5 = 0b11000,
8873 decoded17: u5 = 0b10000,
8874 sz: Sz,
8875 o2: u1 = 0b1,
8876 decoded24: u5 = 0b01110,
8877 U: std.builtin.Signedness = .signed,
8878 Q: Q,
8879 decoded31: u1 = 0b0,
8880 };
8881
8882 /// C7.2.167 FRINTZ (vector)
8883 pub const Frintz = packed struct {
8884 Rd: Register.Encoded,
8885 Rn: Register.Encoded,
8886 decoded10: u2 = 0b10,
8887 opcode: u5 = 0b11001,
8888 decoded17: u5 = 0b10000,
8889 sz: Sz,
8890 o2: u1 = 0b1,
8891 decoded24: u5 = 0b01110,
8892 U: std.builtin.Signedness = .signed,
8893 Q: Q,
8894 decoded31: u1 = 0b0,
8895 };
8896
8897 /// C7.2.84 FCVTPS (vector)
8898 pub const Fcvtps = packed struct {
8899 Rd: Register.Encoded,
8900 Rn: Register.Encoded,
8901 decoded10: u2 = 0b10,
8902 opcode: u5 = 0b11010,
8903 decoded17: u5 = 0b10000,
8904 sz: Sz,
8905 o2: u1 = 0b1,
8906 decoded24: u5 = 0b01110,
8907 U: std.builtin.Signedness = .signed,
8908 Q: Q,
8909 decoded31: u1 = 0b0,
8910 };
8911
8912 /// C7.2.90 FCVTZS (vector, integer)
8913 pub const Fcvtzs = packed struct {
8914 Rd: Register.Encoded,
8915 Rn: Register.Encoded,
8916 decoded10: u2 = 0b10,
8917 opcode: u5 = 0b11011,
8918 decoded17: u5 = 0b10000,
8919 sz: Sz,
8920 o2: u1 = 0b1,
8921 decoded24: u5 = 0b01110,
8922 U: std.builtin.Signedness = .signed,
8923 Q: Q,
8924 decoded31: u1 = 0b0,
8925 };
8926
8927 /// C7.2.144 FRECPE
8928 pub const Frecpe = packed struct {
8929 Rd: Register.Encoded,
8930 Rn: Register.Encoded,
8931 decoded10: u2 = 0b10,
8932 opcode: u5 = 0b11101,
8933 decoded17: u5 = 0b10000,
8934 sz: Sz,
8935 o2: u1 = 0b1,
8936 decoded24: u5 = 0b01110,
8937 U: std.builtin.Signedness = .signed,
8938 Q: Q,
8939 decoded31: u1 = 0b0,
8940 };
8941
8942 /// C7.2.394 USQADD
8943 pub const Usqadd = packed struct {
8944 Rd: Register.Encoded,
8945 Rn: Register.Encoded,
8946 decoded10: u2 = 0b10,
8947 opcode: u5 = 0b00011,
8948 decoded17: u5 = 0b10000,
8949 size: Size,
8950 decoded24: u5 = 0b01110,
8951 U: std.builtin.Signedness = .unsigned,
8952 Q: Q,
8953 decoded31: u1 = 0b0,
8954 };
8955
8956 /// C7.2.292 SQNEG
8957 pub const Sqneg = packed struct {
8958 Rd: Register.Encoded,
8959 Rn: Register.Encoded,
8960 decoded10: u2 = 0b10,
8961 opcode: u5 = 0b00111,
8962 decoded17: u5 = 0b10000,
8963 size: Size,
8964 decoded24: u5 = 0b01110,
8965 U: std.builtin.Signedness = .unsigned,
8966 Q: Q,
8967 decoded31: u1 = 0b0,
8968 };
8969
8970 /// C7.2.30 CMGE (zero)
8971 pub const Cmge = packed struct {
8972 Rd: Register.Encoded,
8973 Rn: Register.Encoded,
8974 decoded10: u2 = 0b10,
8975 opcode: u5 = 0b01000,
8976 decoded17: u5 = 0b10000,
8977 size: Size,
8978 decoded24: u5 = 0b01110,
8979 U: std.builtin.Signedness = .unsigned,
8980 Q: Q,
8981 decoded31: u1 = 0b0,
8982 };
8983
8984 /// C7.2.35 CMLE (zero)
8985 pub const Cmle = packed struct {
8986 Rd: Register.Encoded,
8987 Rn: Register.Encoded,
8988 decoded10: u2 = 0b10,
8989 opcode: u5 = 0b01001,
8990 decoded17: u5 = 0b10000,
8991 size: Size,
8992 decoded24: u5 = 0b01110,
8993 U: std.builtin.Signedness = .unsigned,
8994 Q: Q,
8995 decoded31: u1 = 0b0,
8996 };
8997
8998 /// C7.2.209 NEG (vector)
8999 pub const Neg = packed struct {
9000 Rd: Register.Encoded,
9001 Rn: Register.Encoded,
9002 decoded10: u2 = 0b10,
9003 opcode: u5 = 0b01011,
9004 decoded17: u5 = 0b10000,
9005 size: Size,
9006 decoded24: u5 = 0b01110,
9007 U: std.builtin.Signedness = .unsigned,
9008 Q: Q,
9009 decoded31: u1 = 0b0,
9010 };
9011
9012 /// C7.2.309 SQXTUN
9013 pub const Sqxtun = packed struct {
9014 Rd: Register.Encoded,
9015 Rn: Register.Encoded,
9016 decoded10: u2 = 0b10,
9017 opcode: u5 = 0b10010,
9018 decoded17: u5 = 0b10000,
9019 size: Size,
9020 decoded24: u5 = 0b01110,
9021 U: std.builtin.Signedness = .unsigned,
9022 Q: Q,
9023 decoded31: u1 = 0b0,
9024 };
9025
9026 /// C7.2.381 UQXTN
9027 pub const Uqxtn = packed struct {
9028 Rd: Register.Encoded,
9029 Rn: Register.Encoded,
9030 decoded10: u2 = 0b10,
9031 opcode: u5 = 0b10100,
9032 decoded17: u5 = 0b10000,
9033 size: Size,
9034 decoded24: u5 = 0b01110,
9035 U: std.builtin.Signedness = .unsigned,
9036 Q: Q,
9037 decoded31: u1 = 0b0,
9038 };
9039
9040 /// C7.2.88 FCVTXN
9041 pub const Fcvtxn = packed struct {
9042 Rd: Register.Encoded,
9043 Rn: Register.Encoded,
9044 decoded10: u2 = 0b10,
9045 opcode: u5 = 0b10110,
9046 decoded17: u5 = 0b10000,
9047 sz: Sz,
9048 o2: u1 = 0b0,
9049 decoded24: u5 = 0b01110,
9050 U: std.builtin.Signedness = .unsigned,
9051 Q: Q,
9052 decoded31: u1 = 0b0,
9053 };
9054
9055 /// C7.2.155 FRINTA (vector)
9056 pub const Frinta = packed struct {
9057 Rd: Register.Encoded,
9058 Rn: Register.Encoded,
9059 decoded10: u2 = 0b10,
9060 opcode: u5 = 0b11000,
9061 decoded17: u5 = 0b10000,
9062 sz: Sz,
9063 o2: u1 = 0b0,
9064 decoded24: u5 = 0b01110,
9065 U: std.builtin.Signedness = .unsigned,
9066 Q: Q,
9067 decoded31: u1 = 0b0,
9068 };
9069
9070 /// C7.2.165 FRINTX (vector)
9071 pub const Frintx = packed struct {
9072 Rd: Register.Encoded,
9073 Rn: Register.Encoded,
9074 decoded10: u2 = 0b10,
9075 opcode: u5 = 0b11001,
9076 decoded17: u5 = 0b10000,
9077 sz: Sz,
9078 o2: u1 = 0b0,
9079 decoded24: u5 = 0b01110,
9080 U: std.builtin.Signedness = .unsigned,
9081 Q: Q,
9082 decoded31: u1 = 0b0,
9083 };
9084
9085 /// C7.2.82 FCVTNU (vector)
9086 pub const Fcvtnu = packed struct {
9087 Rd: Register.Encoded,
9088 Rn: Register.Encoded,
9089 decoded10: u2 = 0b10,
9090 opcode: u5 = 0b11010,
9091 decoded17: u5 = 0b10000,
9092 sz: Sz,
9093 o2: u1 = 0b0,
9094 decoded24: u5 = 0b01110,
9095 U: std.builtin.Signedness = .unsigned,
9096 Q: Q,
9097 decoded31: u1 = 0b0,
9098 };
9099
9100 /// C7.2.77 FCVTMU (vector)
9101 pub const Fcvtmu = packed struct {
9102 Rd: Register.Encoded,
9103 Rn: Register.Encoded,
9104 decoded10: u2 = 0b10,
9105 opcode: u5 = 0b11011,
9106 decoded17: u5 = 0b10000,
9107 sz: Sz,
9108 o2: u1 = 0b0,
9109 decoded24: u5 = 0b01110,
9110 U: std.builtin.Signedness = .unsigned,
9111 Q: Q,
9112 decoded31: u1 = 0b0,
9113 };
9114
9115 /// C7.2.72 FCVTAU (vector)
9116 pub const Fcvtau = packed struct {
9117 Rd: Register.Encoded,
9118 Rn: Register.Encoded,
9119 decoded10: u2 = 0b10,
9120 opcode: u5 = 0b11100,
9121 decoded17: u5 = 0b10000,
9122 sz: Sz,
9123 o2: u1 = 0b0,
9124 decoded24: u5 = 0b01110,
9125 U: std.builtin.Signedness = .unsigned,
9126 Q: Q,
9127 decoded31: u1 = 0b0,
9128 };
9129
9130 /// C7.2.353 UCVTF (vector, integer)
9131 pub const Ucvtf = packed struct {
9132 Rd: Register.Encoded,
9133 Rn: Register.Encoded,
9134 decoded10: u2 = 0b10,
9135 opcode: u5 = 0b11101,
9136 decoded17: u5 = 0b10000,
9137 sz: Sz,
9138 o2: u1 = 0b0,
9139 decoded24: u5 = 0b01110,
9140 U: std.builtin.Signedness = .unsigned,
9141 Q: Q,
9142 decoded31: u1 = 0b0,
9143 };
9144
9145 /// C7.2.210 NOT
9146 pub const Not = packed struct {
9147 Rd: Register.Encoded,
9148 Rn: Register.Encoded,
9149 decoded10: u2 = 0b10,
9150 opcode: u5 = 0b00101,
9151 decoded17: u5 = 0b10000,
9152 size: Size = .byte,
9153 decoded24: u5 = 0b01110,
9154 U: std.builtin.Signedness = .unsigned,
9155 Q: Q,
9156 decoded31: u1 = 0b0,
9157 };
9158
9159 /// C7.2.59 FCMGE (zero)
9160 pub const Fcmge = packed struct {
9161 Rd: Register.Encoded,
9162 Rn: Register.Encoded,
9163 decoded10: u2 = 0b10,
9164 opcode: u5 = 0b01100,
9165 decoded17: u5 = 0b10000,
9166 sz: Sz,
9167 o2: u1 = 0b1,
9168 decoded24: u5 = 0b01110,
9169 U: std.builtin.Signedness = .unsigned,
9170 Q: Q,
9171 decoded31: u1 = 0b0,
9172 };
9173
9174 /// C7.2.64 FCMLE (zero)
9175 pub const Fcmle = packed struct {
9176 Rd: Register.Encoded,
9177 Rn: Register.Encoded,
9178 decoded10: u2 = 0b10,
9179 opcode: u5 = 0b01101,
9180 decoded17: u5 = 0b10000,
9181 sz: Sz,
9182 o2: u1 = 0b1,
9183 decoded24: u5 = 0b01110,
9184 U: std.builtin.Signedness = .unsigned,
9185 Q: Q,
9186 decoded31: u1 = 0b0,
9187 };
9188
9189 /// C7.2.139 FNEG (vector)
9190 pub const Fneg = packed struct {
9191 Rd: Register.Encoded,
9192 Rn: Register.Encoded,
9193 decoded10: u2 = 0b10,
9194 opcode: u5 = 0b01111,
9195 decoded17: u5 = 0b10000,
9196 sz: Sz,
9197 o2: u1 = 0b1,
9198 decoded24: u5 = 0b01110,
9199 U: std.builtin.Signedness = .unsigned,
9200 Q: Q,
9201 decoded31: u1 = 0b0,
9202 };
9203
9204 /// C7.2.157 FRINTI (vector)
9205 pub const Frinti = packed struct {
9206 Rd: Register.Encoded,
9207 Rn: Register.Encoded,
9208 decoded10: u2 = 0b10,
9209 opcode: u5 = 0b11001,
9210 decoded17: u5 = 0b10000,
9211 sz: Sz,
9212 o2: u1 = 0b1,
9213 decoded24: u5 = 0b01110,
9214 U: std.builtin.Signedness = .unsigned,
9215 Q: Q,
9216 decoded31: u1 = 0b0,
9217 };
9218
9219 /// C7.2.86 FCVTPU (vector)
9220 pub const Fcvtpu = packed struct {
9221 Rd: Register.Encoded,
9222 Rn: Register.Encoded,
9223 decoded10: u2 = 0b10,
9224 opcode: u5 = 0b11010,
9225 decoded17: u5 = 0b10000,
9226 sz: Sz,
9227 o2: u1 = 0b1,
9228 decoded24: u5 = 0b01110,
9229 U: std.builtin.Signedness = .unsigned,
9230 Q: Q,
9231 decoded31: u1 = 0b0,
9232 };
9233
9234 /// C7.2.94 FCVTZU (vector, integer)
9235 pub const Fcvtzu = packed struct {
9236 Rd: Register.Encoded,
9237 Rn: Register.Encoded,
9238 decoded10: u2 = 0b10,
9239 opcode: u5 = 0b11011,
9240 decoded17: u5 = 0b10000,
9241 sz: Sz,
9242 o2: u1 = 0b1,
9243 decoded24: u5 = 0b01110,
9244 U: std.builtin.Signedness = .unsigned,
9245 Q: Q,
9246 decoded31: u1 = 0b0,
9247 };
9248
9249 /// C7.2.169 FRSQRTE
9250 pub const Frsqrte = packed struct {
9251 Rd: Register.Encoded,
9252 Rn: Register.Encoded,
9253 decoded10: u2 = 0b10,
9254 opcode: u5 = 0b11101,
9255 decoded17: u5 = 0b10000,
9256 sz: Sz,
9257 o2: u1 = 0b1,
9258 decoded24: u5 = 0b01110,
9259 U: std.builtin.Signedness = .unsigned,
9260 Q: Q,
9261 decoded31: u1 = 0b0,
9262 };
9263
9264 /// C7.2.171 FSQRT (vector)
9265 pub const Fsqrt = packed struct {
9266 Rd: Register.Encoded,
9267 Rn: Register.Encoded,
9268 decoded10: u2 = 0b10,
9269 opcode: u5 = 0b11111,
9270 decoded17: u5 = 0b10000,
9271 sz: Sz,
9272 o2: u1 = 0b1,
9273 decoded24: u5 = 0b01110,
9274 U: std.builtin.Signedness = .unsigned,
9275 Q: Q,
9276 decoded31: u1 = 0b0,
9277 };
9278 };
9279
9280 /// Advanced SIMD across lanes
9281 pub const SimdAcrossLanes = packed union {
9282 group: @This().Group,
9283 addv: Addv,
9284
9285 pub const Group = packed struct {
9286 Rd: Register.Encoded,
9287 Rn: Register.Encoded,
9288 decoded10: u2 = 0b10,
9289 opcode: u5,
9290 decoded17: u5 = 0b11000,
9291 size: Size,
9292 decoded24: u5 = 0b01110,
9293 U: std.builtin.Signedness,
9294 Q: Q,
9295 decoded31: u1 = 0b0,
9296 };
9297
9298 /// C7.2.6 ADDV
9299 pub const Addv = packed struct {
9300 Rd: Register.Encoded,
9301 Rn: Register.Encoded,
9302 decoded10: u2 = 0b10,
9303 opcode: u5 = 0b11011,
9304 decoded17: u5 = 0b11000,
9305 size: Size,
9306 decoded24: u5 = 0b01110,
9307 U: std.builtin.Signedness = .signed,
9308 Q: Q,
9309 decoded31: u1 = 0b0,
9310 };
9311 };
9312
9313 /// Advanced SIMD three same
9314 pub const SimdThreeSame = packed union {
9315 group: @This().Group,
9316 addp: Addp,
9317 @"and": And,
9318 bic: Bic,
9319 orr: Orr,
9320 orn: Orn,
9321 eor: Eor,
9322 bsl: Bsl,
9323 bit: Bit,
9324 bif: Bif,
9325
9326 pub const Group = packed struct {
9327 Rd: Register.Encoded,
9328 Rn: Register.Encoded,
9329 decoded10: u1 = 0b1,
9330 opcode: u5,
9331 Rm: Register.Encoded,
9332 decoded21: u1 = 0b1,
9333 size: Size,
9334 decoded24: u5 = 0b01110,
9335 U: std.builtin.Signedness,
9336 Q: Q,
9337 decoded31: u1 = 0b0,
9338 };
9339
9340 /// C7.2.5 ADDP (vector)
9341 pub const Addp = packed struct {
9342 Rd: Register.Encoded,
9343 Rn: Register.Encoded,
9344 decoded10: u1 = 0b1,
9345 opcode: u5 = 0b10111,
9346 Rm: Register.Encoded,
9347 decoded21: u1 = 0b1,
9348 size: Size,
9349 decoded24: u5 = 0b01110,
9350 U: std.builtin.Signedness = .signed,
9351 Q: Q,
9352 decoded31: u1 = 0b0,
9353 };
9354
9355 /// C7.2.11 AND (vector)
9356 pub const And = packed struct {
9357 Rd: Register.Encoded,
9358 Rn: Register.Encoded,
9359 decoded10: u1 = 0b1,
9360 opcode: u5 = 0b00011,
9361 Rm: Register.Encoded,
9362 decoded21: u1 = 0b1,
9363 size: Size = .byte,
9364 decoded24: u5 = 0b01110,
9365 U: std.builtin.Signedness = .signed,
9366 Q: Q,
9367 decoded31: u1 = 0b0,
9368 };
9369
9370 /// C7.2.21 BIC (vector, register)
9371 pub const Bic = packed struct {
9372 Rd: Register.Encoded,
9373 Rn: Register.Encoded,
9374 decoded10: u1 = 0b1,
9375 opcode: u5 = 0b00011,
9376 Rm: Register.Encoded,
9377 decoded21: u1 = 0b1,
9378 size: Size = .half,
9379 decoded24: u5 = 0b01110,
9380 U: std.builtin.Signedness = .signed,
9381 Q: Q,
9382 decoded31: u1 = 0b0,
9383 };
9384
9385 /// C7.2.213 ORR (vector, register)
9386 pub const Orr = packed struct {
9387 Rd: Register.Encoded,
9388 Rn: Register.Encoded,
9389 decoded10: u1 = 0b1,
9390 opcode: u5 = 0b00011,
9391 Rm: Register.Encoded,
9392 decoded21: u1 = 0b1,
9393 size: Size = .single,
9394 decoded24: u5 = 0b01110,
9395 U: std.builtin.Signedness = .signed,
9396 Q: Q,
9397 decoded31: u1 = 0b0,
9398 };
9399
9400 /// C7.2.211 ORN (vector)
9401 pub const Orn = packed struct {
9402 Rd: Register.Encoded,
9403 Rn: Register.Encoded,
9404 decoded10: u1 = 0b1,
9405 opcode: u5 = 0b00011,
9406 Rm: Register.Encoded,
9407 decoded21: u1 = 0b1,
9408 size: Size = .double,
9409 decoded24: u5 = 0b01110,
9410 U: std.builtin.Signedness = .signed,
9411 Q: Q,
9412 decoded31: u1 = 0b0,
9413 };
9414
9415 /// C7.2.41 EOR (vector)
9416 pub const Eor = packed struct {
9417 Rd: Register.Encoded,
9418 Rn: Register.Encoded,
9419 decoded10: u1 = 0b1,
9420 opcode: u5 = 0b00011,
9421 Rm: Register.Encoded,
9422 decoded21: u1 = 0b1,
9423 size: Size = .byte,
9424 decoded24: u5 = 0b01110,
9425 U: std.builtin.Signedness = .unsigned,
9426 Q: Q,
9427 decoded31: u1 = 0b0,
9428 };
9429
9430 /// C7.2.24 BSL
9431 pub const Bsl = packed struct {
9432 Rd: Register.Encoded,
9433 Rn: Register.Encoded,
9434 decoded10: u1 = 0b1,
9435 opcode: u5 = 0b00011,
9436 Rm: Register.Encoded,
9437 decoded21: u1 = 0b1,
9438 size: Size = .half,
9439 decoded24: u5 = 0b01110,
9440 U: std.builtin.Signedness = .unsigned,
9441 Q: Q,
9442 decoded31: u1 = 0b0,
9443 };
9444
9445 /// C7.2.23 BIT
9446 pub const Bit = packed struct {
9447 Rd: Register.Encoded,
9448 Rn: Register.Encoded,
9449 decoded10: u1 = 0b1,
9450 opcode: u5 = 0b00011,
9451 Rm: Register.Encoded,
9452 decoded21: u1 = 0b1,
9453 size: Size = .single,
9454 decoded24: u5 = 0b01110,
9455 U: std.builtin.Signedness = .unsigned,
9456 Q: Q,
9457 decoded31: u1 = 0b0,
9458 };
9459
9460 /// C7.2.22 BIF
9461 pub const Bif = packed struct {
9462 Rd: Register.Encoded,
9463 Rn: Register.Encoded,
9464 decoded10: u1 = 0b1,
9465 opcode: u5 = 0b00011,
9466 Rm: Register.Encoded,
9467 decoded21: u1 = 0b1,
9468 size: Size = .double,
9469 decoded24: u5 = 0b01110,
9470 U: std.builtin.Signedness = .unsigned,
9471 Q: Q,
9472 decoded31: u1 = 0b0,
9473 };
9474 };
9475
9476 /// Advanced SIMD modified immediate
7298 pub const SimdModifiedImmediate = packed union {9477 pub const SimdModifiedImmediate = packed union {
7299 group: @This().Group,9478 group: @This().Group,
7300 movi: Movi,9479 movi: Movi,
...@@ -8152,6 +10331,58 @@ pub const Instruction = packed union {...@@ -8152,6 +10331,58 @@ pub const Instruction = packed union {
8152 };10331 };
8153 };10332 };
815410333
10334 /// Floating-point conditional select
10335 pub const FloatConditionalSelect = packed union {
10336 group: @This().Group,
10337 fcsel: Fcsel,
10338
10339 pub const Group = packed struct {
10340 Rd: Register.Encoded,
10341 Rn: Register.Encoded,
10342 decoded10: u2 = 0b11,
10343 cond: ConditionCode,
10344 Rm: Register.Encoded,
10345 decoded21: u1 = 0b1,
10346 ptype: Ftype,
10347 decoded24: u5 = 0b11110,
10348 S: bool,
10349 decoded30: u1 = 0b0,
10350 M: u1,
10351 };
10352
10353 /// C7.2.68 FCSEL
10354 pub const Fcsel = packed struct {
10355 Rd: Register.Encoded,
10356 Rn: Register.Encoded,
10357 decoded10: u2 = 0b11,
10358 cond: ConditionCode,
10359 Rm: Register.Encoded,
10360 decoded21: u1 = 0b1,
10361 ftype: Ftype,
10362 decoded24: u5 = 0b11110,
10363 S: bool = false,
10364 decoded30: u1 = 0b0,
10365 M: u1 = 0b0,
10366 };
10367
10368 pub const Decoded = union(enum) {
10369 unallocated,
10370 fcsel: Fcsel,
10371 };
10372 pub fn decode(inst: @This()) @This().Decoded {
10373 return switch (inst.group.ptype) {
10374 .quad => .unallocated,
10375 .single, .double, .half => switch (inst.group.S) {
10376 true => .unallocated,
10377 false => switch (inst.group.M) {
10378 0b0 => .{ .fcsel = inst.fcsel },
10379 0b1 => .unallocated,
10380 },
10381 },
10382 };
10383 }
10384 };
10385
8155 /// Floating-point data-processing (3 source)10386 /// Floating-point data-processing (3 source)
8156 pub const FloatDataProcessingThreeSource = packed union {10387 pub const FloatDataProcessingThreeSource = packed union {
8157 group: @This().Group,10388 group: @This().Group,
...@@ -8240,11 +10471,6 @@ pub const Instruction = packed union {...@@ -8240,11 +10471,6 @@ pub const Instruction = packed union {
8240 };10471 };
8241 };10472 };
824210473
8243 pub const Q = enum(u1) {
8244 double = 0b0,
8245 quad = 0b1,
8246 };
8247
8248 pub const Size = enum(u2) {10474 pub const Size = enum(u2) {
8249 byte = 0b00,10475 byte = 0b00,
8250 half = 0b01,10476 half = 0b01,
...@@ -8260,22 +10486,66 @@ pub const Instruction = packed union {...@@ -8260,22 +10486,66 @@ pub const Instruction = packed union {
8260 };10486 };
8261 }10487 }
826210488
8263 pub fn fromVectorSize(vs: Register.VectorSize) Size {10489 pub fn fromVectorSize(vs: Register.VectorSize) Size {
10490 return switch (vs) {
10491 else => unreachable,
10492 .byte => .byte,
10493 .half => .half,
10494 .single => .single,
10495 .double => .double,
10496 };
10497 }
10498 };
10499
10500 pub const Sz = enum(u1) {
10501 single = 0b0,
10502 double = 0b1,
10503
10504 pub fn toVectorSize(sz: Sz) Register.VectorSize {
10505 return switch (sz) {
10506 .single => .single,
10507 .double => .double,
10508 };
10509 }
10510
10511 pub fn fromVectorSize(vs: Register.VectorSize) Sz {
10512 return switch (vs) {
10513 else => unreachable,
10514 .single => .single,
10515 .double => .double,
10516 };
10517 }
10518 };
10519
10520 pub const Q = enum(u1) {
10521 double = 0b0,
10522 quad = 0b1,
10523 };
10524
10525 pub const Ftype = enum(u2) {
10526 single = 0b00,
10527 double = 0b01,
10528 quad = 0b10,
10529 half = 0b11,
10530
10531 pub fn toVectorSize(ftype: Ftype) Register.VectorSize {
10532 return switch (ftype) {
10533 _ => unreachable,
10534 .single => .single,
10535 .double => .double,
10536 .half => .half,
10537 };
10538 }
10539
10540 pub fn fromVectorSize(vs: Register.VectorSize) Ftype {
8264 return switch (vs) {10541 return switch (vs) {
8265 .byte => .byte,10542 else => unreachable,
8266 .half => .half,
8267 .single => .single,10543 .single => .single,
8268 .double => .double,10544 .double => .double,
10545 .half => .half,
8269 };10546 };
8270 }10547 }
8271 };10548 };
8272
8273 pub const Ftype = enum(u2) {
8274 single = 0b00,
8275 double = 0b01,
8276 quad = 0b10,
8277 half = 0b11,
8278 };
8279 };10549 };
828010550
8281 pub const AddSubtractOp = enum(u1) {10551 pub const AddSubtractOp = enum(u1) {
...@@ -8318,6 +10588,33 @@ pub const Instruction = packed union {...@@ -8318,6 +10588,33 @@ pub const Instruction = packed union {
8318 };10588 };
8319 }10589 }
832010590
10591 /// C7.2.1 ABS (zero)
10592 pub fn abs(d: Register, n: Register) Instruction {
10593 switch (d.format) {
10594 else => unreachable,
10595 .scalar => |elem_size| {
10596 assert(elem_size == .double and elem_size == n.format.scalar);
10597 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
10598 .abs = .{
10599 .Rd = d.alias.encode(.{ .V = true }),
10600 .Rn = n.alias.encode(.{ .V = true }),
10601 .size = .fromVectorSize(elem_size),
10602 },
10603 } } };
10604 },
10605 .vector => |arrangement| {
10606 assert(arrangement != .@"1d" and n.format.vector == arrangement);
10607 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
10608 .abs = .{
10609 .Rd = d.alias.encode(.{ .V = true }),
10610 .Rn = n.alias.encode(.{ .V = true }),
10611 .size = arrangement.elemSize(),
10612 .Q = arrangement.size(),
10613 },
10614 } } };
10615 },
10616 }
10617 }
8321 /// C6.2.1 ADC10618 /// C6.2.1 ADC
8322 pub fn adc(d: Register, n: Register, m: Register) Instruction {10619 pub fn adc(d: Register, n: Register, m: Register) Instruction {
8323 const sf = d.format.integer;10620 const sf = d.format.integer;
...@@ -8865,6 +11162,45 @@ pub const Instruction = packed union {...@@ -8865,6 +11162,45 @@ pub const Instruction = packed union {
8865 } },11162 } },
8866 }11163 }
8867 }11164 }
11165 /// C7.2.22 BIF
11166 pub fn bif(d: Register, n: Register, m: Register) Instruction {
11167 const arrangement = d.format.vector;
11168 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
11169 return .{ .data_processing_vector = .{ .simd_three_same = .{
11170 .bif = .{
11171 .Rd = d.alias.encode(.{ .V = true }),
11172 .Rn = n.alias.encode(.{ .V = true }),
11173 .Rm = m.alias.encode(.{ .V = true }),
11174 .Q = arrangement.size(),
11175 },
11176 } } };
11177 }
11178 /// C7.2.23 BIT
11179 pub fn bit(d: Register, n: Register, m: Register) Instruction {
11180 const arrangement = d.format.vector;
11181 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
11182 return .{ .data_processing_vector = .{ .simd_three_same = .{
11183 .bit = .{
11184 .Rd = d.alias.encode(.{ .V = true }),
11185 .Rn = n.alias.encode(.{ .V = true }),
11186 .Rm = m.alias.encode(.{ .V = true }),
11187 .Q = arrangement.size(),
11188 },
11189 } } };
11190 }
11191 /// C7.2.24 BSL
11192 pub fn bsl(d: Register, n: Register, m: Register) Instruction {
11193 const arrangement = d.format.vector;
11194 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
11195 return .{ .data_processing_vector = .{ .simd_three_same = .{
11196 .bsl = .{
11197 .Rd = d.alias.encode(.{ .V = true }),
11198 .Rn = n.alias.encode(.{ .V = true }),
11199 .Rm = m.alias.encode(.{ .V = true }),
11200 .Q = arrangement.size(),
11201 },
11202 } } };
11203 }
8868 /// C6.2.34 BL11204 /// C6.2.34 BL
8869 pub fn bl(label: i28) Instruction {11205 pub fn bl(label: i28) Instruction {
8870 return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{11206 return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
...@@ -8997,6 +11333,151 @@ pub const Instruction = packed union {...@@ -8997,6 +11333,151 @@ pub const Instruction = packed union {
8997 },11333 },
8998 } } };11334 } } };
8999 }11335 }
11336 /// C7.2.28 CMEQ (zero)
11337 pub fn cmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11338 switch (form) {
11339 .zero => switch (d.format) {
11340 else => unreachable,
11341 .scalar => |elem_size| {
11342 assert(elem_size == .double and elem_size == n.format.scalar);
11343 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11344 .cmeq = .{
11345 .Rd = d.alias.encode(.{ .V = true }),
11346 .Rn = n.alias.encode(.{ .V = true }),
11347 .size = .fromVectorSize(elem_size),
11348 },
11349 } } };
11350 },
11351 .vector => |arrangement| {
11352 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11353 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11354 .cmeq = .{
11355 .Rd = d.alias.encode(.{ .V = true }),
11356 .Rn = n.alias.encode(.{ .V = true }),
11357 .size = arrangement.elemSize(),
11358 .Q = arrangement.size(),
11359 },
11360 } } };
11361 },
11362 },
11363 }
11364 }
11365 /// C7.2.30 CMGE (zero)
11366 pub fn cmge(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11367 switch (form) {
11368 .zero => switch (d.format) {
11369 else => unreachable,
11370 .scalar => |elem_size| {
11371 assert(elem_size == .double and elem_size == n.format.scalar);
11372 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11373 .cmge = .{
11374 .Rd = d.alias.encode(.{ .V = true }),
11375 .Rn = n.alias.encode(.{ .V = true }),
11376 .size = .fromVectorSize(elem_size),
11377 },
11378 } } };
11379 },
11380 .vector => |arrangement| {
11381 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11382 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11383 .cmge = .{
11384 .Rd = d.alias.encode(.{ .V = true }),
11385 .Rn = n.alias.encode(.{ .V = true }),
11386 .size = arrangement.elemSize(),
11387 .Q = arrangement.size(),
11388 },
11389 } } };
11390 },
11391 },
11392 }
11393 }
11394 /// C7.2.32 CMGT (zero)
11395 pub fn cmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11396 switch (form) {
11397 .zero => switch (d.format) {
11398 else => unreachable,
11399 .scalar => |elem_size| {
11400 assert(elem_size == .double and elem_size == n.format.scalar);
11401 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11402 .cmgt = .{
11403 .Rd = d.alias.encode(.{ .V = true }),
11404 .Rn = n.alias.encode(.{ .V = true }),
11405 .size = .fromVectorSize(elem_size),
11406 },
11407 } } };
11408 },
11409 .vector => |arrangement| {
11410 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11411 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11412 .cmgt = .{
11413 .Rd = d.alias.encode(.{ .V = true }),
11414 .Rn = n.alias.encode(.{ .V = true }),
11415 .size = arrangement.elemSize(),
11416 .Q = arrangement.size(),
11417 },
11418 } } };
11419 },
11420 },
11421 }
11422 }
11423 /// C7.2.35 CMLE (zero)
11424 pub fn cmle(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11425 switch (form) {
11426 .zero => switch (d.format) {
11427 else => unreachable,
11428 .scalar => |elem_size| {
11429 assert(elem_size == .double and elem_size == n.format.scalar);
11430 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11431 .cmle = .{
11432 .Rd = d.alias.encode(.{ .V = true }),
11433 .Rn = n.alias.encode(.{ .V = true }),
11434 .size = .fromVectorSize(elem_size),
11435 },
11436 } } };
11437 },
11438 .vector => |arrangement| {
11439 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11440 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11441 .cmle = .{
11442 .Rd = d.alias.encode(.{ .V = true }),
11443 .Rn = n.alias.encode(.{ .V = true }),
11444 .size = arrangement.elemSize(),
11445 .Q = arrangement.size(),
11446 },
11447 } } };
11448 },
11449 },
11450 }
11451 }
11452 /// C7.2.36 CMLT (zero)
11453 pub fn cmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11454 switch (form) {
11455 .zero => switch (d.format) {
11456 else => unreachable,
11457 .scalar => |elem_size| {
11458 assert(elem_size == .double and elem_size == n.format.scalar);
11459 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11460 .cmlt = .{
11461 .Rd = d.alias.encode(.{ .V = true }),
11462 .Rn = n.alias.encode(.{ .V = true }),
11463 .size = .fromVectorSize(elem_size),
11464 },
11465 } } };
11466 },
11467 .vector => |arrangement| {
11468 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11469 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11470 .cmlt = .{
11471 .Rd = d.alias.encode(.{ .V = true }),
11472 .Rn = n.alias.encode(.{ .V = true }),
11473 .size = arrangement.elemSize(),
11474 .Q = arrangement.size(),
11475 },
11476 } } };
11477 },
11478 },
11479 }
11480 }
9000 /// C7.2.38 CNT11481 /// C7.2.38 CNT
9001 pub fn cnt(d: Register, n: Register) Instruction {11482 pub fn cnt(d: Register, n: Register) Instruction {
9002 const arrangement = d.format.vector;11483 const arrangement = d.format.vector;
...@@ -9092,6 +11573,57 @@ pub const Instruction = packed union {...@@ -9092,6 +11573,57 @@ pub const Instruction = packed union {
9092 },11573 },
9093 } } };11574 } } };
9094 }11575 }
11576 /// C7.2.39 DUP (element)
11577 /// C7.2.40 DUP (general)
11578 pub fn dup(d: Register, n: Register) Instruction {
11579 switch (d.format) {
11580 else => unreachable,
11581 .scalar => |elem_size| {
11582 assert(@intFromEnum(elem_size) <= @intFromEnum(Register.VectorSize.double) and elem_size == n.format.element.size);
11583 return .{ .data_processing_vector = .{ .simd_scalar_copy = .{
11584 .dup = .{
11585 .Rd = d.alias.encode(.{ .V = true }),
11586 .Rn = n.alias.encode(.{ .V = true }),
11587 .imm5 = @shlExact(@as(u5, n.format.element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)),
11588 },
11589 } } };
11590 },
11591 .vector => |arrangement| {
11592 assert(arrangement != .@"1d");
11593 const elem_size = arrangement.elemSize();
11594 switch (n.format) {
11595 else => unreachable,
11596 .element => |element| {
11597 assert(elem_size.toVectorSize() == element.size);
11598 return .{ .data_processing_vector = .{ .simd_copy = .{
11599 .dup = .{
11600 .Rd = d.alias.encode(.{ .V = true }),
11601 .Rn = n.alias.encode(.{ .V = true }),
11602 .imm4 = .element,
11603 .imm5 = @shlExact(@as(u5, element.index) << 1 | @as(u5, 0b1), @intFromEnum(elem_size)),
11604 .Q = arrangement.size(),
11605 },
11606 } } };
11607 },
11608 .integer => |sf| {
11609 assert(sf == @as(Register.IntegerSize, switch (elem_size) {
11610 .byte, .half, .single => .word,
11611 .double => .doubleword,
11612 }));
11613 return .{ .data_processing_vector = .{ .simd_copy = .{
11614 .dup = .{
11615 .Rd = d.alias.encode(.{ .V = true }),
11616 .Rn = n.alias.encode(.{}),
11617 .imm4 = .general,
11618 .imm5 = @shlExact(@as(u5, 0b1), @intFromEnum(elem_size)),
11619 .Q = arrangement.size(),
11620 },
11621 } } };
11622 },
11623 }
11624 },
11625 }
11626 }
9095 /// C6.2.118 EON (shifted register)11627 /// C6.2.118 EON (shifted register)
9096 pub fn eon(d: Register, n: Register, form: union(enum) {11628 pub fn eon(d: Register, n: Register, form: union(enum) {
9097 register: Register,11629 register: Register,
...@@ -9204,46 +11736,317 @@ pub const Instruction = packed union {...@@ -9204,46 +11736,317 @@ pub const Instruction = packed union {
9204 .word => @as(u5, @intCast(lsb)),11736 .word => @as(u5, @intCast(lsb)),
9205 .doubleword => @as(u6, @intCast(lsb)),11737 .doubleword => @as(u6, @intCast(lsb)),
9206 },11738 },
9207 .Rm = m.alias.encode(.{}),11739 .Rm = m.alias.encode(.{}),
9208 .N = sf,11740 .N = sf,
9209 .sf = sf,11741 .sf = sf,
11742 },
11743 } } };
11744 }
11745 /// C7.2.45 FABS (vector)
11746 /// C7.2.46 FABS (scalar)
11747 pub fn fabs(d: Register, n: Register) Instruction {
11748 switch (d.format) {
11749 else => unreachable,
11750 .vector => |arrangement| {
11751 assert(n.format.vector == arrangement);
11752 switch (arrangement.elemSize()) {
11753 else => unreachable,
11754 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
11755 .fabs = .{
11756 .Rd = d.alias.encode(.{ .V = true }),
11757 .Rn = n.alias.encode(.{ .V = true }),
11758 .Q = arrangement.size(),
11759 },
11760 } } },
11761 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11762 .fabs = .{
11763 .Rd = d.alias.encode(.{ .V = true }),
11764 .Rn = n.alias.encode(.{ .V = true }),
11765 .sz = arrangement.elemSz(),
11766 .Q = arrangement.size(),
11767 },
11768 } } },
11769 }
11770 },
11771 .scalar => |ftype| {
11772 assert(n.format.scalar == ftype);
11773 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
11774 .fabs = .{
11775 .Rd = d.alias.encode(.{ .V = true }),
11776 .Rn = n.alias.encode(.{ .V = true }),
11777 .ftype = .fromVectorSize(ftype),
11778 },
11779 } } };
11780 },
11781 }
11782 }
11783 /// C7.2.50 FADD (scalar)
11784 pub fn fadd(d: Register, n: Register, m: Register) Instruction {
11785 const ftype = d.format.scalar;
11786 assert(n.format.scalar == ftype and m.format.scalar == ftype);
11787 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
11788 .fadd = .{
11789 .Rd = d.alias.encode(.{ .V = true }),
11790 .Rn = n.alias.encode(.{ .V = true }),
11791 .Rm = m.alias.encode(.{ .V = true }),
11792 .ftype = .fromVectorSize(ftype),
11793 },
11794 } } };
11795 }
11796 /// C7.2.57 FCMEQ (zero)
11797 pub fn fcmeq(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11798 switch (form) {
11799 .zero => switch (d.format) {
11800 else => unreachable,
11801 .scalar => |ftype| switch (n.format) {
11802 else => unreachable,
11803 .scalar => |n_scalar| {
11804 assert(n_scalar == ftype);
11805 switch (ftype) {
11806 else => unreachable,
11807 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
11808 .fcmeq = .{
11809 .Rd = d.alias.encode(.{ .V = true }),
11810 .Rn = n.alias.encode(.{ .V = true }),
11811 },
11812 } } },
11813 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11814 .fcmeq = .{
11815 .Rd = d.alias.encode(.{ .V = true }),
11816 .Rn = n.alias.encode(.{ .V = true }),
11817 .sz = .fromVectorSize(ftype),
11818 },
11819 } } },
11820 }
11821 },
11822 },
11823 .vector => |arrangement| {
11824 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11825 switch (arrangement.elemSize()) {
11826 else => unreachable,
11827 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
11828 .fcmeq = .{
11829 .Rd = d.alias.encode(.{ .V = true }),
11830 .Rn = n.alias.encode(.{ .V = true }),
11831 .Q = arrangement.size(),
11832 },
11833 } } },
11834 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11835 .fcmeq = .{
11836 .Rd = d.alias.encode(.{ .V = true }),
11837 .Rn = n.alias.encode(.{ .V = true }),
11838 .sz = arrangement.elemSz(),
11839 .Q = arrangement.size(),
11840 },
11841 } } },
11842 }
11843 },
11844 },
11845 }
11846 }
11847 /// C7.2.59 FCMGE (zero)
11848 pub fn fcmge(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11849 switch (form) {
11850 .zero => switch (d.format) {
11851 else => unreachable,
11852 .scalar => |ftype| switch (n.format) {
11853 else => unreachable,
11854 .scalar => |n_scalar| {
11855 assert(n_scalar == ftype);
11856 switch (ftype) {
11857 else => unreachable,
11858 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
11859 .fcmge = .{
11860 .Rd = d.alias.encode(.{ .V = true }),
11861 .Rn = n.alias.encode(.{ .V = true }),
11862 },
11863 } } },
11864 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11865 .fcmge = .{
11866 .Rd = d.alias.encode(.{ .V = true }),
11867 .Rn = n.alias.encode(.{ .V = true }),
11868 .sz = .fromVectorSize(ftype),
11869 },
11870 } } },
11871 }
11872 },
11873 },
11874 .vector => |arrangement| {
11875 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11876 switch (arrangement.elemSize()) {
11877 else => unreachable,
11878 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
11879 .fcmge = .{
11880 .Rd = d.alias.encode(.{ .V = true }),
11881 .Rn = n.alias.encode(.{ .V = true }),
11882 .Q = arrangement.size(),
11883 },
11884 } } },
11885 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11886 .fcmge = .{
11887 .Rd = d.alias.encode(.{ .V = true }),
11888 .Rn = n.alias.encode(.{ .V = true }),
11889 .sz = arrangement.elemSz(),
11890 .Q = arrangement.size(),
11891 },
11892 } } },
11893 }
11894 },
11895 },
11896 }
11897 }
11898 /// C7.2.61 FCMGT (zero)
11899 pub fn fcmgt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11900 switch (form) {
11901 .zero => switch (d.format) {
11902 else => unreachable,
11903 .scalar => |ftype| switch (n.format) {
11904 else => unreachable,
11905 .scalar => |n_scalar| {
11906 assert(n_scalar == ftype);
11907 switch (ftype) {
11908 else => unreachable,
11909 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
11910 .fcmgt = .{
11911 .Rd = d.alias.encode(.{ .V = true }),
11912 .Rn = n.alias.encode(.{ .V = true }),
11913 },
11914 } } },
11915 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11916 .fcmgt = .{
11917 .Rd = d.alias.encode(.{ .V = true }),
11918 .Rn = n.alias.encode(.{ .V = true }),
11919 .sz = .fromVectorSize(ftype),
11920 },
11921 } } },
11922 }
11923 },
11924 },
11925 .vector => |arrangement| {
11926 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11927 switch (arrangement.elemSize()) {
11928 else => unreachable,
11929 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
11930 .fcmgt = .{
11931 .Rd = d.alias.encode(.{ .V = true }),
11932 .Rn = n.alias.encode(.{ .V = true }),
11933 .Q = arrangement.size(),
11934 },
11935 } } },
11936 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11937 .fcmgt = .{
11938 .Rd = d.alias.encode(.{ .V = true }),
11939 .Rn = n.alias.encode(.{ .V = true }),
11940 .sz = arrangement.elemSz(),
11941 .Q = arrangement.size(),
11942 },
11943 } } },
11944 }
11945 },
9210 },11946 },
9211 } } };11947 }
9212 }11948 }
9213 /// C7.2.46 FABS (scalar)11949 /// C7.2.64 FCMLE (zero)
9214 pub fn fabs(d: Register, n: Register) Instruction {11950 pub fn fcmle(d: Register, n: Register, form: union(enum) { zero }) Instruction {
9215 const ftype = d.format.scalar;11951 switch (form) {
9216 assert(n.format.scalar == ftype);11952 .zero => switch (d.format) {
9217 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{11953 else => unreachable,
9218 .fabs = .{11954 .scalar => |ftype| switch (n.format) {
9219 .Rd = d.alias.encode(.{ .V = true }),
9220 .Rn = n.alias.encode(.{ .V = true }),
9221 .ftype = switch (ftype) {
9222 else => unreachable,11955 else => unreachable,
9223 .single => .single,11956 .scalar => |n_scalar| {
9224 .double => .double,11957 assert(n_scalar == ftype);
9225 .half => .half,11958 switch (ftype) {
11959 else => unreachable,
11960 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
11961 .fcmle = .{
11962 .Rd = d.alias.encode(.{ .V = true }),
11963 .Rn = n.alias.encode(.{ .V = true }),
11964 },
11965 } } },
11966 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
11967 .fcmle = .{
11968 .Rd = d.alias.encode(.{ .V = true }),
11969 .Rn = n.alias.encode(.{ .V = true }),
11970 .sz = .fromVectorSize(ftype),
11971 },
11972 } } },
11973 }
11974 },
11975 },
11976 .vector => |arrangement| {
11977 assert(arrangement != .@"1d" and n.format.vector == arrangement);
11978 switch (arrangement.elemSize()) {
11979 else => unreachable,
11980 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
11981 .fcmle = .{
11982 .Rd = d.alias.encode(.{ .V = true }),
11983 .Rn = n.alias.encode(.{ .V = true }),
11984 .Q = arrangement.size(),
11985 },
11986 } } },
11987 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
11988 .fcmle = .{
11989 .Rd = d.alias.encode(.{ .V = true }),
11990 .Rn = n.alias.encode(.{ .V = true }),
11991 .sz = arrangement.elemSz(),
11992 .Q = arrangement.size(),
11993 },
11994 } } },
11995 }
9226 },11996 },
9227 },11997 },
9228 } } };11998 }
9229 }11999 }
9230 /// C7.2.50 FADD (scalar)12000 /// C7.2.65 FCMLT (zero)
9231 pub fn fadd(d: Register, n: Register, m: Register) Instruction {12001 pub fn fcmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
9232 const ftype = d.format.scalar;12002 switch (form) {
9233 assert(n.format.scalar == ftype and m.format.scalar == ftype);12003 .zero => switch (d.format) {
9234 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{12004 else => unreachable,
9235 .fadd = .{12005 .scalar => |ftype| switch (n.format) {
9236 .Rd = d.alias.encode(.{ .V = true }),
9237 .Rn = n.alias.encode(.{ .V = true }),
9238 .Rm = m.alias.encode(.{ .V = true }),
9239 .ftype = switch (ftype) {
9240 else => unreachable,12006 else => unreachable,
9241 .single => .single,12007 .scalar => |n_scalar| {
9242 .double => .double,12008 assert(n_scalar == ftype);
9243 .half => .half,12009 switch (ftype) {
12010 else => unreachable,
12011 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12012 .fcmlt = .{
12013 .Rd = d.alias.encode(.{ .V = true }),
12014 .Rn = n.alias.encode(.{ .V = true }),
12015 },
12016 } } },
12017 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12018 .fcmlt = .{
12019 .Rd = d.alias.encode(.{ .V = true }),
12020 .Rn = n.alias.encode(.{ .V = true }),
12021 .sz = .fromVectorSize(ftype),
12022 },
12023 } } },
12024 }
12025 },
12026 },
12027 .vector => |arrangement| {
12028 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12029 switch (arrangement.elemSize()) {
12030 else => unreachable,
12031 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12032 .fcmlt = .{
12033 .Rd = d.alias.encode(.{ .V = true }),
12034 .Rn = n.alias.encode(.{ .V = true }),
12035 .Q = arrangement.size(),
12036 },
12037 } } },
12038 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12039 .fcmlt = .{
12040 .Rd = d.alias.encode(.{ .V = true }),
12041 .Rn = n.alias.encode(.{ .V = true }),
12042 .sz = arrangement.elemSz(),
12043 .Q = arrangement.size(),
12044 },
12045 } } },
12046 }
9244 },12047 },
9245 },12048 },
9246 } } };12049 }
9247 }12050 }
9248 /// C7.2.66 FCMP12051 /// C7.2.66 FCMP
9249 pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction {12052 pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction {
...@@ -9256,12 +12059,7 @@ pub const Instruction = packed union {...@@ -9256,12 +12059,7 @@ pub const Instruction = packed union {
9256 .opc0 = .register,12059 .opc0 = .register,
9257 .Rn = n.alias.encode(.{ .V = true }),12060 .Rn = n.alias.encode(.{ .V = true }),
9258 .Rm = m.alias.encode(.{ .V = true }),12061 .Rm = m.alias.encode(.{ .V = true }),
9259 .ftype = switch (ftype) {12062 .ftype = .fromVectorSize(ftype),
9260 else => unreachable,
9261 .single => .single,
9262 .double => .double,
9263 .half => .half,
9264 },
9265 },12063 },
9266 } } };12064 } } };
9267 },12065 },
...@@ -9270,12 +12068,7 @@ pub const Instruction = packed union {...@@ -9270,12 +12068,7 @@ pub const Instruction = packed union {
9270 .opc0 = .register,12068 .opc0 = .register,
9271 .Rn = n.alias.encode(.{ .V = true }),12069 .Rn = n.alias.encode(.{ .V = true }),
9272 .Rm = @enumFromInt(0b00000),12070 .Rm = @enumFromInt(0b00000),
9273 .ftype = switch (ftype) {12071 .ftype = .fromVectorSize(ftype),
9274 else => unreachable,
9275 .single => .single,
9276 .double => .double,
9277 .half => .half,
9278 },
9279 },12072 },
9280 } } },12073 } } },
9281 }12074 }
...@@ -9291,12 +12084,7 @@ pub const Instruction = packed union {...@@ -9291,12 +12084,7 @@ pub const Instruction = packed union {
9291 .opc0 = .zero,12084 .opc0 = .zero,
9292 .Rn = n.alias.encode(.{ .V = true }),12085 .Rn = n.alias.encode(.{ .V = true }),
9293 .Rm = m.alias.encode(.{ .V = true }),12086 .Rm = m.alias.encode(.{ .V = true }),
9294 .ftype = switch (ftype) {12087 .ftype = .fromVectorSize(ftype),
9295 else => unreachable,
9296 .single => .single,
9297 .double => .double,
9298 .half => .half,
9299 },
9300 },12088 },
9301 } } };12089 } } };
9302 },12090 },
...@@ -9305,16 +12093,25 @@ pub const Instruction = packed union {...@@ -9305,16 +12093,25 @@ pub const Instruction = packed union {
9305 .opc0 = .zero,12093 .opc0 = .zero,
9306 .Rn = n.alias.encode(.{ .V = true }),12094 .Rn = n.alias.encode(.{ .V = true }),
9307 .Rm = @enumFromInt(0b00000),12095 .Rm = @enumFromInt(0b00000),
9308 .ftype = switch (ftype) {12096 .ftype = .fromVectorSize(ftype),
9309 else => unreachable,
9310 .single => .single,
9311 .double => .double,
9312 .half => .half,
9313 },
9314 },12097 },
9315 } } },12098 } } },
9316 }12099 }
9317 }12100 }
12101 /// C7.2.68 FCSEL
12102 pub fn fcsel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
12103 const ftype = d.format.scalar;
12104 assert(n.format.scalar == ftype and m.format.scalar == ftype);
12105 return .{ .data_processing_vector = .{ .float_conditional_select = .{
12106 .fcsel = .{
12107 .Rd = d.alias.encode(.{ .V = true }),
12108 .Rn = n.alias.encode(.{ .V = true }),
12109 .cond = cond,
12110 .Rm = m.alias.encode(.{ .V = true }),
12111 .ftype = .fromVectorSize(ftype),
12112 },
12113 } } };
12114 }
9318 /// C7.2.69 FCVT12115 /// C7.2.69 FCVT
9319 pub fn fcvt(d: Register, n: Register) Instruction {12116 pub fn fcvt(d: Register, n: Register) Instruction {
9320 assert(d.format.scalar != n.format.scalar);12117 assert(d.format.scalar != n.format.scalar);
...@@ -9328,174 +12125,589 @@ pub const Instruction = packed union {...@@ -9328,174 +12125,589 @@ pub const Instruction = packed union {
9328 .double => .double,12125 .double => .double,
9329 .half => .half,12126 .half => .half,
9330 },12127 },
9331 .ftype = switch (n.format.scalar) {12128 .ftype = .fromVectorSize(n.format.scalar),
9332 else => unreachable,
9333 .single => .single,
9334 .double => .double,
9335 .half => .half,
9336 },
9337 },12129 },
9338 } } };12130 } } };
9339 }12131 }
12132 /// C7.2.70 FCVTAS (vector)
9340 /// C7.2.71 FCVTAS (scalar)12133 /// C7.2.71 FCVTAS (scalar)
9341 pub fn fcvtas(d: Register, n: Register) Instruction {12134 pub fn fcvtas(d: Register, n: Register) Instruction {
9342 return .{ .data_processing_vector = .{ .convert_float_integer = .{12135 switch (d.format) {
9343 .fcvtas = .{12136 else => unreachable,
9344 .Rd = d.alias.encode(.{}),12137 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9345 .Rn = n.alias.encode(.{ .V = true }),12138 .fcvtas = .{
9346 .ftype = switch (n.format.scalar) {12139 .Rd = d.alias.encode(.{}),
9347 else => unreachable,12140 .Rn = n.alias.encode(.{ .V = true }),
9348 .single => .single,12141 .ftype = .fromVectorSize(n.format.scalar),
9349 .double => .double,12142 .sf = sf,
9350 .half => .half,12143 },
12144 } } },
12145 .scalar => |elem_size| switch (n.format) {
12146 else => unreachable,
12147 .scalar => |ftype| {
12148 assert(ftype == elem_size);
12149 switch (elem_size) {
12150 else => unreachable,
12151 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12152 .fcvtas = .{
12153 .Rd = d.alias.encode(.{ .V = true }),
12154 .Rn = n.alias.encode(.{ .V = true }),
12155 },
12156 } } },
12157 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12158 .fcvtas = .{
12159 .Rd = d.alias.encode(.{ .V = true }),
12160 .Rn = n.alias.encode(.{ .V = true }),
12161 .sz = .fromVectorSize(elem_size),
12162 },
12163 } } },
12164 }
9351 },12165 },
9352 .sf = d.format.integer,
9353 },12166 },
9354 } } };12167 .vector => |arrangement| {
12168 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12169 switch (arrangement.elemSize()) {
12170 else => unreachable,
12171 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12172 .fcvtas = .{
12173 .Rd = d.alias.encode(.{ .V = true }),
12174 .Rn = n.alias.encode(.{ .V = true }),
12175 .Q = arrangement.size(),
12176 },
12177 } } },
12178 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12179 .fcvtas = .{
12180 .Rd = d.alias.encode(.{ .V = true }),
12181 .Rn = n.alias.encode(.{ .V = true }),
12182 .sz = arrangement.elemSz(),
12183 .Q = arrangement.size(),
12184 },
12185 } } },
12186 }
12187 },
12188 }
9355 }12189 }
12190 /// C7.2.72 FCVTAU (vector)
9356 /// C7.2.73 FCVTAU (scalar)12191 /// C7.2.73 FCVTAU (scalar)
9357 pub fn fcvtau(d: Register, n: Register) Instruction {12192 pub fn fcvtau(d: Register, n: Register) Instruction {
9358 return .{ .data_processing_vector = .{ .convert_float_integer = .{12193 switch (d.format) {
9359 .fcvtau = .{12194 else => unreachable,
9360 .Rd = d.alias.encode(.{}),12195 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9361 .Rn = n.alias.encode(.{ .V = true }),12196 .fcvtau = .{
9362 .ftype = switch (n.format.scalar) {12197 .Rd = d.alias.encode(.{}),
9363 else => unreachable,12198 .Rn = n.alias.encode(.{ .V = true }),
9364 .single => .single,12199 .ftype = .fromVectorSize(n.format.scalar),
9365 .double => .double,12200 .sf = sf,
9366 .half => .half,12201 },
12202 } } },
12203 .scalar => |elem_size| switch (n.format) {
12204 else => unreachable,
12205 .scalar => |ftype| {
12206 assert(ftype == elem_size);
12207 switch (elem_size) {
12208 else => unreachable,
12209 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12210 .fcvtau = .{
12211 .Rd = d.alias.encode(.{ .V = true }),
12212 .Rn = n.alias.encode(.{ .V = true }),
12213 },
12214 } } },
12215 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12216 .fcvtau = .{
12217 .Rd = d.alias.encode(.{ .V = true }),
12218 .Rn = n.alias.encode(.{ .V = true }),
12219 .sz = .fromVectorSize(elem_size),
12220 },
12221 } } },
12222 }
9367 },12223 },
9368 .sf = d.format.integer,
9369 },12224 },
9370 } } };12225 .vector => |arrangement| {
12226 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12227 switch (arrangement.elemSize()) {
12228 else => unreachable,
12229 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12230 .fcvtau = .{
12231 .Rd = d.alias.encode(.{ .V = true }),
12232 .Rn = n.alias.encode(.{ .V = true }),
12233 .Q = arrangement.size(),
12234 },
12235 } } },
12236 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12237 .fcvtau = .{
12238 .Rd = d.alias.encode(.{ .V = true }),
12239 .Rn = n.alias.encode(.{ .V = true }),
12240 .sz = arrangement.elemSz(),
12241 .Q = arrangement.size(),
12242 },
12243 } } },
12244 }
12245 },
12246 }
9371 }12247 }
12248 /// C7.2.75 FCVTMS (vector)
9372 /// C7.2.76 FCVTMS (scalar)12249 /// C7.2.76 FCVTMS (scalar)
9373 pub fn fcvtms(d: Register, n: Register) Instruction {12250 pub fn fcvtms(d: Register, n: Register) Instruction {
9374 return .{ .data_processing_vector = .{ .convert_float_integer = .{12251 switch (d.format) {
9375 .fcvtms = .{12252 else => unreachable,
9376 .Rd = d.alias.encode(.{}),12253 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9377 .Rn = n.alias.encode(.{ .V = true }),12254 .fcvtms = .{
9378 .ftype = switch (n.format.scalar) {12255 .Rd = d.alias.encode(.{}),
9379 else => unreachable,12256 .Rn = n.alias.encode(.{ .V = true }),
9380 .single => .single,12257 .ftype = .fromVectorSize(n.format.scalar),
9381 .double => .double,12258 .sf = sf,
9382 .half => .half,12259 },
12260 } } },
12261 .scalar => |elem_size| switch (n.format) {
12262 else => unreachable,
12263 .scalar => |ftype| {
12264 assert(ftype == elem_size);
12265 switch (elem_size) {
12266 else => unreachable,
12267 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12268 .fcvtms = .{
12269 .Rd = d.alias.encode(.{ .V = true }),
12270 .Rn = n.alias.encode(.{ .V = true }),
12271 },
12272 } } },
12273 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12274 .fcvtms = .{
12275 .Rd = d.alias.encode(.{ .V = true }),
12276 .Rn = n.alias.encode(.{ .V = true }),
12277 .sz = .fromVectorSize(elem_size),
12278 },
12279 } } },
12280 }
9383 },12281 },
9384 .sf = d.format.integer,
9385 },12282 },
9386 } } };12283 .vector => |arrangement| {
12284 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12285 switch (arrangement.elemSize()) {
12286 else => unreachable,
12287 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12288 .fcvtms = .{
12289 .Rd = d.alias.encode(.{ .V = true }),
12290 .Rn = n.alias.encode(.{ .V = true }),
12291 .Q = arrangement.size(),
12292 },
12293 } } },
12294 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12295 .fcvtms = .{
12296 .Rd = d.alias.encode(.{ .V = true }),
12297 .Rn = n.alias.encode(.{ .V = true }),
12298 .sz = arrangement.elemSz(),
12299 .Q = arrangement.size(),
12300 },
12301 } } },
12302 }
12303 },
12304 }
9387 }12305 }
12306 /// C7.2.77 FCVTMU (vector)
9388 /// C7.2.78 FCVTMU (scalar)12307 /// C7.2.78 FCVTMU (scalar)
9389 pub fn fcvtmu(d: Register, n: Register) Instruction {12308 pub fn fcvtmu(d: Register, n: Register) Instruction {
9390 return .{ .data_processing_vector = .{ .convert_float_integer = .{12309 switch (d.format) {
9391 .fcvtmu = .{12310 else => unreachable,
9392 .Rd = d.alias.encode(.{}),12311 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9393 .Rn = n.alias.encode(.{ .V = true }),12312 .fcvtmu = .{
9394 .ftype = switch (n.format.scalar) {12313 .Rd = d.alias.encode(.{}),
9395 else => unreachable,12314 .Rn = n.alias.encode(.{ .V = true }),
9396 .single => .single,12315 .ftype = .fromVectorSize(n.format.scalar),
9397 .double => .double,12316 .sf = sf,
9398 .half => .half,12317 },
12318 } } },
12319 .scalar => |elem_size| switch (n.format) {
12320 else => unreachable,
12321 .scalar => |ftype| {
12322 assert(ftype == elem_size);
12323 switch (elem_size) {
12324 else => unreachable,
12325 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12326 .fcvtmu = .{
12327 .Rd = d.alias.encode(.{ .V = true }),
12328 .Rn = n.alias.encode(.{ .V = true }),
12329 },
12330 } } },
12331 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12332 .fcvtmu = .{
12333 .Rd = d.alias.encode(.{ .V = true }),
12334 .Rn = n.alias.encode(.{ .V = true }),
12335 .sz = .fromVectorSize(elem_size),
12336 },
12337 } } },
12338 }
9399 },12339 },
9400 .sf = d.format.integer,
9401 },12340 },
9402 } } };12341 .vector => |arrangement| {
12342 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12343 switch (arrangement.elemSize()) {
12344 else => unreachable,
12345 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12346 .fcvtmu = .{
12347 .Rd = d.alias.encode(.{ .V = true }),
12348 .Rn = n.alias.encode(.{ .V = true }),
12349 .Q = arrangement.size(),
12350 },
12351 } } },
12352 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12353 .fcvtmu = .{
12354 .Rd = d.alias.encode(.{ .V = true }),
12355 .Rn = n.alias.encode(.{ .V = true }),
12356 .sz = arrangement.elemSz(),
12357 .Q = arrangement.size(),
12358 },
12359 } } },
12360 }
12361 },
12362 }
9403 }12363 }
12364 /// C7.2.80 FCVTNS (vector)
9404 /// C7.2.81 FCVTNS (scalar)12365 /// C7.2.81 FCVTNS (scalar)
9405 pub fn fcvtns(d: Register, n: Register) Instruction {12366 pub fn fcvtns(d: Register, n: Register) Instruction {
9406 return .{ .data_processing_vector = .{ .convert_float_integer = .{12367 switch (d.format) {
9407 .fcvtns = .{12368 else => unreachable,
9408 .Rd = d.alias.encode(.{}),12369 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9409 .Rn = n.alias.encode(.{ .V = true }),12370 .fcvtns = .{
9410 .ftype = switch (n.format.scalar) {12371 .Rd = d.alias.encode(.{}),
9411 else => unreachable,12372 .Rn = n.alias.encode(.{ .V = true }),
9412 .single => .single,12373 .ftype = .fromVectorSize(n.format.scalar),
9413 .double => .double,12374 .sf = sf,
9414 .half => .half,12375 },
12376 } } },
12377 .scalar => |elem_size| switch (n.format) {
12378 else => unreachable,
12379 .scalar => |ftype| {
12380 assert(ftype == elem_size);
12381 switch (elem_size) {
12382 else => unreachable,
12383 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12384 .fcvtns = .{
12385 .Rd = d.alias.encode(.{ .V = true }),
12386 .Rn = n.alias.encode(.{ .V = true }),
12387 },
12388 } } },
12389 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12390 .fcvtns = .{
12391 .Rd = d.alias.encode(.{ .V = true }),
12392 .Rn = n.alias.encode(.{ .V = true }),
12393 .sz = .fromVectorSize(elem_size),
12394 },
12395 } } },
12396 }
9415 },12397 },
9416 .sf = d.format.integer,
9417 },12398 },
9418 } } };12399 .vector => |arrangement| {
12400 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12401 switch (arrangement.elemSize()) {
12402 else => unreachable,
12403 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12404 .fcvtns = .{
12405 .Rd = d.alias.encode(.{ .V = true }),
12406 .Rn = n.alias.encode(.{ .V = true }),
12407 .Q = arrangement.size(),
12408 },
12409 } } },
12410 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12411 .fcvtns = .{
12412 .Rd = d.alias.encode(.{ .V = true }),
12413 .Rn = n.alias.encode(.{ .V = true }),
12414 .sz = arrangement.elemSz(),
12415 .Q = arrangement.size(),
12416 },
12417 } } },
12418 }
12419 },
12420 }
9419 }12421 }
12422 /// C7.2.82 FCVTNU (vector)
9420 /// C7.2.83 FCVTNU (scalar)12423 /// C7.2.83 FCVTNU (scalar)
9421 pub fn fcvtnu(d: Register, n: Register) Instruction {12424 pub fn fcvtnu(d: Register, n: Register) Instruction {
9422 return .{ .data_processing_vector = .{ .convert_float_integer = .{12425 switch (d.format) {
9423 .fcvtnu = .{12426 else => unreachable,
9424 .Rd = d.alias.encode(.{}),12427 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9425 .Rn = n.alias.encode(.{ .V = true }),12428 .fcvtnu = .{
9426 .ftype = switch (n.format.scalar) {12429 .Rd = d.alias.encode(.{}),
9427 else => unreachable,12430 .Rn = n.alias.encode(.{ .V = true }),
9428 .single => .single,12431 .ftype = .fromVectorSize(n.format.scalar),
9429 .double => .double,12432 .sf = sf,
9430 .half => .half,12433 },
12434 } } },
12435 .scalar => |elem_size| switch (n.format) {
12436 else => unreachable,
12437 .scalar => |ftype| {
12438 assert(ftype == elem_size);
12439 switch (elem_size) {
12440 else => unreachable,
12441 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12442 .fcvtnu = .{
12443 .Rd = d.alias.encode(.{ .V = true }),
12444 .Rn = n.alias.encode(.{ .V = true }),
12445 },
12446 } } },
12447 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12448 .fcvtnu = .{
12449 .Rd = d.alias.encode(.{ .V = true }),
12450 .Rn = n.alias.encode(.{ .V = true }),
12451 .sz = .fromVectorSize(elem_size),
12452 },
12453 } } },
12454 }
9431 },12455 },
9432 .sf = d.format.integer,
9433 },12456 },
9434 } } };12457 .vector => |arrangement| {
12458 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12459 switch (arrangement.elemSize()) {
12460 else => unreachable,
12461 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12462 .fcvtnu = .{
12463 .Rd = d.alias.encode(.{ .V = true }),
12464 .Rn = n.alias.encode(.{ .V = true }),
12465 .Q = arrangement.size(),
12466 },
12467 } } },
12468 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12469 .fcvtnu = .{
12470 .Rd = d.alias.encode(.{ .V = true }),
12471 .Rn = n.alias.encode(.{ .V = true }),
12472 .sz = arrangement.elemSz(),
12473 .Q = arrangement.size(),
12474 },
12475 } } },
12476 }
12477 },
12478 }
9435 }12479 }
12480 /// C7.2.84 FCVTPS (vector)
9436 /// C7.2.85 FCVTPS (scalar)12481 /// C7.2.85 FCVTPS (scalar)
9437 pub fn fcvtps(d: Register, n: Register) Instruction {12482 pub fn fcvtps(d: Register, n: Register) Instruction {
9438 return .{ .data_processing_vector = .{ .convert_float_integer = .{12483 switch (d.format) {
9439 .fcvtps = .{12484 else => unreachable,
9440 .Rd = d.alias.encode(.{}),12485 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9441 .Rn = n.alias.encode(.{ .V = true }),12486 .fcvtps = .{
9442 .ftype = switch (n.format.scalar) {12487 .Rd = d.alias.encode(.{}),
9443 else => unreachable,12488 .Rn = n.alias.encode(.{ .V = true }),
9444 .single => .single,12489 .ftype = .fromVectorSize(n.format.scalar),
9445 .double => .double,12490 .sf = sf,
9446 .half => .half,12491 },
12492 } } },
12493 .scalar => |elem_size| switch (n.format) {
12494 else => unreachable,
12495 .scalar => |ftype| {
12496 assert(ftype == elem_size);
12497 switch (elem_size) {
12498 else => unreachable,
12499 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12500 .fcvtps = .{
12501 .Rd = d.alias.encode(.{ .V = true }),
12502 .Rn = n.alias.encode(.{ .V = true }),
12503 },
12504 } } },
12505 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12506 .fcvtps = .{
12507 .Rd = d.alias.encode(.{ .V = true }),
12508 .Rn = n.alias.encode(.{ .V = true }),
12509 .sz = .fromVectorSize(elem_size),
12510 },
12511 } } },
12512 }
9447 },12513 },
9448 .sf = d.format.integer,
9449 },12514 },
9450 } } };12515 .vector => |arrangement| {
12516 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12517 switch (arrangement.elemSize()) {
12518 else => unreachable,
12519 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12520 .fcvtps = .{
12521 .Rd = d.alias.encode(.{ .V = true }),
12522 .Rn = n.alias.encode(.{ .V = true }),
12523 .Q = arrangement.size(),
12524 },
12525 } } },
12526 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12527 .fcvtps = .{
12528 .Rd = d.alias.encode(.{ .V = true }),
12529 .Rn = n.alias.encode(.{ .V = true }),
12530 .sz = arrangement.elemSz(),
12531 .Q = arrangement.size(),
12532 },
12533 } } },
12534 }
12535 },
12536 }
9451 }12537 }
12538 /// C7.2.86 FCVTPU (vector)
9452 /// C7.2.87 FCVTPU (scalar)12539 /// C7.2.87 FCVTPU (scalar)
9453 pub fn fcvtpu(d: Register, n: Register) Instruction {12540 pub fn fcvtpu(d: Register, n: Register) Instruction {
9454 return .{ .data_processing_vector = .{ .convert_float_integer = .{12541 switch (d.format) {
9455 .fcvtpu = .{12542 else => unreachable,
9456 .Rd = d.alias.encode(.{}),12543 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9457 .Rn = n.alias.encode(.{ .V = true }),12544 .fcvtpu = .{
9458 .ftype = switch (n.format.scalar) {12545 .Rd = d.alias.encode(.{}),
9459 else => unreachable,12546 .Rn = n.alias.encode(.{ .V = true }),
9460 .single => .single,12547 .ftype = .fromVectorSize(n.format.scalar),
9461 .double => .double,12548 .sf = sf,
9462 .half => .half,12549 },
12550 } } },
12551 .scalar => |elem_size| switch (n.format) {
12552 else => unreachable,
12553 .scalar => |ftype| {
12554 assert(ftype == elem_size);
12555 switch (elem_size) {
12556 else => unreachable,
12557 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12558 .fcvtpu = .{
12559 .Rd = d.alias.encode(.{ .V = true }),
12560 .Rn = n.alias.encode(.{ .V = true }),
12561 },
12562 } } },
12563 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12564 .fcvtpu = .{
12565 .Rd = d.alias.encode(.{ .V = true }),
12566 .Rn = n.alias.encode(.{ .V = true }),
12567 .sz = .fromVectorSize(elem_size),
12568 },
12569 } } },
12570 }
9463 },12571 },
9464 .sf = d.format.integer,
9465 },12572 },
9466 } } };12573 .vector => |arrangement| {
12574 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12575 switch (arrangement.elemSize()) {
12576 else => unreachable,
12577 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12578 .fcvtpu = .{
12579 .Rd = d.alias.encode(.{ .V = true }),
12580 .Rn = n.alias.encode(.{ .V = true }),
12581 .Q = arrangement.size(),
12582 },
12583 } } },
12584 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12585 .fcvtpu = .{
12586 .Rd = d.alias.encode(.{ .V = true }),
12587 .Rn = n.alias.encode(.{ .V = true }),
12588 .sz = arrangement.elemSz(),
12589 .Q = arrangement.size(),
12590 },
12591 } } },
12592 }
12593 },
12594 }
9467 }12595 }
12596 /// C7.2.90 FCVTZS (vector, integer)
9468 /// C7.2.92 FCVTZS (scalar, integer)12597 /// C7.2.92 FCVTZS (scalar, integer)
9469 pub fn fcvtzs(d: Register, n: Register) Instruction {12598 pub fn fcvtzs(d: Register, n: Register) Instruction {
9470 return .{ .data_processing_vector = .{ .convert_float_integer = .{12599 switch (d.format) {
9471 .fcvtzs = .{12600 else => unreachable,
9472 .Rd = d.alias.encode(.{}),12601 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9473 .Rn = n.alias.encode(.{ .V = true }),12602 .fcvtzs = .{
9474 .ftype = switch (n.format.scalar) {12603 .Rd = d.alias.encode(.{}),
9475 else => unreachable,12604 .Rn = n.alias.encode(.{ .V = true }),
9476 .single => .single,12605 .ftype = .fromVectorSize(n.format.scalar),
9477 .double => .double,12606 .sf = sf,
9478 .half => .half,12607 },
12608 } } },
12609 .scalar => |elem_size| switch (n.format) {
12610 else => unreachable,
12611 .scalar => |ftype| {
12612 assert(ftype == elem_size);
12613 switch (elem_size) {
12614 else => unreachable,
12615 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12616 .fcvtzs = .{
12617 .Rd = d.alias.encode(.{ .V = true }),
12618 .Rn = n.alias.encode(.{ .V = true }),
12619 },
12620 } } },
12621 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12622 .fcvtzs = .{
12623 .Rd = d.alias.encode(.{ .V = true }),
12624 .Rn = n.alias.encode(.{ .V = true }),
12625 .sz = .fromVectorSize(elem_size),
12626 },
12627 } } },
12628 }
9479 },12629 },
9480 .sf = d.format.integer,
9481 },12630 },
9482 } } };12631 .vector => |arrangement| {
12632 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12633 switch (arrangement.elemSize()) {
12634 else => unreachable,
12635 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12636 .fcvtzs = .{
12637 .Rd = d.alias.encode(.{ .V = true }),
12638 .Rn = n.alias.encode(.{ .V = true }),
12639 .Q = arrangement.size(),
12640 },
12641 } } },
12642 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12643 .fcvtzs = .{
12644 .Rd = d.alias.encode(.{ .V = true }),
12645 .Rn = n.alias.encode(.{ .V = true }),
12646 .sz = arrangement.elemSz(),
12647 .Q = arrangement.size(),
12648 },
12649 } } },
12650 }
12651 },
12652 }
9483 }12653 }
12654 /// C7.2.94 FCVTZU (vector, integer)
9484 /// C7.2.96 FCVTZU (scalar, integer)12655 /// C7.2.96 FCVTZU (scalar, integer)
9485 pub fn fcvtzu(d: Register, n: Register) Instruction {12656 pub fn fcvtzu(d: Register, n: Register) Instruction {
9486 return .{ .data_processing_vector = .{ .convert_float_integer = .{12657 switch (d.format) {
9487 .fcvtzu = .{12658 else => unreachable,
9488 .Rd = d.alias.encode(.{}),12659 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9489 .Rn = n.alias.encode(.{ .V = true }),12660 .fcvtzu = .{
9490 .ftype = switch (n.format.scalar) {12661 .Rd = d.alias.encode(.{}),
9491 else => unreachable,12662 .Rn = n.alias.encode(.{ .V = true }),
9492 .single => .single,12663 .ftype = .fromVectorSize(n.format.scalar),
9493 .double => .double,12664 .sf = sf,
9494 .half => .half,12665 },
12666 } } },
12667 .scalar => |elem_size| switch (n.format) {
12668 else => unreachable,
12669 .scalar => |ftype| {
12670 assert(ftype == elem_size);
12671 switch (elem_size) {
12672 else => unreachable,
12673 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
12674 .fcvtzu = .{
12675 .Rd = d.alias.encode(.{ .V = true }),
12676 .Rn = n.alias.encode(.{ .V = true }),
12677 },
12678 } } },
12679 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
12680 .fcvtzu = .{
12681 .Rd = d.alias.encode(.{ .V = true }),
12682 .Rn = n.alias.encode(.{ .V = true }),
12683 .sz = .fromVectorSize(elem_size),
12684 },
12685 } } },
12686 }
9495 },12687 },
9496 .sf = d.format.integer,
9497 },12688 },
9498 } } };12689 .vector => |arrangement| {
12690 assert(arrangement != .@"1d" and n.format.vector == arrangement);
12691 switch (arrangement.elemSize()) {
12692 else => unreachable,
12693 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12694 .fcvtzu = .{
12695 .Rd = d.alias.encode(.{ .V = true }),
12696 .Rn = n.alias.encode(.{ .V = true }),
12697 .Q = arrangement.size(),
12698 },
12699 } } },
12700 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12701 .fcvtzu = .{
12702 .Rd = d.alias.encode(.{ .V = true }),
12703 .Rn = n.alias.encode(.{ .V = true }),
12704 .sz = arrangement.elemSz(),
12705 .Q = arrangement.size(),
12706 },
12707 } } },
12708 }
12709 },
12710 }
9499 }12711 }
9500 /// C7.2.98 FDIV (scalar)12712 /// C7.2.98 FDIV (scalar)
9501 pub fn fdiv(d: Register, n: Register, m: Register) Instruction {12713 pub fn fdiv(d: Register, n: Register, m: Register) Instruction {
...@@ -9506,12 +12718,7 @@ pub const Instruction = packed union {...@@ -9506,12 +12718,7 @@ pub const Instruction = packed union {
9506 .Rd = d.alias.encode(.{ .V = true }),12718 .Rd = d.alias.encode(.{ .V = true }),
9507 .Rn = n.alias.encode(.{ .V = true }),12719 .Rn = n.alias.encode(.{ .V = true }),
9508 .Rm = m.alias.encode(.{ .V = true }),12720 .Rm = m.alias.encode(.{ .V = true }),
9509 .ftype = switch (ftype) {12721 .ftype = .fromVectorSize(ftype),
9510 else => unreachable,
9511 .single => .single,
9512 .double => .double,
9513 .half => .half,
9514 },
9515 },12722 },
9516 } } };12723 } } };
9517 }12724 }
...@@ -9536,12 +12743,7 @@ pub const Instruction = packed union {...@@ -9536,12 +12743,7 @@ pub const Instruction = packed union {
9536 .Rn = n.alias.encode(.{ .V = true }),12743 .Rn = n.alias.encode(.{ .V = true }),
9537 .Rm = m.alias.encode(.{ .V = true }),12744 .Rm = m.alias.encode(.{ .V = true }),
9538 .Ra = a.alias.encode(.{ .V = true }),12745 .Ra = a.alias.encode(.{ .V = true }),
9539 .ftype = switch (ftype) {12746 .ftype = .fromVectorSize(ftype),
9540 else => unreachable,
9541 .single => .single,
9542 .double => .double,
9543 .half => .half,
9544 },
9545 },12747 },
9546 } } };12748 } } };
9547 }12749 }
...@@ -9554,12 +12756,7 @@ pub const Instruction = packed union {...@@ -9554,12 +12756,7 @@ pub const Instruction = packed union {
9554 .Rd = d.alias.encode(.{ .V = true }),12756 .Rd = d.alias.encode(.{ .V = true }),
9555 .Rn = n.alias.encode(.{ .V = true }),12757 .Rn = n.alias.encode(.{ .V = true }),
9556 .Rm = m.alias.encode(.{ .V = true }),12758 .Rm = m.alias.encode(.{ .V = true }),
9557 .ftype = switch (ftype) {12759 .ftype = .fromVectorSize(ftype),
9558 else => unreachable,
9559 .single => .single,
9560 .double => .double,
9561 .half => .half,
9562 },
9563 },12760 },
9564 } } };12761 } } };
9565 }12762 }
...@@ -9569,15 +12766,10 @@ pub const Instruction = packed union {...@@ -9569,15 +12766,10 @@ pub const Instruction = packed union {
9569 assert(n.format.scalar == ftype and m.format.scalar == ftype);12766 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9570 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{12767 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9571 .fmaxnm = .{12768 .fmaxnm = .{
9572 .Rd = d.alias.encode(.{ .V = true }),12769 .Rd = d.alias.encode(.{ .V = true }),
9573 .Rn = n.alias.encode(.{ .V = true }),12770 .Rn = n.alias.encode(.{ .V = true }),
9574 .Rm = m.alias.encode(.{ .V = true }),12771 .Rm = m.alias.encode(.{ .V = true }),
9575 .ftype = switch (ftype) {12772 .ftype = .fromVectorSize(ftype),
9576 else => unreachable,
9577 .single => .single,
9578 .double => .double,
9579 .half => .half,
9580 },
9581 },12773 },
9582 } } };12774 } } };
9583 }12775 }
...@@ -9590,12 +12782,7 @@ pub const Instruction = packed union {...@@ -9590,12 +12782,7 @@ pub const Instruction = packed union {
9590 .Rd = d.alias.encode(.{ .V = true }),12782 .Rd = d.alias.encode(.{ .V = true }),
9591 .Rn = n.alias.encode(.{ .V = true }),12783 .Rn = n.alias.encode(.{ .V = true }),
9592 .Rm = m.alias.encode(.{ .V = true }),12784 .Rm = m.alias.encode(.{ .V = true }),
9593 .ftype = switch (ftype) {12785 .ftype = .fromVectorSize(ftype),
9594 else => unreachable,
9595 .single => .single,
9596 .double => .double,
9597 .half => .half,
9598 },
9599 },12786 },
9600 } } };12787 } } };
9601 }12788 }
...@@ -9608,12 +12795,7 @@ pub const Instruction = packed union {...@@ -9608,12 +12795,7 @@ pub const Instruction = packed union {
9608 .Rd = d.alias.encode(.{ .V = true }),12795 .Rd = d.alias.encode(.{ .V = true }),
9609 .Rn = n.alias.encode(.{ .V = true }),12796 .Rn = n.alias.encode(.{ .V = true }),
9610 .Rm = m.alias.encode(.{ .V = true }),12797 .Rm = m.alias.encode(.{ .V = true }),
9611 .ftype = switch (ftype) {12798 .ftype = .fromVectorSize(ftype),
9612 else => unreachable,
9613 .single => .single,
9614 .double => .double,
9615 .half => .half,
9616 },
9617 },12799 },
9618 } } };12800 } } };
9619 }12801 }
...@@ -9640,12 +12822,7 @@ pub const Instruction = packed union {...@@ -9640,12 +12822,7 @@ pub const Instruction = packed union {
9640 .fmov = .{12822 .fmov = .{
9641 .Rd = d.alias.encode(.{ .V = true }),12823 .Rd = d.alias.encode(.{ .V = true }),
9642 .imm8 = imm,12824 .imm8 = imm,
9643 .ftype = switch (ftype) {12825 .ftype = .fromVectorSize(ftype),
9644 else => unreachable,
9645 .single => .single,
9646 .double => .double,
9647 .half => .half,
9648 },
9649 },12826 },
9650 } } },12827 } } },
9651 .vector => |arrangement| {12828 .vector => |arrangement| {
...@@ -9678,12 +12855,7 @@ pub const Instruction = packed union {...@@ -9678,12 +12855,7 @@ pub const Instruction = packed union {
9678 .Rn = n.alias.encode(.{ .V = true }),12855 .Rn = n.alias.encode(.{ .V = true }),
9679 .opcode = .float_to_integer,12856 .opcode = .float_to_integer,
9680 .rmode = .@"0",12857 .rmode = .@"0",
9681 .ftype = switch (ftype) {12858 .ftype = .fromVectorSize(ftype),
9682 else => unreachable,
9683 .single => .single,
9684 .double => .double,
9685 .half => .half,
9686 },
9687 .sf = sf,12859 .sf = sf,
9688 },12860 },
9689 } } };12861 } } };
...@@ -9721,12 +12893,7 @@ pub const Instruction = packed union {...@@ -9721,12 +12893,7 @@ pub const Instruction = packed union {
9721 .Rn = n.alias.encode(.{}),12893 .Rn = n.alias.encode(.{}),
9722 .opcode = .integer_to_float,12894 .opcode = .integer_to_float,
9723 .rmode = .@"0",12895 .rmode = .@"0",
9724 .ftype = switch (ftype) {12896 .ftype = .fromVectorSize(ftype),
9725 else => unreachable,
9726 .single => .single,
9727 .double => .double,
9728 .half => .half,
9729 },
9730 .sf = sf,12897 .sf = sf,
9731 },12898 },
9732 } } };12899 } } };
...@@ -9737,12 +12904,7 @@ pub const Instruction = packed union {...@@ -9737,12 +12904,7 @@ pub const Instruction = packed union {
9737 .fmov = .{12904 .fmov = .{
9738 .Rd = d.alias.encode(.{ .V = true }),12905 .Rd = d.alias.encode(.{ .V = true }),
9739 .Rn = n.alias.encode(.{ .V = true }),12906 .Rn = n.alias.encode(.{ .V = true }),
9740 .ftype = switch (ftype) {12907 .ftype = .fromVectorSize(ftype),
9741 else => unreachable,
9742 .single => .single,
9743 .double => .double,
9744 .half => .half,
9745 },
9746 },12908 },
9747 } } };12909 } } };
9748 },12910 },
...@@ -9779,12 +12941,7 @@ pub const Instruction = packed union {...@@ -9779,12 +12941,7 @@ pub const Instruction = packed union {
9779 .Rn = n.alias.encode(.{ .V = true }),12941 .Rn = n.alias.encode(.{ .V = true }),
9780 .Rm = m.alias.encode(.{ .V = true }),12942 .Rm = m.alias.encode(.{ .V = true }),
9781 .Ra = a.alias.encode(.{ .V = true }),12943 .Ra = a.alias.encode(.{ .V = true }),
9782 .ftype = switch (ftype) {12944 .ftype = .fromVectorSize(ftype),
9783 else => unreachable,
9784 .single => .single,
9785 .double => .double,
9786 .half => .half,
9787 },
9788 },12945 },
9789 } } };12946 } } };
9790 }12947 }
...@@ -9797,31 +12954,47 @@ pub const Instruction = packed union {...@@ -9797,31 +12954,47 @@ pub const Instruction = packed union {
9797 .Rd = d.alias.encode(.{ .V = true }),12954 .Rd = d.alias.encode(.{ .V = true }),
9798 .Rn = n.alias.encode(.{ .V = true }),12955 .Rn = n.alias.encode(.{ .V = true }),
9799 .Rm = m.alias.encode(.{ .V = true }),12956 .Rm = m.alias.encode(.{ .V = true }),
9800 .ftype = switch (ftype) {12957 .ftype = .fromVectorSize(ftype),
9801 else => unreachable,
9802 .single => .single,
9803 .double => .double,
9804 .half => .half,
9805 },
9806 },12958 },
9807 } } };12959 } } };
9808 }12960 }
12961 /// C7.2.139 FNEG (vector)
9809 /// C7.2.140 FNEG (scalar)12962 /// C7.2.140 FNEG (scalar)
9810 pub fn fneg(d: Register, n: Register) Instruction {12963 pub fn fneg(d: Register, n: Register) Instruction {
9811 const ftype = d.format.scalar;12964 switch (d.format) {
9812 assert(n.format.scalar == ftype);12965 else => unreachable,
9813 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{12966 .vector => |arrangement| {
9814 .fneg = .{12967 assert(n.format.vector == arrangement);
9815 .Rd = d.alias.encode(.{ .V = true }),12968 switch (arrangement.elemSize()) {
9816 .Rn = n.alias.encode(.{ .V = true }),
9817 .ftype = switch (ftype) {
9818 else => unreachable,12969 else => unreachable,
9819 .single => .single,12970 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9820 .double => .double,12971 .fneg = .{
9821 .half => .half,12972 .Rd = d.alias.encode(.{ .V = true }),
9822 },12973 .Rn = n.alias.encode(.{ .V = true }),
12974 .Q = arrangement.size(),
12975 },
12976 } } },
12977 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
12978 .fneg = .{
12979 .Rd = d.alias.encode(.{ .V = true }),
12980 .Rn = n.alias.encode(.{ .V = true }),
12981 .sz = arrangement.elemSz(),
12982 .Q = arrangement.size(),
12983 },
12984 } } },
12985 }
9823 },12986 },
9824 } } };12987 .scalar => |ftype| {
12988 assert(n.format.scalar == ftype);
12989 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
12990 .fneg = .{
12991 .Rd = d.alias.encode(.{ .V = true }),
12992 .Rn = n.alias.encode(.{ .V = true }),
12993 .ftype = .fromVectorSize(ftype),
12994 },
12995 } } };
12996 },
12997 }
9825 }12998 }
9826 /// C7.2.141 FNMADD12999 /// C7.2.141 FNMADD
9827 pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction {13000 pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
...@@ -9833,12 +13006,7 @@ pub const Instruction = packed union {...@@ -9833,12 +13006,7 @@ pub const Instruction = packed union {
9833 .Rn = n.alias.encode(.{ .V = true }),13006 .Rn = n.alias.encode(.{ .V = true }),
9834 .Rm = m.alias.encode(.{ .V = true }),13007 .Rm = m.alias.encode(.{ .V = true }),
9835 .Ra = a.alias.encode(.{ .V = true }),13008 .Ra = a.alias.encode(.{ .V = true }),
9836 .ftype = switch (ftype) {13009 .ftype = .fromVectorSize(ftype),
9837 else => unreachable,
9838 .single => .single,
9839 .double => .double,
9840 .half => .half,
9841 },
9842 },13010 },
9843 } } };13011 } } };
9844 }13012 }
...@@ -9852,12 +13020,7 @@ pub const Instruction = packed union {...@@ -9852,12 +13020,7 @@ pub const Instruction = packed union {
9852 .Rn = n.alias.encode(.{ .V = true }),13020 .Rn = n.alias.encode(.{ .V = true }),
9853 .Rm = m.alias.encode(.{ .V = true }),13021 .Rm = m.alias.encode(.{ .V = true }),
9854 .Ra = a.alias.encode(.{ .V = true }),13022 .Ra = a.alias.encode(.{ .V = true }),
9855 .ftype = switch (ftype) {13023 .ftype = .fromVectorSize(ftype),
9856 else => unreachable,
9857 .single => .single,
9858 .double => .double,
9859 .half => .half,
9860 },
9861 },13024 },
9862 } } };13025 } } };
9863 }13026 }
...@@ -9870,150 +13033,313 @@ pub const Instruction = packed union {...@@ -9870,150 +13033,313 @@ pub const Instruction = packed union {
9870 .Rd = d.alias.encode(.{ .V = true }),13033 .Rd = d.alias.encode(.{ .V = true }),
9871 .Rn = n.alias.encode(.{ .V = true }),13034 .Rn = n.alias.encode(.{ .V = true }),
9872 .Rm = m.alias.encode(.{ .V = true }),13035 .Rm = m.alias.encode(.{ .V = true }),
9873 .ftype = switch (ftype) {13036 .ftype = .fromVectorSize(ftype),
9874 else => unreachable,
9875 .single => .single,
9876 .double => .double,
9877 .half => .half,
9878 },
9879 },13037 },
9880 } } };13038 } } };
9881 }13039 }
13040 /// C7.2.155 FRINTA (vector)
9882 /// C7.2.156 FRINTA (scalar)13041 /// C7.2.156 FRINTA (scalar)
9883 pub fn frinta(d: Register, n: Register) Instruction {13042 pub fn frinta(d: Register, n: Register) Instruction {
9884 const ftype = d.format.scalar;13043 switch (d.format) {
9885 assert(n.format.scalar == ftype);13044 else => unreachable,
9886 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13045 .vector => |arrangement| {
9887 .frinta = .{13046 assert(arrangement != .@"1d" and n.format.vector == arrangement);
9888 .Rd = d.alias.encode(.{ .V = true }),13047 switch (arrangement.elemSize()) {
9889 .Rn = n.alias.encode(.{ .V = true }),
9890 .ftype = switch (ftype) {
9891 else => unreachable,13048 else => unreachable,
9892 .single => .single,13049 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9893 .double => .double,13050 .frinta = .{
9894 .half => .half,13051 .Rd = d.alias.encode(.{ .V = true }),
9895 },13052 .Rn = n.alias.encode(.{ .V = true }),
13053 .Q = arrangement.size(),
13054 },
13055 } } },
13056 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13057 .frinta = .{
13058 .Rd = d.alias.encode(.{ .V = true }),
13059 .Rn = n.alias.encode(.{ .V = true }),
13060 .sz = arrangement.elemSz(),
13061 .Q = arrangement.size(),
13062 },
13063 } } },
13064 }
9896 },13065 },
9897 } } };13066 .scalar => |ftype| {
13067 assert(n.format.scalar == ftype);
13068 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13069 .frinta = .{
13070 .Rd = d.alias.encode(.{ .V = true }),
13071 .Rn = n.alias.encode(.{ .V = true }),
13072 .ftype = .fromVectorSize(ftype),
13073 },
13074 } } };
13075 },
13076 }
9898 }13077 }
13078 /// C7.2.157 FRINTI (vector)
9899 /// C7.2.158 FRINTI (scalar)13079 /// C7.2.158 FRINTI (scalar)
9900 pub fn frinti(d: Register, n: Register) Instruction {13080 pub fn frinti(d: Register, n: Register) Instruction {
9901 const ftype = d.format.scalar;13081 switch (d.format) {
9902 assert(n.format.scalar == ftype);13082 else => unreachable,
9903 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13083 .vector => |arrangement| {
9904 .frinti = .{13084 assert(arrangement != .@"1d" and n.format.vector == arrangement);
9905 .Rd = d.alias.encode(.{ .V = true }),13085 switch (arrangement.elemSize()) {
9906 .Rn = n.alias.encode(.{ .V = true }),
9907 .ftype = switch (ftype) {
9908 else => unreachable,13086 else => unreachable,
9909 .single => .single,13087 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9910 .double => .double,13088 .frinti = .{
9911 .half => .half,13089 .Rd = d.alias.encode(.{ .V = true }),
9912 },13090 .Rn = n.alias.encode(.{ .V = true }),
13091 .Q = arrangement.size(),
13092 },
13093 } } },
13094 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13095 .frinti = .{
13096 .Rd = d.alias.encode(.{ .V = true }),
13097 .Rn = n.alias.encode(.{ .V = true }),
13098 .sz = arrangement.elemSz(),
13099 .Q = arrangement.size(),
13100 },
13101 } } },
13102 }
9913 },13103 },
9914 } } };13104 .scalar => |ftype| {
13105 assert(n.format.scalar == ftype);
13106 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13107 .frinti = .{
13108 .Rd = d.alias.encode(.{ .V = true }),
13109 .Rn = n.alias.encode(.{ .V = true }),
13110 .ftype = .fromVectorSize(ftype),
13111 },
13112 } } };
13113 },
13114 }
9915 }13115 }
13116 /// C7.2.159 FRINTM (vector)
9916 /// C7.2.160 FRINTM (scalar)13117 /// C7.2.160 FRINTM (scalar)
9917 pub fn frintm(d: Register, n: Register) Instruction {13118 pub fn frintm(d: Register, n: Register) Instruction {
9918 const ftype = d.format.scalar;13119 switch (d.format) {
9919 assert(n.format.scalar == ftype);13120 else => unreachable,
9920 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13121 .vector => |arrangement| {
9921 .frintm = .{13122 assert(arrangement != .@"1d" and n.format.vector == arrangement);
9922 .Rd = d.alias.encode(.{ .V = true }),13123 switch (arrangement.elemSize()) {
9923 .Rn = n.alias.encode(.{ .V = true }),
9924 .ftype = switch (ftype) {
9925 else => unreachable,13124 else => unreachable,
9926 .single => .single,13125 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9927 .double => .double,13126 .frintm = .{
9928 .half => .half,13127 .Rd = d.alias.encode(.{ .V = true }),
9929 },13128 .Rn = n.alias.encode(.{ .V = true }),
13129 .Q = arrangement.size(),
13130 },
13131 } } },
13132 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13133 .frintm = .{
13134 .Rd = d.alias.encode(.{ .V = true }),
13135 .Rn = n.alias.encode(.{ .V = true }),
13136 .sz = arrangement.elemSz(),
13137 .Q = arrangement.size(),
13138 },
13139 } } },
13140 }
9930 },13141 },
9931 } } };13142 .scalar => |ftype| {
13143 assert(n.format.scalar == ftype);
13144 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13145 .frintm = .{
13146 .Rd = d.alias.encode(.{ .V = true }),
13147 .Rn = n.alias.encode(.{ .V = true }),
13148 .ftype = .fromVectorSize(ftype),
13149 },
13150 } } };
13151 },
13152 }
9932 }13153 }
13154 /// C7.2.161 FRINTN (vector)
9933 /// C7.2.162 FRINTN (scalar)13155 /// C7.2.162 FRINTN (scalar)
9934 pub fn frintn(d: Register, n: Register) Instruction {13156 pub fn frintn(d: Register, n: Register) Instruction {
9935 const ftype = d.format.scalar;13157 switch (d.format) {
9936 assert(n.format.scalar == ftype);13158 else => unreachable,
9937 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13159 .vector => |arrangement| {
9938 .frintn = .{13160 assert(arrangement != .@"1d" and n.format.vector == arrangement);
9939 .Rd = d.alias.encode(.{ .V = true }),13161 switch (arrangement.elemSize()) {
9940 .Rn = n.alias.encode(.{ .V = true }),
9941 .ftype = switch (ftype) {
9942 else => unreachable,13162 else => unreachable,
9943 .single => .single,13163 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9944 .double => .double,13164 .frintn = .{
9945 .half => .half,13165 .Rd = d.alias.encode(.{ .V = true }),
9946 },13166 .Rn = n.alias.encode(.{ .V = true }),
13167 .Q = arrangement.size(),
13168 },
13169 } } },
13170 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13171 .frintn = .{
13172 .Rd = d.alias.encode(.{ .V = true }),
13173 .Rn = n.alias.encode(.{ .V = true }),
13174 .sz = arrangement.elemSz(),
13175 .Q = arrangement.size(),
13176 },
13177 } } },
13178 }
9947 },13179 },
9948 } } };13180 .scalar => |ftype| {
13181 assert(n.format.scalar == ftype);
13182 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13183 .frintn = .{
13184 .Rd = d.alias.encode(.{ .V = true }),
13185 .Rn = n.alias.encode(.{ .V = true }),
13186 .ftype = .fromVectorSize(ftype),
13187 },
13188 } } };
13189 },
13190 }
9949 }13191 }
13192 /// C7.2.163 FRINTP (vector)
9950 /// C7.2.164 FRINTP (scalar)13193 /// C7.2.164 FRINTP (scalar)
9951 pub fn frintp(d: Register, n: Register) Instruction {13194 pub fn frintp(d: Register, n: Register) Instruction {
9952 const ftype = d.format.scalar;13195 switch (d.format) {
9953 assert(n.format.scalar == ftype);13196 else => unreachable,
9954 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13197 .vector => |arrangement| {
9955 .frintp = .{13198 assert(arrangement != .@"1d" and n.format.vector == arrangement);
9956 .Rd = d.alias.encode(.{ .V = true }),13199 switch (arrangement.elemSize()) {
9957 .Rn = n.alias.encode(.{ .V = true }),
9958 .ftype = switch (ftype) {
9959 else => unreachable,13200 else => unreachable,
9960 .single => .single,13201 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9961 .double => .double,13202 .frintp = .{
9962 .half => .half,13203 .Rd = d.alias.encode(.{ .V = true }),
9963 },13204 .Rn = n.alias.encode(.{ .V = true }),
13205 .Q = arrangement.size(),
13206 },
13207 } } },
13208 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13209 .frintp = .{
13210 .Rd = d.alias.encode(.{ .V = true }),
13211 .Rn = n.alias.encode(.{ .V = true }),
13212 .sz = arrangement.elemSz(),
13213 .Q = arrangement.size(),
13214 },
13215 } } },
13216 }
9964 },13217 },
9965 } } };13218 .scalar => |ftype| {
13219 assert(n.format.scalar == ftype);
13220 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13221 .frintp = .{
13222 .Rd = d.alias.encode(.{ .V = true }),
13223 .Rn = n.alias.encode(.{ .V = true }),
13224 .ftype = .fromVectorSize(ftype),
13225 },
13226 } } };
13227 },
13228 }
9966 }13229 }
13230 /// C7.2.165 FRINTX (vector)
9967 /// C7.2.166 FRINTX (scalar)13231 /// C7.2.166 FRINTX (scalar)
9968 pub fn frintx(d: Register, n: Register) Instruction {13232 pub fn frintx(d: Register, n: Register) Instruction {
9969 const ftype = d.format.scalar;13233 switch (d.format) {
9970 assert(n.format.scalar == ftype);13234 else => unreachable,
9971 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13235 .vector => |arrangement| {
9972 .frintx = .{13236 assert(arrangement != .@"1d" and n.format.vector == arrangement);
9973 .Rd = d.alias.encode(.{ .V = true }),13237 switch (arrangement.elemSize()) {
9974 .Rn = n.alias.encode(.{ .V = true }),
9975 .ftype = switch (ftype) {
9976 else => unreachable,13238 else => unreachable,
9977 .single => .single,13239 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9978 .double => .double,13240 .frintx = .{
9979 .half => .half,13241 .Rd = d.alias.encode(.{ .V = true }),
9980 },13242 .Rn = n.alias.encode(.{ .V = true }),
13243 .Q = arrangement.size(),
13244 },
13245 } } },
13246 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13247 .frintx = .{
13248 .Rd = d.alias.encode(.{ .V = true }),
13249 .Rn = n.alias.encode(.{ .V = true }),
13250 .sz = arrangement.elemSz(),
13251 .Q = arrangement.size(),
13252 },
13253 } } },
13254 }
9981 },13255 },
9982 } } };13256 .scalar => |ftype| {
9983 }13257 assert(n.format.scalar == ftype);
9984 /// C7.2.168 FRINTZ (scalar)13258 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9985 pub fn frintz(d: Register, n: Register) Instruction {13259 .frintx = .{
9986 const ftype = d.format.scalar;13260 .Rd = d.alias.encode(.{ .V = true }),
9987 assert(n.format.scalar == ftype);13261 .Rn = n.alias.encode(.{ .V = true }),
9988 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13262 .ftype = .fromVectorSize(ftype),
9989 .frintz = .{13263 },
9990 .Rd = d.alias.encode(.{ .V = true }),13264 } } };
9991 .Rn = n.alias.encode(.{ .V = true }),13265 },
9992 .ftype = switch (ftype) {13266 }
13267 }
13268 /// C7.2.167 FRINTZ (vector)
13269 /// C7.2.168 FRINTZ (scalar)
13270 pub fn frintz(d: Register, n: Register) Instruction {
13271 switch (d.format) {
13272 else => unreachable,
13273 .vector => |arrangement| {
13274 assert(arrangement != .@"1d" and n.format.vector == arrangement);
13275 switch (arrangement.elemSize()) {
9993 else => unreachable,13276 else => unreachable,
9994 .single => .single,13277 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
9995 .double => .double,13278 .frintz = .{
9996 .half => .half,13279 .Rd = d.alias.encode(.{ .V = true }),
9997 },13280 .Rn = n.alias.encode(.{ .V = true }),
13281 .Q = arrangement.size(),
13282 },
13283 } } },
13284 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13285 .frintz = .{
13286 .Rd = d.alias.encode(.{ .V = true }),
13287 .Rn = n.alias.encode(.{ .V = true }),
13288 .sz = arrangement.elemSz(),
13289 .Q = arrangement.size(),
13290 },
13291 } } },
13292 }
9998 },13293 },
9999 } } };13294 .scalar => |ftype| {
13295 assert(n.format.scalar == ftype);
13296 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13297 .frintz = .{
13298 .Rd = d.alias.encode(.{ .V = true }),
13299 .Rn = n.alias.encode(.{ .V = true }),
13300 .ftype = .fromVectorSize(ftype),
13301 },
13302 } } };
13303 },
13304 }
10000 }13305 }
13306 /// C7.2.171 FSQRT (vector)
10001 /// C7.2.172 FSQRT (scalar)13307 /// C7.2.172 FSQRT (scalar)
10002 pub fn fsqrt(d: Register, n: Register) Instruction {13308 pub fn fsqrt(d: Register, n: Register) Instruction {
10003 const ftype = d.format.scalar;13309 switch (d.format) {
10004 assert(n.format.scalar == ftype);13310 else => unreachable,
10005 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{13311 .vector => |arrangement| {
10006 .fsqrt = .{13312 assert(n.format.vector == arrangement);
10007 .Rd = d.alias.encode(.{ .V = true }),13313 switch (arrangement.elemSize()) {
10008 .Rn = n.alias.encode(.{ .V = true }),
10009 .ftype = switch (ftype) {
10010 else => unreachable,13314 else => unreachable,
10011 .single => .single,13315 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
10012 .double => .double,13316 .fsqrt = .{
10013 .half => .half,13317 .Rd = d.alias.encode(.{ .V = true }),
10014 },13318 .Rn = n.alias.encode(.{ .V = true }),
13319 .Q = arrangement.size(),
13320 },
13321 } } },
13322 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
13323 .fsqrt = .{
13324 .Rd = d.alias.encode(.{ .V = true }),
13325 .Rn = n.alias.encode(.{ .V = true }),
13326 .sz = arrangement.elemSz(),
13327 .Q = arrangement.size(),
13328 },
13329 } } },
13330 }
10015 },13331 },
10016 } } };13332 .scalar => |ftype| {
13333 assert(n.format.scalar == ftype);
13334 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13335 .fsqrt = .{
13336 .Rd = d.alias.encode(.{ .V = true }),
13337 .Rn = n.alias.encode(.{ .V = true }),
13338 .ftype = .fromVectorSize(ftype),
13339 },
13340 } } };
13341 },
13342 }
10017 }13343 }
10018 /// C7.2.174 FSUB (scalar)13344 /// C7.2.174 FSUB (scalar)
10019 pub fn fsub(d: Register, n: Register, m: Register) Instruction {13345 pub fn fsub(d: Register, n: Register, m: Register) Instruction {
...@@ -10024,12 +13350,7 @@ pub const Instruction = packed union {...@@ -10024,12 +13350,7 @@ pub const Instruction = packed union {
10024 .Rd = d.alias.encode(.{ .V = true }),13350 .Rd = d.alias.encode(.{ .V = true }),
10025 .Rn = n.alias.encode(.{ .V = true }),13351 .Rn = n.alias.encode(.{ .V = true }),
10026 .Rm = m.alias.encode(.{ .V = true }),13352 .Rm = m.alias.encode(.{ .V = true }),
10027 .ftype = switch (ftype) {13353 .ftype = .fromVectorSize(ftype),
10028 else => unreachable,
10029 .single => .single,
10030 .double => .double,
10031 .half => .half,
10032 },
10033 },13354 },
10034 } } };13355 } } };
10035 }13356 }
...@@ -10087,26 +13408,26 @@ pub const Instruction = packed union {...@@ -10087,26 +13408,26 @@ pub const Instruction = packed union {
10087 },13408 },
10088 } } } };13409 } } } };
10089 },13410 },
10090 .signed_offset => |signed_offset| {13411 .pre_index => |pre_index| {
10091 assert(signed_offset.base.format.integer == .doubleword);13412 assert(pre_index.base.format.integer == .doubleword);
10092 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{13413 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
10093 .ldp = .{13414 .ldp = .{
10094 .Rt = t1.alias.encode(.{}),13415 .Rt = t1.alias.encode(.{}),
10095 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),13416 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10096 .Rt2 = t2.alias.encode(.{}),13417 .Rt2 = t2.alias.encode(.{}),
10097 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),13418 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
10098 .sf = sf,13419 .sf = sf,
10099 },13420 },
10100 } } } };13421 } } } };
10101 },13422 },
10102 .pre_index => |pre_index| {13423 .signed_offset => |signed_offset| {
10103 assert(pre_index.base.format.integer == .doubleword);13424 assert(signed_offset.base.format.integer == .doubleword);
10104 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{13425 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
10105 .ldp = .{13426 .ldp = .{
10106 .Rt = t1.alias.encode(.{}),13427 .Rt = t1.alias.encode(.{}),
10107 .Rn = pre_index.base.alias.encode(.{ .sp = true }),13428 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
10108 .Rt2 = t2.alias.encode(.{}),13429 .Rt2 = t2.alias.encode(.{}),
10109 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),13430 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
10110 .sf = sf,13431 .sf = sf,
10111 },13432 },
10112 } } } };13433 } } } };
...@@ -11019,12 +14340,52 @@ pub const Instruction = packed union {...@@ -11019,12 +14340,52 @@ pub const Instruction = packed union {
11019 },14340 },
11020 } } };14341 } } };
11021 }14342 }
14343 /// C7.2.209 NEG (vector)
14344 pub fn neg(d: Register, n: Register) Instruction {
14345 switch (d.format) {
14346 else => unreachable,
14347 .scalar => |elem_size| {
14348 assert(elem_size == .double and elem_size == n.format.scalar);
14349 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
14350 .neg = .{
14351 .Rd = d.alias.encode(.{ .V = true }),
14352 .Rn = n.alias.encode(.{ .V = true }),
14353 .size = .fromVectorSize(elem_size),
14354 },
14355 } } };
14356 },
14357 .vector => |arrangement| {
14358 assert(arrangement != .@"1d" and n.format.vector == arrangement);
14359 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
14360 .neg = .{
14361 .Rd = d.alias.encode(.{ .V = true }),
14362 .Rn = n.alias.encode(.{ .V = true }),
14363 .size = arrangement.elemSize(),
14364 .Q = arrangement.size(),
14365 },
14366 } } };
14367 },
14368 }
14369 }
11022 /// C6.2.238 NOP14370 /// C6.2.238 NOP
11023 pub fn nop() Instruction {14371 pub fn nop() Instruction {
11024 return .{ .branch_exception_generating_system = .{ .hints = .{14372 return .{ .branch_exception_generating_system = .{ .hints = .{
11025 .nop = .{},14373 .nop = .{},
11026 } } };14374 } } };
11027 }14375 }
14376 /// C7.2.210 NOT
14377 pub fn not(d: Register, n: Register) Instruction {
14378 const arrangement = d.format.vector;
14379 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement);
14380 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
14381 .not = .{
14382 .Rd = d.alias.encode(.{ .V = true }),
14383 .Rn = n.alias.encode(.{ .V = true }),
14384 .size = arrangement.elemSize(),
14385 .Q = arrangement.size(),
14386 },
14387 } } };
14388 }
11028 /// C6.2.239 ORN (shifted register)14389 /// C6.2.239 ORN (shifted register)
11029 /// C7.2.211 ORN (vector)14390 /// C7.2.211 ORN (vector)
11030 pub fn orn(d: Register, n: Register, form: union(enum) {14391 pub fn orn(d: Register, n: Register, form: union(enum) {
...@@ -11341,21 +14702,63 @@ pub const Instruction = packed union {...@@ -11341,21 +14702,63 @@ pub const Instruction = packed union {
11341 },14702 },
11342 } } };14703 } } };
11343 }14704 }
14705 /// C7.2.234 SCVTF (vector, integer)
11344 /// C7.2.236 SCVTF (scalar, integer)14706 /// C7.2.236 SCVTF (scalar, integer)
11345 pub fn scvtf(d: Register, n: Register) Instruction {14707 pub fn scvtf(d: Register, n: Register) Instruction {
11346 return .{ .data_processing_vector = .{ .convert_float_integer = .{14708 switch (d.format) {
11347 .scvtf = .{14709 else => unreachable,
11348 .Rd = d.alias.encode(.{ .V = true }),14710 .scalar => |ftype| switch (n.format) {
11349 .Rn = n.alias.encode(.{}),14711 else => unreachable,
11350 .ftype = switch (d.format.scalar) {14712 .scalar => |elem_size| {
11351 else => unreachable,14713 assert(ftype == elem_size);
11352 .single => .single,14714 switch (ftype) {
11353 .double => .double,14715 else => unreachable,
11354 .half => .half,14716 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
14717 .scvtf = .{
14718 .Rd = d.alias.encode(.{ .V = true }),
14719 .Rn = n.alias.encode(.{ .V = true }),
14720 },
14721 } } },
14722 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
14723 .scvtf = .{
14724 .Rd = d.alias.encode(.{ .V = true }),
14725 .Rn = n.alias.encode(.{ .V = true }),
14726 .sz = .fromVectorSize(ftype),
14727 },
14728 } } },
14729 }
11355 },14730 },
11356 .sf = n.format.integer,14731 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
14732 .scvtf = .{
14733 .Rd = d.alias.encode(.{ .V = true }),
14734 .Rn = n.alias.encode(.{}),
14735 .ftype = .fromVectorSize(ftype),
14736 .sf = sf,
14737 },
14738 } } },
11357 },14739 },
11358 } } };14740 .vector => |arrangement| {
14741 assert(arrangement != .@"1d" and n.format.vector == arrangement);
14742 switch (arrangement.elemSize()) {
14743 else => unreachable,
14744 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
14745 .scvtf = .{
14746 .Rd = d.alias.encode(.{ .V = true }),
14747 .Rn = n.alias.encode(.{ .V = true }),
14748 .Q = arrangement.size(),
14749 },
14750 } } },
14751 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
14752 .scvtf = .{
14753 .Rd = d.alias.encode(.{ .V = true }),
14754 .Rn = n.alias.encode(.{ .V = true }),
14755 .sz = arrangement.elemSz(),
14756 .Q = arrangement.size(),
14757 },
14758 } } },
14759 }
14760 },
14761 }
11359 }14762 }
11360 /// C6.2.270 SDIV14763 /// C6.2.270 SDIV
11361 pub fn sdiv(d: Register, n: Register, m: Register) Instruction {14764 pub fn sdiv(d: Register, n: Register, m: Register) Instruction {
...@@ -11446,6 +14849,60 @@ pub const Instruction = packed union {...@@ -11446,6 +14849,60 @@ pub const Instruction = packed union {
11446 },14849 },
11447 } } };14850 } } };
11448 }14851 }
14852 /// C7.2.282 SQABS
14853 pub fn sqabs(d: Register, n: Register) Instruction {
14854 switch (d.format) {
14855 else => unreachable,
14856 .scalar => |elem_size| {
14857 assert(elem_size == n.format.scalar);
14858 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
14859 .sqabs = .{
14860 .Rd = d.alias.encode(.{ .V = true }),
14861 .Rn = n.alias.encode(.{ .V = true }),
14862 .size = .fromVectorSize(elem_size),
14863 },
14864 } } };
14865 },
14866 .vector => |arrangement| {
14867 assert(arrangement != .@"1d" and n.format.vector == arrangement);
14868 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
14869 .sqabs = .{
14870 .Rd = d.alias.encode(.{ .V = true }),
14871 .Rn = n.alias.encode(.{ .V = true }),
14872 .size = arrangement.elemSize(),
14873 .Q = arrangement.size(),
14874 },
14875 } } };
14876 },
14877 }
14878 }
14879 /// C7.2.308 SQXTN
14880 pub fn sqxtn(d: Register, n: Register) Instruction {
14881 switch (d.format) {
14882 else => unreachable,
14883 .scalar => |elem_size| {
14884 assert(elem_size == n.format.scalar);
14885 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
14886 .sqxtn = .{
14887 .Rd = d.alias.encode(.{ .V = true }),
14888 .Rn = n.alias.encode(.{ .V = true }),
14889 .size = .fromVectorSize(elem_size),
14890 },
14891 } } };
14892 },
14893 .vector => |arrangement| {
14894 assert(arrangement != .@"1d" and n.format.vector == arrangement);
14895 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
14896 .sqxtn = .{
14897 .Rd = d.alias.encode(.{ .V = true }),
14898 .Rn = n.alias.encode(.{ .V = true }),
14899 .size = arrangement.elemSize(),
14900 .Q = arrangement.size(),
14901 },
14902 } } };
14903 },
14904 }
14905 }
11449 /// C6.2.321 STP14906 /// C6.2.321 STP
11450 /// C7.2.330 STP (SIMD&FP)14907 /// C7.2.330 STP (SIMD&FP)
11451 pub fn stp(t1: Register, t2: Register, form: union(enum) {14908 pub fn stp(t1: Register, t2: Register, form: union(enum) {
...@@ -11471,26 +14928,26 @@ pub const Instruction = packed union {...@@ -11471,26 +14928,26 @@ pub const Instruction = packed union {
11471 },14928 },
11472 } } } };14929 } } } };
11473 },14930 },
11474 .signed_offset => |signed_offset| {14931 .pre_index => |pre_index| {
11475 assert(signed_offset.base.format.integer == .doubleword);14932 assert(pre_index.base.format.integer == .doubleword);
11476 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{14933 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
11477 .stp = .{14934 .stp = .{
11478 .Rt = t1.alias.encode(.{}),14935 .Rt = t1.alias.encode(.{}),
11479 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),14936 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11480 .Rt2 = t2.alias.encode(.{}),14937 .Rt2 = t2.alias.encode(.{}),
11481 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),14938 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
11482 .sf = sf,14939 .sf = sf,
11483 },14940 },
11484 } } } };14941 } } } };
11485 },14942 },
11486 .pre_index => |pre_index| {14943 .signed_offset => |signed_offset| {
11487 assert(pre_index.base.format.integer == .doubleword);14944 assert(signed_offset.base.format.integer == .doubleword);
11488 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{14945 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
11489 .stp = .{14946 .stp = .{
11490 .Rt = t1.alias.encode(.{}),14947 .Rt = t1.alias.encode(.{}),
11491 .Rn = pre_index.base.alias.encode(.{ .sp = true }),14948 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
11492 .Rt2 = t2.alias.encode(.{}),14949 .Rt2 = t2.alias.encode(.{}),
11493 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),14950 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
11494 .sf = sf,14951 .sf = sf,
11495 },14952 },
11496 } } } };14953 } } } };
...@@ -11940,6 +15397,33 @@ pub const Instruction = packed union {...@@ -11940,6 +15397,33 @@ pub const Instruction = packed union {
11940 } },15397 } },
11941 }15398 }
11942 }15399 }
15400 /// C7.2.337 SUQADD
15401 pub fn suqadd(d: Register, n: Register) Instruction {
15402 switch (d.format) {
15403 else => unreachable,
15404 .scalar => |elem_size| {
15405 assert(elem_size == n.format.scalar);
15406 return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
15407 .suqadd = .{
15408 .Rd = d.alias.encode(.{ .V = true }),
15409 .Rn = n.alias.encode(.{ .V = true }),
15410 .size = .fromVectorSize(elem_size),
15411 },
15412 } } };
15413 },
15414 .vector => |arrangement| {
15415 assert(arrangement != .@"1d" and n.format.vector == arrangement);
15416 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
15417 .suqadd = .{
15418 .Rd = d.alias.encode(.{ .V = true }),
15419 .Rn = n.alias.encode(.{ .V = true }),
15420 .size = arrangement.elemSize(),
15421 .Q = arrangement.size(),
15422 },
15423 } } };
15424 },
15425 }
15426 }
11943 /// C6.2.365 SVC15427 /// C6.2.365 SVC
11944 pub fn svc(imm: u16) Instruction {15428 pub fn svc(imm: u16) Instruction {
11945 return .{ .branch_exception_generating_system = .{ .exception_generating = .{15429 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
...@@ -12019,21 +15503,63 @@ pub const Instruction = packed union {...@@ -12019,21 +15503,63 @@ pub const Instruction = packed union {
12019 },15503 },
12020 } } };15504 } } };
12021 }15505 }
15506 /// C7.2.353 UCVTF (vector, integer)
12022 /// C7.2.355 UCVTF (scalar, integer)15507 /// C7.2.355 UCVTF (scalar, integer)
12023 pub fn ucvtf(d: Register, n: Register) Instruction {15508 pub fn ucvtf(d: Register, n: Register) Instruction {
12024 return .{ .data_processing_vector = .{ .convert_float_integer = .{15509 switch (d.format) {
12025 .ucvtf = .{15510 else => unreachable,
12026 .Rd = d.alias.encode(.{ .V = true }),15511 .scalar => |ftype| switch (n.format) {
12027 .Rn = n.alias.encode(.{}),15512 else => unreachable,
12028 .ftype = switch (d.format.scalar) {15513 .scalar => |elem_size| {
12029 else => unreachable,15514 assert(ftype == elem_size);
12030 .single => .single,15515 switch (ftype) {
12031 .double => .double,15516 else => unreachable,
12032 .half => .half,15517 .half => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous_fp16 = .{
15518 .ucvtf = .{
15519 .Rd = d.alias.encode(.{ .V = true }),
15520 .Rn = n.alias.encode(.{ .V = true }),
15521 },
15522 } } },
15523 .single, .double => return .{ .data_processing_vector = .{ .simd_scalar_two_register_miscellaneous = .{
15524 .ucvtf = .{
15525 .Rd = d.alias.encode(.{ .V = true }),
15526 .Rn = n.alias.encode(.{ .V = true }),
15527 .sz = .fromVectorSize(ftype),
15528 },
15529 } } },
15530 }
12033 },15531 },
12034 .sf = n.format.integer,15532 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
15533 .ucvtf = .{
15534 .Rd = d.alias.encode(.{ .V = true }),
15535 .Rn = n.alias.encode(.{}),
15536 .ftype = .fromVectorSize(ftype),
15537 .sf = sf,
15538 },
15539 } } },
12035 },15540 },
12036 } } };15541 .vector => |arrangement| {
15542 assert(arrangement != .@"1d" and n.format.vector == arrangement);
15543 switch (arrangement.elemSize()) {
15544 else => unreachable,
15545 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
15546 .ucvtf = .{
15547 .Rd = d.alias.encode(.{ .V = true }),
15548 .Rn = n.alias.encode(.{ .V = true }),
15549 .Q = arrangement.size(),
15550 },
15551 } } },
15552 .single, .double => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
15553 .ucvtf = .{
15554 .Rd = d.alias.encode(.{ .V = true }),
15555 .Rn = n.alias.encode(.{ .V = true }),
15556 .sz = arrangement.elemSz(),
15557 .Q = arrangement.size(),
15558 },
15559 } } },
15560 }
15561 },
15562 }
12037 }15563 }
12038 /// C6.2.387 UDF15564 /// C6.2.387 UDF
12039 pub fn udf(imm: u16) Instruction {15565 pub fn udf(imm: u16) Instruction {
...@@ -12147,7 +15673,7 @@ pub const Instruction = packed union {...@@ -12147,7 +15673,7 @@ pub const Instruction = packed union {
12147 }15673 }
1214815674
12149 comptime {15675 comptime {
12150 @setEvalBranchQuota(68_000);15676 @setEvalBranchQuota(110_000);
12151 verify(@typeName(Instruction), Instruction);15677 verify(@typeName(Instruction), Instruction);
12152 }15678 }
12153 fn verify(name: []const u8, Type: type) void {15679 fn verify(name: []const u8, Type: type) void {
src/codegen/aarch64/instructions.zon+190
...@@ -213,6 +213,63 @@...@@ -213,6 +213,63 @@
213 },213 },
214 .encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },214 .encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
215 },215 },
216 // C6.2.16 ASR (register)
217 .{
218 .pattern = "ASR <Wd>, <Wn>, <Wm>",
219 .symbols = .{
220 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
221 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
222 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
223 },
224 .encode = .{ .asrv, .Wd, .Wn, .Wm },
225 },
226 .{
227 .pattern = "ASR <Xd>, <Xn>, <Xm>",
228 .symbols = .{
229 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
230 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
231 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
232 },
233 .encode = .{ .asrv, .Xd, .Xn, .Xm },
234 },
235 // C6.2.17 ASR (immediate)
236 .{
237 .pattern = "ASR <Wd>, <Wn>, #<shift>",
238 .symbols = .{
239 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
240 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
241 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
242 },
243 .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .shift, .imms = 31 } },
244 },
245 .{
246 .pattern = "ASR <Xd>, <Xn>, #<shift>",
247 .symbols = .{
248 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
249 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
250 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
251 },
252 .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .shift, .imms = 63 } },
253 },
254 // C6.2.18 ASRV
255 .{
256 .pattern = "ASRV <Wd>, <Wn>, <Wm>",
257 .symbols = .{
258 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
259 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
260 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
261 },
262 .encode = .{ .asrv, .Wd, .Wn, .Wm },
263 },
264 .{
265 .pattern = "ASRV <Xd>, <Xn>, <Xm>",
266 .symbols = .{
267 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
268 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
269 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
270 },
271 .encode = .{ .asrv, .Xd, .Xn, .Xm },
272 },
216 // C6.2.35 BLR273 // C6.2.35 BLR
217 .{274 .{
218 .pattern = "BLR <Xn>",275 .pattern = "BLR <Xn>",
...@@ -681,6 +738,82 @@...@@ -681,6 +738,82 @@
681 },738 },
682 .encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },739 .encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
683 },740 },
741 // C6.2.212 LSL (register)
742 .{
743 .pattern = "LSL <Wd>, <Wn>, <Wm>",
744 .symbols = .{
745 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
746 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
747 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
748 },
749 .encode = .{ .lslv, .Wd, .Wn, .Wm },
750 },
751 .{
752 .pattern = "LSL <Xd>, <Xn>, <Xm>",
753 .symbols = .{
754 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
755 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
756 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
757 },
758 .encode = .{ .lslv, .Xd, .Xn, .Xm },
759 },
760 // C6.2.214 LSLV
761 .{
762 .pattern = "LSLV <Wd>, <Wn>, <Wm>",
763 .symbols = .{
764 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
765 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
766 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
767 },
768 .encode = .{ .lslv, .Wd, .Wn, .Wm },
769 },
770 .{
771 .pattern = "LSLV <Xd>, <Xn>, <Xm>",
772 .symbols = .{
773 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
774 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
775 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
776 },
777 .encode = .{ .lslv, .Xd, .Xn, .Xm },
778 },
779 // C6.2.215 LSR (register)
780 .{
781 .pattern = "LSR <Wd>, <Wn>, <Wm>",
782 .symbols = .{
783 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
784 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
785 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
786 },
787 .encode = .{ .lsrv, .Wd, .Wn, .Wm },
788 },
789 .{
790 .pattern = "LSR <Xd>, <Xn>, <Xm>",
791 .symbols = .{
792 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
793 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
794 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
795 },
796 .encode = .{ .lsrv, .Xd, .Xn, .Xm },
797 },
798 // C6.2.217 LSRV
799 .{
800 .pattern = "LSRV <Wd>, <Wn>, <Wm>",
801 .symbols = .{
802 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
803 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
804 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
805 },
806 .encode = .{ .lsrv, .Wd, .Wn, .Wm },
807 },
808 .{
809 .pattern = "LSRV <Xd>, <Xn>, <Xm>",
810 .symbols = .{
811 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
812 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
813 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
814 },
815 .encode = .{ .lsrv, .Xd, .Xn, .Xm },
816 },
684 // C6.2.220 MOV (to/from SP)817 // C6.2.220 MOV (to/from SP)
685 .{818 .{
686 .pattern = "MOV WSP, <Wn|WSP>",819 .pattern = "MOV WSP, <Wn|WSP>",
...@@ -964,6 +1097,63 @@...@@ -964,6 +1097,63 @@
964 },1097 },
965 .encode = .{ .ret, .Xn },1098 .encode = .{ .ret, .Xn },
966 },1099 },
1100 // C6.2.261 ROR (immediate)
1101 .{
1102 .pattern = "ROR <Wd>, <Ws>, #<shift>",
1103 .symbols = .{
1104 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1105 .Ws = .{ .reg = .{ .format = .{ .integer = .word } } },
1106 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1107 },
1108 .encode = .{ .extr, .Wd, .Ws, .Ws, .shift },
1109 },
1110 .{
1111 .pattern = "ROR <Xd>, <Xs>, #<shift>",
1112 .symbols = .{
1113 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1114 .Xs = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1115 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1116 },
1117 .encode = .{ .extr, .Xd, .Xs, .Xs, .shift },
1118 },
1119 // C6.2.262 ROR (register)
1120 .{
1121 .pattern = "ROR <Wd>, <Wn>, <Wm>",
1122 .symbols = .{
1123 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1124 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1125 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1126 },
1127 .encode = .{ .rorv, .Wd, .Wn, .Wm },
1128 },
1129 .{
1130 .pattern = "ROR <Xd>, <Xn>, <Xm>",
1131 .symbols = .{
1132 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1133 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1134 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1135 },
1136 .encode = .{ .rorv, .Xd, .Xn, .Xm },
1137 },
1138 // C6.2.263 RORV
1139 .{
1140 .pattern = "RORV <Wd>, <Wn>, <Wm>",
1141 .symbols = .{
1142 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1143 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1144 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1145 },
1146 .encode = .{ .rorv, .Wd, .Wn, .Wm },
1147 },
1148 .{
1149 .pattern = "RORV <Xd>, <Xn>, <Xm>",
1150 .symbols = .{
1151 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1152 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1153 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1154 },
1155 .encode = .{ .rorv, .Xd, .Xn, .Xm },
1156 },
967 // C6.2.268 SBFM1157 // C6.2.268 SBFM
968 .{1158 .{
969 .pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>",1159 .pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>",
src/codegen/llvm.zig+3-1
...@@ -4339,9 +4339,11 @@ pub const Object = struct {...@@ -4339,9 +4339,11 @@ pub const Object = struct {
4339 /// types to work around a LLVM deficiency when targeting ARM/AArch64.4339 /// types to work around a LLVM deficiency when targeting ARM/AArch64.
4340 fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {4340 fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {
4341 const zcu = pt.zcu;4341 const zcu = pt.zcu;
4342 const ip = &zcu.intern_pool;
4342 const int_ty = switch (ty.zigTypeTag(zcu)) {4343 const int_ty = switch (ty.zigTypeTag(zcu)) {
4343 .int => ty,4344 .int => ty,
4344 .@"enum" => ty.intTagType(zcu),4345 .@"enum" => ty.intTagType(zcu),
4346 .@"struct" => Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),
4345 .float => {4347 .float => {
4346 if (!is_rmw_xchg) return .none;4348 if (!is_rmw_xchg) return .none;
4347 return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));4349 return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));
...@@ -11424,7 +11426,7 @@ pub const FuncGen = struct {...@@ -11424,7 +11426,7 @@ pub const FuncGen = struct {
1142411426
11425 if (workaround_disable_truncate) {11427 if (workaround_disable_truncate) {
11426 // see https://github.com/llvm/llvm-project/issues/6422211428 // see https://github.com/llvm/llvm-project/issues/64222
11427 // disable the truncation codepath for larger that 32bits value - with this heuristic, the backend passes the test suite.11429 // disable the truncation codepath for larger than 32bits value - with this heuristic, the backend passes the test suite.
11428 return try fg.wip.load(access_kind, payload_llvm_ty, payload_ptr, payload_alignment, "");11430 return try fg.wip.load(access_kind, payload_llvm_ty, payload_ptr, payload_alignment, "");
11429 }11431 }
1143011432
src/link/Dwarf.zig+11-28
...@@ -142,8 +142,8 @@ const DebugInfo = struct {...@@ -142,8 +142,8 @@ const DebugInfo = struct {
142 &abbrev_code_buf,142 &abbrev_code_buf,
143 debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,143 debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
144 ) != abbrev_code_buf.len) return error.InputOutput;144 ) != abbrev_code_buf.len) return error.InputOutput;
145 var abbrev_code_br: std.io.Reader = .fixed(&abbrev_code_buf);145 var abbrev_code_reader: std.Io.Reader = .fixed(&abbrev_code_buf);
146 return @enumFromInt(abbrev_code_br.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable);146 return @enumFromInt(abbrev_code_reader.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable);
147 }147 }
148148
149 const trailer_bytes = 1 + 1;149 const trailer_bytes = 1 + 1;
...@@ -2094,7 +2094,7 @@ pub const WipNav = struct {...@@ -2094,7 +2094,7 @@ pub const WipNav = struct {
2094 .generic_decl_const,2094 .generic_decl_const,
2095 .generic_decl_func,2095 .generic_decl_func,
2096 => true,2096 => true,
2097 else => unreachable,2097 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
2098 };2098 };
2099 if (parent_type.getCaptures(zcu).len == 0) {2099 if (parent_type.getCaptures(zcu).len == 0) {
2100 if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);2100 if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);
...@@ -6104,33 +6104,16 @@ fn sectionOffsetBytes(dwarf: *Dwarf) u32 {...@@ -6104,33 +6104,16 @@ fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
6104}6104}
61056105
6106fn uleb128Bytes(value: anytype) u32 {6106fn uleb128Bytes(value: anytype) u32 {
6107 return leb128Bytes(switch (@typeInfo(@TypeOf(value))) {6107 var trash_buffer: [64]u8 = undefined;
6108 .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value),6108 var d: std.Io.Writer.Discarding = .init(&trash_buffer);
6109 .int => |value_info| switch (value_info.signedness) {6109 d.writer.writeUleb128(value) catch unreachable;
6110 .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)),6110 return @intCast(d.count + d.writer.end);
6111 .unsigned => value,
6112 },
6113 else => comptime unreachable,
6114 });
6115}6111}
6116fn sleb128Bytes(value: anytype) u32 {6112fn sleb128Bytes(value: anytype) u32 {
6117 return leb128Bytes(switch (@typeInfo(@TypeOf(value))) {6113 var trash_buffer: [64]u8 = undefined;
6118 .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value),6114 var d: std.Io.Writer.Discarding = .init(&trash_buffer);
6119 .int => |value_info| switch (value_info.signedness) {6115 d.writer.writeSleb128(value) catch unreachable;
6120 .signed => value,6116 return @intCast(d.count + d.writer.end);
6121 .unsigned => @as(@Type(.{ .int = .{ .signedness = .signed, .bits = value_info.bits + 1 } }), value),
6122 },
6123 else => comptime unreachable,
6124 });
6125}
6126fn leb128Bytes(value: anytype) u32 {
6127 const value_info = @typeInfo(@TypeOf(value)).int;
6128 var buffer: [
6129 std.math.divCeil(u16, @intFromBool(value_info.signedness == .signed) + value_info.bits, 7) catch unreachable
6130 ]u8 = undefined;
6131 var bw: Writer = .fixed(&buffer);
6132 bw.writeLeb128(value) catch unreachable;
6133 return @intCast(bw.end);
6134}6117}
61356118
6136/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional6119/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
src/link/Elf/Object.zig+8-5
...@@ -1198,11 +1198,14 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index...@@ -1198,11 +1198,14 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index
1198 const chdr = (try r.takeStruct(elf.Elf64_Chdr)).*;1198 const chdr = (try r.takeStruct(elf.Elf64_Chdr)).*;
1199 switch (chdr.ch_type) {1199 switch (chdr.ch_type) {
1200 .ZLIB => {1200 .ZLIB => {
1201 var bw: Writer = .fixed(try gpa.alloc(u8, std.math.cast(usize, chdr.ch_size) orelse return error.Overflow));1201 var stream: std.Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);
1202 errdefer gpa.free(bw.buffer);1202 var zlib_stream: std.compress.flate.Decompress = .init(&stream, .zlib, &.{});
1203 try std.compress.zlib.decompress(&r, &bw);1203 const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow;
1204 if (bw.end != bw.buffer.len) return error.InputOutput;1204 var aw: std.Io.Writer.Allocating = .init(gpa);
1205 return bw.buffer;1205 try aw.ensureUnusedCapacity(size);
1206 defer aw.deinit();
1207 _ = try zlib_stream.reader.streamRemaining(&aw.writer);
1208 return aw.toOwnedSlice();
1206 },1209 },
1207 else => @panic("TODO unhandled compression scheme"),1210 else => @panic("TODO unhandled compression scheme"),
1208 }1211 }
src/main.zig+7-2
...@@ -361,7 +361,12 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -361,7 +361,12 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
361 dev.check(.env_command);361 dev.check(.env_command);
362 verifyLibcxxCorrectlyLinked();362 verifyLibcxxCorrectlyLinked();
363 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);363 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
364 try @import("print_env.zig").cmdEnv(arena, &stdout_writer.interface);364 try @import("print_env.zig").cmdEnv(
365 arena,
366 &stdout_writer.interface,
367 args,
368 if (native_os == .wasi) wasi_preopens,
369 );
365 return stdout_writer.interface.flush();370 return stdout_writer.interface.flush();
366 } else if (mem.eql(u8, cmd, "reduce")) {371 } else if (mem.eql(u8, cmd, "reduce")) {
367 return jitCmd(gpa, arena, cmd_args, .{372 return jitCmd(gpa, arena, cmd_args, .{
...@@ -4639,7 +4644,7 @@ const usage_init =...@@ -4639,7 +4644,7 @@ const usage_init =
4639 \\ directory.4644 \\ directory.
4640 \\4645 \\
4641 \\Options:4646 \\Options:
4642 \\ -s, --strip Generate files without comments4647 \\ -m, --minimal Use minimal init template
4643 \\ -h, --help Print this help and exit4648 \\ -h, --help Print this help and exit
4644 \\4649 \\
4645 \\4650 \\
src/print_env.zig+33-11
...@@ -1,21 +1,43 @@...@@ -1,21 +1,43 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const build_options = @import("build_options");3const build_options = @import("build_options");
3const introspect = @import("introspect.zig");4const Compilation = @import("Compilation.zig");
4const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
6const EnvVar = std.zig.EnvVar;
5const fatal = std.process.fatal;7const fatal = std.process.fatal;
68
7pub fn cmdEnv(arena: Allocator, out: *std.Io.Writer) !void {9pub fn cmdEnv(
8 const cwd_path = try introspect.getResolvedCwd(arena);10 arena: Allocator,
9 const self_exe_path = try std.fs.selfExePathAlloc(arena);11 out: *std.Io.Writer,
1012 args: []const []const u8,
11 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, cwd_path, self_exe_path) catch |err| {13 wasi_preopens: switch (builtin.target.os.tag) {
12 fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});14 .wasi => std.fs.wasi.Preopens,
15 else => void,
16 },
17) !void {
18 const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
19 const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
20
21 const self_exe_path = switch (builtin.target.os.tag) {
22 .wasi => args[0],
23 else => std.fs.selfExePathAlloc(arena) catch |err| {
24 fatal("unable to find zig self exe path: {s}", .{@errorName(err)});
25 },
13 };26 };
14 defer zig_lib_directory.handle.close();
1527
16 const zig_std_dir = try std.fs.path.join(arena, &[_][]const u8{ zig_lib_directory.path.?, "std" });28 var dirs: Compilation.Directories = .init(
29 arena,
30 override_lib_dir,
31 override_global_cache_dir,
32 .global,
33 if (builtin.target.os.tag == .wasi) wasi_preopens,
34 if (builtin.target.os.tag != .wasi) self_exe_path,
35 );
36 defer dirs.deinit();
1737
18 const global_cache_dir = try introspect.resolveGlobalCacheDir(arena);38 const zig_lib_dir = dirs.zig_lib.path orelse "";
39 const zig_std_dir = try dirs.zig_lib.join(arena, &.{"std"});
40 const global_cache_dir = dirs.global_cache.path orelse "";
1941
20 const host = try std.zig.system.resolveTargetQuery(.{});42 const host = try std.zig.system.resolveTargetQuery(.{});
21 const triple = try host.zigTriple(arena);43 const triple = try host.zigTriple(arena);
...@@ -24,7 +46,7 @@ pub fn cmdEnv(arena: Allocator, out: *std.Io.Writer) !void {...@@ -24,7 +46,7 @@ pub fn cmdEnv(arena: Allocator, out: *std.Io.Writer) !void {
24 var root = try serializer.beginStruct(.{});46 var root = try serializer.beginStruct(.{});
2547
26 try root.field("zig_exe", self_exe_path, .{});48 try root.field("zig_exe", self_exe_path, .{});
27 try root.field("lib_dir", zig_lib_directory.path.?, .{});49 try root.field("lib_dir", zig_lib_dir, .{});
28 try root.field("std_dir", zig_std_dir, .{});50 try root.field("std_dir", zig_std_dir, .{});
29 try root.field("global_cache_dir", global_cache_dir, .{});51 try root.field("global_cache_dir", global_cache_dir, .{});
30 try root.field("version", build_options.version, .{});52 try root.field("version", build_options.version, .{});
src/target.zig+12-6
...@@ -236,7 +236,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {...@@ -236,7 +236,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
236pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {236pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
237 if (target.cpu.arch.isSpirV()) return true;237 if (target.cpu.arch.isSpirV()) return true;
238 if (target.cpu.arch == .x86_64 and target.ptrBitWidth() == 64) {238 if (target.cpu.arch == .x86_64 and target.ptrBitWidth() == 64) {
239 if (target.os.tag == .netbsd) {239 if (target.os.tag == .netbsd or target.os.tag == .openbsd) {
240 // Self-hosted linker needs work: https://github.com/ziglang/zig/issues/24341240 // Self-hosted linker needs work: https://github.com/ziglang/zig/issues/24341
241 return false;241 return false;
242 }242 }
...@@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {...@@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
248 return false;248 return false;
249}249}
250250
251pub fn supportsStackProbing(target: *const std.Target) bool {251pub fn supportsStackProbing(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
252 return target.os.tag != .windows and target.os.tag != .uefi and252 return switch (backend) {
253 (target.cpu.arch == .x86 or target.cpu.arch == .x86_64);253 .stage2_aarch64, .stage2_x86_64 => true,
254 .stage2_llvm => target.os.tag != .windows and target.os.tag != .uefi and
255 (target.cpu.arch == .x86 or target.cpu.arch == .x86_64),
256 else => false,
257 };
254}258}
255259
256pub fn supportsStackProtector(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {260pub 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...@@ -347,7 +351,7 @@ pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.builtin.Opti
347 }351 }
348}352}
349353
350pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool {354pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool {
351 switch (target.os.tag) {355 switch (target.os.tag) {
352 .plan9 => return false,356 .plan9 => return false,
353 else => {},357 else => {},
...@@ -369,7 +373,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime...@@ -369,7 +373,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime
369 };373 };
370}374}
371375
372pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool {376pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool {
373 switch (target.cpu.arch) {377 switch (target.cpu.arch) {
374 .spirv32, .spirv64 => return false,378 .spirv32, .spirv64 => return false,
375 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed379 // 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...@@ -378,6 +382,7 @@ pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime ha
378 }382 }
379 return switch (zigBackend(target, use_llvm)) {383 return switch (zigBackend(target, use_llvm)) {
380 .stage2_llvm => true,384 .stage2_llvm => true,
385 .stage2_wasm => false,
381 .stage2_x86_64 => switch (target.ofmt) {386 .stage2_x86_64 => switch (target.ofmt) {
382 .elf, .macho => true,387 .elf, .macho => true,
383 else => have_llvm,388 else => have_llvm,
...@@ -856,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile...@@ -856,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile
856pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {861pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {
857 return switch (feature) {862 return switch (feature) {
858 .panic_fn => switch (backend) {863 .panic_fn => switch (backend) {
864 .stage2_aarch64,
859 .stage2_c,865 .stage2_c,
860 .stage2_llvm,866 .stage2_llvm,
861 .stage2_x86_64,867 .stage2_x86_64,
test/behavior/array.zig+13-3
...@@ -395,7 +395,6 @@ test "array literal as argument to function" {...@@ -395,7 +395,6 @@ test "array literal as argument to function" {
395}395}
396396
397test "double nested array to const slice cast in array literal" {397test "double nested array to const slice cast in array literal" {
398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
400 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
401 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -541,7 +540,6 @@ test "sentinel element count towards the ABI size calculation" {...@@ -541,7 +540,6 @@ test "sentinel element count towards the ABI size calculation" {
541}540}
542541
543test "zero-sized array with recursive type definition" {542test "zero-sized array with recursive type definition" {
544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
546 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;544 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
547545
...@@ -650,7 +648,6 @@ test "runtime initialized sentinel-terminated array literal" {...@@ -650,7 +648,6 @@ test "runtime initialized sentinel-terminated array literal" {
650}648}
651649
652test "array of array agregate init" {650test "array of array agregate init" {
653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO651 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO652 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
656653
...@@ -1100,3 +1097,16 @@ test "initialize pointer to anyopaque with reference to empty array initializer"...@@ -1100,3 +1097,16 @@ test "initialize pointer to anyopaque with reference to empty array initializer"
1100 // We can't check the value, but it's zero-bit, so the type matching is good enough.1097 // We can't check the value, but it's zero-bit, so the type matching is good enough.
1101 comptime assert(@TypeOf(loaded) == @TypeOf(.{}));1098 comptime assert(@TypeOf(loaded) == @TypeOf(.{}));
1102}1099}
1100
1101test "sentinel of runtime-known array initialization is populated" {
1102 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1103
1104 var rt: u32 = undefined;
1105 rt = 42;
1106
1107 const arr: [1:123]u32 = .{rt};
1108 const elems: [*]const u32 = &arr;
1109
1110 try expect(elems[0] == 42);
1111 try expect(elems[1] == 123);
1112}
test/behavior/atomics.zig+11-5
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
54
6const supports_128_bit_atomics = switch (builtin.cpu.arch) {5const supports_128_bit_atomics = switch (builtin.cpu.arch) {
7 // TODO: Ideally this could be sync'd with the logic in Sema.6 // TODO: Ideally this could be sync'd with the logic in Sema.
...@@ -364,25 +363,32 @@ test "atomics with different types" {...@@ -364,25 +363,32 @@ test "atomics with different types" {
364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO363 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;364 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
366 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;365 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
366 if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // #24282
367367
368 try testAtomicsWithType(bool, true, false);368 try testAtomicsWithType(bool, true, false);
369369
370 try testAtomicsWithType(u1, 0, 1);370 try testAtomicsWithType(u1, 0, 1);
371 try testAtomicsWithType(i4, 0, 1);371 try testAtomicsWithType(i4, 2, 1);
372 try testAtomicsWithType(u5, 0, 1);372 try testAtomicsWithType(u5, 2, 1);
373 try testAtomicsWithType(i15, 0, 1);373 try testAtomicsWithType(i15, 2, 1);
374 try testAtomicsWithType(u24, 0, 1);374 try testAtomicsWithType(u24, 2, 1);
375375
376 try testAtomicsWithType(u0, 0, 0);376 try testAtomicsWithType(u0, 0, 0);
377 try testAtomicsWithType(i0, 0, 0);377 try testAtomicsWithType(i0, 0, 0);
378378
379 try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);379 try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);
380 try testAtomicsWithType(enum(u19) { x = 1234, y = 5678 }, .x, .y);
380381
381 try testAtomicsWithPackedStruct(382 try testAtomicsWithPackedStruct(
382 packed struct { x: u7, y: u24, z: bool },383 packed struct { x: u7, y: u24, z: bool },
383 .{ .x = 1, .y = 2, .z = true },384 .{ .x = 1, .y = 2, .z = true },
384 .{ .x = 3, .y = 4, .z = false },385 .{ .x = 3, .y = 4, .z = false },
385 );386 );
387 try testAtomicsWithPackedStruct(
388 packed struct { x: u19, y: bool },
389 .{ .x = 1, .y = true },
390 .{ .x = 3, .y = false },
391 );
386}392}
387393
388fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {394fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
test/behavior/bit_shifting.zig-2
...@@ -170,8 +170,6 @@ test "Saturating Shift Left" {...@@ -170,8 +170,6 @@ test "Saturating Shift Left" {
170170
171 const S = struct {171 const S = struct {
172 fn shlSat(x: anytype, y: std.math.Log2Int(@TypeOf(x))) @TypeOf(x) {172 fn shlSat(x: anytype, y: std.math.Log2Int(@TypeOf(x))) @TypeOf(x) {
173 // workaround https://github.com/ziglang/zig/issues/23033
174 @setRuntimeSafety(false);
175 return x <<| y;173 return x <<| y;
176 }174 }
177175
test/behavior/cast_int.zig+1
...@@ -217,6 +217,7 @@ test "load non byte-sized value in struct" {...@@ -217,6 +217,7 @@ test "load non byte-sized value in struct" {
217test "load non byte-sized value in union" {217test "load non byte-sized value in union" {
218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
220 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
221 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
222223
test/behavior/decl_literals.zig-2
...@@ -33,7 +33,6 @@ test "decl literal with pointer" {...@@ -33,7 +33,6 @@ test "decl literal with pointer" {
33}33}
3434
35test "call decl literal with optional" {35test "call decl literal with optional" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;37 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;38 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -74,7 +73,6 @@ test "call decl literal" {...@@ -74,7 +73,6 @@ test "call decl literal" {
74}73}
7574
76test "call decl literal with error union" {75test "call decl literal with error union" {
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
78 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO76 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
7977
80 const S = struct {78 const S = struct {
test/behavior/defer.zig-2
...@@ -107,7 +107,6 @@ test "mixing normal and error defers" {...@@ -107,7 +107,6 @@ test "mixing normal and error defers" {
107}107}
108108
109test "errdefer with payload" {109test "errdefer with payload" {
110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;112 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -129,7 +128,6 @@ test "errdefer with payload" {...@@ -129,7 +128,6 @@ test "errdefer with payload" {
129}128}
130129
131test "reference to errdefer payload" {130test "reference to errdefer payload" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO132 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
test/behavior/enum.zig-1
...@@ -926,7 +926,6 @@ test "enum literal casting to tagged union" {...@@ -926,7 +926,6 @@ test "enum literal casting to tagged union" {
926const Bar = enum { A, B, C, D };926const Bar = enum { A, B, C, D };
927927
928test "enum literal casting to error union with payload enum" {928test "enum literal casting to error union with payload enum" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
931930
932 var bar: error{B}!Bar = undefined;931 var bar: error{B}!Bar = undefined;
test/behavior/error.zig-16
...@@ -145,14 +145,11 @@ test "implicit cast to optional to error union to return result loc" {...@@ -145,14 +145,11 @@ test "implicit cast to optional to error union to return result loc" {
145}145}
146146
147test "fn returning empty error set can be passed as fn returning any error" {147test "fn returning empty error set can be passed as fn returning any error" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149
150 entry();148 entry();
151 comptime entry();149 comptime entry();
152}150}
153151
154test "fn returning empty error set can be passed as fn returning any error - pointer" {152test "fn returning empty error set can be passed as fn returning any error - pointer" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
157154
158 entryPtr();155 entryPtr();
...@@ -404,7 +401,6 @@ fn intLiteral(str: []const u8) !?i64 {...@@ -404,7 +401,6 @@ fn intLiteral(str: []const u8) !?i64 {
404}401}
405402
406test "nested error union function call in optional unwrap" {403test "nested error union function call in optional unwrap" {
407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
408 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
410406
...@@ -482,7 +478,6 @@ test "optional error set is the same size as error set" {...@@ -482,7 +478,6 @@ test "optional error set is the same size as error set" {
482}478}
483479
484test "nested catch" {480test "nested catch" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
487482
488 const S = struct {483 const S = struct {
...@@ -590,7 +585,6 @@ test "error union comptime caching" {...@@ -590,7 +585,6 @@ test "error union comptime caching" {
590}585}
591586
592test "@errorName" {587test "@errorName" {
593 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;588 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
595 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO589 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;590 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -605,7 +599,6 @@ fn gimmeItBroke() anyerror {...@@ -605,7 +599,6 @@ fn gimmeItBroke() anyerror {
605}599}
606600
607test "@errorName sentinel length matches slice length" {601test "@errorName sentinel length matches slice length" {
608 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
609 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;602 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO603 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
611 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;604 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -700,7 +693,6 @@ test "coerce error set to the current inferred error set" {...@@ -700,7 +693,6 @@ test "coerce error set to the current inferred error set" {
700}693}
701694
702test "error union payload is properly aligned" {695test "error union payload is properly aligned" {
703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO696 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO697 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
706 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;698 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -759,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {...@@ -759,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {
759}751}
760752
761test "pointer to error union payload" {753test "pointer to error union payload" {
762 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
763 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
764 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
765 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;756 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -847,7 +838,6 @@ test "alignment of wrapping an error union payload" {...@@ -847,7 +838,6 @@ test "alignment of wrapping an error union payload" {
847}838}
848839
849test "compare error union and error set" {840test "compare error union and error set" {
850 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO841 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
852842
853 var a: anyerror = error.Foo;843 var a: anyerror = error.Foo;
...@@ -883,7 +873,6 @@ test "catch within a function that calls no errorable functions" {...@@ -883,7 +873,6 @@ test "catch within a function that calls no errorable functions" {
883}873}
884874
885test "error from comptime string" {875test "error from comptime string" {
886 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
887 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
888 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
889 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;878 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -946,7 +935,6 @@ test "optional error set function parameter" {...@@ -946,7 +935,6 @@ test "optional error set function parameter" {
946}935}
947936
948test "returning an error union containing a type with no runtime bits" {937test "returning an error union containing a type with no runtime bits" {
949 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
950 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
951 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;939 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
952940
...@@ -1038,8 +1026,6 @@ test "errorCast to adhoc inferred error set" {...@@ -1038,8 +1026,6 @@ test "errorCast to adhoc inferred error set" {
1038}1026}
10391027
1040test "@errorCast from error set to error union" {1028test "@errorCast from error set to error union" {
1041 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1042
1043 const S = struct {1029 const S = struct {
1044 fn doTheTest(set: error{ A, B }) error{A}!i32 {1030 fn doTheTest(set: error{ A, B }) error{A}!i32 {
1045 return @errorCast(set);1031 return @errorCast(set);
...@@ -1050,8 +1036,6 @@ test "@errorCast from error set to error union" {...@@ -1050,8 +1036,6 @@ test "@errorCast from error set to error union" {
1050}1036}
10511037
1052test "@errorCast from error union to error union" {1038test "@errorCast from error union to error union" {
1053 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1054
1055 const S = struct {1039 const S = struct {
1056 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {1040 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {
1057 return @errorCast(set);1041 return @errorCast(set);
test/behavior/field_parent_ptr.zig+6-5
...@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;...@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4test "@fieldParentPtr struct" {4test "@fieldParentPtr struct" {
5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;5 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
87
...@@ -587,11 +586,12 @@ test "@fieldParentPtr extern struct last zero-bit field" {...@@ -587,11 +586,12 @@ test "@fieldParentPtr extern struct last zero-bit field" {
587}586}
588587
589test "@fieldParentPtr unaligned packed struct" {588test "@fieldParentPtr unaligned packed struct" {
590 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;589 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
591 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;590 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
592 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;591 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
593 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;592 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;593 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595595
596 const C = packed struct {596 const C = packed struct {
597 a: bool = true,597 a: bool = true,
...@@ -726,11 +726,12 @@ test "@fieldParentPtr unaligned packed struct" {...@@ -726,11 +726,12 @@ test "@fieldParentPtr unaligned packed struct" {
726}726}
727727
728test "@fieldParentPtr aligned packed struct" {728test "@fieldParentPtr aligned packed struct" {
729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;729 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
730 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;730 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
731 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;731 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
732 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;732 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
733 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;733 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
734 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
734735
735 const C = packed struct {736 const C = packed struct {
736 a: f32 = 3.14,737 a: f32 = 3.14,
...@@ -868,6 +869,7 @@ test "@fieldParentPtr nested packed struct" {...@@ -868,6 +869,7 @@ test "@fieldParentPtr nested packed struct" {
868 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;869 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
869 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;870 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
870 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;871 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
872 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
871873
872 {874 {
873 const C = packed struct {875 const C = packed struct {
...@@ -1342,7 +1344,6 @@ test "@fieldParentPtr packed struct last zero-bit field" {...@@ -1342,7 +1344,6 @@ test "@fieldParentPtr packed struct last zero-bit field" {
1342}1344}
13431345
1344test "@fieldParentPtr tagged union" {1346test "@fieldParentPtr tagged union" {
1345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1346 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1347 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1347 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1348 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13481349
...@@ -1479,7 +1480,6 @@ test "@fieldParentPtr tagged union" {...@@ -1479,7 +1480,6 @@ test "@fieldParentPtr tagged union" {
1479}1480}
14801481
1481test "@fieldParentPtr untagged union" {1482test "@fieldParentPtr untagged union" {
1482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1483 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1483 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1484 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1484 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14851485
...@@ -1616,6 +1616,7 @@ test "@fieldParentPtr untagged union" {...@@ -1616,6 +1616,7 @@ test "@fieldParentPtr untagged union" {
1616}1616}
16171617
1618test "@fieldParentPtr extern union" {1618test "@fieldParentPtr extern union" {
1619 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1619 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1620 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1620 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1621 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16211622
test/behavior/inline_switch.zig-2
...@@ -43,7 +43,6 @@ test "inline switch enums" {...@@ -43,7 +43,6 @@ test "inline switch enums" {
4343
44const U = union(E) { a: void, b: u2, c: u3, d: u4 };44const U = union(E) { a: void, b: u2, c: u3, d: u4 };
45test "inline switch unions" {45test "inline switch unions" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4948
...@@ -105,7 +104,6 @@ test "inline else enum" {...@@ -105,7 +104,6 @@ test "inline else enum" {
105}104}
106105
107test "inline else int with gaps" {106test "inline else int with gaps" {
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
111109
test/behavior/math.zig+2-3
...@@ -168,7 +168,6 @@ fn testOneCtz(comptime T: type, x: T) u32 {...@@ -168,7 +168,6 @@ fn testOneCtz(comptime T: type, x: T) u32 {
168}168}
169169
170test "@ctz 128-bit integers" {170test "@ctz 128-bit integers" {
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
174 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -463,7 +462,6 @@ test "binary not big int <= 128 bits" {...@@ -463,7 +462,6 @@ test "binary not big int <= 128 bits" {
463}462}
464463
465test "division" {464test "division" {
466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO466 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;467 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -527,6 +525,8 @@ fn testIntDivision() !void {...@@ -527,6 +525,8 @@ fn testIntDivision() !void {
527 try expect(rem(i32, 10, 12) == 10);525 try expect(rem(i32, 10, 12) == 10);
528 try expect(rem(i32, -14, 12) == -2);526 try expect(rem(i32, -14, 12) == -2);
529 try expect(rem(i32, -2, 12) == -2);527 try expect(rem(i32, -2, 12) == -2);
528 try expect(rem(i32, 118, -12) == 10);
529 try expect(rem(i32, -14, -12) == -2);
530 try expect(rem(i16, -118, 12) == -10);530 try expect(rem(i16, -118, 12) == -10);
531531
532 try expect(divTrunc(i20, 20, -5) == -4);532 try expect(divTrunc(i20, 20, -5) == -4);
...@@ -1819,7 +1819,6 @@ test "runtime int comparison to inf is comptime-known" {...@@ -1819,7 +1819,6 @@ test "runtime int comparison to inf is comptime-known" {
1819}1819}
18201820
1821test "float divide by zero" {1821test "float divide by zero" {
1822 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1823 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1822 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1824 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1823 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1824 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/optional.zig-3
...@@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" {...@@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" {
319}319}
320320
321test "coerce an anon struct literal to optional struct" {321test "coerce an anon struct literal to optional struct" {
322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
324 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
325 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;324 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -391,7 +390,6 @@ test "0-bit child type coerced to optional" {...@@ -391,7 +390,6 @@ test "0-bit child type coerced to optional" {
391}390}
392391
393test "array of optional unaligned types" {392test "array of optional unaligned types" {
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO393 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;395 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -447,7 +445,6 @@ test "optional pointer to zero bit optional payload" {...@@ -447,7 +445,6 @@ test "optional pointer to zero bit optional payload" {
447}445}
448446
449test "optional pointer to zero bit error union payload" {447test "optional pointer to zero bit error union payload" {
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
451 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO448 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO449 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;450 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/packed-struct.zig+1
...@@ -1322,6 +1322,7 @@ test "packed struct equality ignores padding bits" {...@@ -1322,6 +1322,7 @@ test "packed struct equality ignores padding bits" {
1322}1322}
13231323
1324test "packed struct with signed field" {1324test "packed struct with signed field" {
1325 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1325 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13261327
1327 var s: packed struct {1328 var s: packed struct {
test/behavior/pointers.zig-1
...@@ -246,7 +246,6 @@ test "implicit casting between C pointer and optional non-C pointer" {...@@ -246,7 +246,6 @@ test "implicit casting between C pointer and optional non-C pointer" {
246}246}
247247
248test "implicit cast error unions with non-optional to optional pointer" {248test "implicit cast error unions with non-optional to optional pointer" {
249 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;251 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/ptrcast.zig+10
...@@ -552,3 +552,13 @@ test "@ptrCast single-item pointer to slice of bytes" {...@@ -552,3 +552,13 @@ test "@ptrCast single-item pointer to slice of bytes" {
552 try comptime S.doTheTest(void, &{});552 try comptime S.doTheTest(void, &{});
553 try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });553 try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
554}554}
555
556test "@ptrCast array pointer removing sentinel" {
557 const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 };
558 const out: []const i8 = @ptrCast(in);
559 comptime assert(out.len == 4);
560 comptime assert(out[0] == 1);
561 comptime assert(out[1] == 2);
562 comptime assert(out[2] == 3);
563 comptime assert(out[3] == 4);
564}
test/behavior/return_address.zig-1
...@@ -6,7 +6,6 @@ fn retAddr() usize {...@@ -6,7 +6,6 @@ fn retAddr() usize {
6}6}
77
8test "return address" {8test "return address" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/slice.zig-4
...@@ -628,9 +628,6 @@ test "slice syntax resulting in pointer-to-array" {...@@ -628,9 +628,6 @@ test "slice syntax resulting in pointer-to-array" {
628 comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8);628 comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8);
629 comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8);629 comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8);
630 comptime assert(@TypeOf(ptr[1..][0..2 :4]) == *[2:4]u8);630 comptime assert(@TypeOf(ptr[1..][0..2 :4]) == *[2:4]u8);
631 comptime assert(@TypeOf(ptr[1.. :0][0..2]) == *[2]u8);
632 comptime assert(@TypeOf(ptr[1.. :0][0..4]) == *[4]u8);
633 comptime assert(@TypeOf(ptr[1.. :0][0..2 :4]) == *[2:4]u8);
634631
635 var ptr_z: [*:0]u8 = &array;632 var ptr_z: [*:0]u8 = &array;
636 comptime assert(@TypeOf(ptr_z[1..][0..2]) == *[2]u8);633 comptime assert(@TypeOf(ptr_z[1..][0..2]) == *[2]u8);
...@@ -710,7 +707,6 @@ test "slice pointer-to-array zero length" {...@@ -710,7 +707,6 @@ test "slice pointer-to-array zero length" {
710}707}
711708
712test "type coercion of pointer to anon struct literal to pointer to slice" {709test "type coercion of pointer to anon struct literal to pointer to slice" {
713 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
714 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
715 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO711 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;712 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/struct.zig-6
...@@ -797,7 +797,6 @@ test "fn with C calling convention returns struct by value" {...@@ -797,7 +797,6 @@ test "fn with C calling convention returns struct by value" {
797}797}
798798
799test "non-packed struct with u128 entry in union" {799test "non-packed struct with u128 entry in union" {
800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO800 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO801 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
803 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;802 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -956,7 +955,6 @@ test "tuple element initialized with fn call" {...@@ -956,7 +955,6 @@ test "tuple element initialized with fn call" {
956}955}
957956
958test "struct with union field" {957test "struct with union field" {
959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
960 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;958 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
961 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO959 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
962 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO960 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1026,7 +1024,6 @@ test "packed struct with undefined initializers" {...@@ -1026,7 +1024,6 @@ test "packed struct with undefined initializers" {
1026}1024}
10271025
1028test "for loop over pointers to struct, getting field from struct pointer" {1026test "for loop over pointers to struct, getting field from struct pointer" {
1029 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1030 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1027 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1031 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1028 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1032 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1093,7 +1090,6 @@ test "anon init through error unions and optionals" {...@@ -1093,7 +1090,6 @@ test "anon init through error unions and optionals" {
1093}1090}
10941091
1095test "anon init through optional" {1092test "anon init through optional" {
1096 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1097 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1093 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1098 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1094 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1099 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1095 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1113,7 +1109,6 @@ test "anon init through optional" {...@@ -1113,7 +1109,6 @@ test "anon init through optional" {
1113}1109}
11141110
1115test "anon init through error union" {1111test "anon init through error union" {
1116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1113 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1119 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1114 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1398,7 +1393,6 @@ test "struct has only one reference" {...@@ -1398,7 +1393,6 @@ test "struct has only one reference" {
1398}1393}
13991394
1400test "no dependency loop on pointer to optional struct" {1395test "no dependency loop on pointer to optional struct" {
1401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1403 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1397 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14041398
test/behavior/struct_contains_slice_of_itself.zig-2
...@@ -12,7 +12,6 @@ const NodeAligned = struct {...@@ -12,7 +12,6 @@ const NodeAligned = struct {
12};12};
1313
14test "struct contains slice of itself" {14test "struct contains slice of itself" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;16 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1817
...@@ -53,7 +52,6 @@ test "struct contains slice of itself" {...@@ -53,7 +52,6 @@ test "struct contains slice of itself" {
53}52}
5453
55test "struct contains aligned slice of itself" {54test "struct contains aligned slice of itself" {
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;56 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5957
test/behavior/switch.zig+10-9
...@@ -8,7 +8,6 @@ const minInt = std.math.minInt;...@@ -8,7 +8,6 @@ const minInt = std.math.minInt;
8const maxInt = std.math.maxInt;8const maxInt = std.math.maxInt;
99
10test "switch with numbers" {10test "switch with numbers" {
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1413
...@@ -300,7 +299,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {...@@ -300,7 +299,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
300}299}
301300
302test "switch on enum using pointer capture" {301test "switch on enum using pointer capture" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306304
...@@ -361,7 +359,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {...@@ -361,7 +359,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
361}359}
362360
363test "switch on union with some prongs capturing" {361test "switch on union with some prongs capturing" {
364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
367364
...@@ -469,7 +466,6 @@ test "switch on integer with else capturing expr" {...@@ -469,7 +466,6 @@ test "switch on integer with else capturing expr" {
469}466}
470467
471test "else prong of switch on error set excludes other cases" {468test "else prong of switch on error set excludes other cases" {
472 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;471 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -505,7 +501,6 @@ test "else prong of switch on error set excludes other cases" {...@@ -505,7 +501,6 @@ test "else prong of switch on error set excludes other cases" {
505}501}
506502
507test "switch prongs with error set cases make a new error set type for capture value" {503test "switch prongs with error set cases make a new error set type for capture value" {
508 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
509 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
511 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -736,7 +731,6 @@ test "switch on error set with single else" {...@@ -736,7 +731,6 @@ test "switch on error set with single else" {
736}731}
737732
738test "switch capture copies its payload" {733test "switch capture copies its payload" {
739 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
740 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
741 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO735 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
742 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;736 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -931,7 +925,6 @@ test "nested break ignores switch conditions and breaks instead" {...@@ -931,7 +925,6 @@ test "nested break ignores switch conditions and breaks instead" {
931}925}
932926
933test "peer type resolution on switch captures ignores unused payload bits" {927test "peer type resolution on switch captures ignores unused payload bits" {
934 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
935 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;928 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
936 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;929 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
937930
...@@ -976,8 +969,6 @@ test "switch prong captures range" {...@@ -976,8 +969,6 @@ test "switch prong captures range" {
976}969}
977970
978test "prong with inline call to unreachable" {971test "prong with inline call to unreachable" {
979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
980
981 const U = union(enum) {972 const U = union(enum) {
982 void: void,973 void: void,
983 bool: bool,974 bool: bool,
...@@ -1072,3 +1063,13 @@ test "switch on a signed value smaller than the smallest prong value" {...@@ -1072,3 +1063,13 @@ test "switch on a signed value smaller than the smallest prong value" {
1072 else => {},1063 else => {},
1073 }1064 }
1074}1065}
1066
1067test "switch on 8-bit mod result" {
1068 var x: u8 = undefined;
1069 x = 16;
1070 switch (x % 4) {
1071 0 => {},
1072 1, 2, 3 => return error.TestFailed,
1073 else => unreachable,
1074 }
1075}
test/behavior/switch_on_captured_error.zig-1
...@@ -6,7 +6,6 @@ const expectEqual = std.testing.expectEqual;...@@ -6,7 +6,6 @@ const expectEqual = std.testing.expectEqual;
6const builtin = @import("builtin");6const builtin = @import("builtin");
77
8test "switch on error union catch capture" {8test "switch on error union catch capture" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
test/behavior/switch_prong_err_enum.zig-1
...@@ -21,7 +21,6 @@ fn doThing(form_id: u64) anyerror!FormValue {...@@ -21,7 +21,6 @@ fn doThing(form_id: u64) anyerror!FormValue {
21}21}
2222
23test "switch prong returns error enum" {23test "switch prong returns error enum" {
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;26 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/try.zig-1
...@@ -47,7 +47,6 @@ test "try then not executed with assignment" {...@@ -47,7 +47,6 @@ test "try then not executed with assignment" {
47}47}
4848
49test "`try`ing an if/else expression" {49test "`try`ing an if/else expression" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;51 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
53 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;52 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/union.zig-39
...@@ -12,7 +12,6 @@ const FooWithFloats = union {...@@ -12,7 +12,6 @@ const FooWithFloats = union {
12};12};
1313
14test "basic unions with floats" {14test "basic unions with floats" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;17 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -29,7 +28,6 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {...@@ -29,7 +28,6 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {
29}28}
3029
31test "init union with runtime value - floats" {30test "init union with runtime value - floats" {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -41,7 +39,6 @@ test "init union with runtime value - floats" {...@@ -41,7 +39,6 @@ test "init union with runtime value - floats" {
41}39}
4240
43test "basic unions" {41test "basic unions" {
44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -60,7 +57,6 @@ const Foo = union {...@@ -60,7 +57,6 @@ const Foo = union {
60};57};
6158
62test "init union with runtime value" {59test "init union with runtime value" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;60 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO61 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;62 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -101,7 +97,6 @@ const FooExtern = extern union {...@@ -101,7 +97,6 @@ const FooExtern = extern union {
101};97};
10298
103test "basic extern unions" {99test "basic extern unions" {
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107102
...@@ -160,7 +155,6 @@ test "unions embedded in aggregate types" {...@@ -160,7 +155,6 @@ test "unions embedded in aggregate types" {
160}155}
161156
162test "constant tagged union with payload" {157test "constant tagged union with payload" {
163 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
166160
...@@ -263,7 +257,6 @@ fn testComparison() !void {...@@ -263,7 +257,6 @@ fn testComparison() !void {
263}257}
264258
265test "comparison between union and enum literal" {259test "comparison between union and enum literal" {
266 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO261 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;262 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -279,7 +272,6 @@ const TheUnion = union(TheTag) {...@@ -279,7 +272,6 @@ const TheUnion = union(TheTag) {
279 C: i32,272 C: i32,
280};273};
281test "cast union to tag type of union" {274test "cast union to tag type of union" {
282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285277
...@@ -300,7 +292,6 @@ test "union field access gives the enum values" {...@@ -300,7 +292,6 @@ test "union field access gives the enum values" {
300}292}
301293
302test "cast tag type of union to union" {294test "cast tag type of union to union" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306297
...@@ -316,7 +307,6 @@ const Value2 = union(Letter2) {...@@ -316,7 +307,6 @@ const Value2 = union(Letter2) {
316};307};
317308
318test "implicit cast union to its tag type" {309test "implicit cast union to its tag type" {
319 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
320 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
322312
...@@ -337,7 +327,6 @@ pub const PackThis = union(enum) {...@@ -337,7 +327,6 @@ pub const PackThis = union(enum) {
337};327};
338328
339test "constant packed union" {329test "constant packed union" {
340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -483,7 +472,6 @@ pub const FooUnion = union(enum) {...@@ -483,7 +472,6 @@ pub const FooUnion = union(enum) {
483var glbl_array: [2]FooUnion = undefined;472var glbl_array: [2]FooUnion = undefined;
484473
485test "initialize global array of union" {474test "initialize global array of union" {
486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO476 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
489 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;477 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -495,7 +483,6 @@ test "initialize global array of union" {...@@ -495,7 +483,6 @@ test "initialize global array of union" {
495}483}
496484
497test "update the tag value for zero-sized unions" {485test "update the tag value for zero-sized unions" {
498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO487 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
501488
...@@ -734,7 +721,6 @@ test "union with only 1 field casted to its enum type which has enum value speci...@@ -734,7 +721,6 @@ test "union with only 1 field casted to its enum type which has enum value speci
734}721}
735722
736test "@intFromEnum works on unions" {723test "@intFromEnum works on unions" {
737 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
738 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO724 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
739 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO725 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
740726
...@@ -817,7 +803,6 @@ test "return union init with void payload" {...@@ -817,7 +803,6 @@ test "return union init with void payload" {
817}803}
818804
819test "@unionInit stored to a const" {805test "@unionInit stored to a const" {
820 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
821 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO806 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
822 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
823 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;808 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -848,7 +833,6 @@ test "@unionInit stored to a const" {...@@ -848,7 +833,6 @@ test "@unionInit stored to a const" {
848}833}
849834
850test "@unionInit can modify a union type" {835test "@unionInit can modify a union type" {
851 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
852 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO836 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
853 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO837 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
854838
...@@ -871,7 +855,6 @@ test "@unionInit can modify a union type" {...@@ -871,7 +855,6 @@ test "@unionInit can modify a union type" {
871}855}
872856
873test "@unionInit can modify a pointer value" {857test "@unionInit can modify a pointer value" {
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
875 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO858 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
876 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO859 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
877860
...@@ -926,7 +909,6 @@ test "extern union doesn't trigger field check at comptime" {...@@ -926,7 +909,6 @@ test "extern union doesn't trigger field check at comptime" {
926}909}
927910
928test "anonymous union literal syntax" {911test "anonymous union literal syntax" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO912 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO913 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
932 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;914 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -990,7 +972,6 @@ test "function call result coerces from tagged union to the tag" {...@@ -990,7 +972,6 @@ test "function call result coerces from tagged union to the tag" {
990}972}
991973
992test "switching on non exhaustive union" {974test "switching on non exhaustive union" {
993 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
994 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO975 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
995 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO976 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
996977
...@@ -1096,7 +1077,6 @@ test "union enum type gets a separate scope" {...@@ -1096,7 +1077,6 @@ test "union enum type gets a separate scope" {
1096}1077}
10971078
1098test "global variable struct contains union initialized to non-most-aligned field" {1079test "global variable struct contains union initialized to non-most-aligned field" {
1099 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1080 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1081 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1102 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1082 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...@@ -1123,7 +1103,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel
1123}1103}
11241104
1125test "union with no result loc initiated with a runtime value" {1105test "union with no result loc initiated with a runtime value" {
1126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1106 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1108 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1141,7 +1120,6 @@ test "union with no result loc initiated with a runtime value" {...@@ -1141,7 +1120,6 @@ test "union with no result loc initiated with a runtime value" {
1141}1120}
11421121
1143test "union with a large struct field" {1122test "union with a large struct field" {
1144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1125 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1176,7 +1154,6 @@ test "comptime equality of extern unions with same tag" {...@@ -1176,7 +1154,6 @@ test "comptime equality of extern unions with same tag" {
1176}1154}
11771155
1178test "union tag is set when initiated as a temporary value at runtime" {1156test "union tag is set when initiated as a temporary value at runtime" {
1179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1181 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1182 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1159 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1216,7 +1193,6 @@ test "extern union most-aligned field is smaller" {...@@ -1216,7 +1193,6 @@ test "extern union most-aligned field is smaller" {
1216}1193}
12171194
1218test "return an extern union from C calling convention" {1195test "return an extern union from C calling convention" {
1219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1197 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1198 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1248,7 +1224,6 @@ test "return an extern union from C calling convention" {...@@ -1248,7 +1224,6 @@ test "return an extern union from C calling convention" {
1248}1224}
12491225
1250test "noreturn field in union" {1226test "noreturn field in union" {
1251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1227 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1228 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12541229
...@@ -1299,7 +1274,6 @@ test "noreturn field in union" {...@@ -1299,7 +1274,6 @@ test "noreturn field in union" {
1299}1274}
13001275
1301test "@unionInit uses tag value instead of field index" {1276test "@unionInit uses tag value instead of field index" {
1302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1304 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1305 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1279 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1408,7 +1382,6 @@ test "union int tag type is properly managed" {...@@ -1408,7 +1382,6 @@ test "union int tag type is properly managed" {
1408}1382}
14091383
1410test "no dependency loop when function pointer in union returns the union" {1384test "no dependency loop when function pointer in union returns the union" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1385 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1414 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1387 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" {...@@ -1430,7 +1403,6 @@ test "no dependency loop when function pointer in union returns the union" {
1430}1403}
14311404
1432test "union reassignment can use previous value" {1405test "union reassignment can use previous value" {
1433 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1434 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1406 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1435 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1407 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14361408
...@@ -1481,8 +1453,6 @@ test "reinterpreting enum value inside packed union" {...@@ -1481,8 +1453,6 @@ test "reinterpreting enum value inside packed union" {
1481}1453}
14821454
1483test "access the tag of a global tagged union" {1455test "access the tag of a global tagged union" {
1484 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1485
1486 const U = union(enum) {1456 const U = union(enum) {
1487 a,1457 a,
1488 b: u8,1458 b: u8,
...@@ -1634,7 +1604,6 @@ test "union with 128 bit integer" {...@@ -1634,7 +1604,6 @@ test "union with 128 bit integer" {
1634}1604}
16351605
1636test "memset extern union" {1606test "memset extern union" {
1637 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1638 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1607 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16391608
1640 const U = extern union {1609 const U = extern union {
...@@ -1956,7 +1925,6 @@ test "packed union initialized via reintepreted struct field initializer" {...@@ -1956,7 +1925,6 @@ test "packed union initialized via reintepreted struct field initializer" {
1956}1925}
19571926
1958test "store of comptime reinterpreted memory to extern union" {1927test "store of comptime reinterpreted memory to extern union" {
1959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1960 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1928 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19611929
1962 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };1930 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
...@@ -2063,7 +2031,6 @@ test "circular dependency through pointer field of a union" {...@@ -2063,7 +2031,6 @@ test "circular dependency through pointer field of a union" {
2063}2031}
20642032
2065test "pass nested union with rls" {2033test "pass nested union with rls" {
2066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2067 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2034 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2068 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2035 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20692036
...@@ -2085,7 +2052,6 @@ test "pass nested union with rls" {...@@ -2085,7 +2052,6 @@ test "pass nested union with rls" {
2085}2052}
20862053
2087test "runtime union init, most-aligned field != largest" {2054test "runtime union init, most-aligned field != largest" {
2088 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2089 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2055 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2090 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2056 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2091 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2057 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2111,7 +2077,6 @@ test "runtime union init, most-aligned field != largest" {...@@ -2111,7 +2077,6 @@ test "runtime union init, most-aligned field != largest" {
2111}2077}
21122078
2113test "copied union field doesn't alias source" {2079test "copied union field doesn't alias source" {
2114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2080 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2081 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2117 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2082 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2255,7 +2220,6 @@ test "matching captures causes union equivalence" {...@@ -2255,7 +2220,6 @@ test "matching captures causes union equivalence" {
2255}2220}
22562221
2257test "signed enum tag with negative value" {2222test "signed enum tag with negative value" {
2258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2259 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2223 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2224 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2261 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2225 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2312,7 +2276,6 @@ test "extern union @FieldType" {...@@ -2312,7 +2276,6 @@ test "extern union @FieldType" {
2312}2276}
23132277
2314test "assign global tagged union" {2278test "assign global tagged union" {
2315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2316 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2279 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
23172280
2318 const U = union(enum) {2281 const U = union(enum) {
...@@ -2334,8 +2297,6 @@ test "assign global tagged union" {...@@ -2334,8 +2297,6 @@ test "assign global tagged union" {
2334}2297}
23352298
2336test "set mutable union by switching on same union" {2299test "set mutable union by switching on same union" {
2337 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2338
2339 const U = union(enum) {2300 const U = union(enum) {
2340 foo,2301 foo,
2341 bar: usize,2302 bar: usize,
test/behavior/union_with_members.zig-1
...@@ -17,7 +17,6 @@ const ET = union(enum) {...@@ -17,7 +17,6 @@ const ET = union(enum) {
17};17};
1818
19test "enum with members" {19test "enum with members" {
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO21 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/var_args.zig-4
...@@ -92,7 +92,6 @@ fn doNothingWithFirstArg(args: anytype) void {...@@ -92,7 +92,6 @@ fn doNothingWithFirstArg(args: anytype) void {
92}92}
9393
94test "simple variadic function" {94test "simple variadic function" {
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
96 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO95 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -154,7 +153,6 @@ test "simple variadic function" {...@@ -154,7 +153,6 @@ test "simple variadic function" {
154}153}
155154
156test "coerce reference to var arg" {155test "coerce reference to var arg" {
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -234,7 +232,6 @@ test "variadic functions" {...@@ -234,7 +232,6 @@ test "variadic functions" {
234}232}
235233
236test "copy VaList" {234test "copy VaList" {
237 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO236 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
240 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;237 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -269,7 +266,6 @@ test "copy VaList" {...@@ -269,7 +266,6 @@ test "copy VaList" {
269}266}
270267
271test "unused VaList arg" {268test "unused VaList arg" {
272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO270 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
275 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;271 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/while.zig-3
...@@ -174,7 +174,6 @@ test "while with optional as condition with else" {...@@ -174,7 +174,6 @@ test "while with optional as condition with else" {
174}174}
175175
176test "while with error union condition" {176test "while with error union condition" {
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
180 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;179 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -306,7 +305,6 @@ test "while optional 2 break statements and an else" {...@@ -306,7 +305,6 @@ test "while optional 2 break statements and an else" {
306}305}
307306
308test "while error 2 break statements and an else" {307test "while error 2 break statements and an else" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO309 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312310
...@@ -344,7 +342,6 @@ test "else continue outer while" {...@@ -344,7 +342,6 @@ test "else continue outer while" {
344}342}
345343
346test "try terminating an infinite loop" {344test "try terminating an infinite loop" {
347 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
349 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
350347
test/behavior/x86_64/binary.zig-2
...@@ -5473,8 +5473,6 @@ inline fn shlSaturate(comptime Type: type, lhs: Type, rhs: Type) Type {...@@ -5473,8 +5473,6 @@ inline fn shlSaturate(comptime Type: type, lhs: Type, rhs: Type) Type {
5473 // workaround https://github.com/ziglang/zig/issues/231395473 // workaround https://github.com/ziglang/zig/issues/23139
5474 return lhs <<| @min(@abs(rhs), splat(ChangeScalar(Type, u64), imax(u64)));5474 return lhs <<| @min(@abs(rhs), splat(ChangeScalar(Type, u64), imax(u64)));
5475 }5475 }
5476 // workaround https://github.com/ziglang/zig/issues/23033
5477 @setRuntimeSafety(false);
5478 return lhs <<| @abs(rhs);5476 return lhs <<| @abs(rhs);
5479}5477}
5480test shlSaturate {5478test shlSaturate {
test/cases/array_in_anon_struct.zig+1-1
...@@ -19,4 +19,4 @@ pub fn main() !void {...@@ -19,4 +19,4 @@ pub fn main() !void {
1919
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/compile_errors/atomics_with_invalid_type.zig+15-2
...@@ -5,14 +5,27 @@ export fn float() void {...@@ -5,14 +5,27 @@ export fn float() void {
55
6const NormalStruct = struct { x: u32 };6const NormalStruct = struct { x: u32 };
7export fn normalStruct() void {7export fn normalStruct() void {
8 var x: NormalStruct = 0;8 var x: NormalStruct = .{ .x = 0 };
9 _ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);9 _ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);
10}10}
1111
12export fn anyError() void {
13 var x: anyerror = error.A;
14 _ = @cmpxchgWeak(anyerror, &x, error.A, error.B, .seq_cst, .seq_cst);
15}
16
17const ErrorSet = error{ A, B };
18export fn errorSet() void {
19 var x: ErrorSet = error.A;
20 _ = @cmpxchgWeak(ErrorSet, &x, error.A, error.B, .seq_cst, .seq_cst);
21}
22
12// error23// error
13// backend=stage224// backend=stage2
14// target=native25// target=native
15//26//
16// :3:22: error: expected bool, integer, enum, packed struct, or pointer type; found 'f32'27// :3:22: error: expected bool, integer, enum, packed struct, or pointer type; found 'f32'
17// :8:27: error: expected type 'tmp.NormalStruct', found 'comptime_int'28// :9:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'tmp.NormalStruct'
18// :6:22: note: struct declared here29// :6:22: note: struct declared here
30// :14:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'anyerror'
31// :20:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'error{A,B}'
test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig+2-2
...@@ -7,5 +7,5 @@ export fn entry3() callconv(.avr_interrupt) void {}...@@ -7,5 +7,5 @@ export fn entry3() callconv(.avr_interrupt) void {}
7// target=aarch64-linux-none7// target=aarch64-linux-none
8//8//
9// :1:30: error: calling convention 'x86_64_interrupt' only available on architectures 'x86_64'9// :1:30: error: calling convention 'x86_64_interrupt' only available on architectures 'x86_64'
10// :1:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'10// :2:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'
11// :1:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'11// :3:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'
test/cases/compile_errors/comptime_try_non_error.zig+1
...@@ -13,4 +13,5 @@ pub fn bar() u8 {...@@ -13,4 +13,5 @@ pub fn bar() u8 {
13// error13// error
14//14//
15// :6:12: error: expected error union type, found 'u8'15// :6:12: error: expected error union type, found 'u8'
16// :6:12: note: consider omitting 'try'
16// :2:8: note: called at comptime here17// :2:8: note: called at comptime here
test/cases/compile_errors/error_set_membership.zig+1-1
...@@ -25,7 +25,7 @@ pub fn main() Error!void {...@@ -25,7 +25,7 @@ pub fn main() Error!void {
2525
26// error26// error
27// backend=stage227// backend=stage2
28// target=native28// target=x86_64-linux
29//29//
30// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'30// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'
31// :23:29: note: 'error.InvalidDirection' not a member of destination error set31// :23:29: note: 'error.InvalidDirection' not a member of destination error set
test/cases/compile_errors/function_ptr_alignment.zig+1-1
...@@ -10,7 +10,7 @@ comptime {...@@ -10,7 +10,7 @@ comptime {
1010
11// error11// error
12// backend=stage212// backend=stage2
13// target=native13// target=x86_64-linux
14//14//
15// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'15// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
16// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'16// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'
test/cases/compile_errors/int_to_float_coercion_loses_precision.zig created+9
...@@ -0,0 +1,9 @@
1export fn foo() void {
2 const int: u16 = 65535;
3 const float: f16 = int;
4 _ = float;
5}
6
7// error
8//
9// :3:24: error: type 'f16' cannot represent integer value '65535'
test/cases/compile_errors/issue_15572_break_on_inline_while.zig+1-1
...@@ -15,6 +15,6 @@ pub fn main() void {...@@ -15,6 +15,6 @@ pub fn main() void {
1515
16// error16// error
17// backend=stage217// backend=stage2
18// target=native18// target=x86_64-linux
19//19//
20// :9:28: error: incompatible types: 'builtin.Type.EnumField' and 'void'20// :9:28: error: incompatible types: 'builtin.Type.EnumField' and 'void'
test/cases/compile_errors/minmax_nonnumeric_operand.zig created+41
...@@ -0,0 +1,41 @@
1// zig fmt: off
2comptime { _ = @min(0, u32); } // type
3comptime { _ = @max(0, {}); } // void
4comptime { _ = @min(0, false); } // boolean
5comptime { _ = @min(0, &@as(u8, 0)); } // pointer
6comptime { _ = @max(0, [0]u8{}); } // array
7comptime { _ = @min(0, Struct{}); } // struct
8comptime { _ = @max(0, null); } // null
9comptime { _ = @min(0, @as(?u8, 0)); } // nullable
10comptime { _ = @max(0, @as(error{}!u8, 0)); } // error union
11comptime { _ = @min(0, error.Foo); } // error set
12comptime { _ = @max(0, Enum.foo); } // enum
13comptime { _ = @min(0, Union{ .foo = {} }); } // union
14comptime { _ = @max(0, struct { fn func() u8 { return 42; }}.func); }
15comptime { _ = @max(0, .foo); } // enum literal
16
17const Struct = struct {};
18const Enum = enum { foo };
19const Union = union { foo: void };
20
21// error
22// backend=stage2
23// target=native
24//
25// :2:24: error: expected number, found 'type'
26// :3:24: error: expected number, found 'void'
27// :4:24: error: expected number, found 'bool'
28// :5:24: error: expected number, found '*const u8'
29// :6:29: error: expected number, found '[0]u8'
30// :7:30: error: expected number, found 'tmp.Struct'
31// :17:16: note: struct declared here
32// :8:24: error: expected number, found '@TypeOf(null)'
33// :9:24: error: expected number, found '?u8'
34// :10:24: error: expected number, found 'error{}!u8'
35// :11:24: error: expected number, found 'error{Foo}'
36// :12:28: error: expected number, found 'tmp.Enum'
37// :18:14: note: enum declared here
38// :13:29: error: expected number, found 'tmp.Union'
39// :19:15: note: union declared here
40// :14:61: error: expected number, found 'fn () u8'
41// :15:25: error: expected number, found '@Type(.enum_literal)'
test/cases/compile_errors/redundant_try.zig+6
...@@ -43,10 +43,16 @@ comptime {...@@ -43,10 +43,16 @@ comptime {
43// error43// error
44//44//
45// :5:23: error: expected error union type, found 'comptime_int'45// :5:23: error: expected error union type, found 'comptime_int'
46// :5:23: note: consider omitting 'try'
46// :10:23: error: expected error union type, found '@TypeOf(.{})'47// :10:23: error: expected error union type, found '@TypeOf(.{})'
48// :10:23: note: consider omitting 'try'
47// :15:23: error: expected error union type, found 'tmp.S'49// :15:23: error: expected error union type, found 'tmp.S'
48// :1:11: note: struct declared here50// :1:11: note: struct declared here
51// :15:23: note: consider omitting 'try'
49// :20:27: error: expected error union type, found 'tmp.S'52// :20:27: error: expected error union type, found 'tmp.S'
50// :1:11: note: struct declared here53// :1:11: note: struct declared here
54// :20:27: note: consider omitting 'try'
51// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'55// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
56// :25:23: note: consider omitting 'try'
52// :31:13: error: expected error union type, found 'u32'57// :31:13: error: expected error union type, found 'u32'
58// :31:13: note: consider omitting 'try'
test/cases/compile_errors/reify_type_for_tagged_extern_union.zig created+34
...@@ -0,0 +1,34 @@
1const Tag = @Type(.{
2 .@"enum" = .{
3 .tag_type = u2,
4 .fields = &.{
5 .{ .name = "signed", .value = 0 },
6 .{ .name = "unsigned", .value = 1 },
7 },
8 .decls = &.{},
9 .is_exhaustive = true,
10 },
11});
12
13const Extern = @Type(.{
14 .@"union" = .{
15 .layout = .@"extern",
16 .tag_type = Tag,
17 .fields = &.{
18 .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },
19 .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },
20 },
21 .decls = &.{},
22 },
23});
24
25export fn entry() void {
26 const tagged: Extern = .{ .signed = -1 };
27 _ = tagged;
28}
29
30// error
31// backend=stage2
32// target=native
33//
34// :13:16: error: extern union does not support enum tag type
test/cases/compile_errors/reify_type_for_tagged_packed_union.zig created+34
...@@ -0,0 +1,34 @@
1const Tag = @Type(.{
2 .@"enum" = .{
3 .tag_type = u2,
4 .fields = &.{
5 .{ .name = "signed", .value = 0 },
6 .{ .name = "unsigned", .value = 1 },
7 },
8 .decls = &.{},
9 .is_exhaustive = true,
10 },
11});
12
13const Packed = @Type(.{
14 .@"union" = .{
15 .layout = .@"packed",
16 .tag_type = Tag,
17 .fields = &.{
18 .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },
19 .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },
20 },
21 .decls = &.{},
22 },
23});
24
25export fn entry() void {
26 const tagged: Packed = .{ .signed = -1 };
27 _ = tagged;
28}
29
30// error
31// backend=stage2
32// target=native
33//
34// :13:16: error: packed union does not support enum tag type
test/cases/compile_errors/runtime_value_in_comptime_array.zig created+14
...@@ -0,0 +1,14 @@
1fn comptimeArray(comptime _: []const u8) void {}
2fn bar() u8 {
3 return 123;
4}
5export fn entry() void {
6 const y = bar();
7 comptimeArray(&.{y});
8}
9
10// error
11//
12// :7:19: error: unable to resolve comptime value
13// :7:19: note: argument to comptime parameter must be comptime-known
14// :1:18: note: parameter declared comptime here
test/cases/compile_errors/runtime_value_in_comptime_struct.zig created+14
...@@ -0,0 +1,14 @@
1fn comptimeStruct(comptime _: anytype) void {}
2fn bar() u8 {
3 return 123;
4}
5export fn entry() void {
6 const y = bar();
7 comptimeStruct(.{ .foo = y });
8}
9
10// error
11//
12// :7:21: error: unable to resolve comptime value
13// :7:21: note: argument to comptime parameter must be comptime-known
14// :1:19: note: parameter declared comptime here
test/cases/compile_errors/slice_of_many-item_pointer_preserves_sentinel.zig created+18
...@@ -0,0 +1,18 @@
1comptime {
2 var ptr: [*]const u8 = undefined;
3 _ = ptr[0.. :0];
4}
5
6comptime {
7 var ptrz: [*:0]const u8 = undefined;
8 _ = ptrz[0.. :1];
9}
10
11// error
12//
13// :3:18: error: sentinel-terminated slicing of many-item pointer must match existing sentinel
14// :3:9: note: type '[*]const u8' does not have a sentinel
15// :3:12: note: use @ptrCast to cast pointer sentinel
16// :8:19: error: sentinel-terminated slicing of many-item pointer must match existing sentinel
17// :8:19: note: expected sentinel '0', found '1'
18// :8:13: note: use @ptrCast to cast pointer sentinel
test/cases/compile_errors/switch_on_non_err_union.zig+1-1
...@@ -6,6 +6,6 @@ pub fn main() void {...@@ -6,6 +6,6 @@ pub fn main() void {
66
7// error7// error
8// backend=stage28// backend=stage2
9// target=native9// target=x86_64-linux
10//10//
11// :2:23: error: expected error union type, found 'bool'11// :2:23: error: expected error union type, found 'bool'
test/cases/pic_freestanding.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
33
4fn _start() callconv(.naked) void {}4pub fn _start() callconv(.naked) void {}
55
6comptime {6comptime {
7 @export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" });7 @export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" });
test/cases/safety/@alignCast misaligned.zig +1-1
...@@ -22,4 +22,4 @@ fn foo(bytes: []u8) u32 {...@@ -22,4 +22,4 @@ fn foo(bytes: []u8) u32 {
22}22}
23// run23// run
24// backend=stage2,llvm24// backend=stage2,llvm
25// target=native25// target=x86_64-linux,aarch64-linux
test/cases/safety/@enumFromInt - no matching tag value.zig +1-1
...@@ -23,4 +23,4 @@ fn baz(_: Foo) void {}...@@ -23,4 +23,4 @@ fn baz(_: Foo) void {}
2323
24// run24// run
25// backend=stage2,llvm25// backend=stage2,llvm
26// target=native26// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - exhaustive.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() u8 {...@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() u8 {...@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/@errorCast error not present in destination.zig +1-1
...@@ -18,4 +18,4 @@ fn foo(set1: Set1) Set2 {...@@ -18,4 +18,4 @@ fn foo(set1: Set1) Set2 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/@errorCast error union casted to disjoint set.zig +1-1
...@@ -17,4 +17,4 @@ fn foo() anyerror!i32 {...@@ -17,4 +17,4 @@ fn foo() anyerror!i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@intCast to u0.zig +1-1
...@@ -19,4 +19,4 @@ fn bar(one: u1, not_zero: i32) void {...@@ -19,4 +19,4 @@ fn bar(one: u1, not_zero: i32) void {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - negative out of range.zig +1-1
...@@ -17,4 +17,4 @@ fn bar(a: f32) i8 {...@@ -17,4 +17,4 @@ fn bar(a: f32) i8 {
17fn baz(_: i8) void {}17fn baz(_: i8) void {}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig +1-1
...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {
17fn baz(_: u8) void {}17fn baz(_: u8) void {}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - positive out of range.zig +1-1
...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {
17fn baz(_: u8) void {}17fn baz(_: u8) void {}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/@ptrFromInt with misaligned address.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/@tagName on corrupted enum value.zig +1-1
...@@ -23,4 +23,4 @@ pub fn main() !void {...@@ -23,4 +23,4 @@ pub fn main() !void {
2323
24// run24// run
25// backend=stage2,llvm25// backend=stage2,llvm
26// target=native26// target=x86_64-linux
test/cases/safety/@tagName on corrupted union value.zig +1-1
...@@ -24,4 +24,4 @@ pub fn main() !void {...@@ -24,4 +24,4 @@ pub fn main() !void {
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch vector.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/bad union field access.zig +1-1
...@@ -24,4 +24,4 @@ fn bar(f: *Foo) void {...@@ -24,4 +24,4 @@ fn bar(f: *Foo) void {
24}24}
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux
test/cases/safety/calling panic.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/cast []u8 to bigger slice of wrong size.zig +1-1
...@@ -18,4 +18,4 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {...@@ -18,4 +18,4 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/cast integer to global error and no code matches.zig +1-1
...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/empty slice with sentinel out of bounds.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/exact division failure - vectors.zig +1-1
...@@ -20,4 +20,4 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {...@@ -20,4 +20,4 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/exact division failure.zig +1-1
...@@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 {...@@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch.zig+1-1
...@@ -22,4 +22,4 @@ pub fn main() !void {...@@ -22,4 +22,4 @@ pub fn main() !void {
22}22}
23// run23// run
24// backend=stage2,llvm24// backend=stage2,llvm
25// target=native25// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch_three.zig+1-1
...@@ -21,4 +21,4 @@ pub fn main() !void {...@@ -21,4 +21,4 @@ pub fn main() !void {
21}21}
22// run22// run
23// backend=stage2,llvm23// backend=stage2,llvm
24// target=native24// target=x86_64-linux,aarch64-linux
test/cases/safety/ignored expression integer overflow.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/integer addition overflow.zig +1-1
...@@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 {...@@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/integer division by zero - vectors.zig +1-1
...@@ -19,4 +19,4 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {...@@ -19,4 +19,4 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/integer division by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn div0(a: i32, b: i32) i32 {...@@ -17,4 +17,4 @@ fn div0(a: i32, b: i32) i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/integer multiplication overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn mul(a: u16, b: u16) u16 {...@@ -18,4 +18,4 @@ fn mul(a: u16, b: u16) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/integer negation overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn neg(a: i16) i16 {...@@ -18,4 +18,4 @@ fn neg(a: i16) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/integer subtraction overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn sub(a: u16, b: u16) u16 {...@@ -18,4 +18,4 @@ fn sub(a: u16, b: u16) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_alias.zig+1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_len_mismatch.zig+1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/memmove_len_mismatch.zig+1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_bytes.zig+1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_large.zig+1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_bytes.zig+1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_large.zig+1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/modrem by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn div0(a: u32, b: u32) u32 {...@@ -17,4 +17,4 @@ fn div0(a: u32, b: u32) u32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/modulus by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn mod0(a: i32, b: i32) i32 {...@@ -17,4 +17,4 @@ fn mod0(a: i32, b: i32) i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/noreturn returned.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() void {...@@ -20,4 +20,4 @@ pub fn main() void {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/optional unwrap operator on C pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/optional unwrap operator on null pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/optional_empty_error_set.zig+1-1
...@@ -19,4 +19,4 @@ fn foo() !void {...@@ -19,4 +19,4 @@ fn foo() !void {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/out of bounds array slice by length.zig +1-1
...@@ -17,4 +17,4 @@ fn foo(a: u32) u32 {...@@ -17,4 +17,4 @@ fn foo(a: u32) u32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/out of bounds slice access.zig +1-1
...@@ -18,4 +18,4 @@ fn bar(a: []const i32) i32 {...@@ -18,4 +18,4 @@ fn bar(a: []const i32) i32 {
18fn baz(_: i32) void {}18fn baz(_: i32) void {}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer casting null to non-optional pointer.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer casting to null function pointer.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() !void {...@@ -20,4 +20,4 @@ pub fn main() !void {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer slice sentinel mismatch.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/remainder division by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn rem0(a: i32, b: i32) i32 {...@@ -17,4 +17,4 @@ fn rem0(a: i32, b: i32) i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/shift left by huge amount.zig +1-1
...@@ -19,4 +19,4 @@ pub fn main() !void {...@@ -19,4 +19,4 @@ pub fn main() !void {
1919
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/shift right by huge amount.zig +1-1
...@@ -19,4 +19,4 @@ pub fn main() !void {...@@ -19,4 +19,4 @@ pub fn main() !void {
1919
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/signed integer division overflow - vectors.zig +1-1
...@@ -20,4 +20,4 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {...@@ -20,4 +20,4 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/signed integer division overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn div(a: i16, b: i16) i16 {...@@ -18,4 +18,4 @@ fn div(a: i16, b: i16) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux
test/cases/safety/signed integer not fitting in cast to unsigned integer.zig +1-1
...@@ -17,4 +17,4 @@ fn unsigned_cast(x: i32) u32 {...@@ -17,4 +17,4 @@ fn unsigned_cast(x: i32) u32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/signed shift left overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shl(a: i16, b: u4) i16 {...@@ -18,4 +18,4 @@ fn shl(a: i16, b: u4) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/signed shift right overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shr(a: i16, b: u4) i16 {...@@ -18,4 +18,4 @@ fn shr(a: i16, b: u4) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/signed-unsigned vector cast.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/slice by length sentinel mismatch on lhs.zig +1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/slice by length sentinel mismatch on rhs.zig +1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/slice sentinel mismatch - floats.zig +1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
1717
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/slice sentinel mismatch - optional pointers.zig +1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
1717
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/slice slice sentinel mismatch.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/slice start index greater than end index.zig +1-1
...@@ -21,4 +21,4 @@ pub fn main() !void {...@@ -21,4 +21,4 @@ pub fn main() !void {
2121
22// run22// run
23// backend=stage2,llvm23// backend=stage2,llvm
24// target=native24// target=x86_64-linux,aarch64-linux
test/cases/safety/slice with sentinel out of bounds - runtime len.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() !void {...@@ -20,4 +20,4 @@ pub fn main() !void {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/slice with sentinel out of bounds.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/slice_cast_change_len_0.zig+1-1
...@@ -24,4 +24,4 @@ const std = @import("std");...@@ -24,4 +24,4 @@ const std = @import("std");
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=x86_64-linux27// target=x86_64-linux,aarch64-linux
test/cases/safety/slice_cast_change_len_1.zig+1-1
...@@ -24,4 +24,4 @@ const std = @import("std");...@@ -24,4 +24,4 @@ const std = @import("std");
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=x86_64-linux27// target=x86_64-linux,aarch64-linux
test/cases/safety/slice_cast_change_len_2.zig+1-1
...@@ -24,4 +24,4 @@ const std = @import("std");...@@ -24,4 +24,4 @@ const std = @import("std");
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=x86_64-linux27// target=x86_64-linux,aarch64-linux
test/cases/safety/slicing null C pointer - runtime len.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/slicing null C pointer.zig +1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/switch else on corrupt enum value - one prong.zig +1-1
...@@ -21,4 +21,4 @@ pub fn main() !void {...@@ -21,4 +21,4 @@ pub fn main() !void {
21}21}
22// run22// run
23// backend=stage2,llvm23// backend=stage2,llvm
24// target=native24// target=x86_64-linux
test/cases/safety/switch else on corrupt enum value - union.zig +1-1
...@@ -26,4 +26,4 @@ pub fn main() !void {...@@ -26,4 +26,4 @@ pub fn main() !void {
26}26}
27// run27// run
28// backend=stage2,llvm28// backend=stage2,llvm
29// target=native29// target=x86_64-linux
test/cases/safety/switch else on corrupt enum value.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() !void {...@@ -20,4 +20,4 @@ pub fn main() !void {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/switch on corrupted enum value.zig +1-1
...@@ -24,4 +24,4 @@ pub fn main() !void {...@@ -24,4 +24,4 @@ pub fn main() !void {
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux,aarch64-linux
test/cases/safety/switch on corrupted union value.zig +1-1
...@@ -24,4 +24,4 @@ pub fn main() !void {...@@ -24,4 +24,4 @@ pub fn main() !void {
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux
test/cases/safety/truncating vector cast.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/unreachable.zig+1-1
...@@ -12,4 +12,4 @@ pub fn main() !void {...@@ -12,4 +12,4 @@ pub fn main() !void {
12}12}
13// run13// run
14// backend=stage2,llvm14// backend=stage2,llvm
15// target=native15// target=x86_64-linux,aarch64-linux
test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux
test/cases/safety/unsigned shift left overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shl(a: u16, b: u4) u16 {...@@ -18,4 +18,4 @@ fn shl(a: u16, b: u4) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/unsigned shift right overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shr(a: u16, b: u4) u16 {...@@ -18,4 +18,4 @@ fn shr(a: u16, b: u4) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/unsigned-signed vector cast.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/unwrap error switch.zig +1-1
...@@ -18,4 +18,4 @@ fn bar() !void {...@@ -18,4 +18,4 @@ fn bar() !void {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/unwrap error.zig +1-1
...@@ -16,4 +16,4 @@ fn bar() !void {...@@ -16,4 +16,4 @@ fn bar() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/value does not fit in shortening cast - u0.zig +1-1
...@@ -18,4 +18,4 @@ fn shorten_cast(x: u8) u0 {...@@ -18,4 +18,4 @@ fn shorten_cast(x: u8) u0 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/value does not fit in shortening cast.zig +1-1
...@@ -18,4 +18,4 @@ fn shorten_cast(x: i32) i8 {...@@ -18,4 +18,4 @@ fn shorten_cast(x: i32) i8 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/vector integer addition overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {...@@ -19,4 +19,4 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/vector integer multiplication overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {...@@ -19,4 +19,4 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/vector integer negation overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {...@@ -19,4 +19,4 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/vector integer subtraction overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {...@@ -19,4 +19,4 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/zero casted to error.zig +1-1
...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/taking_pointer_of_global_tagged_union.zig+1-1
...@@ -23,4 +23,4 @@ pub fn main() !void {...@@ -23,4 +23,4 @@ pub fn main() !void {
2323
24// run24// run
25// backend=stage2,llvm25// backend=stage2,llvm
26// target=native26// target=x86_64-linux
test/incremental/change_panic_handler-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe1#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe2#target=x86_64-windows-cbe
4#update=initial version3#update=initial version
test/incremental/change_panic_handler_explicit-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe1#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe2#target=x86_64-windows-cbe
4#update=initial version3#update=initial version
test/incremental/type_becomes_comptime_only-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe1#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe2#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted3#target=wasm32-wasi-selfhosted
test/link/build.zig.zon+2-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1.{1.{
2 .name = "link_test_cases",2 .name = .link_test_cases,
3 .fingerprint = 0x404f657576fec9f2,
3 .version = "0.0.0",4 .version = "0.0.0",
4 .dependencies = .{5 .dependencies = .{
5 .bss = .{6 .bss = .{
test/link/elf.zig+369-369
...@@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step {...@@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step {
210 \\}210 \\}
211 ,211 ,
212 });212 });
213 exe.addObject(obj);213 exe.root_module.addObject(obj);
214 exe.linkLibC();214 exe.root_module.link_libc = true;
215215
216 const run = addRunArtifact(exe);216 const run = addRunArtifact(exe);
217 run.expectExitCode(0);217 run.expectExitCode(0);
...@@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {...@@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
235 \\235 \\
236 ,236 ,
237 });237 });
238 main_o.linkLibC();238 main_o.root_module.link_libc = true;
239239
240 const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });240 const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });
241 addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});241 addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});
...@@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {...@@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
253 const exe = addExecutable(b, opts, .{253 const exe = addExecutable(b, opts, .{
254 .name = "test",254 .name = "test",
255 });255 });
256 exe.addObject(main_o);256 exe.root_module.addObject(main_o);
257 exe.linkSystemLibrary2("foo", .{ .needed = true });257 exe.root_module.linkSystemLibrary("foo", .{ .needed = true });
258 exe.addLibraryPath(libfoo.getEmittedBinDirectory());258 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
259 exe.addRPath(libfoo.getEmittedBinDirectory());259 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
260 exe.linkSystemLibrary2("bar", .{ .needed = true });260 exe.root_module.linkSystemLibrary("bar", .{ .needed = true });
261 exe.addLibraryPath(libbar.getEmittedBinDirectory());261 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
262 exe.addRPath(libbar.getEmittedBinDirectory());262 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
263 exe.linkSystemLibrary2("baz", .{ .needed = true });263 exe.root_module.linkSystemLibrary("baz", .{ .needed = true });
264 exe.addLibraryPath(libbaz.getEmittedBinDirectory());264 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
265 exe.addRPath(libbaz.getEmittedBinDirectory());265 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
266 exe.linkLibC();266 exe.root_module.link_libc = true;
267267
268 const run = addRunArtifact(exe);268 const run = addRunArtifact(exe);
269 run.expectStdOutEqual("42\n");269 run.expectStdOutEqual("42\n");
...@@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {...@@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
281 const exe = addExecutable(b, opts, .{281 const exe = addExecutable(b, opts, .{
282 .name = "test",282 .name = "test",
283 });283 });
284 exe.addObject(main_o);284 exe.root_module.addObject(main_o);
285 exe.linkSystemLibrary2("foo", .{ .needed = false });285 exe.root_module.linkSystemLibrary("foo", .{ .needed = false });
286 exe.addLibraryPath(libfoo.getEmittedBinDirectory());286 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
287 exe.addRPath(libfoo.getEmittedBinDirectory());287 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
288 exe.linkSystemLibrary2("bar", .{ .needed = false });288 exe.root_module.linkSystemLibrary("bar", .{ .needed = false });
289 exe.addLibraryPath(libbar.getEmittedBinDirectory());289 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
290 exe.addRPath(libbar.getEmittedBinDirectory());290 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
291 exe.linkSystemLibrary2("baz", .{ .needed = false });291 exe.root_module.linkSystemLibrary("baz", .{ .needed = false });
292 exe.addLibraryPath(libbaz.getEmittedBinDirectory());292 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
293 exe.addRPath(libbaz.getEmittedBinDirectory());293 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
294 exe.linkLibC();294 exe.root_module.link_libc = true;
295295
296 const run = addRunArtifact(exe);296 const run = addRunArtifact(exe);
297 run.expectStdOutEqual("42\n");297 run.expectStdOutEqual("42\n");
...@@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {...@@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
351 ,351 ,
352 .pic = false,352 .pic = false,
353 });353 });
354 main_o.linkLibC();354 main_o.root_module.link_libc = true;
355355
356 const exe = addExecutable(b, opts, .{356 const exe = addExecutable(b, opts, .{
357 .name = "main",357 .name = "main",
358 });358 });
359 exe.addObject(main_o);359 exe.root_module.addObject(main_o);
360 exe.addObject(b_o);360 exe.root_module.addObject(b_o);
361 exe.linkLibrary(dso);361 exe.root_module.linkLibrary(dso);
362 exe.linkLibC();362 exe.root_module.link_libc = true;
363 exe.pie = false;363 exe.pie = false;
364364
365 const run = addRunArtifact(exe);365 const run = addRunArtifact(exe);
...@@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
384 \\}384 \\}
385 ,385 ,
386 });386 });
387 a_o.linkLibCpp();387 a_o.root_module.link_libcpp = true;
388388
389 const main_o = addObject(b, opts, .{389 const main_o = addObject(b, opts, .{
390 .name = "main",390 .name = "main",
...@@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
401 \\}401 \\}
402 ,402 ,
403 });403 });
404 main_o.linkLibCpp();404 main_o.root_module.link_libcpp = true;
405405
406 {406 {
407 const exe = addExecutable(b, opts, .{ .name = "main1" });407 const exe = addExecutable(b, opts, .{ .name = "main1" });
408 exe.addObject(a_o);408 exe.root_module.addObject(a_o);
409 exe.addObject(main_o);409 exe.root_module.addObject(main_o);
410 exe.linkLibCpp();410 exe.root_module.link_libcpp = true;
411411
412 const run = addRunArtifact(exe);412 const run = addRunArtifact(exe);
413 run.expectStdOutEqual(413 run.expectStdOutEqual(
...@@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
420420
421 {421 {
422 const exe = addExecutable(b, opts, .{ .name = "main2" });422 const exe = addExecutable(b, opts, .{ .name = "main2" });
423 exe.addObject(main_o);423 exe.root_module.addObject(main_o);
424 exe.addObject(a_o);424 exe.root_module.addObject(a_o);
425 exe.linkLibCpp();425 exe.root_module.link_libcpp = true;
426426
427 const run = addRunArtifact(exe);427 const run = addRunArtifact(exe);
428 run.expectStdOutEqual(428 run.expectStdOutEqual(
...@@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
435435
436 {436 {
437 const c_o = addObject(b, opts, .{ .name = "c" });437 const c_o = addObject(b, opts, .{ .name = "c" });
438 c_o.addObject(main_o);438 c_o.root_module.addObject(main_o);
439 c_o.addObject(a_o);439 c_o.root_module.addObject(a_o);
440440
441 const exe = addExecutable(b, opts, .{ .name = "main3" });441 const exe = addExecutable(b, opts, .{ .name = "main3" });
442 exe.addObject(c_o);442 exe.root_module.addObject(c_o);
443 exe.linkLibCpp();443 exe.root_module.link_libcpp = true;
444444
445 const run = addRunArtifact(exe);445 const run = addRunArtifact(exe);
446 run.expectStdOutEqual(446 run.expectStdOutEqual(
...@@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
453453
454 {454 {
455 const d_o = addObject(b, opts, .{ .name = "d" });455 const d_o = addObject(b, opts, .{ .name = "d" });
456 d_o.addObject(a_o);456 d_o.root_module.addObject(a_o);
457 d_o.addObject(main_o);457 d_o.root_module.addObject(main_o);
458458
459 const exe = addExecutable(b, opts, .{ .name = "main4" });459 const exe = addExecutable(b, opts, .{ .name = "main4" });
460 exe.addObject(d_o);460 exe.root_module.addObject(d_o);
461 exe.linkLibCpp();461 exe.root_module.link_libcpp = true;
462462
463 const run = addRunArtifact(exe);463 const run = addRunArtifact(exe);
464 run.expectStdOutEqual(464 run.expectStdOutEqual(
...@@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step {...@@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step {
522 \\ printf("%d %d %d\n", foo, bar, baz);522 \\ printf("%d %d %d\n", foo, bar, baz);
523 \\}523 \\}
524 , &.{"-fcommon"});524 , &.{"-fcommon"});
525 exe.linkLibC();525 exe.root_module.link_libc = true;
526526
527 const run = addRunArtifact(exe);527 const run = addRunArtifact(exe);
528 run.expectStdOutEqual("0 5 42\n");528 run.expectStdOutEqual("0 5 42\n");
...@@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {...@@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
549 ,549 ,
550 .c_source_flags = &.{"-fcommon"},550 .c_source_flags = &.{"-fcommon"},
551 });551 });
552 a_o.linkLibC();552 a_o.root_module.link_libc = true;
553553
554 const b_o = addObject(b, opts, .{554 const b_o = addObject(b, opts, .{
555 .name = "b",555 .name = "b",
...@@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {...@@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
575 });575 });
576576
577 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });577 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
578 lib.addObject(b_o);578 lib.root_module.addObject(b_o);
579 lib.addObject(c_o);579 lib.root_module.addObject(c_o);
580 lib.addObject(d_o);580 lib.root_module.addObject(d_o);
581581
582 const exe = addExecutable(b, opts, .{582 const exe = addExecutable(b, opts, .{
583 .name = "test",583 .name = "test",
584 });584 });
585 exe.addObject(a_o);585 exe.root_module.addObject(a_o);
586 exe.linkLibrary(lib);586 exe.root_module.linkLibrary(lib);
587 exe.linkLibC();587 exe.root_module.link_libc = true;
588588
589 const run = addRunArtifact(exe);589 const run = addRunArtifact(exe);
590 run.expectStdOutEqual("5 0 0 -1\n");590 run.expectStdOutEqual("5 0 0 -1\n");
...@@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {...@@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
603 });603 });
604604
605 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });605 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
606 lib.addObject(b_o);606 lib.root_module.addObject(b_o);
607 lib.addObject(e_o);607 lib.root_module.addObject(e_o);
608608
609 const exe = addExecutable(b, opts, .{609 const exe = addExecutable(b, opts, .{
610 .name = "test",610 .name = "test",
611 });611 });
612 exe.addObject(a_o);612 exe.root_module.addObject(a_o);
613 exe.linkLibrary(lib);613 exe.root_module.linkLibrary(lib);
614 exe.linkLibC();614 exe.root_module.link_libc = true;
615615
616 const run = addRunArtifact(exe);616 const run = addRunArtifact(exe);
617 run.expectStdOutEqual("5 0 7 2\n");617 run.expectStdOutEqual("5 0 7 2\n");
...@@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step {...@@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step {
641 \\}641 \\}
642 ,642 ,
643 });643 });
644 exe.linkLibrary(dso);644 exe.root_module.linkLibrary(dso);
645 exe.linkLibC();645 exe.root_module.link_libc = true;
646646
647 const run = addRunArtifact(exe);647 const run = addRunArtifact(exe);
648 run.expectStdOutEqual("3 5\n");648 run.expectStdOutEqual("3 5\n");
...@@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step {...@@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step {
679 \\extern int bar;679 \\extern int bar;
680 \\int *get_bar() { return &bar; }680 \\int *get_bar() { return &bar; }
681 , &.{});681 , &.{});
682 exe.linkLibrary(dso);682 exe.root_module.linkLibrary(dso);
683 exe.linkLibC();683 exe.root_module.link_libc = true;
684 exe.pie = false;684 exe.pie = false;
685685
686 const run = addRunArtifact(exe);686 const run = addRunArtifact(exe);
...@@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {...@@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
712 ,712 ,
713 .pic = false,713 .pic = false,
714 });714 });
715 obj.linkLibC();715 obj.root_module.link_libc = true;
716716
717 const exp_stdout = "5\n";717 const exp_stdout = "5\n";
718718
719 {719 {
720 const exe = addExecutable(b, opts, .{ .name = "main" });720 const exe = addExecutable(b, opts, .{ .name = "main" });
721 exe.addObject(obj);721 exe.root_module.addObject(obj);
722 exe.linkLibrary(a_so);722 exe.root_module.linkLibrary(a_so);
723 exe.linkLibC();723 exe.root_module.link_libc = true;
724 exe.pie = false;724 exe.pie = false;
725725
726 const run = addRunArtifact(exe);726 const run = addRunArtifact(exe);
...@@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {...@@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
737737
738 {738 {
739 const exe = addExecutable(b, opts, .{ .name = "main" });739 const exe = addExecutable(b, opts, .{ .name = "main" });
740 exe.addObject(obj);740 exe.root_module.addObject(obj);
741 exe.linkLibrary(b_so);741 exe.root_module.linkLibrary(b_so);
742 exe.linkLibC();742 exe.root_module.link_libc = true;
743 exe.pie = false;743 exe.pie = false;
744744
745 const run = addRunArtifact(exe);745 const run = addRunArtifact(exe);
...@@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {...@@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
756756
757 {757 {
758 const exe = addExecutable(b, opts, .{ .name = "main" });758 const exe = addExecutable(b, opts, .{ .name = "main" });
759 exe.addObject(obj);759 exe.root_module.addObject(obj);
760 exe.linkLibrary(c_so);760 exe.root_module.linkLibrary(c_so);
761 exe.linkLibC();761 exe.root_module.link_libc = true;
762 exe.pie = false;762 exe.pie = false;
763763
764 const run = addRunArtifact(exe);764 const run = addRunArtifact(exe);
...@@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {...@@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
793 \\ real_hello();793 \\ real_hello();
794 \\}794 \\}
795 , &.{});795 , &.{});
796 dso.linkLibC();796 dso.root_module.link_libc = true;
797797
798 const exe = addExecutable(b, opts, .{ .name = "test" });798 const exe = addExecutable(b, opts, .{ .name = "test" });
799 addCSourceBytes(exe,799 addCSourceBytes(exe,
...@@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {...@@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
806 \\ hello();806 \\ hello();
807 \\}807 \\}
808 , &.{});808 , &.{});
809 exe.linkLibrary(dso);809 exe.root_module.linkLibrary(dso);
810 exe.linkLibC();810 exe.root_module.link_libc = true;
811811
812 const run = addRunArtifact(exe);812 const run = addRunArtifact(exe);
813 run.expectStdOutEqual("Hello WORLD\n");813 run.expectStdOutEqual("Hello WORLD\n");
...@@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {...@@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
825 \\int bar = 5;825 \\int bar = 5;
826 \\int baz() { return foo; }826 \\int baz() { return foo; }
827 , &.{});827 , &.{});
828 dso.linkLibC();828 dso.root_module.link_libc = true;
829829
830 const obj = addObject(b, opts, .{830 const obj = addObject(b, opts, .{
831 .name = "obj",831 .name = "obj",
...@@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {...@@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
833 });833 });
834834
835 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });835 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
836 lib.addObject(obj);836 lib.root_module.addObject(obj);
837837
838 const exe = addExecutable(b, opts, .{ .name = "test" });838 const exe = addExecutable(b, opts, .{ .name = "test" });
839 exe.linkLibrary(dso);839 exe.root_module.linkLibrary(dso);
840 exe.linkLibrary(lib);840 exe.root_module.linkLibrary(lib);
841 addCSourceBytes(exe,841 addCSourceBytes(exe,
842 \\extern int bar;842 \\extern int bar;
843 \\int main() {843 \\int main() {
844 \\ return bar - 5;844 \\ return bar - 5;
845 \\}845 \\}
846 , &.{});846 , &.{});
847 exe.linkLibC();847 exe.root_module.link_libc = true;
848848
849 const run = addRunArtifact(exe);849 const run = addRunArtifact(exe);
850 run.expectExitCode(0);850 run.expectExitCode(0);
...@@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {...@@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
871 \\ std.debug.print("foo={d}\n", .{foo()});871 \\ std.debug.print("foo={d}\n", .{foo()});
872 \\}872 \\}
873 });873 });
874 a_o.linkLibC();874 a_o.root_module.link_libc = true;
875875
876 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes = 876 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes =
877 \\#include <stdio.h>877 \\#include <stdio.h>
...@@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {...@@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
880 \\ fprintf(stderr, "bar=%d\n", bar);880 \\ fprintf(stderr, "bar=%d\n", bar);
881 \\}881 \\}
882 });882 });
883 b_o.linkLibC();883 b_o.root_module.link_libc = true;
884884
885 const c_o = addObject(b, opts, .{ .name = "c" });885 const c_o = addObject(b, opts, .{ .name = "c" });
886 c_o.addObject(a_o);886 c_o.root_module.addObject(a_o);
887 c_o.addObject(b_o);887 c_o.root_module.addObject(b_o);
888888
889 const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes = 889 const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes =
890 \\const std = @import("std");890 \\const std = @import("std");
...@@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {...@@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
895 \\ printBar();895 \\ printBar();
896 \\}896 \\}
897 });897 });
898 exe.addObject(c_o);898 exe.root_module.addObject(c_o);
899 exe.linkLibC();899 exe.root_module.link_libc = true;
900900
901 const run = addRunArtifact(exe);901 const run = addRunArtifact(exe);
902 run.expectStdErrEqual(902 run.expectStdErrEqual(
...@@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {...@@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {
944 });944 });
945945
946 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });946 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
947 lib.addObject(obj1);947 lib.root_module.addObject(obj1);
948 lib.addObject(obj2);948 lib.root_module.addObject(obj2);
949 lib.addObject(obj3);949 lib.root_module.addObject(obj3);
950950
951 const check = lib.checkObject();951 const check = lib.checkObject();
952 check.checkInArchiveSymtab();952 check.checkInArchiveSymtab();
...@@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {...@@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
996 \\}996 \\}
997 ,997 ,
998 });998 });
999 lib.addObject(obj1);999 lib.root_module.addObject(obj1);
10001000
1001 const exe = addExecutable(b, opts, .{1001 const exe = addExecutable(b, opts, .{
1002 .name = "test",1002 .name = "test",
...@@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {...@@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
1008 \\}1008 \\}
1009 ,1009 ,
1010 });1010 });
1011 exe.linkLibrary(lib);1011 exe.root_module.linkLibrary(lib);
10121012
1013 const run = addRunArtifact(exe);1013 const run = addRunArtifact(exe);
1014 run.expectStdErrEqual("44");1014 run.expectStdErrEqual("44");
...@@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {...@@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
1023 const exe = addExecutable(b, opts, .{ .name = "test" });1023 const exe = addExecutable(b, opts, .{ .name = "test" });
1024 addCSourceBytes(exe, "int main() { return 0; }", &.{});1024 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1025 addCSourceBytes(exe, "", &.{});1025 addCSourceBytes(exe, "", &.{});
1026 exe.linkLibC();1026 exe.root_module.link_libc = true;
10271027
1028 const run = addRunArtifact(exe);1028 const run = addRunArtifact(exe);
1029 run.expectExitCode(0);1029 run.expectExitCode(0);
...@@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {...@@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
10521052
1053 {1053 {
1054 const exe = addExecutable(b, opts, .{ .name = "main" });1054 const exe = addExecutable(b, opts, .{ .name = "main" });
1055 exe.addObject(a_o);1055 exe.root_module.addObject(a_o);
1056 exe.addObject(b_o);1056 exe.root_module.addObject(b_o);
1057 exe.entry = .{ .symbol_name = "foo" };1057 exe.entry = .{ .symbol_name = "foo" };
10581058
1059 const check = exe.checkObject();1059 const check = exe.checkObject();
...@@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {...@@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
1068 // cause an artifact collision taking the cached executable from the above1068 // cause an artifact collision taking the cached executable from the above
1069 // step instead of generating a new one.1069 // step instead of generating a new one.
1070 const exe = addExecutable(b, opts, .{ .name = "other" });1070 const exe = addExecutable(b, opts, .{ .name = "other" });
1071 exe.addObject(a_o);1071 exe.root_module.addObject(a_o);
1072 exe.addObject(b_o);1072 exe.root_module.addObject(b_o);
1073 exe.entry = .{ .symbol_name = "bar" };1073 exe.entry = .{ .symbol_name = "bar" };
10741074
1075 const check = exe.checkObject();1075 const check = exe.checkObject();
...@@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step {...@@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step {
1113 \\ return baz;1113 \\ return baz;
1114 \\}1114 \\}
1115 , &.{});1115 , &.{});
1116 exe.addObject(obj);1116 exe.root_module.addObject(obj);
1117 exe.linkLibrary(dso);1117 exe.root_module.linkLibrary(dso);
1118 exe.rdynamic = true;1118 exe.rdynamic = true;
11191119
1120 const check = exe.checkObject();1120 const check = exe.checkObject();
...@@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {...@@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {
1152 \\ foo();1152 \\ foo();
1153 \\}1153 \\}
1154 , &.{});1154 , &.{});
1155 exe.linkLibrary(dso);1155 exe.root_module.linkLibrary(dso);
1156 exe.linkLibC();1156 exe.root_module.link_libc = true;
11571157
1158 const check = exe.checkObject();1158 const check = exe.checkObject();
1159 check.checkInDynamicSymtab();1159 check.checkInDynamicSymtab();
...@@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step {...@@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step {
1181 \\ assert(fn == ptr);1181 \\ assert(fn == ptr);
1182 \\}1182 \\}
1183 , &.{});1183 , &.{});
1184 exe.linkLibrary(dso);1184 exe.root_module.linkLibrary(dso);
1185 exe.root_module.pic = false;1185 exe.root_module.pic = false;
1186 exe.pie = false;1186 exe.pie = false;
11871187
...@@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step {...@@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step {
1216 });1216 });
1217 obj.link_function_sections = true;1217 obj.link_function_sections = true;
1218 obj.link_data_sections = true;1218 obj.link_data_sections = true;
1219 obj.linkLibC();1219 obj.root_module.link_libc = true;
1220 obj.linkLibCpp();1220 obj.root_module.link_libcpp = true;
12211221
1222 {1222 {
1223 const exe = addExecutable(b, opts, .{ .name = "test" });1223 const exe = addExecutable(b, opts, .{ .name = "test" });
1224 exe.addObject(obj);1224 exe.root_module.addObject(obj);
1225 exe.link_gc_sections = false;1225 exe.link_gc_sections = false;
1226 exe.linkLibC();1226 exe.root_module.link_libc = true;
1227 exe.linkLibCpp();1227 exe.root_module.link_libcpp = true;
12281228
1229 const run = addRunArtifact(exe);1229 const run = addRunArtifact(exe);
1230 run.expectStdOutEqual("1 2\n");1230 run.expectStdOutEqual("1 2\n");
...@@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step {...@@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step {
12521252
1253 {1253 {
1254 const exe = addExecutable(b, opts, .{ .name = "test" });1254 const exe = addExecutable(b, opts, .{ .name = "test" });
1255 exe.addObject(obj);1255 exe.root_module.addObject(obj);
1256 exe.link_gc_sections = true;1256 exe.link_gc_sections = true;
1257 exe.linkLibC();1257 exe.root_module.link_libc = true;
1258 exe.linkLibCpp();1258 exe.root_module.link_libcpp = true;
12591259
1260 const run = addRunArtifact(exe);1260 const run = addRunArtifact(exe);
1261 run.expectStdOutEqual("1 2\n");1261 run.expectStdOutEqual("1 2\n");
...@@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {...@@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
1321 \\}1321 \\}
1322 ,1322 ,
1323 });1323 });
1324 exe.addObject(obj);1324 exe.root_module.addObject(obj);
1325 exe.link_gc_sections = false;1325 exe.link_gc_sections = false;
13261326
1327 const run = addRunArtifact(exe);1327 const run = addRunArtifact(exe);
...@@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {...@@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
1363 \\}1363 \\}
1364 ,1364 ,
1365 });1365 });
1366 exe.addObject(obj);1366 exe.root_module.addObject(obj);
1367 exe.link_gc_sections = true;1367 exe.link_gc_sections = true;
13681368
1369 const run = addRunArtifact(exe);1369 const run = addRunArtifact(exe);
...@@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step {...@@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step {
1427 \\}1427 \\}
1428 , &.{});1428 , &.{});
1429 exe.root_module.pic = true;1429 exe.root_module.pic = true;
1430 exe.linkLibC();1430 exe.root_module.link_libc = true;
14311431
1432 const run = addRunArtifact(exe);1432 const run = addRunArtifact(exe);
1433 run.expectExitCode(0);1433 run.expectExitCode(0);
...@@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {...@@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {
1467 \\ assert(foo == p);1467 \\ assert(foo == p);
1468 \\}1468 \\}
1469 , &.{});1469 , &.{});
1470 exe.linkLibrary(dso);1470 exe.root_module.linkLibrary(dso);
1471 exe.linkLibC();1471 exe.root_module.link_libc = true;
1472 exe.linkSystemLibrary2("dl", .{});1472 exe.root_module.linkSystemLibrary("dl", .{});
1473 exe.root_module.pic = false;1473 exe.root_module.pic = false;
1474 exe.pie = false;1474 exe.pie = false;
14751475
...@@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {...@@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
1498 \\}1498 \\}
1499 ,1499 ,
1500 });1500 });
1501 dso.linkLibC();1501 dso.root_module.link_libc = true;
15021502
1503 const exe = addExecutable(b, opts, .{1503 const exe = addExecutable(b, opts, .{
1504 .name = "main",1504 .name = "main",
...@@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {...@@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
1509 \\}1509 \\}
1510 ,1510 ,
1511 });1511 });
1512 exe.linkLibrary(dso);1512 exe.root_module.linkLibrary(dso);
15131513
1514 const run = addRunArtifact(exe);1514 const run = addRunArtifact(exe);
1515 run.expectStdOutEqual("Hello world\n");1515 run.expectStdOutEqual("Hello world\n");
...@@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {...@@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
1540 {1540 {
1541 const exe = addExecutable(b, opts, .{ .name = "main" });1541 const exe = addExecutable(b, opts, .{ .name = "main" });
1542 addCSourceBytes(exe, main_c, &.{});1542 addCSourceBytes(exe, main_c, &.{});
1543 exe.linkLibC();1543 exe.root_module.link_libc = true;
1544 exe.link_z_lazy = true;1544 exe.link_z_lazy = true;
15451545
1546 const run = addRunArtifact(exe);1546 const run = addRunArtifact(exe);
...@@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {...@@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
1550 {1550 {
1551 const exe = addExecutable(b, opts, .{ .name = "other" });1551 const exe = addExecutable(b, opts, .{ .name = "other" });
1552 addCSourceBytes(exe, main_c, &.{});1552 addCSourceBytes(exe, main_c, &.{});
1553 exe.linkLibC();1553 exe.root_module.link_libc = true;
15541554
1555 const run = addRunArtifact(exe);1555 const run = addRunArtifact(exe);
1556 run.expectStdOutEqual("Hello world\n");1556 run.expectStdOutEqual("Hello world\n");
...@@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step {...@@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step {
1576 \\ return real_foobar;1576 \\ return real_foobar;
1577 \\}1577 \\}
1578 , &.{});1578 , &.{});
1579 dso.linkLibC();1579 dso.root_module.link_libc = true;
15801580
1581 const check = dso.checkObject();1581 const check = dso.checkObject();
1582 check.checkInDynamicSymtab();1582 check.checkInDynamicSymtab();
...@@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {...@@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {
1613 \\}1613 \\}
1614 , &.{});1614 , &.{});
1615 exe.root_module.pic = true;1615 exe.root_module.pic = true;
1616 exe.linkLibC();1616 exe.root_module.link_libc = true;
16171617
1618 const run = addRunArtifact(exe);1618 const run = addRunArtifact(exe);
1619 run.expectStdOutEqual("3\n");1619 run.expectStdOutEqual("3\n");
...@@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step {...@@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step {
1642 \\}1642 \\}
1643 , &.{"-fno-plt"});1643 , &.{"-fno-plt"});
1644 exe.root_module.pic = true;1644 exe.root_module.pic = true;
1645 exe.linkLibC();1645 exe.root_module.link_libc = true;
16461646
1647 const run = addRunArtifact(exe);1647 const run = addRunArtifact(exe);
1648 run.expectStdOutEqual("Hello world\n");1648 run.expectStdOutEqual("Hello world\n");
...@@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step {...@@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step {
1669 \\ return 0;1669 \\ return 0;
1670 \\}1670 \\}
1671 , &.{});1671 , &.{});
1672 exe.linkLibC();1672 exe.root_module.link_libc = true;
1673 exe.linkage = .static;1673 exe.linkage = .static;
16741674
1675 const run = addRunArtifact(exe);1675 const run = addRunArtifact(exe);
...@@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {...@@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
1700 exe.linkage = .static;1700 exe.linkage = .static;
1701 exe.root_module.pic = true;1701 exe.root_module.pic = true;
1702 exe.pie = true;1702 exe.pie = true;
1703 exe.linkLibC();1703 exe.root_module.link_libc = true;
17041704
1705 const run = addRunArtifact(exe);1705 const run = addRunArtifact(exe);
1706 run.expectStdOutEqual("Hello world\n");1706 run.expectStdOutEqual("Hello world\n");
...@@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {...@@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {
1733 \\ return 0;1733 \\ return 0;
1734 \\}1734 \\}
1735 , &.{});1735 , &.{});
1736 exe.linkLibC();1736 exe.root_module.link_libc = true;
1737 exe.image_base = 0x8000000;1737 exe.image_base = 0x8000000;
17381738
1739 const run = addRunArtifact(exe);1739 const run = addRunArtifact(exe);
...@@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {...@@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
1779 \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }1779 \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }
1780 ,1780 ,
1781 });1781 });
1782 dso.linkLibC();1782 dso.root_module.link_libc = true;
17831783
1784 const main = addExecutable(b, opts, .{1784 const main = addExecutable(b, opts, .{
1785 .name = "main",1785 .name = "main",
...@@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {...@@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
1798 .strip = true, // TODO temp hack1798 .strip = true, // TODO temp hack
1799 });1799 });
1800 main.pie = true;1800 main.pie = true;
1801 main.linkLibrary(dso);1801 main.root_module.linkLibrary(dso);
18021802
1803 const run = addRunArtifact(main);1803 const run = addRunArtifact(main);
1804 run.expectStdErrEqual(1804 run.expectStdErrEqual(
...@@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {...@@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
1832 }, .{1832 }, .{
1833 .name = "a",1833 .name = "a",
1834 });1834 });
1835 lib.addObject(obj);1835 lib.root_module.addObject(obj);
18361836
1837 const main = addExecutable(b, opts, .{1837 const main = addExecutable(b, opts, .{
1838 .name = "main",1838 .name = "main",
...@@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {...@@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
1844 ,1844 ,
1845 .strip = true, // TODO temp hack1845 .strip = true, // TODO temp hack
1846 });1846 });
1847 main.linkLibrary(lib);1847 main.root_module.linkLibrary(lib);
1848 main.linkLibC();1848 main.root_module.link_libc = true;
18491849
1850 const run = addRunArtifact(main);1850 const run = addRunArtifact(main);
1851 run.expectStdErrEqual("42\n");1851 run.expectStdErrEqual("42\n");
...@@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1864 \\__attribute__((constructor(10000))) void init4() { printf("1"); }1864 \\__attribute__((constructor(10000))) void init4() { printf("1"); }
1865 ,1865 ,
1866 });1866 });
1867 a_o.linkLibC();1867 a_o.root_module.link_libc = true;
18681868
1869 const b_o = addObject(b, opts, .{1869 const b_o = addObject(b, opts, .{
1870 .name = "b",1870 .name = "b",
...@@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1873 \\__attribute__((constructor(1000))) void init3() { printf("2"); }1873 \\__attribute__((constructor(1000))) void init3() { printf("2"); }
1874 ,1874 ,
1875 });1875 });
1876 b_o.linkLibC();1876 b_o.root_module.link_libc = true;
18771877
1878 const c_o = addObject(b, opts, .{1878 const c_o = addObject(b, opts, .{
1879 .name = "c",1879 .name = "c",
...@@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1882 \\__attribute__((constructor)) void init1() { printf("3"); }1882 \\__attribute__((constructor)) void init1() { printf("3"); }
1883 ,1883 ,
1884 });1884 });
1885 c_o.linkLibC();1885 c_o.root_module.link_libc = true;
18861886
1887 const d_o = addObject(b, opts, .{1887 const d_o = addObject(b, opts, .{
1888 .name = "d",1888 .name = "d",
...@@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1891 \\__attribute__((constructor)) void init2() { printf("4"); }1891 \\__attribute__((constructor)) void init2() { printf("4"); }
1892 ,1892 ,
1893 });1893 });
1894 d_o.linkLibC();1894 d_o.root_module.link_libc = true;
18951895
1896 const e_o = addObject(b, opts, .{1896 const e_o = addObject(b, opts, .{
1897 .name = "e",1897 .name = "e",
...@@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1900 \\__attribute__((destructor(10000))) void fini4() { printf("5"); }1900 \\__attribute__((destructor(10000))) void fini4() { printf("5"); }
1901 ,1901 ,
1902 });1902 });
1903 e_o.linkLibC();1903 e_o.root_module.link_libc = true;
19041904
1905 const f_o = addObject(b, opts, .{1905 const f_o = addObject(b, opts, .{
1906 .name = "f",1906 .name = "f",
...@@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1909 \\__attribute__((destructor(1000))) void fini3() { printf("6"); }1909 \\__attribute__((destructor(1000))) void fini3() { printf("6"); }
1910 ,1910 ,
1911 });1911 });
1912 f_o.linkLibC();1912 f_o.root_module.link_libc = true;
19131913
1914 const g_o = addObject(b, opts, .{1914 const g_o = addObject(b, opts, .{
1915 .name = "g",1915 .name = "g",
...@@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1918 \\__attribute__((destructor)) void fini1() { printf("7"); }1918 \\__attribute__((destructor)) void fini1() { printf("7"); }
1919 ,1919 ,
1920 });1920 });
1921 g_o.linkLibC();1921 g_o.root_module.link_libc = true;
19221922
1923 const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes = 1923 const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes =
1924 \\#include <stdio.h>1924 \\#include <stdio.h>
1925 \\__attribute__((destructor)) void fini2() { printf("8"); }1925 \\__attribute__((destructor)) void fini2() { printf("8"); }
1926 });1926 });
1927 h_o.linkLibC();1927 h_o.root_module.link_libc = true;
19281928
1929 const exe = addExecutable(b, opts, .{ .name = "main" });1929 const exe = addExecutable(b, opts, .{ .name = "main" });
1930 addCSourceBytes(exe, "int main() { return 0; }", &.{});1930 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1931 exe.addObject(a_o);1931 exe.root_module.addObject(a_o);
1932 exe.addObject(b_o);1932 exe.root_module.addObject(b_o);
1933 exe.addObject(c_o);1933 exe.root_module.addObject(c_o);
1934 exe.addObject(d_o);1934 exe.root_module.addObject(d_o);
1935 exe.addObject(e_o);1935 exe.root_module.addObject(e_o);
1936 exe.addObject(f_o);1936 exe.root_module.addObject(f_o);
1937 exe.addObject(g_o);1937 exe.root_module.addObject(g_o);
1938 exe.addObject(h_o);1938 exe.root_module.addObject(h_o);
19391939
1940 if (opts.target.result.isGnuLibC()) {1940 if (opts.target.result.isGnuLibC()) {
1941 // TODO I think we need to clarify our use of `-fPIC -fPIE` flags for different targets1941 // 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 {...@@ -1970,7 +1970,7 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
1970 \\}1970 \\}
1971 , &.{});1971 , &.{});
1972 dso.link_function_sections = true;1972 dso.link_function_sections = true;
1973 dso.linkLibC();1973 dso.root_module.link_libc = true;
19741974
1975 const check = dso.checkObject();1975 const check = dso.checkObject();
1976 check.checkInSymtab();1976 check.checkInSymtab();
...@@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {...@@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
1986 \\void greet();1986 \\void greet();
1987 \\int main() { greet(); }1987 \\int main() { greet(); }
1988 , &.{});1988 , &.{});
1989 exe.linkLibrary(dso);1989 exe.root_module.linkLibrary(dso);
1990 exe.linkLibC();1990 exe.root_module.link_libc = true;
19911991
1992 const run = addRunArtifact(exe);1992 const run = addRunArtifact(exe);
1993 run.expectStdOutEqual("Hello world");1993 run.expectStdOutEqual("Hello world");
...@@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {...@@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {
2021 \\}2021 \\}
2022 , &.{});2022 , &.{});
2023 exe.link_function_sections = true;2023 exe.link_function_sections = true;
2024 exe.linkLibC();2024 exe.root_module.link_libc = true;
20252025
2026 const check = exe.checkObject();2026 const check = exe.checkObject();
2027 check.checkInSymtab();2027 check.checkInSymtab();
...@@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step {...@@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step {
2049 \\ return arr[2000];2049 \\ return arr[2000];
2050 \\}2050 \\}
2051 , &.{});2051 , &.{});
2052 exe.linkLibC();2052 exe.root_module.link_libc = true;
2053 // Disabled to work around the ELF linker crashing.2053 // Disabled to work around the ELF linker crashing.
2054 // Can be reproduced on a x86_64-linux host by commenting out the line below.2054 // Can be reproduced on a x86_64-linux host by commenting out the line below.
2055 exe.root_module.sanitize_c = .off;2055 exe.root_module.sanitize_c = .off;
...@@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {...@@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
2071 });2071 });
20722072
2073 const dso = addSharedLibrary(b, opts, .{ .name = "a" });2073 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
2074 dso.addObject(obj);2074 dso.root_module.addObject(obj);
20752075
2076 const lib = addStaticLibrary(b, opts, .{ .name = "b" });2076 const lib = addStaticLibrary(b, opts, .{ .name = "b" });
2077 lib.addObject(obj);2077 lib.root_module.addObject(obj);
20782078
2079 const main_o = addObject(b, opts, .{2079 const main_o = addObject(b, opts, .{
2080 .name = "main",2080 .name = "main",
...@@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {...@@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
2089 // https://github.com/ziglang/zig/issues/174502089 // https://github.com/ziglang/zig/issues/17450
2090 // {2090 // {
2091 // const exe = addExecutable(b, opts, .{ .name = "main1"});2091 // const exe = addExecutable(b, opts, .{ .name = "main1"});
2092 // exe.addObject(main_o);2092 // exe.root_module.addObject(main_o);
2093 // exe.linkSystemLibrary2("a", .{});2093 // exe.root_module.linkSystemLibrary("a", .{});
2094 // exe.addLibraryPath(dso.getEmittedBinDirectory());2094 // exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2095 // exe.addRPath(dso.getEmittedBinDirectory());2095 // exe.root_module.addRPath(dso.getEmittedBinDirectory());
2096 // exe.linkSystemLibrary2("b", .{});2096 // exe.root_module.linkSystemLibrary("b", .{});
2097 // exe.addLibraryPath(lib.getEmittedBinDirectory());2097 // exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2098 // exe.addRPath(lib.getEmittedBinDirectory());2098 // exe.root_module.addRPath(lib.getEmittedBinDirectory());
2099 // exe.linkLibC();2099 // exe.root_module.link_libc = true;
21002100
2101 // const check = exe.checkObject();2101 // const check = exe.checkObject();
2102 // check.checkInDynamicSection();2102 // check.checkInDynamicSection();
...@@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {...@@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
21062106
2107 {2107 {
2108 const exe = addExecutable(b, opts, .{ .name = "main2" });2108 const exe = addExecutable(b, opts, .{ .name = "main2" });
2109 exe.addObject(main_o);2109 exe.root_module.addObject(main_o);
2110 exe.linkSystemLibrary2("b", .{});2110 exe.root_module.linkSystemLibrary("b", .{});
2111 exe.addLibraryPath(lib.getEmittedBinDirectory());2111 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2112 exe.addRPath(lib.getEmittedBinDirectory());2112 exe.root_module.addRPath(lib.getEmittedBinDirectory());
2113 exe.linkSystemLibrary2("a", .{});2113 exe.root_module.linkSystemLibrary("a", .{});
2114 exe.addLibraryPath(dso.getEmittedBinDirectory());2114 exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2115 exe.addRPath(dso.getEmittedBinDirectory());2115 exe.root_module.addRPath(dso.getEmittedBinDirectory());
2116 exe.linkLibC();2116 exe.root_module.link_libc = true;
21172117
2118 const check = exe.checkObject();2118 const check = exe.checkObject();
2119 check.checkInDynamicSection();2119 check.checkInDynamicSection();
...@@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step {...@@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step {
2149 \\ return bar() - baz();2149 \\ return bar() - baz();
2150 \\}2150 \\}
2151 , &.{});2151 , &.{});
2152 exe.linkSystemLibrary2("a", .{});2152 exe.root_module.linkSystemLibrary("a", .{});
2153 exe.addLibraryPath(scripts.getDirectory());2153 exe.root_module.addLibraryPath(scripts.getDirectory());
2154 exe.addLibraryPath(scripts2.getDirectory());2154 exe.root_module.addLibraryPath(scripts2.getDirectory());
2155 exe.addLibraryPath(bar.getEmittedBinDirectory());2155 exe.root_module.addLibraryPath(bar.getEmittedBinDirectory());
2156 exe.addLibraryPath(baz.getEmittedBinDirectory());2156 exe.root_module.addLibraryPath(baz.getEmittedBinDirectory());
2157 exe.addRPath(bar.getEmittedBinDirectory());2157 exe.root_module.addRPath(bar.getEmittedBinDirectory());
2158 exe.addRPath(baz.getEmittedBinDirectory());2158 exe.root_module.addRPath(baz.getEmittedBinDirectory());
2159 exe.linkLibC();2159 exe.root_module.link_libc = true;
2160 exe.allow_so_scripts = true;2160 exe.allow_so_scripts = true;
21612161
2162 const run = addRunArtifact(exe);2162 const run = addRunArtifact(exe);
...@@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {...@@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
21742174
2175 const exe = addExecutable(b, opts, .{ .name = "main" });2175 const exe = addExecutable(b, opts, .{ .name = "main" });
2176 addCSourceBytes(exe, "int main() { return 0; }", &.{});2176 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2177 exe.linkSystemLibrary2("a", .{});2177 exe.root_module.linkSystemLibrary("a", .{});
2178 exe.addLibraryPath(scripts.getDirectory());2178 exe.root_module.addLibraryPath(scripts.getDirectory());
2179 exe.linkLibC();2179 exe.root_module.link_libc = true;
2180 exe.allow_so_scripts = true;2180 exe.allow_so_scripts = true;
21812181
2182 // TODO: A future enhancement could make this error message also mention2182 // TODO: A future enhancement could make this error message also mention
...@@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {...@@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
2213 \\}2213 \\}
2214 ,2214 ,
2215 });2215 });
2216 exe.linkLibrary(so);2216 exe.root_module.linkLibrary(so);
2217 exe.linkLibC();2217 exe.root_module.link_libc = true;
2218 exe.allow_so_scripts = true;2218 exe.allow_so_scripts = true;
22192219
2220 const run = addRunArtifact(exe);2220 const run = addRunArtifact(exe);
...@@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {...@@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {
2269 \\ return foo;2269 \\ return foo;
2270 \\}2270 \\}
2271 , &.{});2271 , &.{});
2272 exe.addObject(obj);2272 exe.root_module.addObject(obj);
2273 exe.linkLibC();2273 exe.root_module.link_libc = true;
22742274
2275 expectLinkErrors(exe, test_step, .{ .exact = &.{2275 expectLinkErrors(exe, test_step, .{ .exact = &.{
2276 "invalid ELF machine type: AARCH64",2276 "invalid ELF machine type: AARCH64",
...@@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step {...@@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step {
2291 \\ return 0;2291 \\ return 0;
2292 \\}2292 \\}
2293 , &.{});2293 , &.{});
2294 exe.linkLibC();2294 exe.root_module.link_libc = true;
22952295
2296 const run = addRunArtifact(exe);2296 const run = addRunArtifact(exe);
2297 run.expectStdOutEqual("Hello World!\n");2297 run.expectStdOutEqual("Hello World!\n");
...@@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {...@@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {
2320 \\ return 0;2320 \\ return 0;
2321 \\}2321 \\}
2322 , &.{});2322 , &.{});
2323 exe.linkLibC();2323 exe.root_module.link_libc = true;
2324 exe.linkLibCpp();2324 exe.root_module.link_libcpp = true;
23252325
2326 const run = addRunArtifact(exe);2326 const run = addRunArtifact(exe);
2327 run.expectStdOutEqual("Hello World!\n");2327 run.expectStdOutEqual("Hello World!\n");
...@@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step {...@@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step {
2364 \\}2364 \\}
2365 ,2365 ,
2366 });2366 });
2367 exe.addObject(obj);2367 exe.root_module.addObject(obj);
23682368
2369 const run = addRunArtifact(exe);2369 const run = addRunArtifact(exe);
2370 run.expectStdErrEqual("84\n");2370 run.expectStdErrEqual("84\n");
...@@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
2389 \\}2389 \\}
2390 ,2390 ,
2391 });2391 });
2392 lib.addObject(obj);2392 lib.root_module.addObject(obj);
23932393
2394 const exe = addExecutable(b, opts, .{2394 const exe = addExecutable(b, opts, .{
2395 .name = "testlib",2395 .name = "testlib",
...@@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
2402 \\}2402 \\}
2403 ,2403 ,
2404 });2404 });
2405 exe.linkLibrary(lib);2405 exe.root_module.linkLibrary(lib);
24062406
2407 const run = addRunArtifact(exe);2407 const run = addRunArtifact(exe);
2408 run.expectStdErrEqual("0\n");2408 run.expectStdErrEqual("0\n");
...@@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {...@@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
2452 \\char16_t *utf16_1 = u"foo";2452 \\char16_t *utf16_1 = u"foo";
2453 \\char32_t *utf32_1 = U"foo";2453 \\char32_t *utf32_1 = U"foo";
2454 , &.{"-O2"});2454 , &.{"-O2"});
2455 obj1.linkLibC();2455 obj1.root_module.link_libc = true;
24562456
2457 const obj2 = addObject(b, opts, .{ .name = "b.o" });2457 const obj2 = addObject(b, opts, .{ .name = "b.o" });
2458 addCSourceBytes(obj2,2458 addCSourceBytes(obj2,
...@@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {...@@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
2481 \\ assert((void*)wide1 != (void*)utf16_1);2481 \\ assert((void*)wide1 != (void*)utf16_1);
2482 \\}2482 \\}
2483 , &.{"-O2"});2483 , &.{"-O2"});
2484 obj2.linkLibC();2484 obj2.root_module.link_libc = true;
24852485
2486 const exe = addExecutable(b, opts, .{ .name = "main" });2486 const exe = addExecutable(b, opts, .{ .name = "main" });
2487 exe.addObject(obj1);2487 exe.root_module.addObject(obj1);
2488 exe.addObject(obj2);2488 exe.root_module.addObject(obj2);
2489 exe.linkLibC();2489 exe.root_module.link_libc = true;
24902490
2491 const run = addRunArtifact(exe);2491 const run = addRunArtifact(exe);
2492 run.expectExitCode(0);2492 run.expectExitCode(0);
...@@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {...@@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25202520
2521 {2521 {
2522 const exe = addExecutable(b, opts, .{ .name = "main1" });2522 const exe = addExecutable(b, opts, .{ .name = "main1" });
2523 exe.addObject(obj1);2523 exe.root_module.addObject(obj1);
2524 exe.addObject(obj2);2524 exe.root_module.addObject(obj2);
25252525
2526 const run = addRunArtifact(exe);2526 const run = addRunArtifact(exe);
2527 run.expectExitCode(0);2527 run.expectExitCode(0);
...@@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {...@@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25372537
2538 {2538 {
2539 const obj3 = addObject(b, opts, .{ .name = "c" });2539 const obj3 = addObject(b, opts, .{ .name = "c" });
2540 obj3.addObject(obj1);2540 obj3.root_module.addObject(obj1);
2541 obj3.addObject(obj2);2541 obj3.root_module.addObject(obj2);
25422542
2543 const exe = addExecutable(b, opts, .{ .name = "main2" });2543 const exe = addExecutable(b, opts, .{ .name = "main2" });
2544 exe.addObject(obj3);2544 exe.root_module.addObject(obj3);
25452545
2546 const run = addRunArtifact(exe);2546 const run = addRunArtifact(exe);
2547 run.expectExitCode(0);2547 run.expectExitCode(0);
...@@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {...@@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
2564 const exe = addExecutable(b, opts, .{ .name = "main" });2564 const exe = addExecutable(b, opts, .{ .name = "main" });
2565 addCSourceBytes(exe, "int main() { return 0; }", &.{});2565 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2566 exe.link_eh_frame_hdr = false;2566 exe.link_eh_frame_hdr = false;
2567 exe.linkLibC();2567 exe.root_module.link_libc = true;
25682568
2569 const check = exe.checkObject();2569 const check = exe.checkObject();
2570 check.checkInHeaders();2570 check.checkInHeaders();
...@@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step {...@@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step {
2586 \\ return 0;2586 \\ return 0;
2587 \\}2587 \\}
2588 , &.{});2588 , &.{});
2589 exe.linkLibC();2589 exe.root_module.link_libc = true;
2590 exe.root_module.pic = true;2590 exe.root_module.pic = true;
2591 exe.pie = true;2591 exe.pie = true;
25922592
...@@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step {...@@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step {
2617 \\ printf("Hello world\n");2617 \\ printf("Hello world\n");
2618 \\}2618 \\}
2619 , &.{});2619 , &.{});
2620 dso.linkLibC();2620 dso.root_module.link_libc = true;
26212621
2622 const exe = addExecutable(b, opts, .{ .name = "main" });2622 const exe = addExecutable(b, opts, .{ .name = "main" });
2623 addCSourceBytes(exe,2623 addCSourceBytes(exe,
...@@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step {...@@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step {
2626 \\void foo() { ignore(hello); }2626 \\void foo() { ignore(hello); }
2627 \\int main() { hello(); }2627 \\int main() { hello(); }
2628 , &.{});2628 , &.{});
2629 exe.linkLibrary(dso);2629 exe.root_module.linkLibrary(dso);
2630 exe.root_module.pic = true;2630 exe.root_module.pic = true;
2631 exe.linkLibC();2631 exe.root_module.link_libc = true;
26322632
2633 const run = addRunArtifact(exe);2633 const run = addRunArtifact(exe);
2634 run.expectStdOutEqual("Hello world\n");2634 run.expectStdOutEqual("Hello world\n");
...@@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {...@@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
2647 });2647 });
26482648
2649 const exe = addExecutable(b, opts, .{ .name = "main1" });2649 const exe = addExecutable(b, opts, .{ .name = "main1" });
2650 exe.addObject(obj);2650 exe.root_module.addObject(obj);
26512651
2652 const check = exe.checkObject();2652 const check = exe.checkObject();
2653 check.checkInDynamicSection();2653 check.checkInDynamicSection();
...@@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {...@@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
2662 \\__attribute__((section(".preinit_array")))2662 \\__attribute__((section(".preinit_array")))
2663 \\void *preinit[] = { preinit_fn };2663 \\void *preinit[] = { preinit_fn };
2664 , &.{});2664 , &.{});
2665 exe.linkLibC();2665 exe.root_module.link_libc = true;
26662666
2667 const check = exe.checkObject();2667 const check = exe.checkObject();
2668 check.checkInDynamicSection();2668 check.checkInDynamicSection();
...@@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step {...@@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step {
2710 });2710 });
27112711
2712 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });2712 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
2713 lib.addObject(obj1);2713 lib.root_module.addObject(obj1);
2714 lib.addObject(obj2);2714 lib.root_module.addObject(obj2);
2715 lib.addObject(obj3);2715 lib.root_module.addObject(obj3);
27162716
2717 const obj5 = addObject(b, opts, .{2717 const obj5 = addObject(b, opts, .{
2718 .name = "obj5",2718 .name = "obj5",
2719 });2719 });
2720 obj5.addObject(obj4);2720 obj5.root_module.addObject(obj4);
2721 obj5.linkLibrary(lib);2721 obj5.root_module.linkLibrary(lib);
27222722
2723 const check = obj5.checkObject();2723 const check = obj5.checkObject();
2724 check.checkInSymtab();2724 check.checkInSymtab();
...@@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2744 \\}2744 \\}
2745 ,2745 ,
2746 });2746 });
2747 obj1.linkLibCpp();2747 obj1.root_module.link_libcpp = true;
2748 const obj2 = addObject(b, opts, .{2748 const obj2 = addObject(b, opts, .{
2749 .name = "obj2",2749 .name = "obj2",
2750 .cpp_source_bytes =2750 .cpp_source_bytes =
...@@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2754 \\}2754 \\}
2755 ,2755 ,
2756 });2756 });
2757 obj2.linkLibCpp();2757 obj2.root_module.link_libcpp = true;
2758 const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes = 2758 const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes =
2759 \\#include <iostream>2759 \\#include <iostream>
2760 \\#include <stdexcept>2760 \\#include <stdexcept>
...@@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2768 \\ return 0;2768 \\ return 0;
2769 \\}2769 \\}
2770 });2770 });
2771 obj3.linkLibCpp();2771 obj3.root_module.link_libcpp = true;
27722772
2773 {2773 {
2774 const obj = addObject(b, opts, .{ .name = "obj" });2774 const obj = addObject(b, opts, .{ .name = "obj" });
2775 obj.addObject(obj1);2775 obj.root_module.addObject(obj1);
2776 obj.addObject(obj2);2776 obj.root_module.addObject(obj2);
2777 obj.linkLibCpp();2777 obj.root_module.link_libcpp = true;
27782778
2779 const exe = addExecutable(b, opts, .{ .name = "test1" });2779 const exe = addExecutable(b, opts, .{ .name = "test1" });
2780 exe.addObject(obj3);2780 exe.root_module.addObject(obj3);
2781 exe.addObject(obj);2781 exe.root_module.addObject(obj);
2782 exe.linkLibCpp();2782 exe.root_module.link_libcpp = true;
27832783
2784 const run = addRunArtifact(exe);2784 const run = addRunArtifact(exe);
2785 run.expectStdOutEqual("exception=Oh no!");2785 run.expectStdOutEqual("exception=Oh no!");
...@@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2788 {2788 {
2789 // Flipping the order should not influence the end result.2789 // Flipping the order should not influence the end result.
2790 const obj = addObject(b, opts, .{ .name = "obj" });2790 const obj = addObject(b, opts, .{ .name = "obj" });
2791 obj.addObject(obj2);2791 obj.root_module.addObject(obj2);
2792 obj.addObject(obj1);2792 obj.root_module.addObject(obj1);
2793 obj.linkLibCpp();2793 obj.root_module.link_libcpp = true;
27942794
2795 const exe = addExecutable(b, opts, .{ .name = "test2" });2795 const exe = addExecutable(b, opts, .{ .name = "test2" });
2796 exe.addObject(obj3);2796 exe.root_module.addObject(obj3);
2797 exe.addObject(obj);2797 exe.root_module.addObject(obj);
2798 exe.linkLibCpp();2798 exe.root_module.link_libcpp = true;
27992799
2800 const run = addRunArtifact(exe);2800 const run = addRunArtifact(exe);
2801 run.expectStdOutEqual("exception=Oh no!");2801 run.expectStdOutEqual("exception=Oh no!");
...@@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {...@@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
2817 \\}2817 \\}
2818 ,2818 ,
2819 });2819 });
2820 obj1.linkLibCpp();2820 obj1.root_module.link_libcpp = true;
2821 const obj2 = addObject(b, opts, .{2821 const obj2 = addObject(b, opts, .{
2822 .name = "obj2",2822 .name = "obj2",
2823 .cpp_source_bytes =2823 .cpp_source_bytes =
...@@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {...@@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
2827 \\}2827 \\}
2828 ,2828 ,
2829 });2829 });
2830 obj2.linkLibCpp();2830 obj2.root_module.link_libcpp = true;
2831 const obj3 = addObject(b, opts, .{2831 const obj3 = addObject(b, opts, .{
2832 .name = "obj3",2832 .name = "obj3",
2833 .cpp_source_bytes =2833 .cpp_source_bytes =
...@@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {...@@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
2844 \\}2844 \\}
2845 ,2845 ,
2846 });2846 });
2847 obj3.linkLibCpp();2847 obj3.root_module.link_libcpp = true;
28482848
2849 const obj = addObject(b, opts, .{ .name = "obj" });2849 const obj = addObject(b, opts, .{ .name = "obj" });
2850 obj.addObject(obj1);2850 obj.root_module.addObject(obj1);
2851 obj.addObject(obj2);2851 obj.root_module.addObject(obj2);
2852 obj.addObject(obj3);2852 obj.root_module.addObject(obj3);
2853 obj.linkLibCpp();2853 obj.root_module.link_libcpp = true;
28542854
2855 const exe = addExecutable(b, opts, .{ .name = "test2" });2855 const exe = addExecutable(b, opts, .{ .name = "test2" });
2856 exe.addObject(obj);2856 exe.root_module.addObject(obj);
2857 exe.linkLibCpp();2857 exe.root_module.link_libcpp = true;
28582858
2859 const run = addRunArtifact(exe);2859 const run = addRunArtifact(exe);
2860 run.expectStdOutEqual("exception=Oh no!");2860 run.expectStdOutEqual("exception=Oh no!");
...@@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {...@@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {
2880 });2880 });
28812881
2882 const obj2 = addObject(b, opts, .{ .name = "b" });2882 const obj2 = addObject(b, opts, .{ .name = "b" });
2883 obj2.addObject(obj1);2883 obj2.root_module.addObject(obj1);
28842884
2885 const check = obj2.checkObject();2885 const check = obj2.checkObject();
2886 check.dumpSection(".rodata.str1.1");2886 check.dumpSection(".rodata.str1.1");
...@@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {...@@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
2905 const obj2 = addObject(b, opts, .{2905 const obj2 = addObject(b, opts, .{
2906 .name = "obj2",2906 .name = "obj2",
2907 });2907 });
2908 obj2.addObject(obj1);2908 obj2.root_module.addObject(obj1);
29092909
2910 const check1 = obj1.checkObject();2910 const check1 = obj1.checkObject();
2911 check1.checkInHeaders();2911 check1.checkInHeaders();
...@@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {...@@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
2940 ,2940 ,
2941 .pic = true,2941 .pic = true,
2942 });2942 });
2943 obj.linkLibC();2943 obj.root_module.link_libc = true;
29442944
2945 {2945 {
2946 const exe = addExecutable(b, opts, .{ .name = "main1" });2946 const exe = addExecutable(b, opts, .{ .name = "main1" });
2947 exe.addObject(obj);2947 exe.root_module.addObject(obj);
2948 exe.linkLibrary(dso);2948 exe.root_module.linkLibrary(dso);
2949 exe.pie = true;2949 exe.pie = true;
29502950
2951 const run = addRunArtifact(exe);2951 const run = addRunArtifact(exe);
...@@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {...@@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
2965 // https://github.com/ziglang/zig/issues/174302965 // https://github.com/ziglang/zig/issues/17430
2966 // {2966 // {
2967 // const exe = addExecutable(b, opts, .{ .name = "main2"});2967 // const exe = addExecutable(b, opts, .{ .name = "main2"});
2968 // exe.addObject(obj);2968 // exe.root_module.addObject(obj);
2969 // exe.linkLibrary(dso);2969 // exe.root_module.linkLibrary(dso);
2970 // exe.pie = false;2970 // exe.pie = false;
29712971
2972 // const run = addRunArtifact(exe);2972 // const run = addRunArtifact(exe);
...@@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step {...@@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step {
2999 \\}2999 \\}
3000 ,3000 ,
3001 });3001 });
3002 obj.linkLibC();3002 obj.root_module.link_libc = true;
30033003
3004 {3004 {
3005 const exe = addExecutable(b, opts, .{ .name = "main1" });3005 const exe = addExecutable(b, opts, .{ .name = "main1" });
3006 exe.addObject(obj);3006 exe.root_module.addObject(obj);
3007 exe.root_module.strip = false;3007 exe.root_module.strip = false;
3008 exe.linkLibC();3008 exe.root_module.link_libc = true;
30093009
3010 const check = exe.checkObject();3010 const check = exe.checkObject();
3011 check.checkInHeaders();3011 check.checkInHeaders();
...@@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step {...@@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step {
30163016
3017 {3017 {
3018 const exe = addExecutable(b, opts, .{ .name = "main2" });3018 const exe = addExecutable(b, opts, .{ .name = "main2" });
3019 exe.addObject(obj);3019 exe.root_module.addObject(obj);
3020 exe.root_module.strip = true;3020 exe.root_module.strip = true;
3021 exe.linkLibC();3021 exe.root_module.link_libc = true;
30223022
3023 const check = exe.checkObject();3023 const check = exe.checkObject();
3024 check.checkInHeaders();3024 check.checkInHeaders();
...@@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {...@@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
30743074
3075 {3075 {
3076 const dso = addSharedLibrary(b, opts, .{ .name = "a" });3076 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3077 dso.addObject(obj);3077 dso.root_module.addObject(obj);
3078 // dso.link_relax = true;3078 // dso.link_relax = true;
30793079
3080 const check = dso.checkObject();3080 const check = dso.checkObject();
...@@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {...@@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
3086 // TODO add -Wl,--no-relax3086 // TODO add -Wl,--no-relax
3087 // {3087 // {
3088 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});3088 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3089 // dso.addObject(obj);3089 // dso.root_module.addObject(obj);
3090 // dso.link_relax = false;3090 // dso.link_relax = false;
30913091
3092 // const check = dso.checkObject();3092 // const check = dso.checkObject();
...@@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step {...@@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step {
3128 \\ return 0;3128 \\ return 0;
3129 \\}3129 \\}
3130 , &.{});3130 , &.{});
3131 exe.linkLibrary(dso);3131 exe.root_module.linkLibrary(dso);
3132 exe.linkLibC();3132 exe.root_module.link_libc = true;
31333133
3134 const run = addRunArtifact(exe);3134 const run = addRunArtifact(exe);
3135 run.expectStdOutEqual("5 3 5 3 5 3\n");3135 run.expectStdOutEqual("5 3 5 3 5 3\n");
...@@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
3159 ,3159 ,
3160 .pic = true,3160 .pic = true,
3161 });3161 });
3162 main_o.linkLibC();3162 main_o.root_module.link_libc = true;
31633163
3164 const a_o = addObject(b, opts, .{3164 const a_o = addObject(b, opts, .{
3165 .name = "a",3165 .name = "a",
...@@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
3184 const exp_stdout = "1 2 3 4 5 6\n";3184 const exp_stdout = "1 2 3 4 5 6\n";
31853185
3186 const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });3186 const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });
3187 dso1.addObject(a_o);3187 dso1.root_module.addObject(a_o);
31883188
3189 const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });3189 const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });
3190 dso2.addObject(b_o);3190 dso2.root_module.addObject(b_o);
3191 // dso2.link_relax = false; // TODO3191 // dso2.link_relax = false; // TODO
31923192
3193 {3193 {
3194 const exe = addExecutable(b, opts, .{ .name = "main1" });3194 const exe = addExecutable(b, opts, .{ .name = "main1" });
3195 exe.addObject(main_o);3195 exe.root_module.addObject(main_o);
3196 exe.linkLibrary(dso1);3196 exe.root_module.linkLibrary(dso1);
3197 exe.linkLibrary(dso2);3197 exe.root_module.linkLibrary(dso2);
31983198
3199 const run = addRunArtifact(exe);3199 const run = addRunArtifact(exe);
3200 run.expectStdOutEqual(exp_stdout);3200 run.expectStdOutEqual(exp_stdout);
...@@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32033203
3204 {3204 {
3205 const exe = addExecutable(b, opts, .{ .name = "main2" });3205 const exe = addExecutable(b, opts, .{ .name = "main2" });
3206 exe.addObject(main_o);3206 exe.root_module.addObject(main_o);
3207 // exe.link_relax = false; // TODO3207 // exe.link_relax = false; // TODO
3208 exe.linkLibrary(dso1);3208 exe.root_module.linkLibrary(dso1);
3209 exe.linkLibrary(dso2);3209 exe.root_module.linkLibrary(dso2);
32103210
3211 const run = addRunArtifact(exe);3211 const run = addRunArtifact(exe);
3212 run.expectStdOutEqual(exp_stdout);3212 run.expectStdOutEqual(exp_stdout);
...@@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
3216 // https://github.com/ziglang/zig/issues/17430 ??3216 // https://github.com/ziglang/zig/issues/17430 ??
3217 // {3217 // {
3218 // const exe = addExecutable(b, opts, .{ .name = "main3"});3218 // const exe = addExecutable(b, opts, .{ .name = "main3"});
3219 // exe.addObject(main_o);3219 // exe.root_module.addObject(main_o);
3220 // exe.linkLibrary(dso1);3220 // exe.root_module.linkLibrary(dso1);
3221 // exe.linkLibrary(dso2);3221 // exe.root_module.linkLibrary(dso2);
3222 // exe.linkage = .static;3222 // exe.linkage = .static;
32233223
3224 // const run = addRunArtifact(exe);3224 // const run = addRunArtifact(exe);
...@@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32283228
3229 // {3229 // {
3230 // const exe = addExecutable(b, opts, .{ .name = "main4"});3230 // const exe = addExecutable(b, opts, .{ .name = "main4"});
3231 // exe.addObject(main_o);3231 // exe.root_module.addObject(main_o);
3232 // // exe.link_relax = false; // TODO3232 // // exe.link_relax = false; // TODO
3233 // exe.linkLibrary(dso1);3233 // exe.root_module.linkLibrary(dso1);
3234 // exe.linkLibrary(dso2);3234 // exe.root_module.linkLibrary(dso2);
3235 // exe.linkage = .static;3235 // exe.linkage = .static;
32363236
3237 // const run = addRunArtifact(exe);3237 // const run = addRunArtifact(exe);
...@@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {...@@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
3265 .c_source_flags = &.{"-fno-plt"},3265 .c_source_flags = &.{"-fno-plt"},
3266 .pic = true,3266 .pic = true,
3267 });3267 });
3268 obj.linkLibC();3268 obj.root_module.link_libc = true;
32693269
3270 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });3270 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });
3271 addCSourceBytes(a_so,3271 addCSourceBytes(a_so,
...@@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {...@@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32843284
3285 {3285 {
3286 const exe = addExecutable(b, opts, .{ .name = "main1" });3286 const exe = addExecutable(b, opts, .{ .name = "main1" });
3287 exe.addObject(obj);3287 exe.root_module.addObject(obj);
3288 exe.linkLibrary(a_so);3288 exe.root_module.linkLibrary(a_so);
3289 exe.linkLibrary(b_so);3289 exe.root_module.linkLibrary(b_so);
3290 exe.linkLibC();3290 exe.root_module.link_libc = true;
32913291
3292 const run = addRunArtifact(exe);3292 const run = addRunArtifact(exe);
3293 run.expectStdOutEqual("1 2 3 4 5 6\n");3293 run.expectStdOutEqual("1 2 3 4 5 6\n");
...@@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {...@@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32963296
3297 {3297 {
3298 const exe = addExecutable(b, opts, .{ .name = "main2" });3298 const exe = addExecutable(b, opts, .{ .name = "main2" });
3299 exe.addObject(obj);3299 exe.root_module.addObject(obj);
3300 exe.linkLibrary(a_so);3300 exe.root_module.linkLibrary(a_so);
3301 exe.linkLibrary(b_so);3301 exe.root_module.linkLibrary(b_so);
3302 exe.linkLibC();3302 exe.root_module.link_libc = true;
3303 // exe.link_relax = false; // TODO3303 // exe.link_relax = false; // TODO
33043304
3305 const run = addRunArtifact(exe);3305 const run = addRunArtifact(exe);
...@@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
3329 ,3329 ,
3330 .pic = true,3330 .pic = true,
3331 });3331 });
3332 a_o.linkLibC();3332 a_o.root_module.link_libc = true;
33333333
3334 const b_o = addObject(b, opts, .{3334 const b_o = addObject(b, opts, .{
3335 .name = "b",3335 .name = "b",
...@@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33423342
3343 {3343 {
3344 const dso = addSharedLibrary(b, opts, .{ .name = "a1" });3344 const dso = addSharedLibrary(b, opts, .{ .name = "a1" });
3345 dso.addObject(a_o);3345 dso.root_module.addObject(a_o);
33463346
3347 const exe = addExecutable(b, opts, .{ .name = "main1" });3347 const exe = addExecutable(b, opts, .{ .name = "main1" });
3348 exe.addObject(b_o);3348 exe.root_module.addObject(b_o);
3349 exe.linkLibrary(dso);3349 exe.root_module.linkLibrary(dso);
3350 exe.linkLibC();3350 exe.root_module.link_libc = true;
33513351
3352 const run = addRunArtifact(exe);3352 const run = addRunArtifact(exe);
3353 run.expectStdOutEqual("1 2 3\n");3353 run.expectStdOutEqual("1 2 3\n");
...@@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33563356
3357 {3357 {
3358 const dso = addSharedLibrary(b, opts, .{ .name = "a2" });3358 const dso = addSharedLibrary(b, opts, .{ .name = "a2" });
3359 dso.addObject(a_o);3359 dso.root_module.addObject(a_o);
3360 // dso.link_relax = false; // TODO3360 // dso.link_relax = false; // TODO
33613361
3362 const exe = addExecutable(b, opts, .{ .name = "main2" });3362 const exe = addExecutable(b, opts, .{ .name = "main2" });
3363 exe.addObject(b_o);3363 exe.root_module.addObject(b_o);
3364 exe.linkLibrary(dso);3364 exe.root_module.linkLibrary(dso);
3365 exe.linkLibC();3365 exe.root_module.link_libc = true;
33663366
3367 const run = addRunArtifact(exe);3367 const run = addRunArtifact(exe);
3368 run.expectStdOutEqual("1 2 3\n");3368 run.expectStdOutEqual("1 2 3\n");
...@@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33713371
3372 // {3372 // {
3373 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});3373 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3374 // dso.addObject(a_o);3374 // dso.root_module.addObject(a_o);
3375 // dso.link_z_nodlopen = true;3375 // dso.link_z_nodlopen = true;
33763376
3377 // const exe = addExecutable(b, opts, .{ .name = "main"});3377 // const exe = addExecutable(b, opts, .{ .name = "main"});
3378 // exe.addObject(b_o);3378 // exe.root_module.addObject(b_o);
3379 // exe.linkLibrary(dso);3379 // exe.root_module.linkLibrary(dso);
33803380
3381 // const run = addRunArtifact(exe);3381 // const run = addRunArtifact(exe);
3382 // run.expectStdOutEqual("1 2 3\n");3382 // run.expectStdOutEqual("1 2 3\n");
...@@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33853385
3386 // {3386 // {
3387 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});3387 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3388 // dso.addObject(a_o);3388 // dso.root_module.addObject(a_o);
3389 // dso.link_relax = false;3389 // dso.link_relax = false;
3390 // dso.link_z_nodlopen = true;3390 // dso.link_z_nodlopen = true;
33913391
3392 // const exe = addExecutable(b, opts, .{ .name = "main"});3392 // const exe = addExecutable(b, opts, .{ .name = "main"});
3393 // exe.addObject(b_o);3393 // exe.root_module.addObject(b_o);
3394 // exe.linkLibrary(dso);3394 // exe.root_module.linkLibrary(dso);
33953395
3396 // const run = addRunArtifact(exe);3396 // const run = addRunArtifact(exe);
3397 // run.expectStdOutEqual("1 2 3\n");3397 // run.expectStdOutEqual("1 2 3\n");
...@@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step {...@@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
3417 \\ printf("%d %d ", foo, bar);3417 \\ printf("%d %d ", foo, bar);
3418 \\}3418 \\}
3419 , &.{});3419 , &.{});
3420 dso.linkLibC();3420 dso.root_module.link_libc = true;
34213421
3422 const main_o = addObject(b, opts, .{3422 const main_o = addObject(b, opts, .{
3423 .name = "main",3423 .name = "main",
...@@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step {...@@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
3435 \\}3435 \\}
3436 ,3436 ,
3437 });3437 });
3438 main_o.linkLibC();3438 main_o.root_module.link_libc = true;
34393439
3440 const exp_stdout = "0 0 3 5 7\n";3440 const exp_stdout = "0 0 3 5 7\n";
34413441
3442 {3442 {
3443 const exe = addExecutable(b, opts, .{ .name = "main1" });3443 const exe = addExecutable(b, opts, .{ .name = "main1" });
3444 exe.addObject(main_o);3444 exe.root_module.addObject(main_o);
3445 exe.linkLibrary(dso);3445 exe.root_module.linkLibrary(dso);
3446 exe.linkLibC();3446 exe.root_module.link_libc = true;
34473447
3448 const run = addRunArtifact(exe);3448 const run = addRunArtifact(exe);
3449 run.expectStdOutEqual(exp_stdout);3449 run.expectStdOutEqual(exp_stdout);
...@@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step {...@@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34523452
3453 {3453 {
3454 const exe = addExecutable(b, opts, .{ .name = "main2" });3454 const exe = addExecutable(b, opts, .{ .name = "main2" });
3455 exe.addObject(main_o);3455 exe.root_module.addObject(main_o);
3456 exe.linkLibrary(dso);3456 exe.root_module.linkLibrary(dso);
3457 exe.linkLibC();3457 exe.root_module.link_libc = true;
3458 // exe.link_relax = false; // TODO3458 // exe.link_relax = false; // TODO
34593459
3460 const run = addRunArtifact(exe);3460 const run = addRunArtifact(exe);
...@@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {...@@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
3500 ,3500 ,
3501 .pic = true,3501 .pic = true,
3502 });3502 });
3503 c_o.linkLibC();3503 c_o.root_module.link_libc = true;
35043504
3505 {3505 {
3506 const dso = addSharedLibrary(b, opts, .{ .name = "a" });3506 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3507 dso.addObject(a_o);3507 dso.root_module.addObject(a_o);
3508 dso.addObject(b_o);3508 dso.root_module.addObject(b_o);
35093509
3510 const exe = addExecutable(b, opts, .{ .name = "main" });3510 const exe = addExecutable(b, opts, .{ .name = "main" });
3511 exe.addObject(c_o);3511 exe.root_module.addObject(c_o);
3512 exe.linkLibrary(dso);3512 exe.root_module.linkLibrary(dso);
3513 exe.linkLibC();3513 exe.root_module.link_libc = true;
35143514
3515 const run = addRunArtifact(exe);3515 const run = addRunArtifact(exe);
3516 run.expectStdOutEqual("42 1 2 3\n");3516 run.expectStdOutEqual("42 1 2 3\n");
...@@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {...@@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
35193519
3520 {3520 {
3521 const exe = addExecutable(b, opts, .{ .name = "main" });3521 const exe = addExecutable(b, opts, .{ .name = "main" });
3522 exe.addObject(a_o);3522 exe.root_module.addObject(a_o);
3523 exe.addObject(b_o);3523 exe.root_module.addObject(b_o);
3524 exe.addObject(c_o);3524 exe.root_module.addObject(c_o);
3525 exe.linkLibC();3525 exe.root_module.link_libc = true;
35263526
3527 const run = addRunArtifact(exe);3527 const run = addRunArtifact(exe);
3528 run.expectStdOutEqual("42 1 2 3\n");3528 run.expectStdOutEqual("42 1 2 3\n");
...@@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step {...@@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step {
3555 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);3555 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);
3556 \\}3556 \\}
3557 , &.{});3557 , &.{});
3558 exe.linkLibC();3558 exe.root_module.link_libc = true;
3559 // Disabled to work around the ELF linker crashing.3559 // Disabled to work around the ELF linker crashing.
3560 // Can be reproduced on a x86_64-linux host by commenting out the line below.3560 // Can be reproduced on a x86_64-linux host by commenting out the line below.
3561 exe.root_module.sanitize_c = .off;3561 exe.root_module.sanitize_c = .off;
...@@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {...@@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {
3580 \\}3580 \\}
3581 , &.{});3581 , &.{});
3582 exe.root_module.pic = true;3582 exe.root_module.pic = true;
3583 exe.linkLibC();3583 exe.root_module.link_libc = true;
35843584
3585 const run = addRunArtifact(exe);3585 const run = addRunArtifact(exe);
3586 run.expectStdOutEqual("1 2 3 0 5\n");3586 run.expectStdOutEqual("1 2 3 0 5\n");
...@@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step {...@@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
3609 .c_source_flags = &.{"-ftls-model=local-dynamic"},3609 .c_source_flags = &.{"-ftls-model=local-dynamic"},
3610 .pic = true,3610 .pic = true,
3611 });3611 });
3612 main_o.linkLibC();3612 main_o.root_module.link_libc = true;
36133613
3614 const a_o = addObject(b, opts, .{3614 const a_o = addObject(b, opts, .{
3615 .name = "a",3615 .name = "a",
...@@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {...@@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36223622
3623 {3623 {
3624 const exe = addExecutable(b, opts, .{ .name = "main1" });3624 const exe = addExecutable(b, opts, .{ .name = "main1" });
3625 exe.addObject(main_o);3625 exe.root_module.addObject(main_o);
3626 exe.addObject(a_o);3626 exe.root_module.addObject(a_o);
3627 exe.linkLibC();3627 exe.root_module.link_libc = true;
36283628
3629 const run = addRunArtifact(exe);3629 const run = addRunArtifact(exe);
3630 run.expectStdOutEqual(exp_stdout);3630 run.expectStdOutEqual(exp_stdout);
...@@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {...@@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36333633
3634 {3634 {
3635 const exe = addExecutable(b, opts, .{ .name = "main2" });3635 const exe = addExecutable(b, opts, .{ .name = "main2" });
3636 exe.addObject(main_o);3636 exe.root_module.addObject(main_o);
3637 exe.addObject(a_o);3637 exe.root_module.addObject(a_o);
3638 exe.linkLibC();3638 exe.root_module.link_libc = true;
3639 // exe.link_relax = false; // TODO3639 // exe.link_relax = false; // TODO
36403640
3641 const run = addRunArtifact(exe);3641 const run = addRunArtifact(exe);
...@@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step {...@@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step {
3668 \\ return 0;3668 \\ return 0;
3669 \\}3669 \\}
3670 , &.{});3670 , &.{});
3671 exe.linkLibrary(dso);3671 exe.root_module.linkLibrary(dso);
3672 exe.linkLibC();3672 exe.root_module.link_libc = true;
36733673
3674 const run = addRunArtifact(exe);3674 const run = addRunArtifact(exe);
3675 run.expectStdOutEqual("1 2\n");3675 run.expectStdOutEqual("1 2\n");
...@@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {...@@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
3699 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },3699 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },
3700 .pic = true,3700 .pic = true,
3701 });3701 });
3702 a_o.linkLibC();3702 a_o.root_module.link_libc = true;
37033703
3704 const b_o = addObject(b, opts, .{3704 const b_o = addObject(b, opts, .{
3705 .name = "b",3705 .name = "b",
...@@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {...@@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37103710
3711 {3711 {
3712 const exe = addExecutable(b, opts, .{ .name = "main1" });3712 const exe = addExecutable(b, opts, .{ .name = "main1" });
3713 exe.addObject(a_o);3713 exe.root_module.addObject(a_o);
3714 exe.addObject(b_o);3714 exe.root_module.addObject(b_o);
3715 exe.linkLibC();3715 exe.root_module.link_libc = true;
37163716
3717 const run = addRunArtifact(exe);3717 const run = addRunArtifact(exe);
3718 run.expectStdOutEqual("3 5 3 5\n");3718 run.expectStdOutEqual("3 5 3 5\n");
...@@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {...@@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37213721
3722 {3722 {
3723 const exe = addExecutable(b, opts, .{ .name = "main2" });3723 const exe = addExecutable(b, opts, .{ .name = "main2" });
3724 exe.addObject(a_o);3724 exe.root_module.addObject(a_o);
3725 exe.addObject(b_o);3725 exe.root_module.addObject(b_o);
3726 exe.linkLibC();3726 exe.root_module.link_libc = true;
3727 // exe.link_relax = false; // TODO3727 // exe.link_relax = false; // TODO
37283728
3729 const run = addRunArtifact(exe);3729 const run = addRunArtifact(exe);
...@@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step {...@@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step {
3756 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;3756 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;
3757 , &.{});3757 , &.{});
3758 exe.root_module.pic = false;3758 exe.root_module.pic = false;
3759 exe.linkLibC();3759 exe.root_module.link_libc = true;
37603760
3761 const run = addRunArtifact(exe);3761 const run = addRunArtifact(exe);
3762 run.expectStdOutEqual("3 5 3 5\n");3762 run.expectStdOutEqual("3 5 3 5\n");
...@@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {...@@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
3784 \\ return NULL;3784 \\ return NULL;
3785 \\}3785 \\}
3786 , &.{});3786 , &.{});
3787 dso.linkLibC();3787 dso.root_module.link_libc = true;
37883788
3789 const exe = addExecutable(b, opts, .{ .name = "main" });3789 const exe = addExecutable(b, opts, .{ .name = "main" });
3790 addCSourceBytes(exe,3790 addCSourceBytes(exe,
...@@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {...@@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
3811 \\ pthread_join(thread, NULL);3811 \\ pthread_join(thread, NULL);
3812 \\}3812 \\}
3813 , &.{});3813 , &.{});
3814 exe.addRPath(dso.getEmittedBinDirectory());3814 exe.root_module.addRPath(dso.getEmittedBinDirectory());
3815 exe.linkLibC();3815 exe.root_module.link_libc = true;
3816 exe.root_module.pic = true;3816 exe.root_module.pic = true;
38173817
3818 const run = addRunArtifact(exe);3818 const run = addRunArtifact(exe);
...@@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step {...@@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step {
3842 ,3842 ,
3843 .pic = true,3843 .pic = true,
3844 });3844 });
3845 obj.linkLibC();3845 obj.root_module.link_libc = true;
38463846
3847 const exe = addExecutable(b, opts, .{ .name = "main" });3847 const exe = addExecutable(b, opts, .{ .name = "main" });
3848 addCSourceBytes(exe,3848 addCSourceBytes(exe,
3849 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;3849 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;
3850 , &.{});3850 , &.{});
3851 exe.addObject(obj);3851 exe.root_module.addObject(obj);
3852 exe.linkLibC();3852 exe.root_module.link_libc = true;
38533853
3854 const run = addRunArtifact(exe);3854 const run = addRunArtifact(exe);
3855 run.expectStdOutEqual("3 5 3 5\n");3855 run.expectStdOutEqual("3 5 3 5\n");
...@@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {...@@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
3889 ,3889 ,
3890 .pic = true,3890 .pic = true,
3891 });3891 });
3892 c_o.linkLibC();3892 c_o.root_module.link_libc = true;
38933893
3894 {3894 {
3895 const exe = addExecutable(b, opts, .{ .name = "main" });3895 const exe = addExecutable(b, opts, .{ .name = "main" });
3896 exe.addObject(a_o);3896 exe.root_module.addObject(a_o);
3897 exe.addObject(b_o);3897 exe.root_module.addObject(b_o);
3898 exe.addObject(c_o);3898 exe.root_module.addObject(c_o);
3899 exe.linkLibC();3899 exe.root_module.link_libc = true;
39003900
3901 const run = addRunArtifact(exe);3901 const run = addRunArtifact(exe);
3902 run.expectStdOutEqual("42\n");3902 run.expectStdOutEqual("42\n");
...@@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {...@@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
39053905
3906 {3906 {
3907 const dso = addSharedLibrary(b, opts, .{ .name = "a" });3907 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3908 dso.addObject(a_o);3908 dso.root_module.addObject(a_o);
3909 dso.addObject(b_o);3909 dso.root_module.addObject(b_o);
39103910
3911 const exe = addExecutable(b, opts, .{ .name = "main" });3911 const exe = addExecutable(b, opts, .{ .name = "main" });
3912 exe.addObject(c_o);3912 exe.root_module.addObject(c_o);
3913 exe.linkLibrary(dso);3913 exe.root_module.linkLibrary(dso);
3914 exe.linkLibC();3914 exe.root_module.link_libc = true;
39153915
3916 const run = addRunArtifact(exe);3916 const run = addRunArtifact(exe);
3917 run.expectStdOutEqual("42\n");3917 run.expectStdOutEqual("42\n");
...@@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step {...@@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step {
3939 \\ return 0;3939 \\ return 0;
3940 \\}3940 \\}
3941 , &.{});3941 , &.{});
3942 exe.linkLibC();3942 exe.root_module.link_libc = true;
39433943
3944 const run = addRunArtifact(exe);3944 const run = addRunArtifact(exe);
3945 run.expectStdOutEqual(3945 run.expectStdOutEqual(
...@@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {...@@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {
3969 \\ return foo;3969 \\ return foo;
3970 \\}3970 \\}
3971 , &.{});3971 , &.{});
3972 exe.linkLibrary(dylib);3972 exe.root_module.linkLibrary(dylib);
3973 exe.linkLibC();3973 exe.root_module.link_libc = true;
39743974
3975 expectLinkErrors(exe, test_step, .{3975 expectLinkErrors(exe, test_step, .{
3976 .contains = "error: failed to parse shared library: BadMagic",3976 .contains = "error: failed to parse shared library: BadMagic",
...@@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {...@@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
3993 ,3993 ,
3994 .c_source_flags = &.{"-ffunction-sections"},3994 .c_source_flags = &.{"-ffunction-sections"},
3995 });3995 });
3996 obj1.linkLibC();3996 obj1.root_module.link_libc = true;
39973997
3998 const obj2 = addObject(b, opts, .{3998 const obj2 = addObject(b, opts, .{
3999 .name = "b",3999 .name = "b",
...@@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {...@@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
4007 ,4007 ,
4008 .c_source_flags = &.{"-ffunction-sections"},4008 .c_source_flags = &.{"-ffunction-sections"},
4009 });4009 });
4010 obj2.linkLibC();4010 obj2.root_module.link_libc = true;
40114011
4012 const exe = addExecutable(b, opts, .{ .name = "main" });4012 const exe = addExecutable(b, opts, .{ .name = "main" });
4013 exe.addObject(obj1);4013 exe.root_module.addObject(obj1);
4014 exe.addObject(obj2);4014 exe.root_module.addObject(obj2);
4015 exe.linkLibC();4015 exe.root_module.link_libc = true;
40164016
4017 expectLinkErrors(exe, test_step, .{ .exact = &.{4017 expectLinkErrors(exe, test_step, .{ .exact = &.{
4018 "error: undefined symbol: foo",4018 "error: undefined symbol: foo",
...@@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step {...@@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
4037 ,4037 ,
4038 .pic = true,4038 .pic = true,
4039 });4039 });
4040 obj.linkLibC();4040 obj.root_module.link_libc = true;
40414041
4042 {4042 {
4043 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4043 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4044 dso.addObject(obj);4044 dso.root_module.addObject(obj);
4045 dso.linkLibC();4045 dso.root_module.link_libc = true;
40464046
4047 const check = dso.checkObject();4047 const check = dso.checkObject();
4048 check.checkInDynamicSymtab();4048 check.checkInDynamicSymtab();
...@@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step {...@@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
40524052
4053 {4053 {
4054 const exe = addExecutable(b, opts, .{ .name = "main" });4054 const exe = addExecutable(b, opts, .{ .name = "main" });
4055 exe.addObject(obj);4055 exe.root_module.addObject(obj);
4056 exe.linkLibC();4056 exe.root_module.link_libc = true;
40574057
4058 const check = exe.checkObject();4058 const check = exe.checkObject();
4059 check.checkInDynamicSymtab();4059 check.checkInDynamicSymtab();
...@@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {...@@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
4084 \\int bar();4084 \\int bar();
4085 \\int main() { printf("bar=%d\n", bar()); }4085 \\int main() { printf("bar=%d\n", bar()); }
4086 , &.{});4086 , &.{});
4087 exe.linkLibrary(dso);4087 exe.root_module.linkLibrary(dso);
4088 exe.linkLibC();4088 exe.root_module.link_libc = true;
40894089
4090 const run = addRunArtifact(exe);4090 const run = addRunArtifact(exe);
4091 run.expectStdOutEqual("bar=-1\n");4091 run.expectStdOutEqual("bar=-1\n");
...@@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {...@@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
4100 \\int bar();4100 \\int bar();
4101 \\int main() { printf("bar=%d\n", bar()); }4101 \\int main() { printf("bar=%d\n", bar()); }
4102 , &.{});4102 , &.{});
4103 exe.linkLibrary(dso);4103 exe.root_module.linkLibrary(dso);
4104 exe.linkLibC();4104 exe.root_module.link_libc = true;
41054105
4106 const run = addRunArtifact(exe);4106 const run = addRunArtifact(exe);
4107 run.expectStdOutEqual("bar=5\n");4107 run.expectStdOutEqual("bar=5\n");
...@@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step {...@@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41224122
4123 {4123 {
4124 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4124 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4125 dso.addObject(obj);4125 dso.root_module.addObject(obj);
41264126
4127 const check = dso.checkObject();4127 const check = dso.checkObject();
4128 check.checkInDynamicSection();4128 check.checkInDynamicSection();
...@@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step {...@@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41324132
4133 {4133 {
4134 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4134 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4135 dso.addObject(obj);4135 dso.root_module.addObject(obj);
4136 dso.link_z_lazy = true;4136 dso.link_z_lazy = true;
41374137
4138 const check = dso.checkObject();4138 const check = dso.checkObject();
...@@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {...@@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {
4150 const exe = addExecutable(b, opts, .{ .name = "main" });4150 const exe = addExecutable(b, opts, .{ .name = "main" });
4151 addCSourceBytes(exe, "int main() { return 0; }", &.{});4151 addCSourceBytes(exe, "int main() { return 0; }", &.{});
4152 exe.stack_size = 0x800000;4152 exe.stack_size = 0x800000;
4153 exe.linkLibC();4153 exe.root_module.link_libc = true;
41544154
4155 const check = exe.checkObject();4155 const check = exe.checkObject();
4156 check.checkInHeaders();4156 check.checkInHeaders();
...@@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step {...@@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step {
4202 });4202 });
42034203
4204 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4204 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4205 dso.addObject(a_o);4205 dso.root_module.addObject(a_o);
4206 dso.addObject(b_o);4206 dso.root_module.addObject(b_o);
4207 dso.link_z_notext = true;4207 dso.link_z_notext = true;
42084208
4209 const exe = addExecutable(b, opts, .{ .name = "main" });4209 const exe = addExecutable(b, opts, .{ .name = "main" });
...@@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step {...@@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step {
4214 \\ printf("%d\n", fnn());4214 \\ printf("%d\n", fnn());
4215 \\}4215 \\}
4216 , &.{});4216 , &.{});
4217 exe.linkLibrary(dso);4217 exe.root_module.linkLibrary(dso);
4218 exe.linkLibC();4218 exe.root_module.link_libc = true;
42194219
4220 const run = addRunArtifact(exe);4220 const run = addRunArtifact(exe);
4221 run.expectStdOutEqual("3\n");4221 run.expectStdOutEqual("3\n");
test/link/link.zig+3-3
...@@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run {...@@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run {
140pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {140pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
141 const b = comp.step.owner;141 const b = comp.step.owner;
142 const file = WriteFile.create(b).add("a.c", bytes);142 const file = WriteFile.create(b).add("a.c", bytes);
143 comp.addCSourceFile(.{ .file = file, .flags = flags });143 comp.root_module.addCSourceFile(.{ .file = file, .flags = flags });
144}144}
145145
146pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {146pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
147 const b = comp.step.owner;147 const b = comp.step.owner;
148 const file = WriteFile.create(b).add("a.cpp", bytes);148 const file = WriteFile.create(b).add("a.cpp", bytes);
149 comp.addCSourceFile(.{ .file = file, .flags = flags });149 comp.root_module.addCSourceFile(.{ .file = file, .flags = flags });
150}150}
151151
152pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {152pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {
153 const b = comp.step.owner;153 const b = comp.step.owner;
154 const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");154 const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");
155 const file = WriteFile.create(b).add("a.s", actual_bytes);155 const file = WriteFile.create(b).add("a.s", actual_bytes);
156 comp.addAssemblyFile(file);156 comp.root_module.addAssemblyFile(file);
157}157}
158158
159pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void {159pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void {
test/link/macho.zig+123-123
...@@ -127,7 +127,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {...@@ -127,7 +127,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
127127
128 {128 {
129 const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });129 const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });
130 exe.addObject(obj);130 exe.root_module.addObject(obj);
131 exe.link_gc_sections = false;131 exe.link_gc_sections = false;
132132
133 const check = exe.checkObject();133 const check = exe.checkObject();
...@@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {...@@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
156156
157 {157 {
158 const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });158 const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });
159 exe.addObject(obj);159 exe.root_module.addObject(obj);
160 exe.link_gc_sections = true;160 exe.link_gc_sections = true;
161161
162 const check = exe.checkObject();162 const check = exe.checkObject();
...@@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {...@@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
206 \\ strong();206 \\ strong();
207 \\}207 \\}
208 });208 });
209 exe.addObject(obj);209 exe.root_module.addObject(obj);
210210
211 expectLinkErrors(exe, test_step, .{ .exact = &.{211 expectLinkErrors(exe, test_step, .{ .exact = &.{
212 "error: duplicate symbol definition: _strong",212 "error: duplicate symbol definition: _strong",
...@@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {...@@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
235235
236 {236 {
237 const exe = addExecutable(b, opts, .{ .name = "main1" });237 const exe = addExecutable(b, opts, .{ .name = "main1" });
238 exe.addObject(main_o);238 exe.root_module.addObject(main_o);
239 exe.root_module.linkFramework("Cocoa", .{});239 exe.root_module.linkFramework("Cocoa", .{});
240240
241 const check = exe.checkObject();241 const check = exe.checkObject();
...@@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {...@@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
254254
255 {255 {
256 const exe = addExecutable(b, opts, .{ .name = "main2" });256 const exe = addExecutable(b, opts, .{ .name = "main2" });
257 exe.addObject(main_o);257 exe.root_module.addObject(main_o);
258 exe.root_module.linkFramework("Cocoa", .{});258 exe.root_module.linkFramework("Cocoa", .{});
259 exe.dead_strip_dylibs = true;259 exe.dead_strip_dylibs = true;
260260
...@@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {...@@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
350 \\ printf("Hello world!");350 \\ printf("Hello world!");
351 \\}351 \\}
352 });352 });
353 exe.addObject(empty);353 exe.root_module.addObject(empty);
354354
355 const run = addRunArtifact(exe);355 const run = addRunArtifact(exe);
356 run.expectStdOutEqual("Hello world!");356 run.expectStdOutEqual("Hello world!");
...@@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step {...@@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step {
451 \\ return 0;451 \\ return 0;
452 \\}452 \\}
453 , &.{});453 , &.{});
454 exe.linkLibrary(dylib);454 exe.root_module.linkLibrary(dylib);
455 exe.entry = .{ .symbol_name = "_bootstrap" };455 exe.entry = .{ .symbol_name = "_bootstrap" };
456 exe.forceUndefinedSymbol("_my_main");456 exe.forceUndefinedSymbol("_my_main");
457457
...@@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {...@@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
604 });604 });
605605
606 const lib = addSharedLibrary(b, opts, .{ .name = "a" });606 const lib = addSharedLibrary(b, opts, .{ .name = "a" });
607 lib.addObject(obj1);607 lib.root_module.addObject(obj1);
608608
609 {609 {
610 const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" });610 const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" });
611 exe.addObject(obj1);611 exe.root_module.addObject(obj1);
612612
613 const check = exe.checkObject();613 const check = exe.checkObject();
614 check.checkInHeaders();614 check.checkInHeaders();
...@@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {...@@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
642 }642 }
643643
644 const exe = addExecutable(b, opts, .{ .name = "main2" });644 const exe = addExecutable(b, opts, .{ .name = "main2" });
645 exe.linkLibrary(lib);645 exe.root_module.linkLibrary(lib);
646 exe.addObject(obj);646 exe.root_module.addObject(obj);
647647
648 const check = exe.checkObject();648 const check = exe.checkObject();
649 check.checkInHeaders();649 check.checkInHeaders();
...@@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {...@@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
665 \\_main:665 \\_main:
666 \\ ret666 \\ ret
667 });667 });
668 exe.linkLibrary(lib);668 exe.root_module.linkLibrary(lib);
669669
670 const check = exe.checkObject();670 const check = exe.checkObject();
671 check.checkInHeaders();671 check.checkInHeaders();
...@@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
910 \\}910 \\}
911 ,911 ,
912 });912 });
913 lib.addObject(obj);913 lib.root_module.addObject(obj);
914914
915 const exe = addExecutable(b, opts, .{915 const exe = addExecutable(b, opts, .{
916 .name = "testlib",916 .name = "testlib",
...@@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
923 \\}923 \\}
924 ,924 ,
925 });925 });
926 exe.linkLibrary(lib);926 exe.root_module.linkLibrary(lib);
927927
928 const run = addRunArtifact(exe);928 const run = addRunArtifact(exe);
929 run.expectStdErrEqual("0\n");929 run.expectStdErrEqual("0\n");
...@@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {...@@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {
10511051
1052 {1052 {
1053 const exe = addExecutable(b, opts, .{ .name = "main1" });1053 const exe = addExecutable(b, opts, .{ .name = "main1" });
1054 exe.addObject(a_o);1054 exe.root_module.addObject(a_o);
1055 exe.addObject(b_o);1055 exe.root_module.addObject(b_o);
1056 exe.addObject(main_o);1056 exe.root_module.addObject(main_o);
1057 runWithChecks(test_step, exe);1057 runWithChecks(test_step, exe);
1058 }1058 }
10591059
1060 {1060 {
1061 const exe = addExecutable(b, opts, .{ .name = "main2" });1061 const exe = addExecutable(b, opts, .{ .name = "main2" });
1062 exe.addObject(b_o);1062 exe.root_module.addObject(b_o);
1063 exe.addObject(a_o);1063 exe.root_module.addObject(a_o);
1064 exe.addObject(main_o);1064 exe.root_module.addObject(main_o);
1065 runWithChecks(test_step, exe);1065 runWithChecks(test_step, exe);
1066 }1066 }
10671067
1068 {1068 {
1069 const c_o = addObject(b, opts, .{ .name = "c" });1069 const c_o = addObject(b, opts, .{ .name = "c" });
1070 c_o.addObject(a_o);1070 c_o.root_module.addObject(a_o);
1071 c_o.addObject(b_o);1071 c_o.root_module.addObject(b_o);
1072 c_o.addObject(main_o);1072 c_o.root_module.addObject(main_o);
10731073
1074 const exe = addExecutable(b, opts, .{ .name = "main3" });1074 const exe = addExecutable(b, opts, .{ .name = "main3" });
1075 exe.addObject(c_o);1075 exe.root_module.addObject(c_o);
1076 runWithChecks(test_step, exe);1076 runWithChecks(test_step, exe);
1077 }1077 }
10781078
...@@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {...@@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {
11671167
1168 {1168 {
1169 const exe = addExecutable(b, opts, .{ .name = "main1" });1169 const exe = addExecutable(b, opts, .{ .name = "main1" });
1170 exe.addObject(a_o);1170 exe.root_module.addObject(a_o);
1171 exe.addObject(b_o);1171 exe.root_module.addObject(b_o);
1172 exe.addObject(main_o);1172 exe.root_module.addObject(main_o);
1173 runWithChecks(test_step, exe);1173 runWithChecks(test_step, exe);
1174 }1174 }
11751175
1176 {1176 {
1177 const exe = addExecutable(b, opts, .{ .name = "main2" });1177 const exe = addExecutable(b, opts, .{ .name = "main2" });
1178 exe.addObject(b_o);1178 exe.root_module.addObject(b_o);
1179 exe.addObject(a_o);1179 exe.root_module.addObject(a_o);
1180 exe.addObject(main_o);1180 exe.root_module.addObject(main_o);
1181 runWithChecks(test_step, exe);1181 runWithChecks(test_step, exe);
1182 }1182 }
11831183
1184 {1184 {
1185 const c_o = addObject(b, opts, .{ .name = "c" });1185 const c_o = addObject(b, opts, .{ .name = "c" });
1186 c_o.addObject(a_o);1186 c_o.root_module.addObject(a_o);
1187 c_o.addObject(b_o);1187 c_o.root_module.addObject(b_o);
1188 c_o.addObject(main_o);1188 c_o.root_module.addObject(main_o);
11891189
1190 const exe = addExecutable(b, opts, .{ .name = "main3" });1190 const exe = addExecutable(b, opts, .{ .name = "main3" });
1191 exe.addObject(c_o);1191 exe.root_module.addObject(c_o);
1192 runWithChecks(test_step, exe);1192 runWithChecks(test_step, exe);
1193 }1193 }
11941194
...@@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {...@@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {
1259 });1259 });
12601260
1261 const exe = addExecutable(b, opts, .{ .name = "main1" });1261 const exe = addExecutable(b, opts, .{ .name = "main1" });
1262 exe.addObject(a_o);1262 exe.root_module.addObject(a_o);
1263 exe.addObject(b_o);1263 exe.root_module.addObject(b_o);
1264 exe.addObject(main_o);1264 exe.root_module.addObject(main_o);
12651265
1266 const check = exe.checkObject();1266 const check = exe.checkObject();
1267 check.dumpSection("__TEXT,__const");1267 check.dumpSection("__TEXT,__const");
...@@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {...@@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {
13351335
1336 {1336 {
1337 const exe = addExecutable(b, opts, .{ .name = "main1" });1337 const exe = addExecutable(b, opts, .{ .name = "main1" });
1338 exe.addObject(a_o);1338 exe.root_module.addObject(a_o);
1339 exe.addObject(b_o);1339 exe.root_module.addObject(b_o);
1340 exe.addObject(main_o);1340 exe.root_module.addObject(main_o);
1341 runWithChecks(test_step, exe);1341 runWithChecks(test_step, exe);
1342 }1342 }
13431343
1344 {1344 {
1345 const exe = addExecutable(b, opts, .{ .name = "main2" });1345 const exe = addExecutable(b, opts, .{ .name = "main2" });
1346 exe.addObject(b_o);1346 exe.root_module.addObject(b_o);
1347 exe.addObject(a_o);1347 exe.root_module.addObject(a_o);
1348 exe.addObject(main_o);1348 exe.root_module.addObject(main_o);
1349 runWithChecks(test_step, exe);1349 runWithChecks(test_step, exe);
1350 }1350 }
13511351
...@@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {...@@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {
14141414
1415 {1415 {
1416 const exe = addExecutable(b, opts, .{ .name = "main1" });1416 const exe = addExecutable(b, opts, .{ .name = "main1" });
1417 exe.addObject(main_o);1417 exe.root_module.addObject(main_o);
1418 exe.addObject(a_o);1418 exe.root_module.addObject(a_o);
1419 exe.root_module.linkFramework("Foundation", .{});1419 exe.root_module.linkFramework("Foundation", .{});
1420 runWithChecks(test_step, exe);1420 runWithChecks(test_step, exe);
1421 }1421 }
14221422
1423 {1423 {
1424 const exe = addExecutable(b, opts, .{ .name = "main2" });1424 const exe = addExecutable(b, opts, .{ .name = "main2" });
1425 exe.addObject(a_o);1425 exe.root_module.addObject(a_o);
1426 exe.addObject(main_o);1426 exe.root_module.addObject(main_o);
1427 exe.root_module.linkFramework("Foundation", .{});1427 exe.root_module.linkFramework("Foundation", .{});
1428 runWithChecks(test_step, exe);1428 runWithChecks(test_step, exe);
1429 }1429 }
14301430
1431 {1431 {
1432 const b_o = addObject(b, opts, .{ .name = "b" });1432 const b_o = addObject(b, opts, .{ .name = "b" });
1433 b_o.addObject(a_o);1433 b_o.root_module.addObject(a_o);
1434 b_o.addObject(main_o);1434 b_o.root_module.addObject(main_o);
14351435
1436 const exe = addExecutable(b, opts, .{ .name = "main3" });1436 const exe = addExecutable(b, opts, .{ .name = "main3" });
1437 exe.addObject(b_o);1437 exe.root_module.addObject(b_o);
1438 exe.root_module.linkFramework("Foundation", .{});1438 exe.root_module.linkFramework("Foundation", .{});
1439 runWithChecks(test_step, exe);1439 runWithChecks(test_step, exe);
1440 }1440 }
...@@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step {...@@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
1610 \\@end1610 \\@end
1611 });1611 });
1612 foo_o.root_module.addIncludePath(foo_h.dirname());1612 foo_o.root_module.addIncludePath(foo_h.dirname());
1613 foo_o.linkLibCpp();1613 foo_o.root_module.link_libcpp = true;
16141614
1615 const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes = 1615 const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes =
1616 \\#import "Foo.h"1616 \\#import "Foo.h"
...@@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step {...@@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
1628 \\}1628 \\}
1629 });1629 });
1630 exe.root_module.addIncludePath(foo_h.dirname());1630 exe.root_module.addIncludePath(foo_h.dirname());
1631 exe.addObject(foo_o);1631 exe.root_module.addObject(foo_o);
1632 exe.linkLibCpp();1632 exe.root_module.link_libcpp = true;
1633 exe.root_module.linkFramework("Foundation", .{});1633 exe.root_module.linkFramework("Foundation", .{});
16341634
1635 const run = addRunArtifact(exe);1635 const run = addRunArtifact(exe);
...@@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step {...@@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step {
1693 \\ return bar() - foo();1693 \\ return bar() - foo();
1694 \\}1694 \\}
1695 });1695 });
1696 exe.linkLibrary(lib);1696 exe.root_module.linkLibrary(lib);
16971697
1698 const run = addRunArtifact(exe);1698 const run = addRunArtifact(exe);
1699 run.expectExitCode(0);1699 run.expectExitCode(0);
...@@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step {...@@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
1711 \\ throw std::runtime_error("Oh no!");1711 \\ throw std::runtime_error("Oh no!");
1712 \\}1712 \\}
1713 });1713 });
1714 a_o.linkLibCpp();1714 a_o.root_module.link_libcpp = true;
17151715
1716 const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes = 1716 const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes =
1717 \\extern int try_me();1717 \\extern int try_me();
...@@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step {...@@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
1733 \\ return 0;1733 \\ return 0;
1734 \\}1734 \\}
1735 });1735 });
1736 main_o.linkLibCpp();1736 main_o.root_module.link_libcpp = true;
17371737
1738 const exp_stdout = "exception=Oh no!";1738 const exp_stdout = "exception=Oh no!";
17391739
1740 {1740 {
1741 const c_o = addObject(b, opts, .{ .name = "c" });1741 const c_o = addObject(b, opts, .{ .name = "c" });
1742 c_o.addObject(a_o);1742 c_o.root_module.addObject(a_o);
1743 c_o.addObject(b_o);1743 c_o.root_module.addObject(b_o);
17441744
1745 const exe = addExecutable(b, opts, .{ .name = "main1" });1745 const exe = addExecutable(b, opts, .{ .name = "main1" });
1746 exe.addObject(main_o);1746 exe.root_module.addObject(main_o);
1747 exe.addObject(c_o);1747 exe.root_module.addObject(c_o);
1748 exe.linkLibCpp();1748 exe.root_module.link_libcpp = true;
17491749
1750 const run = addRunArtifact(exe);1750 const run = addRunArtifact(exe);
1751 run.expectStdOutEqual(exp_stdout);1751 run.expectStdOutEqual(exp_stdout);
...@@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step {...@@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17541754
1755 {1755 {
1756 const d_o = addObject(b, opts, .{ .name = "d" });1756 const d_o = addObject(b, opts, .{ .name = "d" });
1757 d_o.addObject(a_o);1757 d_o.root_module.addObject(a_o);
1758 d_o.addObject(b_o);1758 d_o.root_module.addObject(b_o);
1759 d_o.addObject(main_o);1759 d_o.root_module.addObject(main_o);
17601760
1761 const exe = addExecutable(b, opts, .{ .name = "main2" });1761 const exe = addExecutable(b, opts, .{ .name = "main2" });
1762 exe.addObject(d_o);1762 exe.root_module.addObject(d_o);
1763 exe.linkLibCpp();1763 exe.root_module.link_libcpp = true;
17641764
1765 const run = addRunArtifact(exe);1765 const run = addRunArtifact(exe);
1766 run.expectStdOutEqual(exp_stdout);1766 run.expectStdOutEqual(exp_stdout);
...@@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {...@@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {
1805 });1805 });
18061806
1807 const c_o = addObject(b, opts, .{ .name = "c" });1807 const c_o = addObject(b, opts, .{ .name = "c" });
1808 c_o.addObject(a_o);1808 c_o.root_module.addObject(a_o);
1809 c_o.addObject(b_o);1809 c_o.root_module.addObject(b_o);
1810 c_o.addObject(main_o);1810 c_o.root_module.addObject(main_o);
18111811
1812 const exe = addExecutable(b, opts, .{ .name = "main" });1812 const exe = addExecutable(b, opts, .{ .name = "main" });
1813 exe.addObject(c_o);1813 exe.root_module.addObject(c_o);
18141814
1815 const run = addRunArtifact(exe);1815 const run = addRunArtifact(exe);
1816 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });1816 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
...@@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {...@@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
1833 });1833 });
18341834
1835 const liba = addStaticLibrary(b, opts, .{ .name = "a" });1835 const liba = addStaticLibrary(b, opts, .{ .name = "a" });
1836 liba.addObject(obj);1836 liba.root_module.addObject(obj);
18371837
1838 const dylib = addSharedLibrary(b, opts, .{ .name = "a" });1838 const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
1839 dylib.addObject(obj);1839 dylib.root_module.addObject(obj);
18401840
1841 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 1841 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes =
1842 \\#include<stdio.h>1842 \\#include<stdio.h>
...@@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {...@@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18501850
1851 {1851 {
1852 const exe = addExecutable(b, opts, .{ .name = "main" });1852 const exe = addExecutable(b, opts, .{ .name = "main" });
1853 exe.addObject(main_o);1853 exe.root_module.addObject(main_o);
1854 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });1854 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });
1855 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());1855 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
1856 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());1856 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
...@@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {...@@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18691869
1870 {1870 {
1871 const exe = addExecutable(b, opts, .{ .name = "main" });1871 const exe = addExecutable(b, opts, .{ .name = "main" });
1872 exe.addObject(main_o);1872 exe.root_module.addObject(main_o);
1873 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });1873 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });
1874 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());1874 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
1875 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());1875 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
...@@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
1924 });1924 });
19251925
1926 const exe = addExecutable(b, opts, .{ .name = "test" });1926 const exe = addExecutable(b, opts, .{ .name = "test" });
1927 exe.addObject(obj1);1927 exe.root_module.addObject(obj1);
1928 exe.addObject(obj2);1928 exe.root_module.addObject(obj2);
1929 exe.addObject(main_o);1929 exe.root_module.addObject(main_o);
19301930
1931 const run = b.addRunArtifact(exe);1931 const run = b.addRunArtifact(exe);
1932 run.skip_foreign_checks = true;1932 run.skip_foreign_checks = true;
...@@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
1951 });1951 });
19521952
1953 const exe = addExecutable(b, opts, .{ .name = "test" });1953 const exe = addExecutable(b, opts, .{ .name = "test" });
1954 exe.addObject(obj1);1954 exe.root_module.addObject(obj1);
1955 exe.addObject(obj3);1955 exe.root_module.addObject(obj3);
1956 exe.addObject(main_o);1956 exe.root_module.addObject(main_o);
19571957
1958 const run = b.addRunArtifact(exe);1958 const run = b.addRunArtifact(exe);
1959 run.skip_foreign_checks = true;1959 run.skip_foreign_checks = true;
...@@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
2031 });2031 });
20322032
2033 const exe = addExecutable(b, opts, .{ .name = "main" });2033 const exe = addExecutable(b, opts, .{ .name = "main" });
2034 exe.addObject(obj1);2034 exe.root_module.addObject(obj1);
2035 exe.addObject(obj2);2035 exe.root_module.addObject(obj2);
2036 exe.addObject(main_o);2036 exe.root_module.addObject(main_o);
20372037
2038 const run = addRunArtifact(exe);2038 const run = addRunArtifact(exe);
2039 run.expectStdOutEqual("All your codebase are belong to us.\n");2039 run.expectStdOutEqual("All your codebase are belong to us.\n");
...@@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
2054 });2054 });
20552055
2056 const exe = addExecutable(b, opts, .{ .name = "main2" });2056 const exe = addExecutable(b, opts, .{ .name = "main2" });
2057 exe.addObject(obj1);2057 exe.root_module.addObject(obj1);
2058 exe.addObject(obj2);2058 exe.root_module.addObject(obj2);
2059 exe.addObject(main_o);2059 exe.root_module.addObject(main_o);
20602060
2061 const check = exe.checkObject();2061 const check = exe.checkObject();
2062 check.checkInHeaders();2062 check.checkInHeaders();
...@@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step {...@@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step {
2102 });2102 });
21032103
2104 const exe = addExecutable(b, opts, .{ .name = "main" });2104 const exe = addExecutable(b, opts, .{ .name = "main" });
2105 exe.addObject(a_o);2105 exe.root_module.addObject(a_o);
2106 exe.addObject(b_o);2106 exe.root_module.addObject(b_o);
2107 exe.addObject(main_o);2107 exe.root_module.addObject(main_o);
21082108
2109 const run = addRunArtifact(exe);2109 const run = addRunArtifact(exe);
2110 run.expectStdOutEqual("foo=42,bar=24");2110 run.expectStdOutEqual("foo=42,bar=24");
...@@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {...@@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
2299 \\}2299 \\}
2300 });2300 });
2301 bar_o.root_module.addIncludePath(foo_h.dirname());2301 bar_o.root_module.addIncludePath(foo_h.dirname());
2302 bar_o.linkLibCpp();2302 bar_o.root_module.link_libcpp = true;
23032303
2304 const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes = 2304 const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes =
2305 \\#include "foo.h"2305 \\#include "foo.h"
...@@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {...@@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
2309 \\}2309 \\}
2310 });2310 });
2311 baz_o.root_module.addIncludePath(foo_h.dirname());2311 baz_o.root_module.addIncludePath(foo_h.dirname());
2312 baz_o.linkLibCpp();2312 baz_o.root_module.link_libcpp = true;
23132313
2314 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 2314 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes =
2315 \\extern int bar();2315 \\extern int bar();
...@@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {...@@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
2321 \\}2321 \\}
2322 });2322 });
2323 main_o.root_module.addIncludePath(foo_h.dirname());2323 main_o.root_module.addIncludePath(foo_h.dirname());
2324 main_o.linkLibCpp();2324 main_o.root_module.link_libcpp = true;
23252325
2326 const exe = addExecutable(b, opts, .{ .name = "main" });2326 const exe = addExecutable(b, opts, .{ .name = "main" });
2327 exe.addObject(bar_o);2327 exe.root_module.addObject(bar_o);
2328 exe.addObject(baz_o);2328 exe.root_module.addObject(baz_o);
2329 exe.addObject(main_o);2329 exe.root_module.addObject(main_o);
2330 exe.linkLibCpp();2330 exe.root_module.link_libcpp = true;
23312331
2332 const run = addRunArtifact(exe);2332 const run = addRunArtifact(exe);
2333 run.expectExitCode(0);2333 run.expectExitCode(0);
...@@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {...@@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24452445
2446 {2446 {
2447 const exe = addExecutable(b, opts, .{ .name = "main1" });2447 const exe = addExecutable(b, opts, .{ .name = "main1" });
2448 exe.addObject(main_o);2448 exe.root_module.addObject(main_o);
2449 exe.root_module.linkSystemLibrary("a", .{});2449 exe.root_module.linkSystemLibrary("a", .{});
2450 exe.root_module.linkSystemLibrary("b", .{});2450 exe.root_module.linkSystemLibrary("b", .{});
2451 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());2451 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
...@@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {...@@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24742474
2475 {2475 {
2476 const exe = addExecutable(b, opts, .{ .name = "main2" });2476 const exe = addExecutable(b, opts, .{ .name = "main2" });
2477 exe.addObject(main_o);2477 exe.root_module.addObject(main_o);
2478 exe.root_module.linkSystemLibrary("b", .{});2478 exe.root_module.linkSystemLibrary("b", .{});
2479 exe.root_module.linkSystemLibrary("a", .{});2479 exe.root_module.linkSystemLibrary("a", .{});
2480 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());2480 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
...@@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {...@@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
2510 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" });2510 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" });
25112511
2512 const lib = addStaticLibrary(b, opts, .{ .name = "a" });2512 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2513 lib.addObject(obj);2513 lib.root_module.addObject(obj);
25142514
2515 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });2515 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25162516
2517 {2517 {
2518 const exe = addExecutable(b, opts, .{ .name = "main3" });2518 const exe = addExecutable(b, opts, .{ .name = "main3" });
2519 exe.addObject(main_o);2519 exe.root_module.addObject(main_o);
2520 exe.addObject(obj);2520 exe.root_module.addObject(obj);
2521 exe.discard_local_symbols = true;2521 exe.discard_local_symbols = true;
25222522
2523 const run = addRunArtifact(exe);2523 const run = addRunArtifact(exe);
...@@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {...@@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
25322532
2533 {2533 {
2534 const exe = addExecutable(b, opts, .{ .name = "main4" });2534 const exe = addExecutable(b, opts, .{ .name = "main4" });
2535 exe.addObject(main_o);2535 exe.root_module.addObject(main_o);
2536 exe.linkLibrary(lib);2536 exe.root_module.linkLibrary(lib);
2537 exe.discard_local_symbols = true;2537 exe.discard_local_symbols = true;
25382538
2539 const run = addRunArtifact(exe);2539 const run = addRunArtifact(exe);
...@@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
2555 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });2555 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });
25562556
2557 const lib = addStaticLibrary(b, opts, .{ .name = "a" });2557 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2558 lib.addObject(obj);2558 lib.root_module.addObject(obj);
25592559
2560 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });2560 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25612561
2562 {2562 {
2563 const exe = addExecutable(b, opts, .{ .name = "main1" });2563 const exe = addExecutable(b, opts, .{ .name = "main1" });
2564 exe.addObject(main_o);2564 exe.root_module.addObject(main_o);
2565 exe.linkLibrary(lib);2565 exe.root_module.linkLibrary(lib);
2566 exe.forceUndefinedSymbol("_foo");2566 exe.forceUndefinedSymbol("_foo");
25672567
2568 const run = addRunArtifact(exe);2568 const run = addRunArtifact(exe);
...@@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25772577
2578 {2578 {
2579 const exe = addExecutable(b, opts, .{ .name = "main2" });2579 const exe = addExecutable(b, opts, .{ .name = "main2" });
2580 exe.addObject(main_o);2580 exe.root_module.addObject(main_o);
2581 exe.linkLibrary(lib);2581 exe.root_module.linkLibrary(lib);
2582 exe.forceUndefinedSymbol("_foo");2582 exe.forceUndefinedSymbol("_foo");
2583 exe.link_gc_sections = true;2583 exe.link_gc_sections = true;
25842584
...@@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25942594
2595 {2595 {
2596 const exe = addExecutable(b, opts, .{ .name = "main3" });2596 const exe = addExecutable(b, opts, .{ .name = "main3" });
2597 exe.addObject(main_o);2597 exe.root_module.addObject(main_o);
2598 exe.addObject(obj);2598 exe.root_module.addObject(obj);
25992599
2600 const run = addRunArtifact(exe);2600 const run = addRunArtifact(exe);
2601 run.expectExitCode(0);2601 run.expectExitCode(0);
...@@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
26092609
2610 {2610 {
2611 const exe = addExecutable(b, opts, .{ .name = "main4" });2611 const exe = addExecutable(b, opts, .{ .name = "main4" });
2612 exe.addObject(main_o);2612 exe.root_module.addObject(main_o);
2613 exe.addObject(obj);2613 exe.root_module.addObject(obj);
2614 exe.link_gc_sections = true;2614 exe.link_gc_sections = true;
26152615
2616 const run = addRunArtifact(exe);2616 const run = addRunArtifact(exe);
...@@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {...@@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
2642 \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()});2642 \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()});
2643 \\}2643 \\}
2644 });2644 });
2645 exe.addObject(obj);2645 exe.root_module.addObject(obj);
26462646
2647 // TODO order should match across backends if possible2647 // TODO order should match across backends if possible
2648 if (opts.use_llvm) {2648 if (opts.use_llvm) {
...@@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2764 \\}2764 \\}
2765 });2765 });
2766 main_o.root_module.addIncludePath(all_h.dirname());2766 main_o.root_module.addIncludePath(all_h.dirname());
2767 main_o.linkLibCpp();2767 main_o.root_module.link_libcpp = true;
27682768
2769 const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes = 2769 const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes =
2770 \\#include "all.h"2770 \\#include "all.h"
...@@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2799 \\}2799 \\}
2800 });2800 });
2801 simple_string_o.root_module.addIncludePath(all_h.dirname());2801 simple_string_o.root_module.addIncludePath(all_h.dirname());
2802 simple_string_o.linkLibCpp();2802 simple_string_o.root_module.link_libcpp = true;
28032803
2804 const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes = 2804 const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes =
2805 \\#include "all.h"2805 \\#include "all.h"
...@@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2816 \\}2816 \\}
2817 });2817 });
2818 simple_string_owner_o.root_module.addIncludePath(all_h.dirname());2818 simple_string_owner_o.root_module.addIncludePath(all_h.dirname());
2819 simple_string_owner_o.linkLibCpp();2819 simple_string_owner_o.root_module.link_libcpp = true;
28202820
2821 const exp_stdout =2821 const exp_stdout =
2822 \\Constructed: a2822 \\Constructed: a
...@@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2828 ;2828 ;
28292829
2830 const exe = addExecutable(b, opts, .{ .name = "main" });2830 const exe = addExecutable(b, opts, .{ .name = "main" });
2831 exe.addObject(main_o);2831 exe.root_module.addObject(main_o);
2832 exe.addObject(simple_string_o);2832 exe.root_module.addObject(simple_string_o);
2833 exe.addObject(simple_string_owner_o);2833 exe.root_module.addObject(simple_string_owner_o);
2834 exe.linkLibCpp();2834 exe.root_module.link_libcpp = true;
28352835
2836 const run = addRunArtifact(exe);2836 const run = addRunArtifact(exe);
2837 run.expectStdOutEqual(exp_stdout);2837 run.expectStdOutEqual(exp_stdout);
...@@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {...@@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
2896 \\ return 0;2896 \\ return 0;
2897 \\}2897 \\}
2898 });2898 });
2899 exe.addObject(a_o);2899 exe.root_module.addObject(a_o);
29002900
2901 const run = addRunArtifact(exe);2901 const run = addRunArtifact(exe);
2902 run.expectStdOutEqual("4\n");2902 run.expectStdOutEqual("4\n");
...@@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {...@@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {
2948 \\ return 0;2948 \\ return 0;
2949 \\}2949 \\}
2950 });2950 });
2951 exe.addObject(a_o);2951 exe.root_module.addObject(a_o);
29522952
2953 const run = addRunArtifact(exe);2953 const run = addRunArtifact(exe);
2954 run.expectStdOutEqual("4\n");2954 run.expectStdOutEqual("4\n");
...@@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step {...@@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step {
3052 \\ .quad 03052 \\ .quad 0
3053 \\ .quad _weak_internal_tlv$tlv$init3053 \\ .quad _weak_internal_tlv$tlv$init
3054 });3054 });
3055 exe.linkLibrary(lib);3055 exe.root_module.linkLibrary(lib);
30563056
3057 {3057 {
3058 const check = exe.checkObject();3058 const check = exe.checkObject();
test/link/wasm/extern/build.zig+1-1
...@@ -16,7 +16,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize...@@ -16,7 +16,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
16 .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),16 .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),
17 }),17 }),
18 });18 });
19 exe.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });19 exe.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
20 exe.use_llvm = false;20 exe.use_llvm = false;
21 exe.use_lld = false;21 exe.use_lld = false;
2222
test/src/Cases.zig+2-6
...@@ -436,7 +436,7 @@ fn addFromDirInner(...@@ -436,7 +436,7 @@ fn addFromDirInner(
436 const target = &resolved_target.result;436 const target = &resolved_target.result;
437 for (backends) |backend| {437 for (backends) |backend| {
438 if (backend == .stage2 and438 if (backend == .stage2 and
439 target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64)439 target.cpu.arch != .aarch64 and target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64)
440 {440 {
441 // Other backends don't support new liveness format441 // Other backends don't support new liveness format
442 continue;442 continue;
...@@ -447,10 +447,6 @@ fn addFromDirInner(...@@ -447,10 +447,6 @@ fn addFromDirInner(
447 // Rosetta has issues with ZLD447 // Rosetta has issues with ZLD
448 continue;448 continue;
449 }449 }
450 if (backend == .stage2 and target.ofmt == .coff) {
451 // COFF linker has bitrotted
452 continue;
453 }
454450
455 const next = ctx.cases.items.len;451 const next = ctx.cases.items.len;
456 try ctx.cases.append(.{452 try ctx.cases.append(.{
...@@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps(...@@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps(
560 .root_module = translate_c.createModule(),556 .root_module = translate_c.createModule(),
561 });557 });
562 run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});558 run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
563 run_exe.linkLibC();559 run_exe.root_module.link_libc = true;
564 const run = b.addRunArtifact(run_exe);560 const run = b.addRunArtifact(run_exe);
565 run.step.name = b.fmt("{s} run", .{annotated_case_name});561 run.step.name = b.fmt("{s} run", .{annotated_case_name});
566 run.expectStdOutEqual(output);562 run.expectStdOutEqual(output);
test/src/RunTranslatedC.zig+1-1
...@@ -89,7 +89,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {...@@ -89,7 +89,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
89 .root_module = translate_c.createModule(),89 .root_module = translate_c.createModule(),
90 });90 });
91 exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});91 exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
92 exe.linkLibC();92 exe.root_module.link_libc = true;
93 const run = b.addRunArtifact(exe);93 const run = b.addRunArtifact(exe);
94 run.step.name = b.fmt("{s} run", .{annotated_case_name});94 run.step.name = b.fmt("{s} run", .{annotated_case_name});
95 if (!case.allow_warnings) {95 if (!case.allow_warnings) {
test/standalone/build.zig.zon+4-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1.{1.{
2 .name = .standalone_test_cases,2 .name = .standalone_test_cases,
3 .fingerprint = 0xc0dbdf9c818957be,3 .fingerprint = 0xc0dbdf9c3b92810b,
4 .version = "0.0.0",4 .version = "0.0.0",
5 .dependencies = .{5 .dependencies = .{
6 .simple = .{6 .simple = .{
...@@ -181,6 +181,9 @@...@@ -181,6 +181,9 @@
181 .install_headers = .{181 .install_headers = .{
182 .path = "install_headers",182 .path = "install_headers",
183 },183 },
184 .dependency_options = .{
185 .path = "dependency_options",
186 },
184 .dependencyFromBuildZig = .{187 .dependencyFromBuildZig = .{
185 .path = "dependencyFromBuildZig",188 .path = "dependencyFromBuildZig",
186 },189 },
test/standalone/c_embed_path/build.zig+3-3
...@@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void {...@@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void {
13 .optimize = optimize,13 .optimize = optimize,
14 }),14 }),
15 });15 });
16 exe.addCSourceFile(.{16 exe.root_module.addCSourceFile(.{
17 .file = b.path("test.c"),17 .file = b.path("test.c"),
18 .flags = &.{"-std=c23"},18 .flags = &.{"-std=c23"},
19 });19 });
20 exe.linkLibC();20 exe.root_module.link_libc = true;
21 exe.addEmbedPath(b.path("data"));21 exe.root_module.addEmbedPath(b.path("data"));
2222
23 const run_c_cmd = b.addRunArtifact(exe);23 const run_c_cmd = b.addRunArtifact(exe);
24 run_c_cmd.expectExitCode(0);24 run_c_cmd.expectExitCode(0);
test/standalone/dependencyFromBuildZig/build.zig.zon+2-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1.{1.{
2 .name = "dependencyFromBuildZig",2 .name = .dependencyFromBuildZig,
3 .fingerprint = 0xfd939a1eb8169080,
3 .version = "0.0.0",4 .version = "0.0.0",
4 .dependencies = .{5 .dependencies = .{
5 .other = .{6 .other = .{
test/standalone/dependencyFromBuildZig/other/build.zig.zon+2-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1.{1.{
2 .name = "other",2 .name = .other,
3 .fingerprint = 0xd9583520a2405f6c,
3 .version = "0.0.0",4 .version = "0.0.0",
4 .dependencies = .{},5 .dependencies = .{},
5 .paths = .{""},6 .paths = .{""},
test/standalone/dependency_options/build.zig created+148
...@@ -0,0 +1,148 @@
1const std = @import("std");
2
3pub const Enum = enum { alfa, bravo, charlie };
4
5pub fn build(b: *std.Build) !void {
6 const test_step = b.step("test", "Test passing options to a dependency");
7 b.default_step = test_step;
8
9 const none_specified = b.dependency("other", .{});
10
11 const none_specified_mod = none_specified.module("dummy");
12 if (!none_specified_mod.resolved_target.?.query.eql(b.graph.host.query)) return error.TestFailed;
13 const expected_optimize: std.builtin.OptimizeMode = switch (b.release_mode) {
14 .off => .Debug,
15 .any => unreachable,
16 .fast => .ReleaseFast,
17 .safe => .ReleaseSafe,
18 .small => .ReleaseSmall,
19 };
20 if (none_specified_mod.optimize.? != expected_optimize) return error.TestFailed;
21
22 // Passing null is the same as not specifying the option,
23 // so this should resolve to the same cached dependency instance.
24 const null_specified = b.dependency("other", .{
25 // Null literals
26 .target = null,
27 .optimize = null,
28 .bool = null,
29
30 // Optionals
31 .int = @as(?i64, null),
32 .float = @as(?f64, null),
33
34 // Optionals of the wrong type
35 .string = @as(?usize, null),
36 .@"enum" = @as(?bool, null),
37
38 // Non-defined option names
39 .this_option_does_not_exist = null,
40 .neither_does_this_one = @as(?[]const u8, null),
41 });
42
43 if (null_specified != none_specified) return error.TestFailed;
44
45 const all_specified = b.dependency("other", .{
46 .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
47 .optimize = @as(std.builtin.OptimizeMode, .ReleaseSafe),
48 .bool = @as(bool, true),
49 .int = @as(i64, 123),
50 .float = @as(f64, 0.5),
51 .string = @as([]const u8, "abc"),
52 .string_list = @as([]const []const u8, &.{ "a", "b", "c" }),
53 .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
54 .lazy_path_list = @as([]const std.Build.LazyPath, &.{
55 .{ .cwd_relative = "a.txt" },
56 .{ .cwd_relative = "b.txt" },
57 .{ .cwd_relative = "c.txt" },
58 }),
59 .@"enum" = @as(Enum, .alfa),
60 .enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }),
61 .build_id = @as(std.zig.BuildId, .uuid),
62 .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"),
63 });
64
65 const all_specified_mod = all_specified.module("dummy");
66 if (all_specified_mod.resolved_target.?.result.cpu.arch != .x86_64) return error.TestFailed;
67 if (all_specified_mod.resolved_target.?.result.os.tag != .windows) return error.TestFailed;
68 if (all_specified_mod.resolved_target.?.result.abi != .gnu) return error.TestFailed;
69 if (all_specified_mod.optimize.? != .ReleaseSafe) return error.TestFailed;
70
71 const all_specified_optional = b.dependency("other", .{
72 .target = @as(?std.Build.ResolvedTarget, b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu })),
73 .optimize = @as(?std.builtin.OptimizeMode, .ReleaseSafe),
74 .bool = @as(?bool, true),
75 .int = @as(?i64, 123),
76 .float = @as(?f64, 0.5),
77 .string = @as(?[]const u8, "abc"),
78 .string_list = @as(?[]const []const u8, &.{ "a", "b", "c" }),
79 .lazy_path = @as(?std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
80 .lazy_path_list = @as(?[]const std.Build.LazyPath, &.{
81 .{ .cwd_relative = "a.txt" },
82 .{ .cwd_relative = "b.txt" },
83 .{ .cwd_relative = "c.txt" },
84 }),
85 .@"enum" = @as(?Enum, .alfa),
86 .enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }),
87 .build_id = @as(?std.zig.BuildId, .uuid),
88 .hex_build_id = @as(?std.zig.BuildId, .initHexString("\x12\x34\xcd\xef")),
89 });
90
91 if (all_specified_optional != all_specified) return error.TestFailed;
92
93 const all_specified_literal = b.dependency("other", .{
94 .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
95 .optimize = .ReleaseSafe,
96 .bool = true,
97 .int = 123,
98 .float = 0.5,
99 .string = "abc",
100 .string_list = &[_][]const u8{ "a", "b", "c" },
101 .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
102 .lazy_path_list = &[_]std.Build.LazyPath{
103 .{ .cwd_relative = "a.txt" },
104 .{ .cwd_relative = "b.txt" },
105 .{ .cwd_relative = "c.txt" },
106 },
107 .@"enum" = .alfa,
108 .enum_list = &[_]Enum{ .alfa, .bravo, .charlie },
109 .build_id = .uuid,
110 .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"),
111 });
112
113 if (all_specified_literal != all_specified) return error.TestFailed;
114
115 var mut_string_buf = "abc".*;
116 const mut_string: []u8 = &mut_string_buf;
117 var mut_string_list_buf = [_][]const u8{ "a", "b", "c" };
118 const mut_string_list: [][]const u8 = &mut_string_list_buf;
119 var mut_lazy_path_list_buf = [_]std.Build.LazyPath{
120 .{ .cwd_relative = "a.txt" },
121 .{ .cwd_relative = "b.txt" },
122 .{ .cwd_relative = "c.txt" },
123 };
124 const mut_lazy_path_list: []std.Build.LazyPath = &mut_lazy_path_list_buf;
125 var mut_enum_list_buf = [_]Enum{ .alfa, .bravo, .charlie };
126 const mut_enum_list: []Enum = &mut_enum_list_buf;
127
128 // Most supported option types are serialized to a string representation,
129 // so alternative representations of the same option value should resolve
130 // to the same cached dependency instance.
131 const all_specified_alt = b.dependency("other", .{
132 .target = @as(std.Target.Query, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
133 .optimize = "ReleaseSafe",
134 .bool = .true,
135 .int = "123",
136 .float = @as(f16, 0.5),
137 .string = mut_string,
138 .string_list = mut_string_list,
139 .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
140 .lazy_path_list = mut_lazy_path_list,
141 .@"enum" = "alfa",
142 .enum_list = mut_enum_list,
143 .build_id = "uuid",
144 .hex_build_id = "0x1234cdef",
145 });
146
147 if (all_specified_alt != all_specified) return error.TestFailed;
148}
test/standalone/dependency_options/build.zig.zon created+11
...@@ -0,0 +1,11 @@
1.{
2 .name = .dependency_options,
3 .fingerprint = 0x3e3ce1c1f92ba47e,
4 .version = "0.0.0",
5 .dependencies = .{
6 .other = .{
7 .path = "other",
8 },
9 },
10 .paths = .{""},
11}
test/standalone/dependency_options/other/build.zig created+59
...@@ -0,0 +1,59 @@
1const std = @import("std");
2
3pub const Enum = enum { alfa, bravo, charlie };
4
5pub fn build(b: *std.Build) !void {
6 const target = b.standardTargetOptions(.{});
7 const optimize = b.standardOptimizeOption(.{});
8
9 const expected_bool: bool = true;
10 const expected_int: i64 = 123;
11 const expected_float: f64 = 0.5;
12 const expected_string: []const u8 = "abc";
13 const expected_string_list: []const []const u8 = &.{ "a", "b", "c" };
14 const expected_lazy_path: std.Build.LazyPath = .{ .cwd_relative = "abc.txt" };
15 const expected_lazy_path_list: []const std.Build.LazyPath = &.{
16 .{ .cwd_relative = "a.txt" },
17 .{ .cwd_relative = "b.txt" },
18 .{ .cwd_relative = "c.txt" },
19 };
20 const expected_enum: Enum = .alfa;
21 const expected_enum_list: []const Enum = &.{ .alfa, .bravo, .charlie };
22 const expected_build_id: std.zig.BuildId = .uuid;
23 const expected_hex_build_id: std.zig.BuildId = .initHexString("\x12\x34\xcd\xef");
24
25 const @"bool" = b.option(bool, "bool", "bool") orelse expected_bool;
26 const int = b.option(i64, "int", "int") orelse expected_int;
27 const float = b.option(f64, "float", "float") orelse expected_float;
28 const string = b.option([]const u8, "string", "string") orelse expected_string;
29 const string_list = b.option([]const []const u8, "string_list", "string_list") orelse expected_string_list;
30 const lazy_path = b.option(std.Build.LazyPath, "lazy_path", "lazy_path") orelse expected_lazy_path;
31 const lazy_path_list = b.option([]const std.Build.LazyPath, "lazy_path_list", "lazy_path_list") orelse expected_lazy_path_list;
32 const @"enum" = b.option(Enum, "enum", "enum") orelse expected_enum;
33 const enum_list = b.option([]const Enum, "enum_list", "enum_list") orelse expected_enum_list;
34 const build_id = b.option(std.zig.BuildId, "build_id", "build_id") orelse expected_build_id;
35 const hex_build_id = b.option(std.zig.BuildId, "hex_build_id", "hex_build_id") orelse expected_hex_build_id;
36
37 if (@"bool" != expected_bool) return error.TestFailed;
38 if (int != expected_int) return error.TestFailed;
39 if (float != expected_float) return error.TestFailed;
40 if (!std.mem.eql(u8, string, expected_string)) return error.TestFailed;
41 if (string_list.len != expected_string_list.len) return error.TestFailed;
42 for (string_list, expected_string_list) |x, y| {
43 if (!std.mem.eql(u8, x, y)) return error.TestFailed;
44 }
45 if (!std.mem.eql(u8, lazy_path.cwd_relative, expected_lazy_path.cwd_relative)) return error.TestFailed;
46 for (lazy_path_list, expected_lazy_path_list) |x, y| {
47 if (!std.mem.eql(u8, x.cwd_relative, y.cwd_relative)) return error.TestFailed;
48 }
49 if (@"enum" != expected_enum) return error.TestFailed;
50 if (!std.mem.eql(Enum, enum_list, expected_enum_list)) return error.TestFailed;
51 if (!std.meta.eql(build_id, expected_build_id)) return error.TestFailed;
52 if (!hex_build_id.eql(expected_hex_build_id)) return error.TestFailed;
53
54 _ = b.addModule("dummy", .{
55 .root_source_file = b.path("build.zig"),
56 .target = target,
57 .optimize = optimize,
58 });
59}
test/standalone/dependency_options/other/build.zig.zon created+7
...@@ -0,0 +1,7 @@
1.{
2 .name = .other,
3 .fingerprint = 0xd95835207bc8b630,
4 .version = "0.0.0",
5 .dependencies = .{},
6 .paths = .{""},
7}
test/standalone/extern/build.zig+2-2
...@@ -31,8 +31,8 @@ pub fn build(b: *std.Build) void {...@@ -31,8 +31,8 @@ pub fn build(b: *std.Build) void {
31 .target = b.graph.host,31 .target = b.graph.host,
32 .optimize = optimize,32 .optimize = optimize,
33 }) });33 }) });
34 test_exe.addObject(obj);34 test_exe.root_module.addObject(obj);
35 test_exe.linkLibrary(shared);35 test_exe.root_module.linkLibrary(shared);
3636
37 test_step.dependOn(&b.addRunArtifact(test_exe).step);37 test_step.dependOn(&b.addRunArtifact(test_exe).step);
38}38}
test/standalone/issue_794/build.zig+1-1
...@@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {...@@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {
8 .root_source_file = b.path("main.zig"),8 .root_source_file = b.path("main.zig"),
9 .target = b.graph.host,9 .target = b.graph.host,
10 }) });10 }) });
11 test_artifact.addIncludePath(b.path("a_directory"));11 test_artifact.root_module.addIncludePath(b.path("a_directory"));
1212
13 // TODO: actually check the output13 // TODO: actually check the output
14 _ = test_artifact.getEmittedBin();14 _ = test_artifact.getEmittedBin();
test/standalone/stack_iterator/build.zig+1-1
...@@ -109,7 +109,7 @@ pub fn build(b: *std.Build) void {...@@ -109,7 +109,7 @@ pub fn build(b: *std.Build) void {
109 // .use_llvm = true,109 // .use_llvm = true,
110 // });110 // });
111111
112 // exe.linkLibrary(c_shared_lib);112 // exe.root_module.linkLibrary(c_shared_lib);
113113
114 // const run_cmd = b.addRunArtifact(exe);114 // const run_cmd = b.addRunArtifact(exe);
115 // test_step.dependOn(&run_cmd.step);115 // test_step.dependOn(&run_cmd.step);
test/tests.zig+2-2
...@@ -2371,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2371,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2371 } else "";2371 } else "";
2372 const use_pic = if (test_target.pic == true) "-pic" else "";2372 const use_pic = if (test_target.pic == true) "-pic" else "";
23732373
2374 for (options.include_paths) |include_path| these_tests.addIncludePath(b.path(include_path));2374 for (options.include_paths) |include_path| these_tests.root_module.addIncludePath(b.path(include_path));
23752375
2376 if (target.os.tag == .windows) {2376 if (target.os.tag == .windows) {
2377 for (options.windows_libs) |lib| these_tests.linkSystemLibrary(lib);2377 for (options.windows_libs) |lib| these_tests.root_module.linkSystemLibrary(lib, .{});
2378 }2378 }
23792379
2380 const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{2380 const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{