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 {
32153215 to increase their development pace.
32163216 </p>
32173217 <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.
32193219 </p>
32203220 <p>
32213221 There are a few ways to activate this error return tracing feature:
......@@ -4319,7 +4319,7 @@ comptime {
43194319 </p>
43204320 <p>
43214321 {#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.
43234323 </p>
43244324 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
43254325 {#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}
......@@ -4333,7 +4333,7 @@ comptime {
43334333 </p>
43344334 <p>
43354335 {#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.
43374337 </p>
43384338 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
43394339 <p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>
......@@ -4347,7 +4347,7 @@ comptime {
43474347 </p>
43484348 <p>
43494349 {#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.
43514351 </p>
43524352 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
43534353 {#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
......@@ -4576,8 +4576,8 @@ comptime {
45764576 more efficiently in machine instructions.
45774577 </p>
45784578 <p>
4579 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4580 an integer or an enum.
4579 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
4580 an integer, an enum, or a packed struct.
45814581 </p>
45824582 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
45834583 <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
46084608 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
46094609 </p>
46104610 <p>
4611 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4612 an integer or an enum.
4611 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
4612 an integer, an enum, or a packed struct.
46134613 </p>
46144614 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
46154615 <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
48404840 <p>
48414841 This builtin can be called from a {#link|comptime#} block to conditionally export symbols.
48424842 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 to
4843 {#syntax#}options.linkage{#endsyntax#} is {#syntax#}.strong{#endsyntax#}, this is equivalent to
48444844 the {#syntax#}export{#endsyntax#} keyword used on a function:
48454845 </p>
48464846 {#code|export_builtin.zig#}
......@@ -4952,34 +4952,25 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
49524952 {#header_close#}
49534953
49544954 {#header_open|@import#}
4955 <pre>{#syntax#}@import(comptime path: []const u8) type{#endsyntax#}</pre>
4956 <p>
4957 This function finds a zig file corresponding to {#syntax#}path{#endsyntax#} and adds it to the build,
4958 if it is not already added.
4959 </p>
4960 <p>
4961 Zig source files are implicitly structs, with a name equal to the file's basename with the extension
4962 truncated. {#syntax#}@import{#endsyntax#} returns the struct type corresponding to the file.
4963 </p>
4964 <p>
4965 Declarations which have the {#syntax#}pub{#endsyntax#} keyword may be referenced from a different
4966 source file than the one they are declared in.
4967 </p>
4968 <p>
4969 {#syntax#}path{#endsyntax#} can be a relative path or it can be the name of a package.
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>
4955 <pre>{#syntax#}@import(comptime target: []const u8) anytype{#endsyntax#}</pre>
4956 <p>Imports the file at {#syntax#}target{#endsyntax#}, adding it to the compilation if it is not already
4957 added. {#syntax#}target{#endsyntax#} is either a relative path to another file from the file containing
4958 the {#syntax#}@import{#endsyntax#} call, or it is the name of a {#link|module|Compilation Model#}, with
4959 the import referring to the root source file of that module. Either way, the file path must end in
4960 either <code>.zig</code> (for a Zig source file) or <code>.zon</code> (for a ZON data file).</p>
4961 <p>If {#syntax#}target{#endsyntax#} refers to a Zig source file, then {#syntax#}@import{#endsyntax#} returns
4962 that file's {#link|corresponding struct type|Source File Structs#}, essentially as if the builtin call was
4963 replaced by {#syntax#}struct { FILE_CONTENTS }{#endsyntax#}. The return type is {#syntax#}type{#endsyntax#}.</p>
4964 <p>If {#syntax#}target{#endsyntax#} refers to a ZON file, then {#syntax#}@import{#endsyntax#} returns the value
4965 of the literal in the file. If there is an inferred {#link|result type|Result Types#}, then the return type
4966 is that type, and the ZON literal is interpreted as that type ({#link|Result Types#} are propagated through
4967 the ZON expression). Otherwise, the return type is the type of the equivalent Zig expression, essentially as
4968 if the builtin call was replaced by the ZON file contents.</p>
4969 <p>The following modules are always available for import:</p>
49764970 <ul>
49774971 <li>{#syntax#}@import("std"){#endsyntax#} - Zig Standard Library</li>
4978 <li>{#syntax#}@import("builtin"){#endsyntax#} - Target-specific information
4979 The command <code>zig build-exe --show-builtin</code> outputs the source to stdout for reference.
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.
4972 <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>
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>.
49834974 </li>
49844975 </ul>
49854976 {#see_also|Compile Variables|@embedFile#}
......@@ -5179,7 +5170,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
51795170 <pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>
51805171 <p>
51815172 Modulus division. For unsigned integers this is the same as
5182 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
5173 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
51835174 operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
51845175 </p>
51855176 <ul>
......@@ -5284,7 +5275,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
52845275 <pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
52855276 <p>
52865277 Remainder division. For unsigned integers this is the same as
5287 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator > 0{#endsyntax#}, otherwise the
5278 {#syntax#}numerator % denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#}, otherwise the
52885279 operation will result in a {#link|Remainder Division by Zero#} when runtime safety checks are enabled.
52895280 </p>
52905281 <ul>
doc/langref/build.zig+4-2
......@@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void {
44 const optimize = b.standardOptimizeOption(.{});
55 const exe = b.addExecutable(.{
66 .name = "example",
7 .root_source_file = b.path("example.zig"),
8 .optimize = optimize,
7 .root_module = b.createModule(.{
8 .root_source_file = b.path("example.zig"),
9 .optimize = optimize,
10 }),
911 });
1012 b.default_step.dependOn(&exe.step);
1113}
doc/langref/build_c.zig+8-4
......@@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void {
44 const lib = b.addLibrary(.{
55 .linkage = .dynamic,
66 .name = "mathtest",
7 .root_source_file = b.path("mathtest.zig"),
7 .root_module = b.createModule(.{
8 .root_source_file = b.path("mathtest.zig"),
9 }),
810 .version = .{ .major = 1, .minor = 0, .patch = 0 },
911 });
1012 const exe = b.addExecutable(.{
1113 .name = "test",
14 .root_module = b.createModule(.{
15 .link_libc = true,
16 }),
1217 });
13 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
14 exe.linkLibrary(lib);
15 exe.linkSystemLibrary("c");
18 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
19 exe.root_module.linkLibrary(lib);
1620
1721 b.default_step.dependOn(&exe.step);
1822
doc/langref/build_object.zig+8-4
......@@ -3,15 +3,19 @@ const std = @import("std");
33pub fn build(b: *std.Build) void {
44 const obj = b.addObject(.{
55 .name = "base64",
6 .root_source_file = b.path("base64.zig"),
6 .root_module = b.createModule(.{
7 .root_source_file = b.path("base64.zig"),
8 }),
79 });
810
911 const exe = b.addExecutable(.{
1012 .name = "test",
13 .root_module = b.createModule(.{
14 .link_libc = true,
15 }),
1116 });
12 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
13 exe.addObject(obj);
14 exe.linkSystemLibrary("c");
17 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
18 exe.root_module.addObject(obj);
1519 b.installArtifact(exe);
1620}
1721
doc/langref/test_coerce_slices_arrays_and_pointers.zig+7
......@@ -67,4 +67,11 @@ test "*T to *[1]T" {
6767 try expect(z[0] == 1234);
6868}
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
7077// test
lib/compiler/build_runner.zig+6-2
......@@ -696,8 +696,11 @@ fn runStepNames(
696696 .failures, .none => true,
697697 else => false,
698698 };
699 if (failure_count == 0 and failures_only) {
700 return run.cleanExit();
699 if (failure_count == 0) {
700 std.Progress.setStatus(.success);
701 if (failures_only) return run.cleanExit();
702 } else {
703 std.Progress.setStatus(.failure);
701704 }
702705
703706 const ttyconf = run.ttyconf;
......@@ -1149,6 +1152,7 @@ fn workerMakeOneStep(
11491152 } else |err| switch (err) {
11501153 error.MakeFailed => {
11511154 @atomicStore(Step.State, &s.state, .failure, .seq_cst);
1155 std.Progress.setStatus(.failure_working);
11521156 break :handle_result;
11531157 },
11541158 error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
lib/compiler_rt.zig+1-1
......@@ -240,7 +240,7 @@ comptime {
240240 _ = @import("compiler_rt/udivmodti4.zig");
241241
242242 // extra
243 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/os_version_check.zig");
243 _ = @import("compiler_rt/os_version_check.zig");
244244 _ = @import("compiler_rt/emutls.zig");
245245 _ = @import("compiler_rt/arm.zig");
246246 _ = @import("compiler_rt/aulldiv.zig");
lib/std/Build.zig+151-76
......@@ -409,104 +409,179 @@ fn createChildOnly(
409409 return child;
410410}
411411
412fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap {
413 var user_input_options = UserInputOptionsMap.init(allocator);
412fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap {
413 var map = UserInputOptionsMap.init(arena);
414414 inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
415 const v = @field(args, field.name);
416 const T = @TypeOf(v);
417 switch (T) {
418 Target.Query => {
419 user_input_options.put(field.name, .{
420 .name = field.name,
421 .value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") },
422 .used = false,
423 }) catch @panic("OOM");
424 user_input_options.put("cpu", .{
425 .name = "cpu",
426 .value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") },
427 .used = false,
428 }) catch @panic("OOM");
429 },
430 ResolvedTarget => {
431 user_input_options.put(field.name, .{
432 .name = field.name,
433 .value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") },
434 .used = false,
435 }) catch @panic("OOM");
436 user_input_options.put("cpu", .{
437 .name = "cpu",
438 .value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") },
439 .used = false,
440 }) catch @panic("OOM");
441 },
442 LazyPath => {
443 user_input_options.put(field.name, .{
415 if (field.type == @Type(.null)) continue;
416 addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name));
417 }
418 return map;
419}
420
421fn addUserInputOptionFromArg(
422 arena: Allocator,
423 map: *UserInputOptionsMap,
424 field: std.builtin.Type.StructField,
425 comptime T: type,
426 /// If null, the value won't be added, but `T` will still be type-checked.
427 maybe_value: ?T,
428) void {
429 switch (T) {
430 Target.Query => return if (maybe_value) |v| {
431 map.put(field.name, .{
432 .name = field.name,
433 .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") },
434 .used = false,
435 }) catch @panic("OOM");
436 map.put("cpu", .{
437 .name = "cpu",
438 .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") },
439 .used = false,
440 }) catch @panic("OOM");
441 },
442 ResolvedTarget => return if (maybe_value) |v| {
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, .{
444496 .name = field.name,
445 .value = .{ .lazy_path = v.dupeInner(allocator) },
497 .value = .{ .scalar = if (v) "true" else "false" },
446498 .used = false,
447499 }) catch @panic("OOM");
448500 },
449 []const LazyPath => {
450 var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");
451 for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
452 user_input_options.put(field.name, .{
501 .@"enum", .enum_literal => return if (maybe_value) |v| {
502 map.put(field.name, .{
453503 .name = field.name,
454 .value = .{ .lazy_path_list = list },
504 .value = .{ .scalar = @tagName(v) },
455505 .used = false,
456506 }) catch @panic("OOM");
457507 },
458 []const u8 => {
459 user_input_options.put(field.name, .{
508 .comptime_int, .int => return if (maybe_value) |v| {
509 map.put(field.name, .{
460510 .name = field.name,
461 .value = .{ .scalar = v },
511 .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") },
462512 .used = false,
463513 }) catch @panic("OOM");
464514 },
465 []const []const u8 => {
466 var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM");
467 list.appendSliceAssumeCapacity(v);
468
469 user_input_options.put(field.name, .{
515 .comptime_float, .float => return if (maybe_value) |v| {
516 map.put(field.name, .{
470517 .name = field.name,
471 .value = .{ .list = list },
518 .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") },
472519 .used = false,
473520 }) catch @panic("OOM");
474521 },
475 else => switch (@typeInfo(T)) {
476 .bool => {
477 user_input_options.put(field.name, .{
478 .name = field.name,
479 .value = .{ .scalar = if (v) "true" else "false" },
480 .used = false,
481 }) catch @panic("OOM");
482 },
483 .@"enum", .enum_literal => {
484 user_input_options.put(field.name, .{
485 .name = field.name,
486 .value = .{ .scalar = @tagName(v) },
487 .used = false,
488 }) catch @panic("OOM");
522 .pointer => |ptr_info| switch (ptr_info.size) {
523 .one => switch (@typeInfo(ptr_info.child)) {
524 .array => |array_info| {
525 comptime var slice_info = ptr_info;
526 slice_info.size = .slice;
527 slice_info.is_const = true;
528 slice_info.child = array_info.child;
529 slice_info.sentinel_ptr = null;
530 addUserInputOptionFromArg(
531 arena,
532 map,
533 field,
534 @Type(.{ .pointer = slice_info }),
535 maybe_value orelse null,
536 );
537 return;
538 },
539 else => {},
489540 },
490 .comptime_int, .int => {
491 user_input_options.put(field.name, .{
492 .name = field.name,
493 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") },
494 .used = false,
495 }) catch @panic("OOM");
541 .slice => switch (@typeInfo(ptr_info.child)) {
542 .@"enum" => return if (maybe_value) |v| {
543 var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
544 for (v) |tag| list.appendAssumeCapacity(@tagName(tag));
545 map.put(field.name, .{
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 },
496564 },
497 .comptime_float, .float => {
498 user_input_options.put(field.name, .{
499 .name = field.name,
500 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") },
501 .used = false,
502 }) catch @panic("OOM");
565 else => {},
566 },
567 .null => unreachable,
568 .optional => |info| switch (@typeInfo(info.child)) {
569 .optional => {},
570 else => {
571 addUserInputOptionFromArg(
572 arena,
573 map,
574 field,
575 info.child,
576 maybe_value orelse null,
577 );
578 return;
503579 },
504 else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
505580 },
506 }
581 else => {},
582 },
507583 }
508
509 return user_input_options;
584 @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type));
510585}
511586
512587const OrderedUserValue = union(enum) {
lib/std/Build/Step/Compile.zig+42-4
......@@ -681,10 +681,14 @@ pub fn producesImplib(compile: *Compile) bool {
681681 return compile.isDll();
682682}
683683
684/// Deprecated; use `compile.root_module.link_libc = true` instead.
685/// To be removed after 0.15.0 is tagged.
684686pub fn linkLibC(compile: *Compile) void {
685687 compile.root_module.link_libc = true;
686688}
687689
690/// Deprecated; use `compile.root_module.link_libcpp = true` instead.
691/// To be removed after 0.15.0 is tagged.
688692pub fn linkLibCpp(compile: *Compile) void {
689693 compile.root_module.link_libcpp = true;
690694}
......@@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {
802806 };
803807}
804808
809/// Deprecated; use `compile.root_module.linkSystemLibrary(name, .{})` instead.
810/// To be removed after 0.15.0 is tagged.
805811pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void {
806812 return compile.root_module.linkSystemLibrary(name, .{});
807813}
808814
815/// Deprecated; use `compile.root_module.linkSystemLibrary(name, options)` instead.
816/// To be removed after 0.15.0 is tagged.
809817pub fn linkSystemLibrary2(
810818 compile: *Compile,
811819 name: []const u8,
......@@ -814,22 +822,26 @@ pub fn linkSystemLibrary2(
814822 return compile.root_module.linkSystemLibrary(name, options);
815823}
816824
825/// Deprecated; use `c.root_module.linkFramework(name, .{})` instead.
826/// To be removed after 0.15.0 is tagged.
817827pub fn linkFramework(c: *Compile, name: []const u8) void {
818828 c.root_module.linkFramework(name, .{});
819829}
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.
822833pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {
823834 compile.root_module.addCSourceFiles(options);
824835}
825836
837/// Deprecated; use `compile.root_module.addCSourceFile(source)` instead.
838/// To be removed after 0.15.0 is tagged.
826839pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {
827840 compile.root_module.addCSourceFile(source);
828841}
829842
830/// Resource files must have the extension `.rc`.
831/// Can be called regardless of target. The .rc file will be ignored
832/// if the target object format does not support embedded resources.
843/// Deprecated; use `compile.root_module.addWin32ResourceFile(source)` instead.
844/// To be removed after 0.15.0 is tagged.
833845pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {
834846 compile.root_module.addWin32ResourceFile(source);
835847}
......@@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
915927 return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);
916928}
917929
930/// Deprecated; use `compile.root_module.addAssemblyFile(source)` instead.
931/// To be removed after 0.15.0 is tagged.
918932pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {
919933 compile.root_module.addAssemblyFile(source);
920934}
921935
936/// Deprecated; use `compile.root_module.addObjectFile(source)` instead.
937/// To be removed after 0.15.0 is tagged.
922938pub fn addObjectFile(compile: *Compile, source: LazyPath) void {
923939 compile.root_module.addObjectFile(source);
924940}
925941
942/// Deprecated; use `compile.root_module.addObject(object)` instead.
943/// To be removed after 0.15.0 is tagged.
926944pub fn addObject(compile: *Compile, object: *Compile) void {
927945 compile.root_module.addObject(object);
928946}
929947
948/// Deprecated; use `compile.root_module.linkLibrary(library)` instead.
949/// To be removed after 0.15.0 is tagged.
930950pub fn linkLibrary(compile: *Compile, library: *Compile) void {
931951 compile.root_module.linkLibrary(library);
932952}
933953
954/// Deprecated; use `compile.root_module.addAfterIncludePath(lazy_path)` instead.
955/// To be removed after 0.15.0 is tagged.
934956pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void {
935957 compile.root_module.addAfterIncludePath(lazy_path);
936958}
937959
960/// Deprecated; use `compile.root_module.addSystemIncludePath(lazy_path)` instead.
961/// To be removed after 0.15.0 is tagged.
938962pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void {
939963 compile.root_module.addSystemIncludePath(lazy_path);
940964}
941965
966/// Deprecated; use `compile.root_module.addIncludePath(lazy_path)` instead.
967/// To be removed after 0.15.0 is tagged.
942968pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void {
943969 compile.root_module.addIncludePath(lazy_path);
944970}
945971
972/// Deprecated; use `compile.root_module.addConfigHeader(config_header)` instead.
973/// To be removed after 0.15.0 is tagged.
946974pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void {
947975 compile.root_module.addConfigHeader(config_header);
948976}
949977
978/// Deprecated; use `compile.root_module.addEmbedPath(lazy_path)` instead.
979/// To be removed after 0.15.0 is tagged.
950980pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void {
951981 compile.root_module.addEmbedPath(lazy_path);
952982}
953983
984/// Deprecated; use `compile.root_module.addLibraryPath(directory_path)` instead.
985/// To be removed after 0.15.0 is tagged.
954986pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void {
955987 compile.root_module.addLibraryPath(directory_path);
956988}
957989
990/// Deprecated; use `compile.root_module.addRPath(directory_path)` instead.
991/// To be removed after 0.15.0 is tagged.
958992pub fn addRPath(compile: *Compile, directory_path: LazyPath) void {
959993 compile.root_module.addRPath(directory_path);
960994}
961995
996/// Deprecated; use `compile.root_module.addSystemFrameworkPath(directory_path)` instead.
997/// To be removed after 0.15.0 is tagged.
962998pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
963999 compile.root_module.addSystemFrameworkPath(directory_path);
9641000}
9651001
1002/// Deprecated; use `compile.root_module.addFrameworkPath(directory_path)` instead.
1003/// To be removed after 0.15.0 is tagged.
9661004pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
9671005 compile.root_module.addFrameworkPath(directory_path);
9681006}
lib/std/Build/Step/Run.zig+10
......@@ -1391,6 +1391,16 @@ fn runCommand(
13911391 }
13921392 },
13931393 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
13941404 try step.handleChildProcessTerm(result.term, cwd, final_argv);
13951405 },
13961406 }
lib/std/Io.zig+1-2
......@@ -354,7 +354,7 @@ pub fn Poller(comptime StreamEnum: type) type {
354354 const unused = r.buffer[r.end..];
355355 if (unused.len >= min_len) return unused;
356356 }
357 if (r.seek > 0) r.rebase();
357 if (r.seek > 0) r.rebase(r.buffer.len) catch unreachable;
358358 {
359359 var list: std.ArrayListUnmanaged(u8) = .{
360360 .items = r.buffer[0..r.end],
......@@ -544,7 +544,6 @@ pub fn PollFiles(comptime StreamEnum: type) type {
544544
545545test {
546546 _ = Reader;
547 _ = Reader.Limited;
548547 _ = Writer;
549548 _ = tty;
550549 _ = @import("Io/test.zig");
lib/std/Io/DeprecatedReader.zig+1
......@@ -397,6 +397,7 @@ pub const Adapter = struct {
397397 a.err = err;
398398 return error.ReadFailed;
399399 };
400 if (n == 0) return error.EndOfStream;
400401 w.advance(n);
401402 return n;
402403 }
lib/std/Io/Reader.zig+284-213
......@@ -43,8 +43,8 @@ pub const VTable = struct {
4343 ///
4444 /// In addition to, or instead of writing to `w`, the implementation may
4545 /// choose to store data in `buffer`, modifying `seek` and `end`
46 /// accordingly. Stream implementations are encouraged to take advantage of
47 /// this if simplifies the logic.
46 /// accordingly. Implementations are encouraged to take advantage of
47 /// this if it simplifies the logic.
4848 stream: *const fn (r: *Reader, w: *Writer, limit: Limit) StreamError!usize,
4949
5050 /// Consumes bytes from the internally tracked stream position without
......@@ -67,6 +67,37 @@ pub const VTable = struct {
6767 ///
6868 /// This function is only called when `buffer` is empty.
6969 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,
70101};
71102
72103pub const StreamError = error{
......@@ -97,6 +128,10 @@ pub const ShortError = error{
97128 ReadFailed,
98129};
99130
131pub const RebaseError = error{
132 EndOfStream,
133};
134
100135pub const failing: Reader = .{
101136 .vtable = &.{
102137 .stream = failingStream,
......@@ -122,6 +157,8 @@ pub fn fixed(buffer: []const u8) Reader {
122157 .vtable = &.{
123158 .stream = endingStream,
124159 .discard = endingDiscard,
160 .readVec = endingReadVec,
161 .rebase = endingRebase,
125162 },
126163 // This cast is safe because all potential writes to it will instead
127164 // return `error.EndOfStream`.
......@@ -153,18 +190,18 @@ pub fn discard(r: *Reader, limit: Limit) Error!usize {
153190 }
154191 break :l .limited(n - buffered_len);
155192 } else .unlimited;
156 r.seek = 0;
157 r.end = 0;
193 r.seek = r.end;
158194 const n = try r.vtable.discard(r, remaining);
159195 assert(n <= @intFromEnum(remaining));
160196 return buffered_len + n;
161197}
162198
163199pub fn defaultDiscard(r: *Reader, limit: Limit) Error!usize {
164 assert(r.seek == 0);
165 assert(r.end == 0);
166 var dw: Writer.Discarding = .init(r.buffer);
167 const n = r.stream(&dw.writer, limit) catch |err| switch (err) {
200 assert(r.seek == r.end);
201 r.seek = 0;
202 r.end = 0;
203 var d: Writer.Discarding = .init(r.buffer);
204 const n = r.stream(&d.writer, limit) catch |err| switch (err) {
168205 error.WriteFailed => unreachable,
169206 error.ReadFailed => return error.ReadFailed,
170207 error.EndOfStream => return error.EndOfStream,
......@@ -229,8 +266,7 @@ pub fn streamRemaining(r: *Reader, w: *Writer) StreamRemainingError!usize {
229266/// number of bytes discarded.
230267pub fn discardRemaining(r: *Reader) ShortError!usize {
231268 var offset: usize = r.end - r.seek;
232 r.seek = 0;
233 r.end = 0;
269 r.seek = r.end;
234270 while (true) {
235271 offset += r.vtable.discard(r, .unlimited) catch |err| switch (err) {
236272 error.EndOfStream => return offset,
......@@ -277,7 +313,8 @@ pub fn appendRemaining(
277313 list: *std.ArrayListAlignedUnmanaged(u8, alignment),
278314 limit: Limit,
279315) 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.
281318 const buffer_contents = r.buffer[r.seek..r.end];
282319 const copy_len = limit.minInt(buffer_contents.len);
283320 try list.appendSlice(gpa, r.buffer[0..copy_len]);
......@@ -286,32 +323,67 @@ pub fn appendRemaining(
286323 r.seek = 0;
287324 r.end = 0;
288325 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 };
289332 while (true) {
290 try list.ensureUnusedCapacity(gpa, 1);
333 try list.ensureUnusedCapacity(gpa, 2);
291334 const cap = list.unusedCapacitySlice();
292 const dest = cap[0..@min(cap.len, remaining)];
293 if (remaining - dest.len == 0) {
294 // Additionally provides `buffer` to detect end.
295 const new_remaining = readVecInner(r, &.{}, dest, remaining) catch |err| switch (err) {
296 error.EndOfStream => {
297 if (r.bufferedLen() != 0) return error.StreamTooLong;
298 return;
299 },
300 error.ReadFailed => return error.ReadFailed,
301 };
302 list.items.len += remaining - new_remaining;
303 remaining = new_remaining;
304 } else {
305 // Leave `buffer` empty, appending directly to `list`.
306 var dest_w: Writer = .fixed(dest);
307 const n = r.vtable.stream(r, &dest_w, .limited(dest.len)) catch |err| switch (err) {
308 error.WriteFailed => unreachable, // Prevented by the limit.
309 error.EndOfStream => return,
310 error.ReadFailed => return error.ReadFailed,
311 };
312 list.items.len += n;
313 remaining -= n;
335 const dest = cap[0..@min(cap.len, remaining + 1)];
336 writer.buffer = list.allocatedSlice();
337 writer.end = list.items.len;
338 const n = r.vtable.stream(r, &writer, .limited(dest.len)) catch |err| switch (err) {
339 error.WriteFailed => unreachable, // Prevented by the limit.
340 error.EndOfStream => return,
341 error.ReadFailed => return error.ReadFailed,
342 };
343 list.items.len += n;
344 if (n > remaining) {
345 // Move the byte to `Reader.buffer` so it is not lost.
346 assert(n - remaining == 1);
347 assert(r.end == 0);
348 r.buffer[0] = list.items[list.items.len - 1];
349 list.items.len -= 1;
350 r.end = 1;
351 return;
314352 }
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;
315387 }
316388}
317389
......@@ -323,95 +395,50 @@ pub fn appendRemaining(
323395///
324396/// The reader's internal logical seek position moves forward in accordance
325397/// with the number of bytes returned from this function.
326pub fn readVec(r: *Reader, data: []const []u8) Error!usize {
327 return readVecLimit(r, data, .unlimited);
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);
398pub fn readVec(r: *Reader, data: [][]u8) Error!usize {
399 var seek = r.seek;
340400 for (data, 0..) |buf, i| {
341 const buffer_contents = r.buffer[r.seek..r.end];
342 const copy_len = @min(buffer_contents.len, buf.len, remaining);
343 @memcpy(buf[0..copy_len], buffer_contents[0..copy_len]);
344 r.seek += copy_len;
345 remaining -= copy_len;
346 if (remaining == 0) break;
401 const contents = r.buffer[seek..r.end];
402 const copy_len = @min(contents.len, buf.len);
403 @memcpy(buf[0..copy_len], contents[0..copy_len]);
404 seek += copy_len;
347405 if (buf.len - copy_len == 0) continue;
348406
349 // All of `buffer` has been copied to `data`. We now set up a structure
350 // that enables the `Writer.writableVector` API, while also ensuring
351 // API that directly operates on the `Writable.buffer` has its minimum
352 // buffer capacity requirements met.
353 r.seek = 0;
354 r.end = 0;
355 remaining = try readVecInner(r, data[i + 1 ..], buf[copy_len..], remaining);
356 break;
407 // All of `buffer` has been copied to `data`.
408 const n = seek - r.seek;
409 r.seek = seek;
410 data[i] = buf[copy_len..];
411 defer data[i] = buf;
412 return n + (r.vtable.readVec(r, data[i..]) catch |err| switch (err) {
413 error.EndOfStream => if (n == 0) return error.EndOfStream else 0,
414 error.ReadFailed => return error.ReadFailed,
415 });
357416 }
358 return @intFromEnum(limit) - remaining;
417 const n = seek - r.seek;
418 r.seek = seek;
419 return n;
359420}
360421
361fn readVecInner(r: *Reader, middle: []const []u8, first: []u8, remaining: usize) Error!usize {
362 var wrapper: Writer.VectorWrapper = .{
363 .it = .{
364 .first = first,
365 .middle = middle,
366 .last = r.buffer,
367 },
368 .writer = .{
369 .buffer = if (first.len >= r.buffer.len) first else r.buffer,
370 .vtable = Writer.VectorWrapper.vtable,
371 },
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);
422/// Writes to `Reader.buffer` or `data`, whichever has larger capacity.
423pub fn defaultReadVec(r: *Reader, data: [][]u8) Error!usize {
424 assert(r.seek == r.end);
425 r.seek = 0;
426 r.end = 0;
427 const first = data[0];
428 const direct = first.len >= r.buffer.len;
429 var writer: Writer = .{
430 .buffer = if (direct) first else r.buffer,
431 .end = 0,
432 .vtable = &.{ .drain = Writer.fixedDrain },
379433 };
380 var n = r.vtable.stream(r, &wrapper.writer, limit) catch |err| switch (err) {
381 error.WriteFailed => {
382 assert(!wrapper.used);
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 },
434 const limit: Limit = .limited(writer.buffer.len - writer.end);
435 const n = r.vtable.stream(r, &writer, limit) catch |err| switch (err) {
436 error.WriteFailed => unreachable,
391437 else => |e| return e,
392438 };
393 if (!wrapper.used) {
394 if (wrapper.writer.buffer.ptr == first.ptr) {
395 return remaining - n;
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;
439 if (direct) return n;
440 r.end += n;
441 return 0;
415442}
416443
417444pub fn buffered(r: *Reader) []u8 {
......@@ -422,8 +449,8 @@ pub fn bufferedLen(r: *const Reader) usize {
422449 return r.end - r.seek;
423450}
424451
425pub fn hashed(r: *Reader, hasher: anytype) Hashed(@TypeOf(hasher)) {
426 return .{ .in = r, .hasher = hasher };
452pub fn hashed(r: *Reader, hasher: anytype, buffer: []u8) Hashed(@TypeOf(hasher)) {
453 return .init(r, hasher, buffer);
427454}
428455
429456pub fn readVecAll(r: *Reader, data: [][]u8) Error!void {
......@@ -498,8 +525,7 @@ pub fn toss(r: *Reader, n: usize) void {
498525
499526/// Equivalent to `toss(r.bufferedLen())`.
500527pub fn tossBuffered(r: *Reader) void {
501 r.seek = 0;
502 r.end = 0;
528 r.seek = r.end;
503529}
504530
505531/// Equivalent to `peek` followed by `toss`.
......@@ -586,8 +612,7 @@ pub fn discardShort(r: *Reader, n: usize) ShortError!usize {
586612 return n;
587613 }
588614 var remaining = n - (r.end - r.seek);
589 r.end = 0;
590 r.seek = 0;
615 r.seek = r.end;
591616 while (true) {
592617 const discard_len = r.vtable.discard(r, .limited(remaining)) catch |err| switch (err) {
593618 error.EndOfStream => return n - remaining,
......@@ -625,29 +650,24 @@ pub fn readSliceAll(r: *Reader, buffer: []u8) Error!void {
625650/// See also:
626651/// * `readSliceAll`
627652pub 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;
629663 while (true) {
630 const buffer_contents = r.buffer[r.seek..r.end];
631 const dest = buffer[i..];
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) {
664 data[0] = buffer[i..];
665 i += readVec(r, &data) catch |err| switch (err) {
644666 error.EndOfStream => return i,
645667 error.ReadFailed => return error.ReadFailed,
646668 };
647 if (new_remaining_len == 0) return buffer.len;
648 i += remaining.len - new_remaining_len;
669 if (buffer.len - i == 0) return buffer.len;
649670 }
650 return buffer.len;
651671}
652672
653673/// 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 {
780800 @branchHint(.likely);
781801 return buffer[seek .. end + 1];
782802 }
783 if (r.vtable.stream == &endingStream) {
784 // Protect the `@constCast` of `fixed`.
785 return error.EndOfStream;
786 }
787 r.rebase();
803 // TODO take a parameter for max search length rather than relying on buffer capacity
804 try rebase(r, r.buffer.len);
788805 while (r.buffer.len - r.end != 0) {
789806 const end_cap = r.buffer[r.end..];
790807 var writer: Writer = .fixed(end_cap);
......@@ -1041,20 +1058,7 @@ pub fn fill(r: *Reader, n: usize) Error!void {
10411058/// Missing this optimization can result in wall-clock time for the most affected benchmarks
10421059/// increasing by a factor of 5 or more.
10431060fn fillUnbuffered(r: *Reader, n: usize) Error!void {
1044 if (r.seek + n <= r.buffer.len) while (true) {
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);
1061 try rebase(r, n);
10581062 var writer: Writer = .{
10591063 .buffer = r.buffer,
10601064 .vtable = &.{ .drain = Writer.fixedDrain },
......@@ -1074,7 +1078,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
10741078///
10751079/// Asserts buffer capacity is at least 1.
10761080pub fn fillMore(r: *Reader) Error!void {
1077 rebaseCapacity(r, 1);
1081 try rebase(r, 1);
10781082 var writer: Writer = .{
10791083 .buffer = r.buffer,
10801084 .end = r.end,
......@@ -1251,7 +1255,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
12511255
12521256pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {
12531257 if (n <= r.buffer.len) return;
1254 if (r.seek > 0) rebase(r);
1258 if (r.seek > 0) rebase(r, r.buffer.len);
12551259 var list: ArrayList(u8) = .{
12561260 .items = r.buffer[0..r.end],
12571261 .capacity = r.buffer.len,
......@@ -1297,37 +1301,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu
12971301 }
12981302}
12991303
1300/// Left-aligns data such that `r.seek` becomes zero.
1301///
1302/// If `r.seek` is not already zero then `buffer` is mutated, making it illegal
1303/// to call this function with a const-casted `buffer`, such as in the case of
1304/// `fixed`. This issue can be avoided:
1305/// * in implementations, by attempting a read before a rebase, in which
1306/// case the read will return `error.EndOfStream`, preventing the rebase.
1307/// * in usage, by copying into a mutable buffer before initializing `fixed`.
1308pub fn rebase(r: *Reader) void {
1309 if (r.seek == 0) return;
1304/// Ensures `capacity` more data can be buffered without rebasing.
1305pub fn rebase(r: *Reader, capacity: usize) RebaseError!void {
1306 if (r.end + capacity <= r.buffer.len) return;
1307 return r.vtable.rebase(r, capacity);
1308}
1309
1310pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void {
1311 if (r.end <= r.buffer.len - capacity) return;
13101312 const data = r.buffer[r.seek..r.end];
13111313 @memmove(r.buffer[0..data.len], data);
13121314 r.seek = 0;
13131315 r.end = data.len;
13141316}
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
13311318/// Advances the stream and decreases the size of the storage buffer by `n`,
13321319/// returning the range of bytes no longer accessible by `r`.
13331320///
......@@ -1648,19 +1635,6 @@ test readVec {
16481635 try testing.expectEqualStrings(std.ascii.letters[26..], bufs[1]);
16491636}
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
16641638test "expected error.EndOfStream" {
16651639 // Unit test inspired by https://github.com/ziglang/zig/issues/17733
16661640 var buffer: [3]u8 = undefined;
......@@ -1670,6 +1644,17 @@ test "expected error.EndOfStream" {
16701644 try std.testing.expectError(error.EndOfStream, r.take(3));
16711645}
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
16731658fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
16741659 _ = r;
16751660 _ = w;
......@@ -1677,12 +1662,24 @@ fn endingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
16771662 return error.EndOfStream;
16781663}
16791664
1665fn endingReadVec(r: *Reader, data: [][]u8) Error!usize {
1666 _ = r;
1667 _ = data;
1668 return error.EndOfStream;
1669}
1670
16801671fn endingDiscard(r: *Reader, limit: Limit) Error!usize {
16811672 _ = r;
16821673 _ = limit;
16831674 return error.EndOfStream;
16841675}
16851676
1677fn endingRebase(r: *Reader, capacity: usize) RebaseError!void {
1678 _ = r;
1679 _ = capacity;
1680 return error.EndOfStream;
1681}
1682
16861683fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
16871684 _ = r;
16881685 _ = w;
......@@ -1696,6 +1693,15 @@ fn failingDiscard(r: *Reader, limit: Limit) Error!usize {
16961693 return error.ReadFailed;
16971694}
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
16991705test "readAlloc when the backing reader provides one byte at a time" {
17001706 const str = "This is a test";
17011707 var tiny_buffer: [1]u8 = undefined;
......@@ -1759,15 +1765,16 @@ pub fn Hashed(comptime Hasher: type) type {
17591765 return struct {
17601766 in: *Reader,
17611767 hasher: Hasher,
1762 interface: Reader,
1768 reader: Reader,
17631769
17641770 pub fn init(in: *Reader, hasher: Hasher, buffer: []u8) @This() {
17651771 return .{
17661772 .in = in,
17671773 .hasher = hasher,
1768 .interface = .{
1774 .reader = .{
17691775 .vtable = &.{
1770 .read = @This().read,
1776 .stream = @This().stream,
1777 .readVec = @This().readVec,
17711778 .discard = @This().discard,
17721779 },
17731780 .buffer = buffer,
......@@ -1777,33 +1784,97 @@ pub fn Hashed(comptime Hasher: type) type {
17771784 };
17781785 }
17791786
1780 fn read(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1781 const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
1782 const data = w.writableVector(limit);
1787 fn stream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1788 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
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));
17831799 const n = try this.in.readVec(data);
1784 const result = w.advanceVector(n);
17851800 var remaining: usize = n;
17861801 for (data) |slice| {
17871802 if (remaining < slice.len) {
17881803 this.hasher.update(slice[0..remaining]);
1789 return result;
1804 return n;
17901805 } else {
17911806 remaining -= slice.len;
17921807 this.hasher.update(slice);
17931808 }
17941809 }
17951810 assert(remaining == 0);
1796 return result;
1811 return n;
17971812 }
17981813
17991814 fn discard(r: *Reader, limit: Limit) Error!usize {
1800 const this: *@This() = @alignCast(@fieldParentPtr("interface", r));
1801 var w = this.hasher.writer(&.{});
1802 const n = this.in.stream(&w, limit) catch |err| switch (err) {
1803 error.WriteFailed => unreachable,
1804 else => |e| return e,
1805 };
1806 return n;
1815 const this: *@This() = @alignCast(@fieldParentPtr("reader", r));
1816 const peeked = limit.slice(try this.in.peekGreedy(1));
1817 this.hasher.update(peeked);
1818 this.in.toss(peeked.len);
1819 return peeked.len;
18071820 }
18081821 };
18091822}
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!
342342 return big_slice[0..len];
343343}
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
436345pub fn ensureUnusedCapacity(w: *Writer, n: usize) Error!void {
437346 _ = try writableSliceGreedy(w, n);
438347}
......@@ -451,13 +360,6 @@ pub fn advance(w: *Writer, n: usize) void {
451360 w.end = new_end;
452361}
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
461363/// The `data` parameter is mutable because this function needs to mutate the
462364/// fields in order to handle partial writes from `VTable.writeSplat`.
463365pub fn writeVecAll(w: *Writer, data: [][]const u8) Error!void {
......@@ -1614,17 +1516,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)
16141516}
16151517
16161518pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
1617 if (std.math.signbit(value)) try w.writeByte('-');
1618 if (std.math.isNan(value)) return w.writeAll(switch (case) {
1519 const v = switch (@TypeOf(value)) {
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) {
16191527 .lower => "nan",
16201528 .upper => "NAN",
16211529 });
1622 if (std.math.isInf(value)) return w.writeAll(switch (case) {
1530 if (std.math.isInf(v)) return w.writeAll(switch (case) {
16231531 .lower => "inf",
16241532 .upper => "INF",
16251533 });
16261534
1627 const T = @TypeOf(value);
1535 const T = @TypeOf(v);
16281536 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
16291537
16301538 const mantissa_bits = std.math.floatMantissaBits(T);
......@@ -1634,7 +1542,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi
16341542 const exponent_mask = (1 << exponent_bits) - 1;
16351543 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
16361544
1637 const as_bits: TU = @bitCast(value);
1545 const as_bits: TU = @bitCast(v);
16381546 var mantissa = as_bits & mantissa_mask;
16391547 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
23612269 const pattern = data[data.len - 1];
23622270 const dest = w.buffer[w.end..];
23632271 switch (pattern.len) {
2364 0 => return w.end,
2272 0 => return 0,
23652273 1 => {
23662274 assert(splat >= dest.len);
23672275 @memset(dest, pattern[0]);
......@@ -2381,6 +2289,13 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
23812289 }
23822290}
23832291
2292pub fn unreachableDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usize {
2293 _ = w;
2294 _ = data;
2295 _ = splat;
2296 unreachable;
2297}
2298
23842299/// Provides a `Writer` implementation based on calling `Hasher.update`, sending
23852300/// all data also to an underlying `Writer`.
23862301///
......@@ -2391,6 +2306,8 @@ pub fn fixedDrain(w: *Writer, data: []const []const u8, splat: usize) Error!usiz
23912306/// generic. A better solution will involve creating a writer for each hash
23922307/// function, where the splat buffer can be tailored to the hash implementation
23932308/// details.
2309///
2310/// Contrast with `Hashing` which terminates the stream pipeline.
23942311pub fn Hashed(comptime Hasher: type) type {
23952312 return struct {
23962313 out: *Writer,
......@@ -2463,6 +2380,52 @@ pub fn Hashed(comptime Hasher: type) type {
24632380 };
24642381}
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
24662429/// Maintains `Writer` state such that it writes to the unused capacity of an
24672430/// array list, filling it up completely before making a call through the
24682431/// 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" {
5757 try tmp.dir.deleteFile(tmp_file_name);
5858}
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
10560test "File seek ops" {
10661 var tmp = tmpDir(.{});
10762 defer tmp.cleanup();
lib/std/Progress.zig+70-1
......@@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent,
2525/// Accessed atomically.
2626done: bool,
2727need_clear: bool,
28status: Status,
2829
2930refresh_rate_ns: u64,
3031initial_delay_ns: u64,
......@@ -47,6 +48,22 @@ node_freelist: Freelist,
4748/// value may at times temporarily exceed the node count.
4849node_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
5067const Freelist = packed struct(u32) {
5168 head: Node.OptionalIndex,
5269 /// Whenever `node_freelist` is added to, this generation is incremented
......@@ -383,6 +400,7 @@ var global_progress: Progress = .{
383400 .draw_buffer = undefined,
384401 .done = false,
385402 .need_clear = false,
403 .status = .working,
386404
387405 .node_parents = &node_parents_buffer,
388406 .node_storage = &node_storage_buffer,
......@@ -498,6 +516,11 @@ pub fn start(options: Options) Node {
498516 return root_node;
499517}
500518
519pub fn setStatus(new_status: Status) void {
520 if (noop_impl) return;
521 @atomicStore(Status, &global_progress.status, new_status, .monotonic);
522}
523
501524/// Returns whether a resize is needed to learn the terminal size.
502525fn wait(timeout_ns: u64) bool {
503526 const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|
......@@ -678,6 +701,14 @@ const save = "\x1b7";
678701const restore = "\x1b8";
679702const 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
681712const TreeSymbol = enum {
682713 /// ├─
683714 tee,
......@@ -760,7 +791,7 @@ fn clearWrittenWithEscapeCodes() anyerror!void {
760791 if (noop_impl or !global_progress.need_clear) return;
761792
762793 global_progress.need_clear = false;
763 try write(clear);
794 try write(clear ++ progress_remove);
764795}
765796
766797/// U+25BA or â–º
......@@ -1203,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
12031234 i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index);
12041235
12051236 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
12061274 if (nl_n > 0) {
12071275 buf[i] = '\r';
12081276 i += 1;
......@@ -1480,6 +1548,7 @@ const have_sigwinch = switch (builtin.os.tag) {
14801548 .visionos,
14811549 .dragonfly,
14821550 .freebsd,
1551 .serenity,
14831552 => true,
14841553
14851554 else => false,
lib/std/builtin.zig+6-3
......@@ -897,8 +897,8 @@ pub const VaList = switch (builtin.cpu.arch) {
897897 .windows => *u8,
898898 .ios, .macos, .tvos, .watchos, .visionos => *u8,
899899 else => switch (builtin.zig_backend) {
900 .stage2_aarch64 => VaListAarch64,
901 else => @compileError("disabled due to miscompilations"),
900 else => VaListAarch64,
901 .stage2_llvm => @compileError("disabled due to miscompilations"),
902902 },
903903 },
904904 .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {
......@@ -923,7 +923,10 @@ pub const VaList = switch (builtin.cpu.arch) {
923923 .wasm32, .wasm64 => *anyopaque,
924924 .x86 => *u8,
925925 .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 },
927930 else => VaListX86_64,
928931 },
929932 .xtensa => VaListXtensa,
lib/std/c.zig+44-15
......@@ -204,6 +204,29 @@ pub const passwd = switch (native_os) {
204204 shell: ?[*:0]const u8, // default shell
205205 expire: time_t, // account expiration
206206 },
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 },
207230 else => void,
208231};
209232
......@@ -3291,8 +3314,8 @@ pub const T = switch (native_os) {
32913314 .macos, .ios, .tvos, .watchos, .visionos => struct {
32923315 pub const IOCGWINSZ = ior(0x40000000, 't', 104, @sizeOf(winsize));
32933316
3294 fn ior(inout: u32, group: usize, num: usize, len: usize) usize {
3295 return (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num));
3317 fn ior(inout: u32, group_arg: usize, num: usize, len: usize) usize {
3318 return (inout | ((len & IOCPARM_MASK) << 16) | ((group_arg) << 8) | (num));
32963319 }
32973320 },
32983321 .freebsd => struct {
......@@ -4121,7 +4144,7 @@ pub const msghdr_const = switch (native_os) {
41214144 .serenity => extern struct {
41224145 name: ?*const anyopaque,
41234146 namelen: socklen_t,
4124 iov: [*]const iovec,
4147 iov: [*]const iovec_const,
41254148 iovlen: c_uint,
41264149 control: ?*const anyopaque,
41274150 controllen: socklen_t,
......@@ -8604,7 +8627,7 @@ pub const O = switch (native_os) {
86048627 },
86058628 // https://github.com/SerenityOS/serenity/blob/2808b0376406a40e31293bb3bcb9170374e90506/Kernel/API/POSIX/fcntl.h#L28-L43
86068629 .serenity => packed struct(c_int) {
8607 ACCMODE: std.posix.ACCMODE = .RDONLY,
8630 ACCMODE: std.posix.ACCMODE = .NONE,
86088631 EXEC: bool = false,
86098632 CREAT: bool = false,
86108633 EXCL: bool = false,
......@@ -8760,10 +8783,10 @@ pub const MAP = switch (native_os) {
87608783 },
87618784 // https://github.com/SerenityOS/serenity/blob/6d59d4d3d9e76e39112842ec487840828f1c9bfe/Kernel/API/POSIX/sys/mman.h#L16-L26
87628785 .serenity => packed struct(c_int) {
8763 FILE: bool = false,
8764 SHARED: bool = false,
8765 PRIVATE: bool = false,
8766 _3: u2 = 0,
8786 TYPE: enum(u4) {
8787 SHARED = 0x01,
8788 PRIVATE = 0x02,
8789 },
87678790 FIXED: bool = false,
87688791 ANONYMOUS: bool = false,
87698792 STACK: bool = false,
......@@ -8771,7 +8794,7 @@ pub const MAP = switch (native_os) {
87718794 RANDOMIZED: bool = false,
87728795 PURGEABLE: bool = false,
87738796 FIXED_NOREPLACE: bool = false,
8774 _: std.meta.Int(.unsigned, @bitSizeOf(c_int) - 12) = 0,
8797 _: std.meta.Int(.unsigned, @bitSizeOf(c_int) - 11) = 0,
87758798 },
87768799 else => void,
87778800};
......@@ -10261,9 +10284,20 @@ pub const fstatat = switch (native_os) {
1026110284 },
1026210285 else => private.fstatat,
1026310286};
10264
10287pub extern "c" fn getpwent() ?*passwd;
10288pub extern "c" fn endpwent() void;
10289pub extern "c" fn setpwent() void;
1026510290pub 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;
1026610292pub 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;
1026710301pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
1026810302pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
1026910303pub 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;
1099211026pub const bcrypt_checkpass = openbsd.bcrypt_checkpass;
1099311027pub const bcrypt_gensalt = openbsd.bcrypt_gensalt;
1099411028pub const bcrypt_newhash = openbsd.bcrypt_newhash;
10995pub const endpwent = openbsd.endpwent;
10996pub const getpwent = openbsd.getpwent;
10997pub const getpwnam_r = openbsd.getpwnam_r;
1099811029pub const getpwnam_shadow = openbsd.getpwnam_shadow;
10999pub const getpwuid_r = openbsd.getpwuid_r;
1100011030pub const getpwuid_shadow = openbsd.getpwuid_shadow;
1100111031pub const getthrid = openbsd.getthrid;
1100211032pub const login_cap_t = openbsd.login_cap_t;
......@@ -11013,7 +11043,6 @@ pub const pthread_spinlock_t = openbsd.pthread_spinlock_t;
1101311043pub const pw_dup = openbsd.pw_dup;
1101411044pub const setclasscontext = openbsd.setclasscontext;
1101511045pub const setpassent = openbsd.setpassent;
11016pub const setpwent = openbsd.setpwent;
1101711046pub const setusercontext = openbsd.setusercontext;
1101811047pub const uid_from_user = openbsd.uid_from_user;
1101911048pub 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;
8181
8282pub extern "c" fn getpwuid_shadow(uid: uid_t) ?*passwd;
8383pub 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;
8984pub extern "c" fn setpassent(stayopen: c_int) c_int;
9085pub extern "c" fn uid_from_user(name: [*:0]const u8, uid: *uid_t) c_int;
9186pub 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 @@
1const builtin = @import("builtin");
21const std = @import("../std.zig");
3const testing = std.testing;
4const Writer = std.io.Writer;
2
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
622/// Container of the deflate bit stream body. Container adds header before
723/// deflate bit stream and footer after. It can bi gzip, zlib or raw (no header,
......@@ -13,7 +29,6 @@ const Writer = std.io.Writer;
1329/// Gzip format is defined in rfc 1952. Header has 10+ bytes and footer 4 bytes
1430/// crc32 checksum and 4 bytes of uncompressed data length.
1531///
16///
1732/// rfc 1950: https://datatracker.ietf.org/doc/html/rfc1950#page-4
1833/// rfc 1952: https://datatracker.ietf.org/doc/html/rfc1952#page-5
1934pub const Container = enum {
......@@ -77,14 +92,14 @@ pub const Container = enum {
7792 raw: void,
7893 gzip: struct {
7994 crc: std.hash.Crc32 = .init(),
80 count: usize = 0,
95 count: u32 = 0,
8196 },
8297 zlib: std.hash.Adler32,
8398
8499 pub fn init(containter: Container) Hasher {
85100 return switch (containter) {
86101 .gzip => .{ .gzip = .{} },
87 .zlib => .{ .zlib = .init() },
102 .zlib => .{ .zlib = .{} },
88103 .raw => .raw,
89104 };
90105 }
......@@ -98,7 +113,7 @@ pub const Container = enum {
98113 .raw => {},
99114 .gzip => |*gzip| {
100115 gzip.update(buf);
101 gzip.count += buf.len;
116 gzip.count +%= buf.len;
102117 },
103118 .zlib => |*zlib| {
104119 zlib.update(buf);
......@@ -107,7 +122,7 @@ pub const Container = enum {
107122 }
108123 }
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 {
111126 var bits: [4]u8 = undefined;
112127 switch (hasher.*) {
113128 .gzip => |*gzip| {
......@@ -133,502 +148,33 @@ pub const Container = enum {
133148 }
134149 }
135150 };
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" {
182 const print = std.debug.print;
183 var cmp_buf: [64 * 1024]u8 = undefined; // compressed data buffer
184 var dcm_buf: [64 * 1024]u8 = undefined; // decompressed data buffer
185
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,
152 pub const Metadata = union(Container) {
153 raw: void,
154 gzip: struct {
155 crc: u32 = 0,
156 count: u32 = 0,
211157 },
212 .{
213 .data = @embedFile("flate/testdata/fuzz/deflate-stream.expect"),
214 .gzip_sizes = [_]usize{ 351, 347, 347, 347, 347, 347 },
215 .huffman_only_size = 498,
216 .store_size = 747,
158 zlib: struct {
159 adler: u32 = 0,
217160 },
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" {
351 try testDecompress(.zlib, &[_]u8{
352 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0xc0, 0x00, 0xc1, 0xff,
353 0xff, 0x43, 0x30, 0x03, 0x03, 0xc3, 0xff, 0xff, 0xff, 0x01,
354 0x83, 0x95, 0x0b, 0xf5,
355 }, &[_]u8{
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());
162 pub fn init(containter: Container) Metadata {
163 return switch (containter) {
164 .gzip => .{ .gzip = .{} },
165 .zlib => .{ .zlib = .{} },
166 .raw => .raw,
167 };
567168 }
568169
569 // store compressor/decompressor
570 {
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());
170 pub fn container(m: Metadata) Container {
171 return m;
582172 }
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,
610173 };
174};
611175
612 var stream: std.io.Reader = .fixed(&data);
613 const reader = stream.reader();
614
615 var dcp = Decompress.init(reader);
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]);
176test {
177 _ = HuffmanEncoder;
178 _ = Compress;
179 _ = Decompress;
634180}
lib/std/compress/flate/BlockWriter.zig+83-187
......@@ -8,34 +8,54 @@ const Writer = std.io.Writer;
88const BlockWriter = @This();
99const flate = @import("../flate.zig");
1010const Compress = flate.Compress;
11const huffman = flate.huffman;
11const HuffmanEncoder = flate.HuffmanEncoder;
1212const Token = @import("Token.zig");
1313
14const codegen_order = huffman.codegen_order;
14const codegen_order = HuffmanEncoder.codegen_order;
1515const end_code_mark = 255;
1616
1717output: *Writer,
1818
19codegen_freq: [huffman.codegen_code_count]u16 = undefined,
20literal_freq: [huffman.max_num_lit]u16 = undefined,
21distance_freq: [huffman.distance_code_count]u16 = undefined,
22codegen: [huffman.max_num_lit + huffman.distance_code_count + 1]u8 = undefined,
23literal_encoding: Compress.LiteralEncoder = .{},
24distance_encoding: Compress.DistanceEncoder = .{},
25codegen_encoding: Compress.CodegenEncoder = .{},
26fixed_literal_encoding: Compress.LiteralEncoder,
27fixed_distance_encoding: Compress.DistanceEncoder,
28huff_distance: Compress.DistanceEncoder,
19codegen_freq: [HuffmanEncoder.codegen_code_count]u16,
20literal_freq: [HuffmanEncoder.max_num_lit]u16,
21distance_freq: [HuffmanEncoder.distance_code_count]u16,
22codegen: [HuffmanEncoder.max_num_lit + HuffmanEncoder.distance_code_count + 1]u8,
23literal_encoding: HuffmanEncoder,
24distance_encoding: HuffmanEncoder,
25codegen_encoding: HuffmanEncoder,
26fixed_literal_encoding: HuffmanEncoder,
27fixed_distance_encoding: HuffmanEncoder,
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
3034pub fn init(output: *Writer) BlockWriter {
3135 return .{
3236 .output = output,
33 .fixed_literal_encoding = Compress.fixedLiteralEncoder(),
34 .fixed_distance_encoding = Compress.fixedDistanceEncoder(),
35 .huff_distance = Compress.huffmanDistanceEncoder(),
37 .codegen_freq = undefined,
38 .literal_freq = undefined,
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,
3650 };
3751}
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
3959/// Flush intrenal bit buffer to the writer.
4060/// Should be called only when bit stream is at byte boundary.
4161///
......@@ -46,27 +66,23 @@ pub fn flush(self: *BlockWriter) Writer.Error!void {
4666 try self.bit_writer.flush();
4767}
4868
49pub fn setWriter(self: *BlockWriter, new_writer: *Writer) void {
50 self.bit_writer.setWriter(new_writer);
51}
52
5369fn writeCode(self: *BlockWriter, c: Compress.HuffCode) Writer.Error!void {
5470 try self.bit_writer.writeBits(c.code, c.len);
5571}
5672
57// 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 single
59// array). This method generates that run-length encoding.
60//
61// The result is written into the codegen array, and the frequencies
62// of each code is written into the codegen_freq array.
63// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
64// information. Code bad_code is an end marker
65//
66// num_literals: The number of literals in literal_encoding
67// num_distances: The number of distances in distance_encoding
68// lit_enc: The literal encoder to use
69// dist_enc: The distance encoder to use
73/// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
74/// the literal and distance lengths arrays (which are concatenated into a single
75/// array). This method generates that run-length encoding.
76///
77/// The result is written into the codegen array, and the frequencies
78/// of each code is written into the codegen_freq array.
79/// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
80/// information. Code bad_code is an end marker
81///
82/// num_literals: The number of literals in literal_encoding
83/// num_distances: The number of distances in distance_encoding
84/// lit_enc: The literal encoder to use
85/// dist_enc: The distance encoder to use
7086fn generateCodegen(
7187 self: *BlockWriter,
7288 num_literals: u32,
......@@ -167,7 +183,7 @@ const DynamicSize = struct {
167183 num_codegens: u32,
168184};
169185
170// dynamicSize returns the size of dynamically encoded data in bits.
186/// dynamicSize returns the size of dynamically encoded data in bits.
171187fn dynamicSize(
172188 self: *BlockWriter,
173189 lit_enc: *Compress.LiteralEncoder, // literal encoder
......@@ -194,7 +210,7 @@ fn dynamicSize(
194210 };
195211}
196212
197// fixedSize returns the size of dynamically encoded data in bits.
213/// fixedSize returns the size of dynamically encoded data in bits.
198214fn fixedSize(self: *BlockWriter, extra_bits: u32) u32 {
199215 return 3 +
200216 self.fixed_literal_encoding.bitLength(&self.literal_freq) +
......@@ -207,25 +223,25 @@ const StoredSize = struct {
207223 storable: bool,
208224};
209225
210// storedSizeFits calculates the stored size, including header.
211// The function returns the size in bits and whether the block
212// fits inside a single block.
226/// storedSizeFits calculates the stored size, including header.
227/// The function returns the size in bits and whether the block
228/// fits inside a single block.
213229fn storedSizeFits(in: ?[]const u8) StoredSize {
214230 if (in == null) {
215231 return .{ .size = 0, .storable = false };
216232 }
217 if (in.?.len <= huffman.max_store_block_size) {
233 if (in.?.len <= HuffmanEncoder.max_store_block_size) {
218234 return .{ .size = @as(u32, @intCast((in.?.len + 5) * 8)), .storable = true };
219235 }
220236 return .{ .size = 0, .storable = false };
221237}
222238
223// Write the header of a dynamic Huffman block to the output stream.
224//
225// num_literals: The number of literals specified in codegen
226// num_distances: The number of distances specified in codegen
227// num_codegens: The number of codegens used in codegen
228// eof: Is it the end-of-file? (end of stream)
239/// Write the header of a dynamic Huffman block to the output stream.
240///
241/// num_literals: The number of literals specified in codegen
242/// num_distances: The number of distances specified in codegen
243/// num_codegens: The number of codegens used in codegen
244/// eof: Is it the end-of-file? (end of stream)
229245fn dynamicHeader(
230246 self: *BlockWriter,
231247 num_literals: u32,
......@@ -291,11 +307,11 @@ fn fixedHeader(self: *BlockWriter, eof: bool) Writer.Error!void {
291307 try self.bit_writer.writeBits(value, 3);
292308}
293309
294// 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 data
296// is larger than the original bytes, the data will be written as a
297// stored block.
298// If the input is null, the tokens will always be Huffman encoded.
310/// Write a block of tokens with the smallest encoding. Will choose block type.
311/// The original input can be supplied, and if the huffman encoded data
312/// is larger than the original bytes, the data will be written as a
313/// stored block.
314/// If the input is null, the tokens will always be Huffman encoded.
299315pub fn write(self: *BlockWriter, tokens: []const Token, eof: bool, input: ?[]const u8) Writer.Error!void {
300316 const lit_and_dist = self.indexTokens(tokens);
301317 const num_literals = lit_and_dist.num_literals;
......@@ -379,11 +395,11 @@ pub fn storedBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Erro
379395 try self.bit_writer.writeBytes(input);
380396}
381397
382// writeBlockDynamic encodes a block using a dynamic Huffman table.
383// This should be used if the symbols used have a disproportionate
384// histogram distribution.
385// If input is supplied and the compression savings are below 1/16th of the
386// input size the block is stored.
398/// writeBlockDynamic encodes a block using a dynamic Huffman table.
399/// This should be used if the symbols used have a disproportionate
400/// histogram distribution.
401/// If input is supplied and the compression savings are below 1/16th of the
402/// input size the block is stored.
387403fn dynamicBlock(
388404 self: *BlockWriter,
389405 tokens: []const Token,
......@@ -429,10 +445,10 @@ const TotalIndexedTokens = struct {
429445 num_distances: u32,
430446};
431447
432// Indexes a slice of tokens followed by an end_block_marker, and updates
433// literal_freq and distance_freq, and generates literal_encoding
434// and distance_encoding.
435// The number of literal and distance tokens is returned.
448/// Indexes a slice of tokens followed by an end_block_marker, and updates
449/// literal_freq and distance_freq, and generates literal_encoding
450/// and distance_encoding.
451/// The number of literal and distance tokens is returned.
436452fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
437453 var num_literals: u32 = 0;
438454 var num_distances: u32 = 0;
......@@ -453,7 +469,7 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
453469 self.distance_freq[t.distanceCode()] += 1;
454470 }
455471 // 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
458474 // get the number of literals
459475 num_literals = @as(u32, @intCast(self.literal_freq.len));
......@@ -479,8 +495,8 @@ fn indexTokens(self: *BlockWriter, tokens: []const Token) TotalIndexedTokens {
479495 };
480496}
481497
482// Writes a slice of tokens to the output followed by and end_block_marker.
483// codes for literal and distance encoding must be supplied.
498/// Writes a slice of tokens to the output followed by and end_block_marker.
499/// codes for literal and distance encoding must be supplied.
484500fn writeTokens(
485501 self: *BlockWriter,
486502 tokens: []const Token,
......@@ -508,18 +524,18 @@ fn writeTokens(
508524 }
509525 }
510526 // 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]);
512528}
513529
514// Encodes a block of bytes as either Huffman encoded literals or uncompressed bytes
515// if the results only gains very little from compression.
530/// Encodes a block of bytes as either Huffman encoded literals or uncompressed bytes
531/// if the results only gains very little from compression.
516532pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Error!void {
517533 // Add everything as literals
518534 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;
523539 self.distance_freq[0] = 1;
524540 const num_distances = 1;
525541
......@@ -560,10 +576,9 @@ pub fn huffmanBlock(self: *BlockWriter, input: []const u8, eof: bool) Writer.Err
560576 const c = encoding[t];
561577 try self.bit_writer.writeBits(c.code, c.len);
562578 }
563 try self.writeCode(encoding[huffman.end_block_marker]);
579 try self.writeCode(encoding[HuffmanEncoder.end_block_marker]);
564580}
565581
566// histogram accumulates a histogram of b in h.
567582fn histogram(b: []const u8, h: *[286]u16) void {
568583 // Clear histogram
569584 for (h, 0..) |_, i| {
......@@ -575,122 +590,3 @@ fn histogram(b: []const u8, h: *[286]u16) void {
575590 lh[t] += 1;
576591 }
577592}
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 @@
3939//!
4040//!
4141//! Allocates statically ~400K (192K lookup, 128K tokens, 64K window).
42
4243const builtin = @import("builtin");
4344const std = @import("std");
44const io = std.io;
4545const assert = std.debug.assert;
4646const testing = std.testing;
4747const expect = testing.expect;
4848const mem = std.mem;
4949const math = std.math;
50const Writer = std.io.Writer;
51const Reader = std.io.Reader;
50const Writer = std.Io.Writer;
5251
5352const Compress = @This();
5453const Token = @import("Token.zig");
......@@ -56,26 +55,23 @@ const BlockWriter = @import("BlockWriter.zig");
5655const flate = @import("../flate.zig");
5756const Container = flate.Container;
5857const Lookup = @import("Lookup.zig");
59const huffman = flate.huffman;
58const HuffmanEncoder = flate.HuffmanEncoder;
59const LiteralNode = HuffmanEncoder.LiteralNode;
6060
6161lookup: Lookup = .{},
6262tokens: Tokens = .{},
63/// Asserted to have a buffer capacity of at least `flate.max_window_len`.
64input: *std.io.Reader,
6563block_writer: BlockWriter,
6664level: LevelArgs,
6765hasher: Container.Hasher,
68reader: std.io.Reader,
66writer: Writer,
67state: State,
6968
7069// Match and literal at the previous position.
7170// Used for lazy match finding in processWindow.
7271prev_match: ?Token = null,
7372prev_literal: ?u8 = null,
7473
75pub const Options = struct {
76 level: Level = .default,
77 container: Container = .raw,
78};
74pub const State = enum { header, middle, ended };
7975
8076/// Trades between speed and compression size.
8177/// Starts with level 4: in [zlib](https://github.com/madler/zlib/blob/abd3d1a28930f89375d4b41408b39f6c1be157b2/deflate.c#L115C1-L117C43)
......@@ -119,188 +115,24 @@ const LevelArgs = struct {
119115 }
120116};
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 {
123124 return .{
124 .input = input,
125 .block_writer = undefined,
125 .block_writer = .init(output),
126126 .level = .get(options.level),
127127 .hasher = .init(options.container),
128128 .state = .header,
129 .reader = .{
129 .writer = .{
130130 .buffer = buffer,
131 .stream = stream,
131 .vtable = &.{ .drain = drain },
132132 },
133133 };
134134}
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
304136// Tokens store
305137const Tokens = struct {
306138 list: [n_tokens]Token = undefined,
......@@ -324,527 +156,112 @@ const Tokens = struct {
324156 }
325157};
326158
327/// Creates huffman only deflate blocks. Disables Lempel-Ziv match searching and
328/// only performs Huffman entropy encoding. Results in faster compression, much
329/// less memory requirements during compression but bigger compressed sizes.
330pub const Huffman = SimpleCompressor(.huffman, .raw);
331
332/// Creates store blocks only. Data are not compressed only packed into deflate
333/// store blocks. That adds 9 bytes of header for each block. Max stored block
334/// size is 64K. Block is emitted when flush is called on on finish.
335pub const store = struct {
336 pub fn Compressor(comptime container: Container, comptime WriterType: type) type {
337 return SimpleCompressor(.store, container, WriterType);
338 }
339
340 pub fn compressor(comptime container: Container, writer: anytype) !store.Compressor(container, @TypeOf(writer)) {
341 return try store.Compressor(container, @TypeOf(writer)).init(writer);
159fn drain(me: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {
160 _ = data;
161 _ = splat;
162 const c: *Compress = @fieldParentPtr("writer", me);
163 const out = c.block_writer.output;
164 switch (c.state) {
165 .header => {
166 c.state = .middle;
167 const header = c.hasher.container().header();
168 try out.writeAll(header);
169 return header.len;
170 },
171 .middle => {},
172 .ended => unreachable,
342173 }
343};
344174
345const SimpleCompressorKind = enum {
346 huffman,
347 store,
348};
175 const buffered = me.buffered();
176 const min_lookahead = Token.min_length + Token.max_length;
177 const history_plus_lookahead_len = flate.history_len + min_lookahead;
178 if (buffered.len < history_plus_lookahead_len) return 0;
179 const lookahead = buffered[flate.history_len..];
349180
350fn simpleCompressor(
351 comptime kind: SimpleCompressorKind,
352 comptime container: Container,
353 writer: anytype,
354) !SimpleCompressor(kind, container, @TypeOf(writer)) {
355 return try SimpleCompressor(kind, container, @TypeOf(writer)).init(writer);
181 // TODO tokenize
182 _ = lookahead;
183 //c.hasher.update(lookahead[0..n]);
184 @panic("TODO");
356185}
357186
358fn SimpleCompressor(
359 comptime kind: SimpleCompressorKind,
360 comptime container: Container,
361 comptime WriterType: type,
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 };
187pub fn end(c: *Compress) !void {
188 try endUnflushed(c);
189 const out = c.block_writer.output;
190 try out.flush();
404191}
405192
406const LiteralNode = struct {
407 literal: u16,
408 freq: u16,
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,
193pub fn endUnflushed(c: *Compress) !void {
194 while (c.writer.end != 0) _ = try drain(&c.writer, &.{""}, 1);
195 c.state = .ended;
418196
419 // The frequency of the next character to add to this level
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};
197 const out = c.block_writer.output;
430198
431// hcode is a huffman code with a bit code and bit length.
432pub const HuffCode = struct {
433 code: u16 = 0,
434 len: u16 = 0,
199 // TODO flush tokens
435200
436 // set sets the code and length of an hcode.
437 fn set(self: *HuffCode, code: u16, length: u16) void {
438 self.len = length;
439 self.code = code;
201 switch (c.hasher) {
202 .gzip => |*gzip| {
203 // GZIP 8 bytes footer
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 => {},
440219 }
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 };
676220}
677221
678fn maxNode() LiteralNode {
679 return LiteralNode{
680 .literal = math.maxInt(u16),
681 .freq = math.maxInt(u16),
682 };
683}
684
685pub fn huffmanEncoder(comptime size: u32) HuffmanEncoder(size) {
686 return .{};
687}
222pub const Simple = struct {
223 /// Note that store blocks are limited to 65535 bytes.
224 buffer: []u8,
225 wp: usize,
226 block_writer: BlockWriter,
227 hasher: Container.Hasher,
228 strategy: Strategy,
688229
689pub const LiteralEncoder = HuffmanEncoder(huffman.max_num_frequencies);
690pub const DistanceEncoder = HuffmanEncoder(huffman.distance_code_count);
691pub const CodegenEncoder = HuffmanEncoder(19);
230 pub const Strategy = enum { huffman, store };
692231
693// Generates a HuffmanCode corresponding to the fixed literal table
694pub fn fixedLiteralEncoder() LiteralEncoder {
695 var h: LiteralEncoder = undefined;
696 var ch: u16 = 0;
697
698 while (ch < huffman.max_num_frequencies) : (ch += 1) {
699 var bits: u16 = undefined;
700 var size: u16 = undefined;
701 switch (ch) {
702 0...143 => {
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 };
232 pub fn init(output: *Writer, buffer: []u8, container: Container, strategy: Strategy) !Simple {
233 const header = container.header();
234 try output.writeAll(header);
235 return .{
236 .buffer = buffer,
237 .wp = 0,
238 .block_writer = .init(output),
239 .hasher = .init(container),
240 .strategy = strategy,
241 };
724242 }
725 return h;
726}
727243
728pub fn fixedDistanceEncoder() DistanceEncoder {
729 var h: DistanceEncoder = undefined;
730 for (h.codes, 0..) |_, ch| {
731 h.codes[ch] = HuffCode{ .code = bitReverse(u16, @as(u16, @intCast(ch)), 5), .len = 5 };
244 pub fn flush(self: *Simple) !void {
245 try self.flushBuffer(false);
246 try self.block_writer.storedBlock("", false);
247 try self.block_writer.flush();
732248 }
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 {
747 _ = context;
748 return a.literal < b.literal;
749}
750
751fn byFreq(context: void, a: LiteralNode, b: LiteralNode) bool {
752 _ = context;
753 if (a.freq == b.freq) {
754 return a.literal < b.literal;
250 pub fn finish(self: *Simple) !void {
251 try self.flushBuffer(true);
252 try self.block_writer.flush();
253 try self.hasher.container().writeFooter(&self.hasher, self.block_writer.output);
755254 }
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);
811 }
812 switch (c.hasher) {
813 .gzip => |*gzip| {
814 // GZIP 8 bytes footer
815 // - 4 bytes, CRC32 (CRC-32)
816 // - 4 bytes, ISIZE (Input SIZE) - size of the original (uncompressed) input data modulo 2^32
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 },
256 fn flushBuffer(self: *Simple, final: bool) !void {
257 const buf = self.buffer[0..self.wp];
258 switch (self.strategy) {
259 .huffman => try self.block_writer.huffmanBlock(buf, final),
260 .store => try self.block_writer.storedBlock(buf, final),
261 }
262 self.wp = 0;
846263 }
847}
264};
848265
849266test "generate a Huffman code from an array of frequencies" {
850267 var freqs: [19]u16 = [_]u16{
......@@ -869,7 +286,14 @@ test "generate a Huffman code from an array of frequencies" {
869286 5, // 18
870287 };
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 };
873297 enc.generate(freqs[0..], 7);
874298
875299 try testing.expectEqual(@as(u32, 141), enc.bitLength(freqs[0..]));
......@@ -906,360 +330,3 @@ test "generate a Huffman code from an array of frequencies" {
906330 try testing.expectEqual(@as(u16, 0x1f), enc.codes[7].code);
907331 try testing.expectEqual(@as(u16, 0x3f), enc.codes[16].code);
908332}
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 @@
11const std = @import("../../std.zig");
2const assert = std.debug.assert;
23const flate = std.compress.flate;
3const Container = flate.Container;
4const Token = @import("Token.zig");
54const testing = std.testing;
5const Writer = std.Io.Writer;
6const Reader = std.Io.Reader;
7const Container = flate.Container;
8
69const Decompress = @This();
7const Writer = std.io.Writer;
8const Reader = std.io.Reader;
10const Token = @import("Token.zig");
911
1012input: *Reader,
13next_bits: usize,
14remaining_bits: std.math.Log2Int(usize),
15
1116reader: Reader,
12/// Hashes, produces checksum, of uncompressed data for gzip/zlib footer.
13hasher: Container.Hasher,
17
18container_metadata: Container.Metadata,
1419
1520lit_dec: LiteralDecoder,
1621dst_dec: DistanceDecoder,
......@@ -18,7 +23,7 @@ dst_dec: DistanceDecoder,
1823final_block: bool,
1924state: State,
2025
21read_err: ?Error,
26err: ?Error,
2227
2328const BlockType = enum(u2) {
2429 stored = 0,
......@@ -32,6 +37,8 @@ const State = union(enum) {
3237 stored_block: u16,
3338 fixed_block,
3439 dynamic_block,
40 dynamic_block_literal: u8,
41 dynamic_block_match: u16,
3542 protocol_footer,
3643 end,
3744};
......@@ -39,43 +46,139 @@ const State = union(enum) {
3946pub const Error = Container.Error || error{
4047 InvalidCode,
4148 InvalidMatch,
42 InvalidBlockType,
4349 WrongStoredBlockNlen,
4450 InvalidDynamicBlockHeader,
45 EndOfStream,
4651 ReadFailed,
4752 OversubscribedHuffmanTree,
4853 IncompleteHuffmanTree,
4954 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,
5070};
5171
5272pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
5373 return .{
5474 .reader = .{
55 // TODO populate discard so that when an amount is discarded that
56 // includes an entire frame, skip decoding that frame.
57 .vtable = &.{ .stream = stream },
75 .vtable = if (buffer.len == 0) &direct_vtable else &indirect_vtable,
5876 .buffer = buffer,
5977 .seek = 0,
6078 .end = 0,
6179 },
6280 .input = input,
63 .hasher = .init(container),
81 .next_bits = 0,
82 .remaining_bits = 0,
83 .container_metadata = .init(container),
6484 .lit_dec = .{},
6585 .dst_dec = .{},
6686 .final_block = false,
6787 .state = .protocol_header,
68 .read_err = null,
88 .err = null,
6989 };
7090}
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
72175fn decodeLength(self: *Decompress, code: u8) !u16 {
73176 if (code > 28) return error.InvalidCode;
74177 const ml = Token.matchLength(code);
75178 return if (ml.extra_bits == 0) // 0 - 5 extra bits
76179 ml.base
77180 else
78 ml.base + try self.takeNBitsBuffered(ml.extra_bits);
181 ml.base + try self.takeBitsRuntime(ml.extra_bits);
79182}
80183
81184fn decodeDistance(self: *Decompress, code: u8) !u16 {
......@@ -84,7 +187,7 @@ fn decodeDistance(self: *Decompress, code: u8) !u16 {
84187 return if (md.extra_bits == 0) // 0 - 13 extra bits
85188 md.base
86189 else
87 md.base + try self.takeNBitsBuffered(md.extra_bits);
190 md.base + try self.takeBitsRuntime(md.extra_bits);
88191}
89192
90193// 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
119222 }
120223}
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.
126225fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {
127 const sym = try decoder.find(try self.peekBitsReverseBuffered(u15));
128 try self.shiftBits(sym.code_bits);
226 // Maximum code len is 15 bits.
227 const sym = try decoder.find(@bitReverse(try self.peekBits(u15)));
228 try self.tossBits(sym.code_bits);
129229 return sym;
130230}
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 {
133233 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
134 return readInner(d, w, limit) catch |err| switch (err) {
135 error.EndOfStream => return error.EndOfStream,
234 return streamFallible(d, w, limit);
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 },
136254 error.WriteFailed => return error.WriteFailed,
137255 else => |e| {
138256 // In the event of an error, state is unmodified so that it can be
139257 // better used to diagnose the failure.
140 d.read_err = e;
258 d.err = e;
141259 return error.ReadFailed;
142260 },
143261 };
144262}
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);
147266 const in = d.input;
148267 sw: switch (d.state) {
149 .protocol_header => switch (d.hasher.container()) {
268 .protocol_header => switch (d.container_metadata.container()) {
150269 .gzip => {
151270 const Header = extern struct {
152271 magic: u16 align(1),
......@@ -163,7 +282,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
163282 xfl: u8,
164283 os: u8,
165284 };
166 const header = try in.takeStructEndian(Header, .little);
285 const header = try in.takeStruct(Header, .little);
167286 if (header.magic != 0x8b1f or header.method != 0x08)
168287 return error.BadGzipHeader;
169288 if (header.flags.extra) {
......@@ -171,10 +290,10 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
171290 try in.discardAll(extra_len);
172291 }
173292 if (header.flags.name) {
174 try in.discardDelimiterInclusive(0);
293 _ = try in.discardDelimiterInclusive(0);
175294 }
176295 if (header.flags.comment) {
177 try in.discardDelimiterInclusive(0);
296 _ = try in.discardDelimiterInclusive(0);
178297 }
179298 if (header.flags.hcrc) {
180299 try in.discardAll(2);
......@@ -182,25 +301,19 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
182301 continue :sw .block_header;
183302 },
184303 .zlib => {
185 const Header = extern struct {
186 cmf: packed struct(u8) {
187 cm: u4,
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;
304 const header = try in.takeArray(2);
305 const cmf: packed struct(u8) { cm: u4, cinfo: u4 } = @bitCast(header[0]);
306 if (cmf.cm != 8 or cmf.cinfo > 7) return error.BadZlibHeader;
194307 continue :sw .block_header;
195308 },
196309 .raw => continue :sw .block_header,
197310 },
198311 .block_header => {
199312 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));
201314 switch (block_type) {
202315 .stored => {
203 d.alignBitsToByte(); // skip padding until byte boundary
316 d.alignBitsDiscarding();
204317 // everything after this is byte aligned in stored block
205318 const len = try in.takeInt(u16, .little);
206319 const nlen = try in.takeInt(u16, .little);
......@@ -217,19 +330,20 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
217330 return error.InvalidDynamicBlockHeader;
218331
219332 // lengths for code lengths
220 var cl_lens = [_]u4{0} ** 19;
221 for (0..hclen) |i| {
222 cl_lens[flate.huffman.codegen_order[i]] = try d.takeBits(u3);
333 var cl_lens: [19]u4 = @splat(0);
334 for (flate.HuffmanEncoder.codegen_order[0..hclen]) |i| {
335 cl_lens[i] = try d.takeBits(u3);
223336 }
224337 var cl_dec: CodegenDecoder = .{};
225338 try cl_dec.generate(&cl_lens);
226339
227340 // decoded code lengths
228 var dec_lens = [_]u4{0} ** (286 + 30);
341 var dec_lens: [286 + 30]u4 = @splat(0);
229342 var pos: usize = 0;
230343 while (pos < hlit + hdist) {
231 const sym = try cl_dec.find(try d.peekBitsReverse(u7));
232 try d.shiftBits(sym.code_bits);
344 const peeked = @bitReverse(try d.peekBits(u7));
345 const sym = try cl_dec.find(peeked);
346 try d.tossBits(sym.code_bits);
233347 pos += try d.dynamicCodeLength(sym.symbol, &dec_lens, pos);
234348 }
235349 if (pos > hlit + hdist) {
......@@ -240,7 +354,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
240354 try d.lit_dec.generate(dec_lens[0..hlit]);
241355
242356 // 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
245359 continue :sw .dynamic_block;
246360 },
......@@ -248,8 +362,8 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
248362 },
249363 .stored_block => |remaining_len| {
250364 const out = try w.writableSliceGreedyPreserve(flate.history_len, 1);
251 const limited_out = limit.min(.limited(remaining_len)).slice(out);
252 const n = try d.input.readVec(&.{limited_out});
365 var limited_out: [1][]u8 = .{limit.min(.limited(remaining_len)).slice(out)};
366 const n = try d.input.readVec(&limited_out);
253367 if (remaining_len - n == 0) {
254368 d.state = if (d.final_block) .protocol_footer else .block_header;
255369 } else {
......@@ -259,68 +373,99 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
259373 return n;
260374 },
261375 .fixed_block => {
262 const start = w.count;
263 while (@intFromEnum(limit) > w.count - start) {
376 while (remaining > 0) {
264377 const code = try d.readFixedCode();
265378 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 },
267383 256 => {
268384 d.state = if (d.final_block) .protocol_footer else .block_header;
269 return w.count - start;
385 return @intFromEnum(limit) - remaining;
270386 },
271387 257...285 => {
272388 // Handles fixed block non literal (length) code.
273389 // Length code is followed by 5 bits of distance code.
274390 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)));
276392 try writeMatch(w, length, distance);
393 remaining -= length;
277394 },
278395 else => return error.InvalidCode,
279396 }
280397 }
281398 d.state = .fixed_block;
282 return w.count - start;
399 return @intFromEnum(limit) - remaining;
283400 },
284401 .dynamic_block => {
285 // In larger archives most blocks are usually dynamic, so decompression
286 // performance depends on this logic.
287 const start = w.count;
288 while (@intFromEnum(limit) > w.count - start) {
289 const sym = try d.decodeSymbol(&d.lit_dec);
290
291 switch (sym.kind) {
292 .literal => try w.writeBytePreserve(flate.history_len, sym.symbol),
293 .match => {
294 // Decode match backreference <length, distance>
295 const length = try d.decodeLength(sym.symbol);
296 const dsm = try d.decodeSymbol(&d.dst_dec);
297 const distance = try d.decodeDistance(dsm.symbol);
298 try writeMatch(w, length, distance);
299 },
300 .end_of_block => {
301 d.state = if (d.final_block) .protocol_footer else .block_header;
302 return w.count - start;
303 },
304 }
402 // In larger archives most blocks are usually dynamic, so
403 // decompression performance depends on this logic.
404 var sym = try d.decodeSymbol(&d.lit_dec);
405 sym: switch (sym.kind) {
406 .literal => {
407 if (remaining != 0) {
408 @branchHint(.likely);
409 remaining -= 1;
410 try w.writeBytePreserve(flate.history_len, sym.symbol);
411 sym = try d.decodeSymbol(&d.lit_dec);
412 continue :sym sym.kind;
413 } else {
414 d.state = .{ .dynamic_block_literal = sym.symbol };
415 return @intFromEnum(limit) - remaining;
416 }
417 },
418 .match => {
419 // Decode match backreference <length, distance>
420 const length = try d.decodeLength(sym.symbol);
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;
305446 }
306 d.state = .dynamic_block;
307 return w.count - start;
308447 },
309448 .protocol_footer => {
310 d.alignBitsToByte();
311 switch (d.hasher) {
449 switch (d.container_metadata) {
312450 .gzip => |*gzip| {
313 if (try in.takeInt(u32, .little) != gzip.crc.final()) return error.WrongGzipChecksum;
314 if (try in.takeInt(u32, .little) != gzip.count) return error.WrongGzipSize;
451 d.alignBitsDiscarding();
452 gzip.* = .{
453 .crc = try in.takeInt(u32, .little),
454 .count = try in.takeInt(u32, .little),
455 };
315456 },
316457 .zlib => |*zlib| {
317 const chksum: u32 = @byteSwap(zlib.final());
318 if (try in.takeInt(u32, .big) != chksum) return error.WrongZlibChecksum;
458 d.alignBitsDiscarding();
459 zlib.* = .{
460 .adler = try in.takeInt(u32, .little),
461 };
462 },
463 .raw => {
464 d.alignBitsPreserving();
319465 },
320 .raw => {},
321466 }
322467 d.state = .end;
323 return 0;
468 return @intFromEnum(limit) - remaining;
324469 },
325470 .end => return error.EndOfStream,
326471 }
......@@ -328,53 +473,184 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.io.Limit) (Error || Reader.S
328473
329474/// Write match (back-reference to the same data slice) starting at `distance`
330475/// back from current write position, and `length` of bytes.
331fn writeMatch(bw: *Writer, length: u16, distance: u16) !void {
332 _ = bw;
333 _ = length;
334 _ = distance;
335 @panic("TODO");
476fn writeMatch(w: *Writer, length: u16, distance: u16) !void {
477 if (w.end < distance) return error.InvalidMatch;
478 if (length < Token.base_length) return error.InvalidMatch;
479 if (length > Token.max_length) return error.InvalidMatch;
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;
336510}
337511
338fn takeBits(d: *Decompress, comptime T: type) !T {
339 _ = d;
340 @panic("TODO");
512fn takeBitsEnding(d: *Decompress, comptime U: type) !U {
513 const remaining_bits = d.remaining_bits;
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);
341561}
342562
343fn takeBitsReverseBuffered(d: *Decompress, comptime T: type) !T {
344 _ = d;
345 @panic("TODO");
563/// If there is any unconsumed data, handles EndOfStream by pretending there
564/// are zeroes afterwards.
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];
346571}
347572
348fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 {
349 _ = d;
350 _ = n;
351 @panic("TODO");
573fn tossBits(d: *Decompress, n: u4) !void {
574 const remaining_bits = d.remaining_bits;
575 const next_bits = d.next_bits;
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 }
352589}
353590
354fn peekBitsReverse(d: *Decompress, comptime T: type) !T {
355 _ = d;
356 @panic("TODO");
591fn tossBitsEnding(d: *Decompress, n: u4) !void {
592 const remaining_bits = d.remaining_bits;
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));
357604}
358605
359fn peekBitsReverseBuffered(d: *Decompress, comptime T: type) !T {
360 _ = d;
361 @panic("TODO");
606fn takeBitsRuntime(d: *Decompress, n: u4) !u16 {
607 const x = try peekBits(d, u16);
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;
362612}
363613
364fn alignBitsToByte(d: *Decompress) void {
365 _ = d;
366 @panic("TODO");
614fn alignBitsDiscarding(d: *Decompress) void {
615 const remaining_bits = d.remaining_bits;
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;
367622}
368623
369fn shiftBits(d: *Decompress, n: u6) !void {
370 _ = d;
371 _ = n;
372 @panic("TODO");
624fn alignBitsPreserving(d: *Decompress) void {
625 const remaining_bits: usize = d.remaining_bits;
626 if (remaining_bits == 0) return;
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;
373632}
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
375646fn readFixedCode(d: *Decompress) !u16 {
376 _ = d;
377 @panic("TODO");
647 const code7 = @bitReverse(try d.takeBits(u7));
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 };
378654}
379655
380656pub const Symbol = packed struct {
......@@ -620,10 +896,15 @@ test "init/find" {
620896}
621897
622898test "encode/decode literals" {
623 const LiteralEncoder = std.compress.flate.Compress.LiteralEncoder;
624
899 var codes: [flate.HuffmanEncoder.max_num_frequencies]flate.HuffmanEncoder.Code = undefined;
625900 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 };
627908 // create frequencies
628909 var freq = [_]u16{0} ** 286;
629910 freq[256] = 1; // ensure we have end of block code
......@@ -670,214 +951,210 @@ test "encode/decode literals" {
670951 }
671952}
672953
673test "decompress" {
674 const cases = [_]struct {
675 in: []const u8,
676 out: []const u8,
677 }{
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 }
954test "non compressed block (type 0)" {
955 try testDecompress(.raw, &[_]u8{
956 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
957 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
958 }, "Hello world\n");
714959}
715960
716test "gzip decompress" {
717 const cases = [_]struct {
718 in: []const u8,
719 out: []const u8,
720 }{
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 }
961test "fixed code block (type 1)" {
962 try testDecompress(.raw, &[_]u8{
963 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
964 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
965 }, "Hello world\n");
773966}
774967
775test "zlib decompress" {
776 const cases = [_]struct {
777 in: []const u8,
778 out: []const u8,
779 }{
780 // non compressed block (type 0)
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 }
968test "dynamic block (type 2)" {
969 try testDecompress(.raw, &[_]u8{
970 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
971 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,
972 0x16, 0x96, 0x5c, 0x1e, 0x94, 0xcb, 0x6d, 0x01,
973 }, "ABCDEABCD ABCDEABCD");
801974}
802975
803test "fuzzing tests" {
804 const cases = [_]struct {
805 input: []const u8,
806 out: []const u8 = "",
807 err: ?anyerror = null,
808 }{
809 .{ .input = "deflate-stream", .out = @embedFile("testdata/fuzz/deflate-stream.expect") }, // 0
810 .{ .input = "empty-distance-alphabet01" },
811 .{ .input = "empty-distance-alphabet02" },
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 };
976test "gzip non compressed block (type 0)" {
977 try testDecompress(.gzip, &[_]u8{
978 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, // gzip header (10 bytes)
979 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
980 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
981 0xd5, 0xe0, 0x39, 0xb7, // gzip footer: checksum
982 0x0c, 0x00, 0x00, 0x00, // gzip footer: size
983 }, "Hello world\n");
984}
850985
851 inline for (cases, 0..) |c, case_no| {
852 var in: Reader = .fixed(@embedFile("testdata/fuzz/" ++ c.input ++ ".input"));
853 var aw: Writer.Allocating = .init(testing.allocator);
854 defer aw.deinit();
855 errdefer std.debug.print("test case failed {}\n", .{case_no});
856
857 var decompress: Decompress = .init(&in, .raw);
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 }
986test "gzip fixed code block (type 1)" {
987 try testDecompress(.gzip, &[_]u8{
988 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, // gzip header (10 bytes)
989 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
990 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
991 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00, // gzip footer (chksum, len)
992 }, "Hello world\n");
867993}
868994
869test "bug 18966" {
870 const input = @embedFile("testdata/fuzz/bug_18966.input");
871 const expect = @embedFile("testdata/fuzz/bug_18966.expect");
995test "gzip dynamic block (type 2)" {
996 try testDecompress(.gzip, &[_]u8{
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);
874 var aw: Writer.Allocating = .init(testing.allocator);
875 defer aw.deinit();
1005test "gzip header with name" {
1006 try testDecompress(.gzip, &[_]u8{
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);
878 var decompress_br = decompress.readable(&.{});
879 _ = try decompress_br.streamRemaining(&aw.interface);
880 try testing.expectEqualStrings(expect, aw.getWritten());
1013test "zlib decompress non compressed block (type 0)" {
1014 try testDecompress(.zlib, &[_]u8{
1015 0x78, 0b10_0_11100, // zlib header (2 bytes)
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 );
8811158}
8821159
8831160test "reading into empty buffer" {
......@@ -887,8 +1164,104 @@ test "reading into empty buffer" {
8871164 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
8881165 };
8891166 var in: Reader = .fixed(input);
890 var decomp: Decompress = .init(&in, .raw);
891 var decompress_br = decomp.readable(&.{});
892 var buf: [0]u8 = undefined;
893 try testing.expectEqual(0, try decompress_br.readVec(&.{&buf}));
1167 var decomp: Decompress = .init(&in, .raw, &.{});
1168 const r = &decomp.reader;
1169 var bufs: [1][]u8 = .{&.{}};
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());
8941267}
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");
66const testing = std.testing;
77const expect = testing.expect;
88const flate = @import("../flate.zig");
9const Token = @import("Token.zig");
910
1011const Lookup = @This();
1112
1213const prime4 = 0x9E3779B1; // 4 bytes prime number 2654435761
1314const chain_len = 2 * flate.history_len;
1415
16pub const bits = 15;
17pub const len = 1 << bits;
18pub const shift = 32 - bits;
19
1520// Maps hash => first position
16head: [flate.lookup.len]u16 = [_]u16{0} ** flate.lookup.len,
21head: [len]u16 = [_]u16{0} ** len,
1722// Maps position => previous positions for the same hash value
1823chain: [chain_len]u16 = [_]u16{0} ** (chain_len),
1924
......@@ -52,8 +57,8 @@ pub fn slide(self: *Lookup, n: u16) void {
5257
5358// Add `len` 4 bytes hashes from `data` into lookup.
5459// Position of the first byte is `pos`.
55pub fn bulkAdd(self: *Lookup, data: []const u8, len: u16, pos: u16) void {
56 if (len == 0 or data.len < flate.match.min_length) {
60pub fn bulkAdd(self: *Lookup, data: []const u8, length: u16, pos: u16) void {
61 if (length == 0 or data.len < Token.min_length) {
5762 return;
5863 }
5964 var hb =
......@@ -64,7 +69,7 @@ pub fn bulkAdd(self: *Lookup, data: []const u8, len: u16, pos: u16) void {
6469 _ = self.set(hashu(hb), pos);
6570
6671 var i = pos;
67 for (4..@min(len + 3, data.len)) |j| {
72 for (4..@min(length + 3, data.len)) |j| {
6873 hb = (hb << 8) | @as(u32, data[j]);
6974 i += 1;
7075 _ = self.set(hashu(hb), i);
......@@ -80,7 +85,7 @@ fn hash(b: *const [4]u8) u32 {
8085}
8186
8287fn hashu(v: u32) u32 {
83 return @intCast((v *% prime4) >> flate.lookup.shift);
88 return @intCast((v *% prime4) >> shift);
8489}
8590
8691test add {
lib/std/compress/flate/Token.zig+13-7
......@@ -6,7 +6,6 @@ const std = @import("std");
66const assert = std.debug.assert;
77const print = std.debug.print;
88const expect = std.testing.expect;
9const match = std.compress.flate.match;
109
1110const Token = @This();
1211
......@@ -21,16 +20,23 @@ dist: u15 = 0,
2120len_lit: u8 = 0,
2221kind: 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
2430pub fn literal(t: Token) u8 {
2531 return t.len_lit;
2632}
2733
2834pub fn distance(t: Token) u16 {
29 return @as(u16, t.dist) + match.min_distance;
35 return @as(u16, t.dist) + min_distance;
3036}
3137
3238pub fn length(t: Token) u16 {
33 return @as(u16, t.len_lit) + match.base_length;
39 return @as(u16, t.len_lit) + base_length;
3440}
3541
3642pub fn initLiteral(lit: u8) Token {
......@@ -40,12 +46,12 @@ pub fn initLiteral(lit: u8) Token {
4046// distance range 1 - 32768, stored in dist as 0 - 32767 (u15)
4147// length range 3 - 258, stored in len_lit as 0 - 255 (u8)
4248pub fn initMatch(dist: u16, len: u16) Token {
43 assert(len >= match.min_length and len <= match.max_length);
44 assert(dist >= match.min_distance and dist <= match.max_distance);
49 assert(len >= min_length and len <= max_length);
50 assert(dist >= min_distance and dist <= max_distance);
4551 return .{
4652 .kind = .match,
47 .dist = @intCast(dist - match.min_distance),
48 .len_lit = @intCast(len - match.base_length),
53 .dist = @intCast(dist - min_distance),
54 .len_lit = @intCast(len - base_length),
4955 };
5056}
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) {
1212};
1313
1414fn readStreamFlags(reader: anytype, check: *Check) !void {
15 var bit_reader = std.io.bitReader(.little, reader);
16
17 const reserved1 = try bit_reader.readBitsNoEof(u8, 8);
18 if (reserved1 != 0)
19 return error.CorruptInput;
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;
15 const reserved1 = try reader.readByte();
16 if (reserved1 != 0) return error.CorruptInput;
17 const byte = try reader.readByte();
18 if ((byte >> 4) != 0) return error.CorruptInput;
19 check.* = @enumFromInt(@as(u4, @truncate(byte)));
2620}
2721
2822pub 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 {
3131 /// Verifying checksums is not implemented yet and will cause a panic if
3232 /// you set this to true.
3333 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`.
3540 window_len: u32 = zstd.default_window_len,
3641};
3742
......@@ -69,8 +74,10 @@ pub const Error = error{
6974 WindowSizeUnknown,
7075};
7176
72/// If buffer that is written to is not big enough, some streams will fail with
73/// `error.OutputBufferUndersize`. A safe value is `zstd.default_window_len * 2`.
77/// When connecting `reader` to a `Writer`, `buffer` should be empty, and
78/// `Writer.buffer` capacity has requirements based on `Options.window_len`.
79///
80/// Otherwise, `buffer` has those requirements.
7481pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
7582 return .{
7683 .input = input,
......@@ -78,7 +85,12 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
7885 .verify_checksum = options.verify_checksum,
7986 .window_len = options.window_len,
8087 .reader = .{
81 .vtable = &.{ .stream = stream },
88 .vtable = &.{
89 .stream = stream,
90 .rebase = rebase,
91 .discard = discard,
92 .readVec = readVec,
93 },
8294 .buffer = buffer,
8395 .seek = 0,
8496 .end = 0,
......@@ -86,6 +98,60 @@ pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
8698 };
8799}
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
89155fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
90156 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
91157 const in = d.input;
lib/std/debug/Dwarf.zig+16-12
......@@ -2019,10 +2019,14 @@ pub fn compactUnwindToDwarfRegNumber(unwind_reg_number: u3) !u8 {
20192019/// This function is to make it handy to comment out the return and make it
20202020/// into a crash when working on this file.
20212021pub fn bad() error{InvalidDebugInfo} {
2022 if (debug_debug_mode) @panic("bad dwarf");
2022 invalidDebugInfoDetected();
20232023 return error.InvalidDebugInfo;
20242024}
20252025
2026fn invalidDebugInfoDetected() void {
2027 if (debug_debug_mode) @panic("bad dwarf");
2028}
2029
20262030fn missing() error{MissingDebugInfo} {
20272031 if (debug_debug_mode) @panic("missing dwarf");
20282032 return error.MissingDebugInfo;
......@@ -2235,23 +2239,23 @@ pub const ElfModule = struct {
22352239
22362240 const section_bytes = try chopSlice(mapped_mem, shdr.sh_offset, shdr.sh_size);
22372241 sections[section_index.?] = if ((shdr.sh_flags & elf.SHF_COMPRESSED) > 0) blk: {
2238 var section_reader: std.io.Reader = .fixed(section_bytes);
2239 const chdr = section_reader.takeStruct(elf.Chdr) catch continue;
2242 var section_reader: std.Io.Reader = .fixed(section_bytes);
2243 const chdr = section_reader.takeStruct(elf.Chdr, endian) catch continue;
22402244 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, &.{});
2244
2245 const decompressed_section = zlib_stream.reader.allocRemaining(gpa, .limited(ch_size)) catch
2246 var decompress: std.compress.flate.Decompress = .init(&section_reader, .zlib, &.{});
2247 var decompressed_section: std.ArrayListUnmanaged(u8) = .empty;
2248 defer decompressed_section.deinit(gpa);
2249 decompress.reader.appendRemainingUnlimited(gpa, null, &decompressed_section, std.compress.flate.history_len) catch {
2250 invalidDebugInfoDetected();
22462251 continue;
2247 if (decompressed_section.len != ch_size) {
2248 gpa.free(decompressed_section);
2252 };
2253 if (chdr.ch_size != decompressed_section.items.len) {
2254 invalidDebugInfoDetected();
22492255 continue;
22502256 }
2251 errdefer gpa.free(decompressed_section);
2252
22532257 break :blk .{
2254 .data = decompressed_section,
2258 .data = try decompressed_section.toOwnedSlice(gpa),
22552259 .virtual_address = shdr.sh_addr,
22562260 .owned = true,
22572261 };
lib/std/enums.zig+34-20
......@@ -1317,9 +1317,9 @@ test "EnumSet non-exhaustive" {
13171317}
13181318
13191319pub fn EnumIndexer(comptime E: type) type {
1320 // Assumes that the enum fields are sorted in ascending order (optimistic).
1321 // Unsorted enums may require the user to manually increase the quota.
1322 @setEvalBranchQuota(3 * @typeInfo(E).@"enum".fields.len + eval_branch_quota_cushion);
1320 // n log n for `std.mem.sortUnstable` call below.
1321 const fields_len = @typeInfo(E).@"enum".fields.len;
1322 @setEvalBranchQuota(3 * fields_len * std.math.log2(@max(fields_len, 1)) + eval_branch_quota_cushion);
13231323
13241324 if (!@typeInfo(E).@"enum".is_exhaustive) {
13251325 const BackingInt = @typeInfo(E).@"enum".tag_type;
......@@ -1354,10 +1354,6 @@ pub fn EnumIndexer(comptime E: type) type {
13541354 };
13551355 }
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
13611357 if (fields_len == 0) {
13621358 return struct {
13631359 pub const Key = E;
......@@ -1373,22 +1369,17 @@ pub fn EnumIndexer(comptime E: type) type {
13731369 };
13741370 }
13751371
1376 const min = fields[0].value;
1377 const max = fields[fields.len - 1].value;
1378
1379 const SortContext = struct {
1380 fields: []EnumField,
1372 var fields: [fields_len]EnumField = @typeInfo(E).@"enum".fields[0..].*;
13811373
1382 pub fn lessThan(comptime ctx: @This(), comptime a: usize, comptime b: usize) bool {
1383 return ctx.fields[a].value < ctx.fields[b].value;
1374 std.mem.sortUnstable(EnumField, &fields, {}, struct {
1375 fn lessThan(ctx: void, lhs: EnumField, rhs: EnumField) bool {
1376 ctx;
1377 return lhs.value < rhs.value;
13841378 }
1379 }.lessThan);
13851380
1386 pub fn swap(comptime ctx: @This(), comptime a: usize, comptime b: usize) void {
1387 return std.mem.swap(EnumField, &ctx.fields[a], &ctx.fields[b]);
1388 }
1389 };
1390 std.sort.insertionContext(0, fields_len, SortContext{ .fields = &fields });
1391
1381 const min = fields[0].value;
1382 const max = fields[fields_len - 1].value;
13921383 if (max - min == fields.len - 1) {
13931384 return struct {
13941385 pub const Key = E;
......@@ -1538,6 +1529,29 @@ test "EnumIndexer empty" {
15381529 try testing.expectEqual(0, Indexer.count);
15391530}
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
15411555test values {
15421556 const E = enum {
15431557 X,
lib/std/fmt.zig+2
......@@ -1101,6 +1101,8 @@ test "float.libc.sanity" {
11011101}
11021102
11031103test "union" {
1104 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1105
11041106 const TU = union(enum) {
11051107 float: f32,
11061108 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
912912/// * Whether reading should be done via fd-to-fd syscalls (e.g. `sendfile`)
913913/// versus plain variants (e.g. `read`).
914914///
915/// Fulfills the `std.io.Reader` interface.
915/// Fulfills the `std.Io.Reader` interface.
916916pub const Reader = struct {
917917 file: File,
918918 err: ?ReadError = null,
......@@ -923,7 +923,7 @@ pub const Reader = struct {
923923 size: ?u64 = null,
924924 size_err: ?GetEndPosError = null,
925925 seek_err: ?Reader.SeekError = null,
926 interface: std.io.Reader,
926 interface: std.Io.Reader,
927927
928928 pub const SeekError = File.SeekError || error{
929929 /// Seeking fell back to reading, and reached the end before the requested seek position.
......@@ -960,11 +960,12 @@ pub const Reader = struct {
960960 }
961961 };
962962
963 pub fn initInterface(buffer: []u8) std.io.Reader {
963 pub fn initInterface(buffer: []u8) std.Io.Reader {
964964 return .{
965965 .vtable = &.{
966966 .stream = Reader.stream,
967967 .discard = Reader.discard,
968 .readVec = Reader.readVec,
968969 },
969970 .buffer = buffer,
970971 .seek = 0,
......@@ -1077,7 +1078,7 @@ pub const Reader = struct {
10771078 /// vectors through the underlying read calls as possible.
10781079 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 {
10811082 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
10821083 switch (r.mode) {
10831084 .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) {
......@@ -1088,16 +1089,33 @@ pub const Reader = struct {
10881089 else => |e| return e,
10891090 },
10901091 .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 => {
10911111 if (is_windows) {
10921112 // Unfortunately, `ReadFileScatter` cannot be used since it
10931113 // requires page alignment.
1094 const dest = limit.slice(try w.writableSliceGreedy(1));
1095 const n = try readPositional(r, dest);
1096 w.advance(n);
1097 return n;
1114 return readPositional(r, data[0]);
10981115 }
10991116 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];
11011119 assert(dest[0].len > 0);
11021120 const n = posix.preadv(r.file.handle, dest, r.pos) catch |err| switch (err) {
11031121 error.Unseekable => {
......@@ -1122,19 +1140,22 @@ pub const Reader = struct {
11221140 return error.EndOfStream;
11231141 }
11241142 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;
11261149 },
1127 .streaming_reading => {
1150 .streaming, .streaming_reading => {
11281151 if (is_windows) {
11291152 // Unfortunately, `ReadFileScatter` cannot be used since it
11301153 // requires page alignment.
1131 const dest = limit.slice(try w.writableSliceGreedy(1));
1132 const n = try readStreaming(r, dest);
1133 w.advance(n);
1134 return n;
1154 return readStreaming(r, data[0]);
11351155 }
11361156 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];
11381159 assert(dest[0].len > 0);
11391160 const n = posix.readv(r.file.handle, dest) catch |err| {
11401161 r.err = err;
......@@ -1145,13 +1166,18 @@ pub const Reader = struct {
11451166 return error.EndOfStream;
11461167 }
11471168 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;
11491175 },
11501176 .failure => return error.ReadFailed,
11511177 }
11521178 }
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 {
11551181 const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader));
11561182 const file = r.file;
11571183 const pos = r.pos;
......@@ -1230,7 +1256,7 @@ pub const Reader = struct {
12301256 }
12311257 }
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 {
12341260 const n = r.file.pread(dest, r.pos) catch |err| switch (err) {
12351261 error.Unseekable => {
12361262 r.mode = r.mode.toStreaming();
......@@ -1257,7 +1283,7 @@ pub const Reader = struct {
12571283 return n;
12581284 }
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 {
12611287 const n = r.file.read(dest) catch |err| {
12621288 r.err = err;
12631289 return error.ReadFailed;
......@@ -1270,7 +1296,7 @@ pub const Reader = struct {
12701296 return n;
12711297 }
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 {
12741300 switch (r.mode) {
12751301 .positional, .positional_reading => return readPositional(r, dest),
12761302 .streaming, .streaming_reading => return readStreaming(r, dest),
......@@ -1296,7 +1322,7 @@ pub const Writer = struct {
12961322 copy_file_range_err: ?CopyFileRangeError = null,
12971323 fcopyfile_err: ?FcopyfileError = null,
12981324 seek_err: ?SeekError = null,
1299 interface: std.io.Writer,
1325 interface: std.Io.Writer,
13001326
13011327 pub const Mode = Reader.Mode;
13021328
......@@ -1333,13 +1359,13 @@ pub const Writer = struct {
13331359 };
13341360 }
13351361
1336 pub fn initInterface(buffer: []u8) std.io.Writer {
1362 pub fn initInterface(buffer: []u8) std.Io.Writer {
13371363 return .{
13381364 .vtable = &.{
13391365 .drain = drain,
13401366 .sendFile = switch (builtin.zig_backend) {
13411367 else => sendFile,
1342 .stage2_aarch64 => std.io.Writer.unimplementedSendFile,
1368 .stage2_aarch64 => std.Io.Writer.unimplementedSendFile,
13431369 },
13441370 },
13451371 .buffer = buffer,
......@@ -1357,7 +1383,7 @@ pub const Writer = struct {
13571383 };
13581384 }
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 {
13611387 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
13621388 const handle = w.file.handle;
13631389 const buffered = io_w.buffered();
......@@ -1507,10 +1533,10 @@ pub const Writer = struct {
15071533 }
15081534
15091535 pub fn sendFile(
1510 io_w: *std.io.Writer,
1536 io_w: *std.Io.Writer,
15111537 file_reader: *Reader,
1512 limit: std.io.Limit,
1513 ) std.io.Writer.FileError!usize {
1538 limit: std.Io.Limit,
1539 ) std.Io.Writer.FileError!usize {
15141540 const reader_buffered = file_reader.interface.buffered();
15151541 if (reader_buffered.len >= @intFromEnum(limit))
15161542 return sendFileBuffered(io_w, file_reader, reader_buffered);
......@@ -1772,10 +1798,10 @@ pub const Writer = struct {
17721798 }
17731799
17741800 fn sendFileBuffered(
1775 io_w: *std.io.Writer,
1801 io_w: *std.Io.Writer,
17761802 file_reader: *Reader,
17771803 reader_buffered: []const u8,
1778 ) std.io.Writer.FileError!usize {
1804 ) std.Io.Writer.FileError!usize {
17791805 const n = try drain(io_w, &.{reader_buffered}, 1);
17801806 file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed;
17811807 return n;
......@@ -1798,7 +1824,7 @@ pub const Writer = struct {
17981824 }
17991825 }
18001826
1801 pub const EndError = SetEndPosError || std.io.Writer.Error;
1827 pub const EndError = SetEndPosError || std.Io.Writer.Error;
18021828
18031829 /// Flushes any buffered data and sets the end position of the file.
18041830 ///
lib/std/hash.zig+2-3
......@@ -1,5 +1,4 @@
1const adler = @import("hash/adler.zig");
2pub const Adler32 = adler.Adler32;
1pub const Adler32 = @import("hash/Adler32.zig");
32
43const auto_hash = @import("hash/auto_hash.zig");
54pub const autoHash = auto_hash.autoHash;
......@@ -115,7 +114,7 @@ test int {
115114}
116115
117116test {
118 _ = adler;
117 _ = Adler32;
119118 _ = auto_hash;
120119 _ = crc;
121120 _ = 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 {
4545
4646pub fn iterativeApi(comptime Hash: anytype) !void {
4747 // Sum(1..32) = 528
48 var buf: [528]u8 = [_]u8{0} ** 528;
48 var buf: [528]u8 = @splat(0);
4949 var len: usize = 0;
5050 const seed = 0;
5151
lib/std/heap.zig+1-1
......@@ -146,7 +146,7 @@ const CAllocator = struct {
146146 else {};
147147
148148 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,
150150 else => false,
151151 };
152152
lib/std/math.zig+7-3
......@@ -1358,11 +1358,15 @@ pub fn lossyCast(comptime T: type, value: anytype) T {
13581358 }
13591359 },
13601360 .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));
13611365 if (isNan(value)) {
13621366 return 0;
1363 } else if (value >= maxInt(T)) {
1367 } else if (value >= max) {
13641368 return maxInt(T);
1365 } else if (value <= minInt(T)) {
1369 } else if (value <= min) {
13661370 return minInt(T);
13671371 } else {
13681372 return @intFromFloat(value);
......@@ -1379,7 +1383,7 @@ test lossyCast {
13791383 try testing.expect(lossyCast(i16, 70000.0) == @as(i16, 32767));
13801384 try testing.expect(lossyCast(u32, @as(i16, -255)) == @as(u32, 0));
13811385 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));
13831387 try testing.expect(lossyCast(u32, nan(f32)) == 0);
13841388}
13851389
lib/std/math/gamma.zig+16-16
......@@ -189,19 +189,19 @@ fn series(comptime T: type, abs: T) T {
189189 2.5066282746310002701649081771338373386264310793408,
190190 };
191191 const denominator = [_]T{
192 0,
193 39916800,
194 120543840,
195 150917976,
196 105258076,
197 45995730,
198 13339535,
199 2637558,
200 357423,
201 32670,
202 1925,
203 66,
204 1,
192 0.0,
193 39916800.0,
194 120543840.0,
195 150917976.0,
196 105258076.0,
197 45995730.0,
198 13339535.0,
199 2637558.0,
200 357423.0,
201 32670.0,
202 1925.0,
203 66.0,
204 1.0,
205205 };
206206 var num: T = 0;
207207 var den: T = 0;
......@@ -244,9 +244,9 @@ const expectApproxEqRel = std.testing.expectApproxEqRel;
244244test gamma {
245245 inline for (&.{ f32, f64 }) |T| {
246246 const eps = @sqrt(std.math.floatEps(T));
247 try expectApproxEqRel(@as(T, 120), gamma(T, 6), eps);
248 try expectApproxEqRel(@as(T, 362880), gamma(T, 10), eps);
249 try expectApproxEqRel(@as(T, 6402373705728000), gamma(T, 19), eps);
247 try expectApproxEqRel(@as(T, 120.0), gamma(T, 6), eps);
248 try expectApproxEqRel(@as(T, 362880.0), gamma(T, 10), eps);
249 try expectApproxEqRel(@as(T, 6402373705728000.0), gamma(T, 19), eps);
250250
251251 try expectApproxEqRel(@as(T, 332.7590766955334570), gamma(T, 0.003), eps);
252252 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 {
7474 r = modf(@as(T, 43874.3));
7575 try expectEqual(43874.0, r.ipart);
7676 // 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);
7878 try expectApproxEqAbs(expected_b, r.fpart, epsilon);
7979
8080 r = modf(@as(T, 1234.340780));
lib/std/math/pow.zig+2-2
......@@ -192,8 +192,8 @@ fn isOddInteger(x: f64) bool {
192192}
193193
194194test isOddInteger {
195 try expect(isOddInteger(math.maxInt(i64) * 2) == false);
196 try expect(isOddInteger(math.maxInt(i64) * 2 + 1) == false);
195 try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2)) == false);
196 try expect(isOddInteger(@floatFromInt(math.maxInt(i64) * 2 + 1)) == false);
197197 try expect(isOddInteger(1 << 53) == false);
198198 try expect(isOddInteger(12.0) == false);
199199 try expect(isOddInteger(15.0) == true);
lib/std/net.zig+35-18
......@@ -7,7 +7,7 @@ const net = @This();
77const mem = std.mem;
88const posix = std.posix;
99const fs = std.fs;
10const io = std.io;
10const Io = std.Io;
1111const native_endian = builtin.target.cpu.arch.endian();
1212const native_os = builtin.os.tag;
1313const windows = std.os.windows;
......@@ -165,7 +165,7 @@ pub const Address = extern union {
165165 }
166166 }
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 {
169169 switch (self.any.family) {
170170 posix.AF.INET => try self.in.format(w),
171171 posix.AF.INET6 => try self.in6.format(w),
......@@ -342,7 +342,7 @@ pub const Ip4Address = extern struct {
342342 self.sa.port = mem.nativeToBig(u16, port);
343343 }
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 {
346346 const bytes: *const [4]u8 = @ptrCast(&self.sa.addr);
347347 try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], self.getPort() });
348348 }
......@@ -633,7 +633,7 @@ pub const Ip6Address = extern struct {
633633 self.sa.port = mem.nativeToBig(u16, port);
634634 }
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 {
637637 const port = mem.bigToNative(u16, self.sa.port);
638638 if (mem.eql(u8, self.sa.addr[0..12], &[_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) {
639639 try w.print("[::ffff:{d}.{d}.{d}.{d}]:{d}", .{
......@@ -1348,7 +1348,7 @@ fn parseHosts(
13481348 name: []const u8,
13491349 family: posix.sa_family_t,
13501350 port: u16,
1351 br: *io.Reader,
1351 br: *Io.Reader,
13521352) error{ OutOfMemory, ReadFailed }!void {
13531353 while (true) {
13541354 const line = br.takeDelimiterExclusive('\n') catch |err| switch (err) {
......@@ -1402,7 +1402,7 @@ test parseHosts {
14021402 // TODO parsing addresses should not have OS dependencies
14031403 return error.SkipZigTest;
14041404 }
1405 var reader: std.io.Reader = .fixed(
1405 var reader: Io.Reader = .fixed(
14061406 \\127.0.0.1 localhost
14071407 \\::1 localhost
14081408 \\127.0.0.2 abcd
......@@ -1583,7 +1583,7 @@ const ResolvConf = struct {
15831583 const Directive = enum { options, nameserver, domain, search };
15841584 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 {
15871587 const gpa = rc.gpa;
15881588 while (reader.takeSentinel('\n')) |line_with_comment| {
15891589 const line = line: {
......@@ -1894,7 +1894,7 @@ pub const Stream = struct {
18941894 pub const Reader = switch (native_os) {
18951895 .windows => struct {
18961896 /// Use `interface` for portable code.
1897 interface_state: io.Reader,
1897 interface_state: Io.Reader,
18981898 /// Use `getStream` for portable code.
18991899 net_stream: Stream,
19001900 /// Use `getError` for portable code.
......@@ -1910,14 +1910,17 @@ pub const Stream = struct {
19101910 return r.error_state;
19111911 }
19121912
1913 pub fn interface(r: *Reader) *io.Reader {
1913 pub fn interface(r: *Reader) *Io.Reader {
19141914 return &r.interface_state;
19151915 }
19161916
19171917 pub fn init(net_stream: Stream, buffer: []u8) Reader {
19181918 return .{
19191919 .interface_state = .{
1920 .vtable = &.{ .stream = stream },
1920 .vtable = &.{
1921 .stream = stream,
1922 .readVec = readVec,
1923 },
19211924 .buffer = buffer,
19221925 .seek = 0,
19231926 .end = 0,
......@@ -1927,16 +1930,30 @@ pub const Stream = struct {
19271930 };
19281931 }
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 {
19311942 const r: *Reader = @alignCast(@fieldParentPtr("interface_state", io_r));
19321943 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];
19341946 assert(bufs[0].len != 0);
19351947 const n = streamBufs(r, bufs) catch |err| {
19361948 r.error_state = err;
19371949 return error.ReadFailed;
19381950 };
19391951 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 }
19401957 return n;
19411958 }
19421959
......@@ -1968,7 +1985,7 @@ pub const Stream = struct {
19681985
19691986 pub const Error = ReadError;
19701987
1971 pub fn interface(r: *Reader) *io.Reader {
1988 pub fn interface(r: *Reader) *Io.Reader {
19721989 return &r.file_reader.interface;
19731990 }
19741991
......@@ -1996,7 +2013,7 @@ pub const Stream = struct {
19962013 pub const Writer = switch (native_os) {
19972014 .windows => struct {
19982015 /// This field is present on all systems.
1999 interface: io.Writer,
2016 interface: Io.Writer,
20002017 /// Use `getStream` for cross-platform support.
20012018 stream: Stream,
20022019 /// This field is present on all systems.
......@@ -2034,7 +2051,7 @@ pub const Stream = struct {
20342051 }
20352052 }
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 {
20382055 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
20392056 const buffered = io_w.buffered();
20402057 comptime assert(native_os == .windows);
......@@ -2106,7 +2123,7 @@ pub const Stream = struct {
21062123 },
21072124 else => struct {
21082125 /// This field is present on all systems.
2109 interface: io.Writer,
2126 interface: Io.Writer,
21102127
21112128 err: ?Error = null,
21122129 file_writer: File.Writer,
......@@ -2138,7 +2155,7 @@ pub const Stream = struct {
21382155 i.* += 1;
21392156 }
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 {
21422159 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
21432160 const buffered = io_w.buffered();
21442161 var iovecs: [max_buffers_len]posix.iovec_const = undefined;
......@@ -2190,7 +2207,7 @@ pub const Stream = struct {
21902207 });
21912208 }
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 {
21942211 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
21952212 const n = try w.file_writer.interface.sendFileHeader(io_w.buffered(), file_reader, limit);
21962213 return io_w.consume(n);
lib/std/posix.zig+3-1
......@@ -204,6 +204,7 @@ pub const ACCMODE = switch (native_os) {
204204 // implements this suggestion.
205205 // https://github.com/SerenityOS/serenity/blob/4adc51fdf6af7d50679c48b39362e062f5a3b2cb/Kernel/API/POSIX/fcntl.h#L28-L30
206206 .serenity => enum(u2) {
207 NONE = 0,
207208 RDONLY = 1,
208209 WRONLY = 2,
209210 RDWR = 3,
......@@ -1128,8 +1129,9 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
11281129/// * Windows
11291130/// On these systems, the read races with concurrent writes to the same file descriptor.
11301131pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
1132 // NOTE: serenity does not have preadv but it *does* have pwritev.
11311133 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,
11331135 else => false,
11341136 };
11351137 if (have_pread_but_not_preadv) {
lib/std/start.zig+1-1
......@@ -626,7 +626,6 @@ pub inline fn callMain() u8 {
626626
627627 const result = root.main() catch |err| {
628628 switch (builtin.zig_backend) {
629 .stage2_aarch64,
630629 .stage2_powerpc,
631630 .stage2_riscv64,
632631 => {
......@@ -700,6 +699,7 @@ fn maybeIgnoreSigpipe() void {
700699 .visionos,
701700 .dragonfly,
702701 .freebsd,
702 .serenity,
703703 => true,
704704
705705 else => false,
lib/std/zig.zig+30-9
......@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {
321321 try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));
322322 try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));
323323 }
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 }
324345};
325346
326347pub const LtoMode = enum { none, full, thin };
......@@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
364385/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
365386///
366387/// See also `fmtIdFlags`.
367pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
368 return .{ .data = .{ .bytes = bytes, .flags = .{} } };
388pub fn fmtId(bytes: []const u8) FormatId {
389 return .{ .bytes = bytes, .flags = .{} };
369390}
370391
371392/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
372393///
373394/// See also `fmtId`.
374pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) {
375 return .{ .data = .{ .bytes = bytes, .flags = flags } };
395pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) FormatId {
396 return .{ .bytes = bytes, .flags = flags };
376397}
377398
378pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
379 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } };
399pub fn fmtIdPU(bytes: []const u8) FormatId {
400 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } };
380401}
381402
382pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {
383 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } };
403pub fn fmtIdP(bytes: []const u8) FormatId {
404 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true } };
384405}
385406
386407test fmtId {
......@@ -426,7 +447,7 @@ pub const FormatId = struct {
426447 };
427448
428449 /// 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 {
430451 const bytes = ctx.bytes;
431452 if (isValidId(bytes) and
432453 (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 {
33613361 /// The `main_token` might be a ** token, which is shared with a
33623362 /// parent/child pointer type and may require special handling.
33633363 ptr_type_sentinel,
3364 /// The `data` field is a `.opt_node_and_node`:
3364 /// The `data` field is a `.extra_and_node`:
33653365 /// 1. a `ExtraIndex` to `PtrType`.
33663366 /// 2. a `Node.Index` to the element type expression.
33673367 ///
......@@ -3370,7 +3370,7 @@ pub const Node = struct {
33703370 /// The `main_token` might be a ** token, which is shared with a
33713371 /// parent/child pointer type and may require special handling.
33723372 ptr_type,
3373 /// The `data` field is a `.opt_node_and_node`:
3373 /// The `data` field is a `.extra_and_node`:
33743374 /// 1. a `ExtraIndex` to `PtrTypeBitRange`.
33753375 /// 2. a `Node.Index` to the element type expression.
33763376 ///
lib/std/zip.zig+45-43
......@@ -7,8 +7,9 @@ const builtin = @import("builtin");
77const std = @import("std");
88const File = std.fs.File;
99const is_le = builtin.target.cpu.arch.endian() == .little;
10const Writer = std.io.Writer;
11const Reader = std.io.Reader;
10const Writer = std.Io.Writer;
11const Reader = std.Io.Reader;
12const flate = std.compress.flate;
1213
1314pub const CompressionMethod = enum(u16) {
1415 store = 0,
......@@ -117,6 +118,7 @@ pub const EndRecord = extern struct {
117118 pub const FindFileError = File.GetEndPosError || File.SeekError || File.ReadError || error{
118119 ZipNoEndRecord,
119120 EndOfStream,
121 ReadFailed,
120122 };
121123
122124 pub fn findFile(fr: *File.Reader) FindFileError!EndRecord {
......@@ -137,8 +139,7 @@ pub const EndRecord = extern struct {
137139
138140 try fr.seekTo(end_pos - @as(u64, new_loaded_len));
139141 const read_buf: []u8 = buf[buf.len - new_loaded_len ..][0..read_len];
140 var br = fr.interface().unbuffered();
141 br.readSlice(read_buf) catch |err| switch (err) {
142 fr.interface.readSliceAll(read_buf) catch |err| switch (err) {
142143 error.ReadFailed => return fr.err.?,
143144 error.EndOfStream => return error.EndOfStream,
144145 };
......@@ -164,7 +165,7 @@ pub const EndRecord = extern struct {
164165pub const Decompress = struct {
165166 interface: Reader,
166167 state: union {
167 inflate: std.compress.flate.Decompress,
168 inflate: flate.Decompress,
168169 store: *Reader,
169170 },
170171
......@@ -201,7 +202,7 @@ pub const Decompress = struct {
201202
202203 fn streamDeflate(r: *Reader, w: *Writer, limit: std.io.Limit) Reader.StreamError!usize {
203204 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);
205206 }
206207};
207208
......@@ -305,7 +306,7 @@ pub const Iterator = struct {
305306 if (locator_end_offset > stream_len)
306307 return error.ZipTruncated;
307308 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) {
309310 error.ReadFailed => return input.err.?,
310311 error.EndOfStream => return error.EndOfStream,
311312 };
......@@ -318,7 +319,7 @@ pub const Iterator = struct {
318319
319320 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) {
322323 error.ReadFailed => return input.err.?,
323324 error.EndOfStream => return error.EndOfStream,
324325 };
......@@ -374,7 +375,7 @@ pub const Iterator = struct {
374375 const header_zip_offset = self.cd_zip_offset + self.cd_record_offset;
375376 const input = self.input;
376377 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) {
378379 error.ReadFailed => return input.err.?,
379380 error.EndOfStream => return error.EndOfStream,
380381 };
......@@ -405,7 +406,7 @@ pub const Iterator = struct {
405406 const extra = extra_buf[0..header.extra_len];
406407
407408 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) {
409410 error.ReadFailed => return input.err.?,
410411 error.EndOfStream => return error.EndOfStream,
411412 };
......@@ -460,7 +461,7 @@ pub const Iterator = struct {
460461 options: ExtractOptions,
461462 filename_buf: []u8,
462463 dest: std.fs.Dir,
463 ) !u32 {
464 ) !void {
464465 if (filename_buf.len < self.filename_len)
465466 return error.ZipInsufficientBuffer;
466467 switch (self.compression_method) {
......@@ -470,13 +471,13 @@ pub const Iterator = struct {
470471 const filename = filename_buf[0..self.filename_len];
471472 {
472473 try stream.seekTo(self.header_zip_offset + @sizeOf(CentralDirectoryFileHeader));
473 try stream.interface.readSlice(filename);
474 try stream.interface.readSliceAll(filename);
474475 }
475476
476477 const local_data_header_offset: u64 = local_data_header_offset: {
477478 const local_header = blk: {
478479 try stream.seekTo(self.file_offset);
479 break :blk try stream.interface.takeStructEndian(LocalFileHeader, .little);
480 break :blk try stream.interface.takeStruct(LocalFileHeader, .little);
480481 };
481482 if (!std.mem.eql(u8, &local_header.signature, &local_file_header_sig))
482483 return error.ZipBadFileOffset;
......@@ -502,7 +503,7 @@ pub const Iterator = struct {
502503
503504 {
504505 try stream.seekTo(self.file_offset + @sizeOf(LocalFileHeader) + local_header.filename_len);
505 try stream.interface.readSlice(extra);
506 try stream.interface.readSliceAll(extra);
506507 }
507508
508509 var extra_offset: usize = 0;
......@@ -550,7 +551,7 @@ pub const Iterator = struct {
550551 if (self.uncompressed_size != 0)
551552 return error.ZipBadDirectorySize;
552553 try dest.makePath(filename[0 .. filename.len - 1]);
553 return std.hash.Crc32.hash(&.{});
554 return;
554555 }
555556
556557 const out_file = blk: {
......@@ -564,31 +565,36 @@ pub const Iterator = struct {
564565 break :blk try dest.createFile(filename, .{ .exclusive = true });
565566 };
566567 defer out_file.close();
567 var file_writer = out_file.writer();
568 var file_bw = file_writer.writer(&.{});
568 var out_file_buffer: [1024]u8 = undefined;
569 var file_writer = out_file.writer(&out_file_buffer);
569570 const local_data_file_offset: u64 =
570571 @as(u64, self.file_offset) +
571572 @as(u64, @sizeOf(LocalFileHeader)) +
572573 local_data_header_offset;
573574 try stream.seekTo(local_data_file_offset);
574 var limited_file_reader = stream.interface.limited(.limited(self.compressed_size));
575 var file_read_buffer: [1000]u8 = undefined;
576 var decompress_read_buffer: [1000]u8 = undefined;
577 var limited_br = limited_file_reader.reader().buffered(&file_read_buffer);
578 var decompress: Decompress = undefined;
579 var decompress_br = decompress.readable(&limited_br, self.compression_method, &decompress_read_buffer);
580 const start_out = file_bw.count;
581 var hash_writer = file_bw.hashed(std.hash.Crc32.init());
582 var hash_bw = hash_writer.writer(&.{});
583 decompress_br.readAll(&hash_bw, .limited(self.uncompressed_size)) catch |err| switch (err) {
584 error.ReadFailed => return stream.err.?,
585 error.WriteFailed => return file_writer.err.?,
586 error.EndOfStream => return error.ZipDecompressTruncated,
587 };
588 if (limited_file_reader.remaining.nonzero()) return error.ZipDecompressTruncated;
589 const written = file_bw.count - start_out;
590 if (written != self.uncompressed_size) return error.ZipUncompressSizeMismatch;
591 return hash_writer.hasher.final();
575
576 // TODO limit based on self.compressed_size
577
578 switch (self.compression_method) {
579 .store => {
580 stream.interface.streamExact64(&file_writer.interface, self.uncompressed_size) catch |err| switch (err) {
581 error.ReadFailed => return stream.err.?,
582 error.WriteFailed => return file_writer.err.?,
583 error.EndOfStream => return error.ZipDecompressTruncated,
584 };
585 },
586 .deflate => {
587 var flate_buffer: [flate.max_window_len]u8 = undefined;
588 var decompress: flate.Decompress = .init(&stream.interface, .raw, &flate_buffer);
589 decompress.reader.streamExact64(&file_writer.interface, self.uncompressed_size) catch |err| switch (err) {
590 error.ReadFailed => return stream.err.?,
591 error.WriteFailed => return file_writer.err orelse decompress.err.?,
592 error.EndOfStream => return error.ZipDecompressTruncated,
593 };
594 },
595 else => return error.UnsupportedCompressionMethod,
596 }
597 try file_writer.end();
592598 }
593599 };
594600};
......@@ -636,25 +642,21 @@ pub const ExtractOptions = struct {
636642 /// Allow filenames within the zip to use backslashes. Back slashes are normalized
637643 /// to forward slashes before forwarding them to platform APIs.
638644 allow_backslashes: bool = false,
639
640645 diagnostics: ?*Diagnostics = null,
646 verify_checksums: bool = false,
641647};
642648
643649/// Extract the zipped files to the given `dest` directory.
644650pub fn extract(dest: std.fs.Dir, fr: *File.Reader, options: ExtractOptions) !void {
651 if (options.verify_checksums) @panic("TODO unimplemented");
652
645653 var iter = try Iterator.init(fr);
646654
647655 var filename_buf: [std.fs.max_path_bytes]u8 = undefined;
648656 while (try iter.next()) |entry| {
649 const crc32 = try entry.extract(fr, options, &filename_buf, dest);
650 if (crc32 != entry.crc32)
651 return error.ZipCrcMismatch;
657 try entry.extract(fr, options, &filename_buf, dest);
652658 if (options.diagnostics) |d| {
653659 try d.nextFilename(filename_buf[0..entry.filename_len]);
654660 }
655661 }
656662}
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" {
27742774
27752775 // Test big integers
27762776 try std.testing.expectEqual(
2777 @as(f32, 36893488147419103231),
2777 @as(f32, 36893488147419103231.0),
27782778 try fromSlice(f32, gpa, "36893488147419103231", null, .{}),
27792779 );
27802780 try std.testing.expectEqual(
2781 @as(f32, -36893488147419103231),
2781 @as(f32, -36893488147419103231.0),
27822782 try fromSlice(f32, gpa, "-36893488147419103231", null, .{}),
27832783 );
27842784 try std.testing.expectEqual(@as(f128, 0x1ffffffffffffffff), try fromSlice(
......@@ -2788,7 +2788,7 @@ test "std.zon parse float" {
27882788 null,
27892789 .{},
27902790 ));
2791 try std.testing.expectEqual(@as(f32, 0x1ffffffffffffffff), try fromSlice(
2791 try std.testing.expectEqual(@as(f32, @floatFromInt(0x1ffffffffffffffff)), try fromSlice(
27922792 f32,
27932793 gpa,
27942794 "0x1ffffffffffffffff",
src/Compilation.zig+6-4
......@@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
18161816 if (options.skip_linker_dependencies) break :s .none;
18171817 const want = options.want_compiler_rt orelse is_exe_or_dyn_lib;
18181818 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)) {
18201820 if (output_mode == .Obj) break :s .zcu;
1821 if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64)
1822 break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
1821 if (switch (target_util.zigBackend(target, use_llvm)) {
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;
18231825 }
18241826 if (is_exe_or_dyn_lib) break :s .lib;
18251827 break :s .obj;
......@@ -1854,7 +1856,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
18541856 const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib);
18551857 if (!want_ubsan_rt) break :s .none;
18561858 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;
18581860 if (is_exe_or_dyn_lib) break :s .lib;
18591861 break :s .obj;
18601862 };
src/Package/Fetch.zig+20-81
......@@ -1203,12 +1203,11 @@ fn unpackResource(
12031203 return unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
12041204 },
12051205 .@"tar.gz" => {
1206 const reader = resource.reader();
1207 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);
1208 var dcp = std.compress.gzip.decompressor(br.reader());
1209 var adapter_buffer: [1024]u8 = undefined;
1210 var adapter = dcp.reader().adaptToNewApi(&adapter_buffer);
1211 return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1206 var adapter_buffer: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
1207 var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
1208 var flate_buffer: [std.compress.flate.max_window_len]u8 = undefined;
1209 var decompress: std.compress.flate.Decompress = .init(&adapter.new_interface, .gzip, &flate_buffer);
1210 return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
12121211 },
12131212 .@"tar.xz" => {
12141213 const gpa = f.arena.child_allocator;
......@@ -1352,7 +1351,10 @@ fn unzip(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {
13521351 ));
13531352 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, .{
13561358 .allow_backslashes = true,
13571359 .diagnostics = &diagnostics,
13581360 }) 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
13841386 defer pack_dir.close();
13851387 var pack_file = try pack_dir.createFile("pkg.pack", .{ .read = true });
13861388 defer pack_file.close();
1387 _ = try resource.fetch_stream.reader().readRemaining(pack_file.writer());
1388 try pack_file.sync();
1389 var pack_file_buffer: [4096]u8 = undefined;
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
13901395 var index_file = try pack_dir.createFile("pkg.idx", .{ .read = true });
13911396 defer index_file.close();
1397 var index_file_buffer: [2000]u8 = undefined;
1398 var index_file_writer = index_file.writer(&index_file_buffer);
13921399 {
13931400 const index_prog_node = f.prog_node.start("Index pack", 0);
13941401 defer index_prog_node.end();
1395 var buffer: [4096]u8 = undefined;
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();
1402 try git.indexPack(gpa, object_format, &pack_file_reader, &index_file_writer);
14001403 }
14011404
14021405 {
1406 var index_file_reader = index_file.reader(&index_file_buffer);
14031407 const checkout_prog_node = f.prog_node.start("Checkout", 0);
14041408 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);
14061411 defer repository.deinit();
14071412 var diagnostics: git.Diagnostics = .{ .allocator = arena };
14081413 try repository.checkout(out_dir, resource.want_oid, &diagnostics);
......@@ -2069,72 +2074,6 @@ const UnpackResult = struct {
20692074 }
20702075};
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
21382077test "tarball with duplicate paths" {
21392078 // This tarball has duplicate path 'dir1/file1' to simulate case sensitve
21402079 // file system on any file sytstem.
src/Package/Fetch/git.zig+463-10
......@@ -73,6 +73,33 @@ pub const Oid = union(Format) {
7373 }
7474 };
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
76103 pub fn fromBytes(oid_format: Format, bytes: []const u8) Oid {
77104 assert(bytes.len == oid_format.byteLength());
78105 return switch (oid_format) {
......@@ -80,8 +107,15 @@ pub const Oid = union(Format) {
80107 };
81108 }
82109
110<<<<<<< HEAD
83111 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
84117 return switch (oid_format) {
118<<<<<<< HEAD
85119 .sha1 => {
86120 var result: Oid = .{ .sha1 = undefined };
87121 try reader.readSlice(&result.sha1);
......@@ -92,6 +126,11 @@ pub const Oid = union(Format) {
92126 try reader.readSlice(&result.sha256);
93127 return result;
94128 },
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
95134 };
96135 }
97136
......@@ -261,7 +300,6 @@ pub const Repository = struct {
261300 };
262301 defer file.close();
263302 try file.writeAll(file_object.data);
264 try file.sync();
265303 },
266304 .symlink => {
267305 try repository.odb.seekOid(entry.oid);
......@@ -392,15 +430,27 @@ const Odb = struct {
392430
393431 /// Reads the object at the current position in the database.
394432 fn readObject(odb: *Odb) !Object {
433<<<<<<< HEAD
395434 var base_offset = odb.pack_file.pos;
396435 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
397441 var base_header: EntryHeader = undefined;
398442 var delta_offsets: std.ArrayListUnmanaged(u64) = .empty;
399443 defer delta_offsets.deinit(odb.allocator);
400444 const base_object = while (true) {
401445 if (odb.cache.get(base_offset)) |base_object| break base_object;
402446
447<<<<<<< HEAD
403448 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
404454 switch (base_header) {
405455 .ofs_delta => |ofs_delta| {
406456 try delta_offsets.append(odb.allocator, base_offset);
......@@ -410,10 +460,22 @@ const Odb = struct {
410460 .ref_delta => |ref_delta| {
411461 try delta_offsets.append(odb.allocator, base_offset);
412462 try odb.seekOid(ref_delta.base_object);
463<<<<<<< HEAD
413464 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
414470 },
415471 else => {
472<<<<<<< HEAD
416473 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
417479 errdefer odb.allocator.free(base_data);
418480 const base_object: Object = .{ .type = base_header.objectType(), .data = base_data };
419481 try odb.cache.put(odb.allocator, base_offset, base_object);
......@@ -443,8 +505,14 @@ const Odb = struct {
443505 const found_index = while (start_index < end_index) {
444506 const mid_index = start_index + (end_index - start_index) / 2;
445507 try odb.index_file.seekTo(IndexHeader.size + mid_index * oid_length);
508<<<<<<< HEAD
446509 var br = odb.index_file.interface().unbuffered();
447510 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
448516 switch (mem.order(u8, mid_oid.slice(), oid.slice())) {
449517 .lt => start_index = mid_index + 1,
450518 .gt => end_index = mid_index,
......@@ -456,14 +524,26 @@ const Odb = struct {
456524 const offset_values_start = IndexHeader.size + n_objects * (oid_length + 4);
457525 var buffer: [8]u8 = undefined;
458526 try odb.index_file.seekTo(offset_values_start + found_index * 4);
527<<<<<<< HEAD
459528 var br = odb.index_file.interface().buffered(&buffer);
460529 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
461535 const pack_offset = pack_offset: {
462536 if (l1_offset.big) {
463537 const l2_offset_values_start = offset_values_start + n_objects * 4;
464538 try odb.index_file.seekTo(l2_offset_values_start + l1_offset.value * 4);
539<<<<<<< HEAD
465540 br = odb.index_file.interface().buffered(&buffer);
466541 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
467547 } else {
468548 break :pack_offset l1_offset.value;
469549 }
......@@ -1119,12 +1199,48 @@ const PackHeader = struct {
11191199 const signature = "PACK";
11201200 const supported_version = 2;
11211201
1202<<<<<<< HEAD
11221203 fn read(reader: *std.io.Reader) !PackHeader {
11231204 const actual_signature = try reader.take(4);
11241205 if (!mem.eql(u8, actual_signature, signature)) return error.InvalidHeader;
11251206 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
11261230 if (version != supported_version) return error.UnsupportedVersion;
1231<<<<<<< HEAD
11271232 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
11281244 return .{ .total_objects = total_objects };
11291245 }
11301246};
......@@ -1173,10 +1289,30 @@ const EntryHeader = union(Type) {
11731289 };
11741290 }
11751291
1292<<<<<<< HEAD
11761293 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
11771299 const InitialByte = packed struct { len: u4, type: u3, has_next: bool };
1300<<<<<<< HEAD
11781301 const initial: InitialByte = @bitCast(try reader.takeByte());
11791302 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
11801316 var uncompressed_length: u64 = initial.len;
11811317 uncompressed_length |= std.math.shlExact(u64, rest_len, 4) catch return error.InvalidFormat;
11821318 const @"type" = std.enums.fromInt(EntryHeader.Type, initial.type) orelse return error.InvalidFormat;
......@@ -1199,8 +1335,15 @@ const EntryHeader = union(Type) {
11991335 }
12001336};
12011337
1338<<<<<<< HEAD
12021339fn readSizeVarInt(r: *std.io.Reader) !u64 {
1340||||||| 733b208256
1341fn readSizeVarInt(r: anytype) !u64 {
1342=======
1343fn readOffsetVarInt(r: *std.Io.Reader) !u64 {
1344>>>>>>> origin/flate
12031345 const Byte = packed struct { value: u7, has_next: bool };
1346<<<<<<< HEAD
12041347 var b: Byte = @bitCast(try r.takeByte());
12051348 var value: u64 = b.value;
12061349 var shift: u6 = 0;
......@@ -1215,6 +1358,24 @@ fn readSizeVarInt(r: *std.io.Reader) !u64 {
12151358fn readOffsetVarInt(r: *std.io.Reader) !u64 {
12161359 const Byte = packed struct { value: u7, has_next: bool };
12171360 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
12181379 var value: u64 = b.value;
12191380 while (b.has_next) {
12201381 b = @bitCast(try r.takeByte());
......@@ -1231,12 +1392,37 @@ const IndexHeader = struct {
12311392 const supported_version = 2;
12321393 const size = 4 + 4 + @sizeOf([256]u32);
12331394
1395<<<<<<< HEAD
12341396 fn read(index_header: *IndexHeader, br: *std.io.Reader) !void {
12351397 const sig = try br.take(4);
12361398 if (!mem.eql(u8, sig, signature)) return error.InvalidHeader;
12371399 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
12381411 if (version != supported_version) return error.UnsupportedVersion;
1412<<<<<<< HEAD
12391413 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
12401426 }
12411427};
12421428
......@@ -1305,10 +1491,18 @@ pub fn indexPack(
13051491 }
13061492 @memset(fan_out_table[fan_out_index..], count);
13071493
1494<<<<<<< HEAD
13081495 var index_writer_bw = index_writer.writer(&.{});
13091496 var index_hashed_writer = index_writer_bw.hashed(Oid.Hasher.init(format));
13101497 var write_buffer: [256]u8 = undefined;
13111498 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
13121506 try writer.writeAll(IndexHeader.signature);
13131507 try writer.writeInt(u32, IndexHeader.supported_version, .big);
13141508 for (fan_out_table) |fan_out_entry| {
......@@ -1342,7 +1536,14 @@ pub fn indexPack(
13421536 try writer.writeAll(pack_checksum.slice());
13431537 try writer.flush();
13441538 const index_checksum = index_hashed_writer.hasher.finalResult();
1539<<<<<<< HEAD
13451540 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
13461547}
13471548
13481549/// Performs the first pass over the packfile data for index construction.
......@@ -1356,11 +1557,29 @@ fn indexPackFirstPass(
13561557 index_entries: *std.AutoHashMapUnmanaged(Oid, IndexEntry),
13571558 pending_deltas: *std.ArrayListUnmanaged(IndexEntry),
13581559) !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;
13591570 var pack_buffer: [2048]u8 = undefined; // Reasonably large buffer for file system.
13601571 var pack_hashed = pack.interface.hashed(Oid.Hasher.init(format), &pack_buffer);
1572>>>>>>> origin/flate
13611573
1574<<<<<<< HEAD
13621575 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
13641583 for (0..pack_header.total_objects) |_| {
13651584 const entry_offset = pack.pos - pack_hashed.interface.buffered().len;
13661585 var entry_buffer: [64]u8 = undefined; // Buffer only needed for loading EntryHeader.
......@@ -1370,40 +1589,111 @@ fn indexPackFirstPass(
13701589 var entry_decompress_stream: zlib.Decompressor = .init(&entry_crc32_br);
13711590 // Decompress uses large output buffer; no input buffer needed.
13721591 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
13731603 switch (entry_header) {
13741604 .commit, .tree, .blob, .tag => |object| {
1605<<<<<<< HEAD
13751606 var oid_hasher = Oid.Hasher.init(format);
13761607 var oid_hasher_buffer: [zlib.max_window_len]u8 = undefined;
13771608 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
13781619 // The object header is not included in the pack data but is
1620<<<<<<< HEAD
13791621 // part of the object's ID.
13801622 try oid_hasher_bw.print("{s} {d}\x00", .{ @tagName(entry_header), object.uncompressed_length });
13811623 const n = try entry_decompress_br.readRemaining(&oid_hasher_bw);
13821624 if (n != object.uncompressed_length) return error.InvalidObject;
13831625 try oid_hasher_bw.flush();
13841626 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
13851644 try index_entries.put(allocator, oid, .{
13861645 .offset = entry_offset,
1387 .crc32 = entry_crc32_reader.hasher.final(),
1646 .crc32 = 0,
13881647 });
13891648 },
13901649 inline .ofs_delta, .ref_delta => |delta| {
1650<<<<<<< HEAD
13911651 const n = try entry_decompress_br.discardRemaining();
13921652 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
13931667 try pending_deltas.append(allocator, .{
13941668 .offset = entry_offset,
1395 .crc32 = entry_crc32_reader.hasher.final(),
1669 .crc32 = 0,
13961670 });
13971671 },
13981672 }
13991673 }
14001674
1675<<<<<<< HEAD
14011676 const pack_checksum = pack_hashed.hasher.finalResult();
14021677 const recorded_checksum = try Oid.readBytes(format, &pack.interface);
14031678 if (!mem.eql(u8, pack_checksum.slice(), recorded_checksum.slice())) {
14041679 return error.CorruptedPack;
14051680 }
14061681 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
14071697}
14081698
14091699/// Attempts to determine the final object ID of the given deltified object.
......@@ -1448,6 +1738,7 @@ fn indexPackHashDelta(
14481738
14491739 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
14501740
1741<<<<<<< HEAD
14511742 var entry_hasher: Oid.Hasher = .init(format);
14521743 var entry_hasher_buffer: [64]u8 = undefined;
14531744 var entry_hasher_bw = entry_hasher.writer(&entry_hasher_buffer);
......@@ -1456,6 +1747,21 @@ fn indexPackHashDelta(
14561747 entry_hasher_bw.writeAll(base_data) catch unreachable;
14571748 entry_hasher_bw.flush() catch unreachable;
14581749 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
14591765}
14601766
14611767/// Resolves a chain of deltas, returning the final base object data. `pack` is
......@@ -1477,6 +1783,7 @@ fn resolveDeltaChain(
14771783
14781784 const delta_offset = delta_offsets[i];
14791785 try pack.seekTo(delta_offset);
1786<<<<<<< HEAD
14801787 const delta_header = try EntryHeader.read(format, &pack.interface);
14811788 _ = delta_header;
14821789 var delta_decompress: zlib.Decompressor = .init(&pack.interface);
......@@ -1484,12 +1791,41 @@ fn resolveDeltaChain(
14841791 var delta_reader = delta_decompress.reader(&delta_decompress_buffer);
14851792 _ = try readSizeVarInt(&delta_reader); // base object size
14861793 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
14871812 const expanded_alloc_size = std.math.cast(usize, expanded_size) orelse return error.ObjectTooLarge;
14881813 const expanded_data = try allocator.alloc(u8, expanded_alloc_size);
14891814 errdefer allocator.free(expanded_data);
1815<<<<<<< HEAD
14901816 var expanded_delta_stream: Writer = .fixed(expanded_data);
14911817 try expandDelta(base_data, &delta_reader, &expanded_delta_stream);
14921818 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
14941830 try cache.put(allocator, delta_offset, .{ .type = base_object.type, .data = expanded_data });
14951831 base_data = expanded_data;
......@@ -1497,21 +1833,68 @@ fn resolveDeltaChain(
14971833 return base_data;
14981834}
14991835
1836<<<<<<< HEAD
15001837/// Reads the complete contents of an object from `reader`.
15011838fn 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
15021850 const alloc_size = std.math.cast(usize, size) orelse return error.ObjectTooLarge;
1851<<<<<<< HEAD
15031852 var decompress: zlib.Decompressor = .init(reader);
15041853 var buffer: std.ArrayListUnmanaged(u8) = .empty;
15051854 defer buffer.deinit(gpa);
15061855 try decompress.reader().readRemainingArrayList(gpa, null, &buffer, .limited(alloc_size), zlib.max_window_len);
15071856 if (buffer.items.len < size) return error.EndOfStream;
15081857 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
15091877}
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
15111888/// The format of the delta data is documented in
15121889/// [pack-format](https://git-scm.com/docs/pack-format).
1890<<<<<<< HEAD
15131891fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *Writer) !void {
15141892 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
15151898 while (true) {
15161899 const inst: packed struct { value: u7, copy: bool } = @bitCast(delta_reader.takeByte() catch |e| switch (e) {
15171900 error.EndOfStream => return,
......@@ -1533,7 +1916,13 @@ fn expandDelta(base_object: []const u8, delta_reader: *std.io.Reader, writer: *W
15331916 .offset3 = if (available.offset3) try delta_reader.takeByte() else 0,
15341917 .offset4 = if (available.offset4) try delta_reader.takeByte() else 0,
15351918 };
1919<<<<<<< HEAD
15361920 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
15371926 const size_parts: packed struct { size1: u8, size2: u8, size3: u8 } = .{
15381927 .size1 = if (available.size1) try delta_reader.takeByte() else 0,
15391928 .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
15411930 };
15421931 var size: u24 = @bitCast(size_parts);
15431932 if (size == 0) size = 0x10000;
1933<<<<<<< HEAD
15441934
15451935 try writer.writeAll(base_object[base_offset..][0..size]);
15461936 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
15471945 } else if (inst.value != 0) {
1946<<<<<<< HEAD
15481947 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
15491955 } else {
15501956 return error.InvalidDeltaInstruction;
15511957 }
......@@ -1575,25 +1981,46 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
15751981 defer pack_file.close();
15761982 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
15781987 var index_file = try git_dir.dir.createFile("testrepo.idx", .{ .read = true });
15791988 defer index_file.close();
1989<<<<<<< HEAD
15801990 var index_file_writer = index_file.writer();
15811991 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
15832000 // Arbitrary size limit on files read while checking the repository contents
15842001 // (all files in the test repo are known to be smaller than this)
15852002 const max_file_size = 8192;
15862003
1587 const index_file_data = try git_dir.dir.readFileAlloc(testing.allocator, "testrepo.idx", max_file_size);
1588 defer testing.allocator.free(index_file_data);
1589 // testrepo.idx is generated by Git. The index created by this file should
1590 // match it exactly. Running `git verify-pack -v testrepo.pack` can verify
1591 // this.
1592 const testrepo_idx = @embedFile("git/testdata/testrepo-" ++ @tagName(format) ++ ".idx");
1593 try testing.expectEqualSlices(u8, testrepo_idx, index_file_data);
2004 if (!skip_checksums) {
2005 const index_file_data = try git_dir.dir.readFileAlloc(testing.allocator, "testrepo.idx", max_file_size);
2006 defer testing.allocator.free(index_file_data);
2007 // testrepo.idx is generated by Git. The index created by this file should
2008 // match it exactly. Running `git verify-pack -v testrepo.pack` can verify
2009 // this.
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
15952015 var index_file_reader = index_file_writer.moveToReader();
15962016 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
15972024 defer repository.deinit();
15982025
15992026 var worktree = testing.tmpDir(.{ .iterate = true });
......@@ -1663,6 +2090,12 @@ fn runRepositoryTest(comptime format: Oid.Format, head_commit: []const u8) !void
16632090 try testing.expectEqualStrings(expected_file_contents, actual_file_contents);
16642091}
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
16662099test "SHA-1 packfile indexing and checkout" {
16672100 try runRepositoryTest(.sha1, "dd582c0720819ab7130b103635bd7271b9fd4feb");
16682101}
......@@ -1688,6 +2121,9 @@ pub fn main() !void {
16882121
16892122 var pack_file = try std.fs.cwd().openFile(args[2], .{});
16902123 defer pack_file.close();
2124 var pack_file_buffer: [4096]u8 = undefined;
2125 var pack_file_reader = pack_file.reader(&pack_file_buffer);
2126
16912127 const commit = try Oid.parse(format, args[3]);
16922128 var worktree = try std.fs.cwd().makeOpenPath(args[4], .{});
16932129 defer worktree.close();
......@@ -1698,15 +2134,32 @@ pub fn main() !void {
16982134 std.debug.print("Starting index...\n", .{});
16992135 var index_file = try git_dir.createFile("idx", .{ .read = true });
17002136 defer index_file.close();
2137<<<<<<< HEAD
17012138 var index_file_writer = index_file.writer();
17022139 var pack_file_reader = pack_file.reader();
17032140 try indexPack(gpa, format, &pack_file_reader, &index_file_writer);
17042141 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
17062153 std.debug.print("Starting checkout...\n", .{});
2154<<<<<<< HEAD
17072155 var index_file_reader = index_file_writer.moveToReader();
17082156 var repository: Repository = undefined;
17092157 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
17102163 defer repository.deinit();
17112164 var diagnostics: Diagnostics = .{ .allocator = gpa };
17122165 defer diagnostics.deinit();
src/Package/Module.zig+1-1
......@@ -250,7 +250,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
250250 };
251251
252252 const stack_check = b: {
253 if (!target_util.supportsStackProbing(target)) {
253 if (!target_util.supportsStackProbing(target, zig_backend)) {
254254 if (options.inherited.stack_check == true)
255255 return error.StackCheckUnsupportedByTarget;
256256 break :b false;
src/Sema.zig+223-603
......@@ -1905,8 +1905,12 @@ fn analyzeBodyInner(
19051905 const err_union = try sema.resolveInst(extra.data.operand);
19061906 const err_union_ty = sema.typeOf(err_union);
19071907 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
1908 return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{
1909 err_union_ty.fmt(pt),
1908 return sema.failWithOwnedErrorMsg(block, msg: {
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;
19101914 });
19111915 }
19121916 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,
39223926 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
39233927 const ptr_to_map = switch (store_inst.tag) {
39243928 .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
39263930 .optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself.
39273931 else => unreachable,
39283932 };
......@@ -4055,19 +4059,33 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
40554059 }
40564060
40574061 // 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`, or
4059 // `set_union_tag` instructions were already done above.
4062 // Any implicit stores performed by `optional_payload_ptr_set` or `errunion_payload_ptr_set`
4063 // instructions were already done above.
40604064
40614065 for (stores) |store_inst_idx| {
40624066 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
40634067 switch (store_inst.tag) {
4064 .set_union_tag => {}, // Handled implicitly by field pointers above
40654068 .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 },
40664084 .store, .store_safe => {
40674085 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
40684086 const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;
40694087 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));
40714089 },
40724090 else => unreachable,
40734091 }
......@@ -4099,14 +4117,13 @@ fn finishResolveComptimeKnownAllocPtr(
40994117 // We're almost done - we have the resolved comptime value. We just need to
41004118 // eliminate the now-dead runtime instructions.
41014119
4102 // We will rewrite the AIR to eliminate the alloc and all stores to it.
4103 // This will cause instructions deriving field pointers etc of the alloc to
4104 // become invalid, however, since we are removing all stores to those pointers,
4105 // they will be eliminated by Liveness before they reach codegen.
4106
4107 // The specifics of this instruction aren't really important: we just want
4108 // Liveness to elide it.
4109 const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{ .ty = .u8_type, .operand = .zero_u8 } } };
4120 // This instruction has type `alloc_ty`, meaning we can rewrite the `alloc` AIR instruction to
4121 // this one to drop the side effect. We also need to rewrite the stores; we'll turn them to this
4122 // too because it doesn't really matter what they become.
4123 const nop_inst: Air.Inst = .{ .tag = .bitcast, .data = .{ .ty_op = .{
4124 .ty = .fromIntern(alloc_ty.toIntern()),
4125 .operand = .zero_usize,
4126 } } };
41104127
41114128 sema.air_instructions.set(@intFromEnum(alloc_inst), nop_inst);
41124129 for (comptime_info.stores.items(.inst)) |store_inst| {
......@@ -4829,13 +4846,13 @@ fn zirValidatePtrStructInit(
48294846 agg_ty,
48304847 init_src,
48314848 instrs,
4849 object_ptr,
48324850 ),
48334851 .@"union" => return sema.validateUnionInit(
48344852 block,
48354853 agg_ty,
48364854 init_src,
48374855 instrs,
4838 object_ptr,
48394856 ),
48404857 else => unreachable,
48414858 }
......@@ -4847,164 +4864,28 @@ fn validateUnionInit(
48474864 union_ty: Type,
48484865 init_src: LazySrcLoc,
48494866 instrs: []const Zir.Inst.Index,
4850 union_ptr: Air.Inst.Ref,
48514867) CompileError!void {
4852 const pt = sema.pt;
4853 const zcu = pt.zcu;
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.
4868 if (instrs.len == 1) {
4869 // Trvial validation done, and the union tag was already set by machinery in `unionFieldPtr`.
48804870 return;
48814871 }
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];
4884 const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
4885 const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node });
4886 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
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;
4880 for (instrs[1..]) |inst| {
4881 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
4882 const inst_src = block.src(.{ .node_offset_initializer = inst_data.src_node });
4883 try sema.errNote(inst_src, msg, "additional initializer here", .{});
49274884 }
4928 switch (air_tags[@intFromEnum(store_inst)]) {
4929 .store, .store_safe => {},
4930 else => continue,
4931 }
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 }
4885 try sema.addDeclaredHereNote(msg, union_ty);
4886 break :msg msg;
4887 };
4888 return sema.failWithOwnedErrorMsg(block, msg);
50084889}
50094890
50104891fn validateStructInit(
......@@ -5013,187 +4894,62 @@ fn validateStructInit(
50134894 struct_ty: Type,
50144895 init_src: LazySrcLoc,
50154896 instrs: []const Zir.Inst.Index,
4897 struct_ptr: Air.Inst.Ref,
50164898) CompileError!void {
50174899 const pt = sema.pt;
50184900 const zcu = pt.zcu;
50194901 const gpa = sema.gpa;
50204902 const ip = &zcu.intern_pool;
50214903
5022 const field_indices = try gpa.alloc(u32, instrs.len);
5023 defer gpa.free(field_indices);
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));
4904 // Tracks whether each field was explicitly initialized.
4905 const found_fields = try gpa.alloc(bool, struct_ty.structFieldCount(zcu));
50274906 defer gpa.free(found_fields);
5028 @memset(found_fields, .none);
5029
5030 var struct_ptr_zir_ref: Zir.Inst.Ref = undefined;
4907 @memset(found_fields, false);
50314908
5032 for (instrs, field_indices) |field_ptr, *field_index| {
4909 for (instrs) |field_ptr| {
50334910 const field_ptr_data = sema.code.instructions.items(.data)[@intFromEnum(field_ptr)].pl_node;
50344911 const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node });
50354912 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;
50374913 const field_name = try ip.getOrPutString(
50384914 gpa,
50394915 pt.tid,
50404916 sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
50414917 .no_embedded_nulls,
50424918 );
5043 field_index.* = if (struct_ty.isTuple(zcu))
4919 const field_index = if (struct_ty.isTuple(zcu))
50444920 try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
50454921 else
50464922 try sema.structFieldIndex(block, struct_ty, field_name, field_src);
5047 assert(found_fields[field_index.*] == .none);
5048 found_fields[field_index.*] = field_ptr.toOptional();
4923 assert(found_fields[field_index] == false);
4924 found_fields[field_index] = true;
50494925 }
50504926
5051 var root_msg: ?*Zcu.ErrorMsg = null;
5052 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
5053
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);
4927 // Our job is simply to deal with default field values. Specifically, any field which was not
4928 // explicitly initialized must have its default value stored to the field pointer, or, if the
4929 // field has no default value, a compile error must be emitted instead.
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 initialization
5118 // ends up being comptime-known.
5119 const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(zcu));
4945 var root_msg: ?*Zcu.ErrorMsg = null;
4946 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
51204947
5121 field: for (found_fields, 0..) |opt_field_ptr, i_usize| {
4948 for (found_fields, 0..) |explicit, i_usize| {
4949 if (explicit) continue;
51224950 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);
51974953 const default_val = struct_ty.structFieldDefaultValue(i, zcu);
51984954 if (default_val.toIntern() == .unreachable_value) {
51994955 const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {
......@@ -5214,70 +4970,6 @@ fn validateStructInit(
52144970 }
52154971 continue;
52164972 }
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
52824974 const field_src = init_src; // TODO better source location
52834975 const default_field_ptr = if (struct_ty.isTuple(zcu))
......@@ -5285,8 +4977,13 @@ fn validateStructInit(
52854977 else
52864978 try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty);
52874979 try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr);
5288 const init = Air.internedToRef(field_values[i]);
5289 try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
4980 try sema.storePtr2(block, init_src, default_field_ptr, init_src, .fromValue(default_val), 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);
52904987 }
52914988}
52924989
......@@ -5307,15 +5004,14 @@ fn zirValidatePtrArrayInit(
53075004 const array_ty = sema.typeOf(array_ptr).childType(zcu).optEuBaseType(zcu);
53085005 const array_len = array_ty.arrayLen(zcu);
53095006
5310 // Collect the comptime element values in case the array literal ends up
5311 // being comptime-known.
5312 const element_vals = try sema.arena.alloc(
5313 InternPool.Index,
5314 try sema.usizeCast(block, init_src, array_len),
5315 );
5007 // Analagously to `validateStructInit`, our job is to handle default fields; either emitting AIR
5008 // to initialize them, or emitting a compile error if an unspecified field has no default. For
5009 // tuples, there are literally default field values, although they're guaranteed to be comptime
5010 // fields so we don't need to initialize them. For arrays, we may have a sentinel, which is never
5011 // specified so we always need to initialize here. For vectors, there's no such thing.
53165012
5317 if (instrs.len != array_len) switch (array_ty.zigTypeTag(zcu)) {
5318 .@"struct" => {
5013 switch (array_ty.zigTypeTag(zcu)) {
5014 .@"struct" => if (instrs.len != array_len) {
53195015 var root_msg: ?*Zcu.ErrorMsg = null;
53205016 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
53215017
......@@ -5332,8 +5028,6 @@ fn zirValidatePtrArrayInit(
53325028 }
53335029 continue;
53345030 }
5335
5336 element_vals[i] = default_val;
53375031 }
53385032
53395033 if (root_msg) |msg| {
......@@ -5341,162 +5035,25 @@ fn zirValidatePtrArrayInit(
53415035 return sema.failWithOwnedErrorMsg(block, msg);
53425036 }
53435037 },
5344 .array => {
5038
5039 .array => if (instrs.len != array_len) {
53455040 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{
53465041 array_len, instrs.len,
53475042 });
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);
53485048 },
5349 .vector => {
5049
5050 .vector => if (instrs.len != array_len) {
53505051 return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{
53515052 array_len, instrs.len,
53525053 });
53535054 },
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 = .{
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);
5056 else => unreachable,
55005057 }
55015058}
55025059
......@@ -5774,8 +5331,6 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
57745331 const tracy = trace(@src());
57755332 defer tracy.end();
57765333
5777 const pt = sema.pt;
5778 const zcu = pt.zcu;
57795334 const zir_tags = sema.code.instructions.items(.tag);
57805335 const zir_datas = sema.code.instructions.items(.data);
57815336 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
57895344 else
57905345 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
58025347 const ptr_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
58035348 const operand_src = block.src(.{ .node_offset_store_operand = inst_data.src_node });
58045349 const air_tag: Air.Inst.Tag = if (is_ret)
......@@ -14136,7 +13681,7 @@ fn zirShl(
1413613681 try sema.requireRuntimeBlock(block, src, runtime_src);
1413713682 if (block.wantSafety()) {
1413813683 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)) {
1414013685 const bit_count_val = try pt.intValue(scalar_rhs_ty, bit_count);
1414113686 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {
1414213687 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!
1863418179 const pt = sema.pt;
1863518180 const zcu = pt.zcu;
1863618181 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
18637 return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{
18638 err_union_ty.fmt(pt),
18182 return sema.failWithOwnedErrorMsg(parent_block, msg: {
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;
1863918188 });
1864018189 }
1864118190 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
1869418243 const pt = sema.pt;
1869518244 const zcu = pt.zcu;
1869618245 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
18697 return sema.fail(parent_block, operand_src, "expected error union type, found '{f}'", .{
18698 err_union_ty.fmt(pt),
18246 return sema.failWithOwnedErrorMsg(parent_block, msg: {
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;
1869918252 });
1870018253 }
1870118254 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
......@@ -20019,7 +19572,7 @@ fn structInitAnon(
2001919572 try sema.declareDependency(.{ .interned = struct_ty });
2002019573 try sema.addTypeReferenceEntry(src, struct_ty);
2002119574
20022 const runtime_index = opt_runtime_index orelse {
19575 _ = opt_runtime_index orelse {
2002319576 const struct_val = try pt.intern(.{ .aggregate = .{
2002419577 .ty = struct_ty,
2002519578 .storage = .{ .elems = values },
......@@ -20027,11 +19580,6 @@ fn structInitAnon(
2002719580 return sema.addConstantMaybeRef(struct_val, is_ref);
2002819581 };
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
2003519583 if (is_ref) {
2003619584 const target = zcu.getTarget();
2003719585 const alloc_ty = try pt.ptrTypeSema(.{
......@@ -20160,7 +19708,7 @@ fn zirArrayInit(
2016019708 if (!comptime_known) break @intCast(i);
2016119709 } else null;
2016219710
20163 const runtime_index = opt_runtime_index orelse {
19711 _ = opt_runtime_index orelse {
2016419712 const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len);
2016519713 for (elem_vals, resolved_args) |*val, arg| {
2016619714 // We checked that all args are comptime above.
......@@ -20175,11 +19723,6 @@ fn zirArrayInit(
2017519723 return sema.addConstantMaybeRef(result_val.toIntern(), is_ref);
2017619724 };
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
2018319726 if (is_ref) {
2018419727 const target = zcu.getTarget();
2018519728 const alloc_ty = try pt.ptrTypeSema(.{
......@@ -21089,6 +20632,16 @@ fn zirReify(
2108920632 }
2109020633 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
2109220645 const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });
2109320646
2109420647 return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
......@@ -22483,11 +22036,18 @@ fn ptrCastFull(
2248322036 .slice => {},
2248422037 .many, .c, .one => break :len null,
2248522038 }
22486 // `null` 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) {
22488 .one => 1,
22489 .slice => src_len: {
22490 const operand_val = try sema.resolveValue(operand) orelse break :src_len null;
22039 // A `null` length means the operand is a runtime-known slice (so the length is runtime-known).
22040 // `src_elem_type` is different from `src_info.child` if the latter is an array, to ensure we ignore sentinels.
22041 const src_elem_ty: Type, const opt_src_len: ?u64 = switch (src_info.flags.size) {
22042 .one => src: {
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 };
2249122051 if (operand_val.isUndef(zcu)) break :len .undef;
2249222052 const slice_val = switch (operand_ty.zigTypeTag(zcu)) {
2249322053 .optional => operand_val.optionalValue(zcu) orelse break :len .undef,
......@@ -22496,14 +22056,13 @@ fn ptrCastFull(
2249622056 };
2249722057 const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));
2249822058 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) };
2250022060 },
2250122061 .many, .c => {
2250222062 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});
2250322063 },
2250422064 };
2250522065 const dest_elem_ty: Type = .fromInterned(dest_info.child);
22506 const src_elem_ty: Type = .fromInterned(src_info.child);
2250722066 if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) {
2250822067 break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice;
2250922068 }
......@@ -22519,7 +22078,7 @@ fn ptrCastFull(
2251922078 const bytes = src_len * src_elem_size;
2252022079 const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {
2252122080 .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)}),
2252322082 else => unreachable,
2252422083 };
2252522084 break :len .{ .constant = dest_len };
......@@ -25052,6 +24611,7 @@ fn analyzeMinMax(
2505224611 } else {
2505324612 for (operands[1..], operand_srcs[1..]) |operand, operand_src| {
2505424613 const operand_ty = sema.typeOf(operand);
24614 try sema.checkNumericType(block, operand_src, operand_ty);
2505524615 if (operand_ty.zigTypeTag(zcu) == .vector) {
2505624616 return sema.failWithOwnedErrorMsg(block, msg: {
2505724617 const msg = try sema.errMsg(operand_srcs[0], "expected vector, found '{f}'", .{first_operand_ty.fmt(pt)});
......@@ -28009,15 +27569,24 @@ fn unionFieldPtr(
2800927569 return Air.internedToRef(field_ptr_val.toIntern());
2801027570 }
2801127571
28012 if (!initializing and union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and
28013 union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)
28014 {
28015 const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);
28016 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
28017 // TODO would it be better if get_union_tag supported pointers to unions?
28018 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
28019 const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_ty), union_val);
28020 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag);
27572 // If the union has a tag, we must either set or or safety check it depending on `initializing`.
27573 tag: {
27574 if (union_ty.containerLayout(zcu) != .auto) break :tag;
27575 const tag_ty: Type = .fromInterned(union_obj.enum_tag_ty);
27576 if (try sema.typeHasOnePossibleValue(tag_ty) != null) break :tag;
27577 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
27578 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
27579 const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
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 }
2802127590 }
2802227591 if (field_ty.zigTypeTag(zcu) == .noreturn) {
2802327592 _ = try block.addNoOp(.unreach);
......@@ -29166,17 +28735,36 @@ fn coerceExtra(
2916628735 break :int;
2916728736 };
2916828737 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);
29169 // TODO implement this compile error
29170 //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty);
29171 //if (!int_again_val.eql(val, inst_ty, zcu)) {
29172 // return sema.fail(
29173 // block,
29174 // inst_src,
29175 // "type '{f}' cannot represent integer value '{f}'",
29176 // .{ dest_ty.fmt(pt), val },
29177 // );
29178 //}
29179 return Air.internedToRef(result_val.toIntern());
28738 const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {
28739 else => unreachable,
28740 .undef => true,
28741 .float => |float| fits: {
28742 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
28743 const operand_big_int = val.toBigInt(&buffer, zcu);
28744 switch (float.storage) {
28745 inline else => |x| {
28746 if (!std.math.isFinite(x)) break :fits false;
28747 var result_big_int: std.math.big.int.Mutable = .{
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);
2918028768 },
2918128769 else => {},
2918228770 },
......@@ -32309,6 +31897,38 @@ fn analyzeSlice(
3230931897 break :e try sema.coerce(block, .usize, uncasted_end, end_src);
3231031898 } else break :e try sema.coerce(block, .usize, uncasted_end_opt, end_src);
3231131899 }
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 }
3231231932 return sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
3231331933 };
3231431934
src/Zcu.zig+6-1
......@@ -3859,7 +3859,12 @@ pub fn atomicPtrAlignment(
38593859 }
38603860 return .none;
38613861 }
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));
38633868 const bit_count = ty.intInfo(zcu).bits;
38643869 if (bit_count > max_atomic_bits) {
38653870 diags.* = .{
src/arch/x86_64/CodeGen.zig+33-24
......@@ -1103,11 +1103,7 @@ const FormatAirData = struct {
11031103 inst: Air.Inst.Index,
11041104};
11051105fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {
1106 // not acceptable implementation because it ignores `w`:
1107 //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1108 _ = data;
1109 _ = w;
1110 @panic("TODO: unimplemented");
1106 data.self.air.writeInst(w, data.inst, data.self.pt, data.self.liveness);
11111107}
11121108fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {
11131109 return .{ .data = .{ .self = self, .inst = inst } };
......@@ -168141,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168141168137 .unused,
168142168138 .unused,
168143168139 },
168144 .dst_temps = .{ .{ .cc = .b }, .unused },
168140 .dst_temps = .{ .{ .cc = .be }, .unused },
168145168141 .clobbers = .{ .eflags = true },
168146168142 .each = .{ .once = &.{
168147168143 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
......@@ -168165,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168165168161 .unused,
168166168162 .unused,
168167168163 },
168168 .dst_temps = .{ .{ .cc = .b }, .unused },
168164 .dst_temps = .{ .{ .cc = .be }, .unused },
168169168165 .clobbers = .{ .eflags = true },
168170168166 .each = .{ .once = &.{
168171168167 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
......@@ -168189,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168189168185 .unused,
168190168186 .unused,
168191168187 },
168192 .dst_temps = .{ .{ .cc = .b }, .unused },
168188 .dst_temps = .{ .{ .cc = .be }, .unused },
168193168189 .clobbers = .{ .eflags = true },
168194168190 .each = .{ .once = &.{
168195168191 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
......@@ -179300,10 +179296,13 @@ fn lowerSwitchBr(
179300179296 } else undefined;
179301179297 const table_start: u31 = @intCast(cg.mir_table.items.len);
179302179298 {
179303 const condition_index_reg = if (condition_index.isRegister())
179304 condition_index.getReg().?
179305 else
179306 try cg.copyToTmpRegister(.usize, condition_index);
179299 const condition_index_reg = condition_index_reg: {
179300 if (condition_index.isRegister()) {
179301 const condition_index_reg = condition_index.getReg().?;
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 };
179307179306 const condition_index_lock = cg.register_manager.lockReg(condition_index_reg);
179308179307 defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock);
179309179308 try cg.truncateRegister(condition_ty, condition_index_reg);
......@@ -191921,18 +191920,15 @@ const Select = struct {
191921191920 error.InvalidInstruction => {
191922191921 const fixes = @tagName(mir_tag[0]);
191923191922 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
191924 return s.cg.fail(
191925 "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'",
191926 .{
191927 fixes[0..fixes_blank],
191928 @tagName(mir_tag[1]),
191929 fixes[fixes_blank + 1 ..],
191930 @tagName(mir_ops[0]),
191931 @tagName(mir_ops[1]),
191932 @tagName(mir_ops[2]),
191933 @tagName(mir_ops[3]),
191934 },
191935 );
191923 return s.cg.fail("invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", .{
191924 fixes[0..fixes_blank],
191925 @tagName(mir_tag[1]),
191926 fixes[fixes_blank + 1 ..],
191927 @tagName(mir_ops[0]),
191928 @tagName(mir_ops[1]),
191929 @tagName(mir_ops[2]),
191930 @tagName(mir_ops[3]),
191931 });
191936191932 },
191937191933 else => |e| return e,
191938191934 };
......@@ -194424,6 +194420,18 @@ fn select(
194424194420 while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {
194425194421 if (try src_pattern.convert(src_temp, cg)) break;
194426194422 } 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 }
194427194435 @memcpy(s_src_temps[0..src_temps.len], src_temps);
194428194436 std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]);
194429194437
......@@ -194442,6 +194450,7 @@ fn select(
194442194450 }
194443194451 assert(s.top == 0);
194444194452
194453 for (src_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194445194454 for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194446194455 for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194447194456 caller_preserved: {
src/arch/x86_64/Emit.zig+6-5
......@@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void {
168168 else if (emit.bin_file.cast(.macho)) |macho_file|
169169 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
170170 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
171 else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: {
172 const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
173 return emit.fail("{s} creating lazy symbol", .{@errorName(err)});
174 break :sym_index coff_file.getAtom(atom).getSymbolIndex().?;
175 } else if (emit.bin_file.cast(.plan9)) |p9_file|
171 else if (emit.bin_file.cast(.coff)) |coff_file|
172 if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom|
173 coff_file.getAtom(atom).getSymbolIndex().?
174 else |err|
175 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
176 else if (emit.bin_file.cast(.plan9)) |p9_file|
176177 p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
177178 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
178179 else
src/codegen/aarch64.zig+36-23
......@@ -19,8 +19,12 @@ pub fn generate(
1919) !Mir {
2020 const zcu = pt.zcu;
2121 const gpa = zcu.gpa;
22 const ip = &zcu.intern_pool;
2223 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;
2428 assert(liveness.* == null);
2529
2630 const mod = zcu.navFileScope(func.owner_nav).mod.?;
......@@ -47,6 +51,7 @@ pub fn generate(
4751 .literals = .empty,
4852 .nav_relocs = .empty,
4953 .uav_relocs = .empty,
54 .lazy_relocs = .empty,
5055 .global_relocs = .empty,
5156 .literal_relocs = .empty,
5257
......@@ -60,23 +65,32 @@ pub fn generate(
6065 .values = .empty,
6166 };
6267 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
6471 const air_main_body = air.getMainBody();
6572 var param_it: Select.CallAbiIterator = .init;
6673 const air_args = for (air_main_body, 0..) |air_inst_index, body_index| {
6774 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();
69 const param_vi = try param_it.param(&isel, param_ty);
75 const arg = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg;
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 };
7084 tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) });
7185 try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?);
7286 } else unreachable;
7387
7488 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;
7690 const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start);
7791
7892 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;
8094 const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start);
8195
8296 const frame_record = 2;
......@@ -84,11 +98,16 @@ pub fn generate(
8498 .base = .fp,
8599 .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2),
86100 };
87 isel.va_list = .{
88 .__stack = named_stack_args.withOffset(param_it.nsaa),
89 .__gr_top = named_stack_args,
90 .__vr_top = .{ .base = .fp, .offset = 0 },
91 };
101 const stack_var_args = named_stack_args.withOffset(param_it.nsaa);
102 const gr_top = named_stack_args;
103 const vr_top: Select.Value.Indirect = .{ .base = .fp, .offset = 0 };
104 isel.va_list = if (is_sysv) .{ .sysv = .{
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
93112 // translate arg locations from caller-based to callee-based
94113 for (air_args) |air_inst_index| {
......@@ -101,15 +120,13 @@ pub fn generate(
101120 };
102121 switch (passed_vi.parent(&isel)) {
103122 .unallocated => if (!mod.strip) {
104 var part_it = arg_vi.parts(&isel);
105 const first_passed_part_vi = part_it.next() orelse passed_vi;
123 var part_it = passed_vi.parts(&isel);
124 const first_passed_part_vi = part_it.next().?;
106125 const hint_ra = first_passed_part_vi.hint(&isel).?;
107126 passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())
108 isel.va_list.__vr_top.withOffset(@as(i8, -16) *
109 (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
127 vr_top.withOffset(@as(i8, -16) * (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
110128 else
111 isel.va_list.__gr_top.withOffset(@as(i8, -8) *
112 (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
129 gr_top.withOffset(@as(i8, -8) * (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
113130 },
114131 .stack_slot => |stack_slot| {
115132 assert(stack_slot.base == .sp);
......@@ -151,13 +168,7 @@ pub fn generate(
151168 isel.verify(true);
152169
153170 const prologue = isel.instructions.items.len;
154 const epilogue = try isel.layout(
155 param_it,
156 func_type.is_var_args,
157 saved_gra_len,
158 saved_vra_len,
159 mod,
160 );
171 const epilogue = try isel.layout(param_it, is_sysv_var_args, saved_gra_len, saved_vra_len, mod);
161172
162173 const instructions = try isel.instructions.toOwnedSlice(gpa);
163174 var mir: Mir = .{
......@@ -167,6 +178,7 @@ pub fn generate(
167178 .literals = &.{},
168179 .nav_relocs = &.{},
169180 .uav_relocs = &.{},
181 .lazy_relocs = &.{},
170182 .global_relocs = &.{},
171183 .literal_relocs = &.{},
172184 };
......@@ -174,6 +186,7 @@ pub fn generate(
174186 mir.literals = try isel.literals.toOwnedSlice(gpa);
175187 mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);
176188 mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);
189 mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa);
177190 mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);
178191 mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);
179192 return mir;
src/codegen/aarch64/Assemble.zig+26-6
......@@ -6,14 +6,19 @@ pub const Operand = union(enum) {
66};
77
88pub fn nextInstruction(as: *Assemble) !?Instruction {
9 @setEvalBranchQuota(37_000);
9 @setEvalBranchQuota(42_000);
1010 comptime var ct_token_buf: [token_buf_len]u8 = undefined;
1111 var token_buf: [token_buf_len]u8 = undefined;
1212 const original_source = while (true) {
1313 const original_source = as.source;
1414 const source_token = try as.nextToken(&token_buf, .{});
15 if (source_token.len == 0) return null;
16 if (source_token[0] != '\n') break original_source;
15 switch (source_token.len) {
16 0 => return null,
17 else => switch (source_token[0]) {
18 else => break original_source,
19 '\n', ';' => {},
20 },
21 }
1722 };
1823 log.debug(
1924 \\.
......@@ -52,7 +57,13 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
5257 std.zig.fmtString(source_token),
5358 });
5459 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 }
5667 const encode = @field(Instruction, @tagName(instruction.encode[0]));
5768 const Encode = @TypeOf(encode);
5869 var args: std.meta.ArgsTuple(Encode) = undefined;
......@@ -65,7 +76,7 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
6576 const symbol = &@field(symbols, symbol_name);
6677 symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;
6778 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;
6980 }
7081 }
7182 log.debug("'{s}' not matched...", .{instruction.pattern});
......@@ -125,6 +136,15 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
125136 }
126137}
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
128148const token_buf_len = "v31.b[15]".len;
129149fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
130150 operands: bool = false,
......@@ -134,7 +154,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
134154 while (true) c: switch (as.source[0]) {
135155 0 => return as.source[0..0],
136156 '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..],
137 '\n', '!', '#', ',', '[', ']' => {
157 '\n', '!', '#', ',', ';', '[', ']' => {
138158 defer as.source = as.source[1..];
139159 return as.source[0..1];
140160 },
src/codegen/aarch64/Mir.zig+106-33
......@@ -4,6 +4,7 @@ epilogue: []const Instruction,
44literals: []const u32,
55nav_relocs: []const Reloc.Nav,
66uav_relocs: []const Reloc.Uav,
7lazy_relocs: []const Reloc.Lazy,
78global_relocs: []const Reloc.Global,
89literal_relocs: []const Reloc.Literal,
910
......@@ -21,8 +22,13 @@ pub const Reloc = struct {
2122 reloc: Reloc,
2223 };
2324
25 pub const Lazy = struct {
26 symbol: link.File.LazySymbol,
27 reloc: Reloc,
28 };
29
2430 pub const Global = struct {
25 global: [*:0]const u8,
31 name: [*:0]const u8,
2632 reloc: Reloc,
2733 };
2834
......@@ -38,6 +44,7 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
3844 gpa.free(mir.literals);
3945 gpa.free(mir.nav_relocs);
4046 gpa.free(mir.uav_relocs);
47 gpa.free(mir.lazy_relocs);
4148 gpa.free(mir.global_relocs);
4249 gpa.free(mir.literal_relocs);
4350 mir.* = undefined;
......@@ -119,16 +126,37 @@ pub fn emit(
119126 body_end - Instruction.size * (1 + uav_reloc.reloc.label),
120127 uav_reloc.reloc.addend,
121128 );
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 );
122150 for (mir.global_relocs) |global_reloc| try emitReloc(
123151 lf,
124152 zcu,
125153 func.owner_nav,
126154 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)
128156 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)
130158 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")
132160 else
133161 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
134162 mir.body[global_reloc.reloc.label],
......@@ -172,35 +200,6 @@ fn emitReloc(
172200 const gpa = zcu.gpa;
173201 switch (instruction.decode()) {
174202 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 },
204203 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
205204 const zo = ef.zigObjectPtr().?;
206205 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
......@@ -259,6 +258,80 @@ fn emitReloc(
259258 },
260259 }
261260 },
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 },
262335 }
263336}
264337
src/codegen/aarch64/Select.zig+2031-547
......@@ -22,15 +22,21 @@ instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction),
2222literals: std.ArrayListUnmanaged(u32),
2323nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav),
2424uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav),
25lazy_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Lazy),
2526global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global),
2627literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal),
2728
2829// Stack Frame
2930returns: bool,
30va_list: struct {
31 __stack: Value.Indirect,
32 __gr_top: Value.Indirect,
33 __vr_top: Value.Indirect,
31va_list: union(enum) {
32 other: Value.Indirect,
33 sysv: struct {
34 __stack: Value.Indirect,
35 __gr_top: Value.Indirect,
36 __vr_top: Value.Indirect,
37 __gr_offs: i32,
38 __vr_offs: i32,
39 },
3440},
3541stack_size: u24,
3642stack_align: InternPool.Alignment,
......@@ -50,11 +56,11 @@ pub const Block = struct {
5056 std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),
5157 );
5258
53 fn branch(block: *const Block, isel: *Select) !void {
54 if (isel.instructions.items.len > block.target_label) {
55 try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - block.target_label) << 2)));
59 fn branch(target_block: *const Block, isel: *Select) !void {
60 if (isel.instructions.items.len > target_block.target_label) {
61 try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - target_block.target_label) << 2)));
5662 }
57 try isel.merge(&block.live_registers, .{});
63 try isel.merge(&target_block.live_registers, .{});
5864 }
5965};
6066
......@@ -84,12 +90,12 @@ pub const Loop = struct {
8490
8591 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 {
8894 try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1);
89 const repeat_list_tail = loop.repeat_list;
90 loop.repeat_list = @intCast(isel.instructions.items.len);
95 const repeat_list_tail = target_loop.repeat_list;
96 target_loop.repeat_list = @intCast(isel.instructions.items.len);
9197 isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail));
92 try isel.merge(&loop.live_registers, .{});
98 try isel.merge(&target_loop.live_registers, .{});
9399 }
94100};
95101
......@@ -108,6 +114,7 @@ pub fn deinit(isel: *Select) void {
108114 isel.literals.deinit(gpa);
109115 isel.nav_relocs.deinit(gpa);
110116 isel.uav_relocs.deinit(gpa);
117 isel.lazy_relocs.deinit(gpa);
111118 isel.global_relocs.deinit(gpa);
112119 isel.literal_relocs.deinit(gpa);
113120
......@@ -406,13 +413,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
406413
407414 air_body_index += 1;
408415 },
409 .breakpoint,
410 .dbg_stmt,
411 .dbg_empty_stmt,
412 .dbg_var_ptr,
413 .dbg_var_val,
414 .dbg_arg_inline,
415 => {
416 .breakpoint, .dbg_stmt, .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, .c_va_end => {
416417 air_body_index += 1;
417418 air_inst_index = air_body[air_body_index];
418419 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 {
426427 const extra = isel.air.extraData(Air.Call, pl_op.payload);
427428 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
428429 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
430437 try isel.analyzeUse(pl_op.operand);
431438 var param_it: CallAbiIterator = .init;
432 for (args) |arg| {
439 for (args, 0..) |arg, arg_index| {
433440 const restore_values_len = isel.values.items.len;
434441 defer isel.values.shrinkRetainingCapacity(restore_values_len);
435 const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;
436 const param_parent = param_vi.parent(isel);
437 switch (switch (param_parent) {
438 .unallocated, .stack_slot => param_parent,
442 const param_vi = param_vi: {
443 const param_ty = isel.air.typeOf(arg, ip);
444 if (arg_index >= func_info.param_types.len) {
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,
439456 .value, .constant => unreachable,
440 .address => |address_vi| address_vi.parent(isel),
441 }) {
457 .address => |address_vi| address_vi,
458 };
459 switch (passed_vi.parent(isel)) {
442460 .unallocated => {},
443461 .stack_slot => |stack_slot| {
444462 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 );
446467 },
447468 .value, .constant, .address => unreachable,
448469 }
......@@ -582,7 +603,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
582603
583604 air_body_index += 1;
584605 },
585 .@"try", .try_cold, .try_ptr, .try_ptr_cold => {
606 .@"try", .try_cold => {
586607 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
587608 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 {
594615 air_inst_index = air_body[air_body_index];
595616 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
596617 },
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 },
597630 .ret, .ret_safe, .ret_load => {
598631 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
599632 isel.returns = true;
......@@ -788,7 +821,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
788821 air_inst_index = air_body[air_body_index];
789822 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
790823 },
791 .set_err_return_trace, .c_va_end => {
824 .set_err_return_trace => {
792825 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
793826
794827 try isel.analyzeUse(un_op);
......@@ -864,7 +897,7 @@ pub fn finishAnalysis(isel: *Select) !void {
864897 }
865898}
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 {
868901 const zcu = isel.pt.zcu;
869902 const ip = &zcu.intern_pool;
870903 const gpa = zcu.gpa;
......@@ -946,7 +979,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
946979 }
947980 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
948981 },
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| {
950983 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
951984 defer res_vi.value.deref(isel);
952985
......@@ -954,13 +987,16 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
954987 const ty = isel.air.typeOf(bin_op.lhs, ip);
955988 if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) {
956989 else => unreachable,
957 .add, .add_wrap => .add,
958 .sub, .sub_wrap => .sub,
959 }, try isel.use(bin_op.rhs), .{ .wrap = switch (air_tag) {
960 else => unreachable,
961 .add, .sub => false,
962 .add_wrap, .sub_wrap => true,
963 } }) else switch (ty.floatBits(isel.target)) {
990 .add, .add_safe, .add_wrap => .add,
991 .sub, .sub_safe, .sub_wrap => .sub,
992 }, try isel.use(bin_op.rhs), .{
993 .overflow = switch (air_tag) {
994 else => unreachable,
995 .add, .sub => .@"unreachable",
996 .add_safe, .sub_safe => .{ .panic = .integer_overflow },
997 .add_wrap, .sub_wrap => .wrap,
998 },
999 }) else switch (ty.floatBits(isel.target)) {
9641000 else => unreachable,
9651001 16, 32, 64 => |bits| {
9661002 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 {
10211057
10221058 try call.prepareCallee(isel);
10231059 try isel.global_relocs.append(gpa, .{
1024 .global = switch (air_tag) {
1060 .name = switch (air_tag) {
10251061 else => unreachable,
10261062 .add, .add_optimized => switch (bits) {
10271063 else => unreachable,
......@@ -1336,7 +1372,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
13361372
13371373 try call.prepareCallee(isel);
13381374 try isel.global_relocs.append(gpa, .{
1339 .global = switch (bits) {
1375 .name = switch (bits) {
13401376 else => unreachable,
13411377 16 => "__mulhf3",
13421378 32 => "__mulsf3",
......@@ -1379,6 +1415,143 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
13791415 }
13801416 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
13811417 },
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 },
13821555 .mul_sat => |air_tag| {
13831556 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
13841557 defer res_vi.value.deref(isel);
......@@ -1674,7 +1847,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
16741847
16751848 try call.prepareCallee(isel);
16761849 try isel.global_relocs.append(gpa, .{
1677 .global = switch (bits) {
1850 .name = switch (bits) {
16781851 else => unreachable,
16791852 16 => "__divhf3",
16801853 32 => "__divsf3",
......@@ -1746,8 +1919,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
17461919 switch (bits) {
17471920 else => unreachable,
17481921 1...32 => {
1749 try isel.emit(.sub(res_ra.w(), div_ra.w(), .{ .register = rem_ra.w() }));
1750 try isel.emit(.csinc(rem_ra.w(), .wzr, .wzr, .ge));
1922 try isel.emit(.csel(res_ra.w(), div_ra.w(), rem_ra.w(), .pl));
1923 try isel.emit(.sub(rem_ra.w(), div_ra.w(), .{ .immediate = 1 }));
17511924 try isel.emit(.ccmp(
17521925 rem_ra.w(),
17531926 .{ .immediate = 0 },
......@@ -1759,8 +1932,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
17591932 try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
17601933 },
17611934 33...64 => {
1762 try isel.emit(.sub(res_ra.x(), div_ra.x(), .{ .register = rem_ra.x() }));
1763 try isel.emit(.csinc(rem_ra.x(), .xzr, .xzr, .ge));
1935 try isel.emit(.csel(res_ra.x(), div_ra.x(), rem_ra.x(), .pl));
1936 try isel.emit(.sub(rem_ra.x(), div_ra.x(), .{ .immediate = 1 }));
17641937 try isel.emit(.ccmp(
17651938 rem_ra.x(),
17661939 .{ .immediate = 0 },
......@@ -1813,7 +1986,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
18131986
18141987 try call.prepareCallee(isel);
18151988 try isel.global_relocs.append(gpa, .{
1816 .global = switch (int_info.signedness) {
1989 .name = switch (int_info.signedness) {
18171990 .signed => "__divti3",
18181991 .unsigned => "__udivti3",
18191992 },
......@@ -1917,7 +2090,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
19172090 else => unreachable,
19182091 .div_trunc, .div_trunc_optimized => {
19192092 try isel.global_relocs.append(gpa, .{
1920 .global = switch (bits) {
2093 .name = switch (bits) {
19212094 else => unreachable,
19222095 16 => "__trunch",
19232096 32 => "truncf",
......@@ -1931,7 +2104,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
19312104 },
19322105 .div_floor, .div_floor_optimized => {
19332106 try isel.global_relocs.append(gpa, .{
1934 .global = switch (bits) {
2107 .name = switch (bits) {
19352108 else => unreachable,
19362109 16 => "__floorh",
19372110 32 => "floorf",
......@@ -1946,7 +2119,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
19462119 .div_exact, .div_exact_optimized => {},
19472120 }
19482121 try isel.global_relocs.append(gpa, .{
1949 .global = switch (bits) {
2122 .name = switch (bits) {
19502123 else => unreachable,
19512124 16 => "__divhf3",
19522125 32 => "__divsf3",
......@@ -1989,7 +2162,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
19892162 }
19902163 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
19912164 },
1992 .rem => |air_tag| {
2165 .rem, .rem_optimized, .mod, .mod_optimized => |air_tag| {
19932166 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
19942167 defer res_vi.value.deref(isel);
19952168
......@@ -2007,17 +2180,57 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
20072180 const rhs_mat = try rhs_vi.matReg(isel);
20082181 const div_ra = try isel.allocIntReg();
20092182 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);
20102223 switch (int_info.bits) {
20112224 else => unreachable,
20122225 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()));
20142227 try isel.emit(switch (int_info.signedness) {
20152228 .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
20162229 .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
20172230 });
20182231 },
20192232 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()));
20212234 try isel.emit(switch (int_info.signedness) {
20222235 .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
20232236 .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 {
20282241 try lhs_mat.finish(isel);
20292242 } else {
20302243 const bits = ty.floatBits(isel.target);
2031
2032 try call.prepareReturn(isel);
2033 switch (bits) {
2244 switch (air_tag) {
20342245 else => unreachable,
2035 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2036 80 => {
2037 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2038 const res_hi16_vi = try res_hi16_it.only(isel);
2039 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2040 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2041 const res_lo64_vi = try res_lo64_it.only(isel);
2042 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2246 .rem, .rem_optimized => {
2247 if (!res_vi.value.isUsed(isel)) break :unused;
2248 try call.prepareReturn(isel);
2249 switch (bits) {
2250 else => unreachable,
2251 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2252 80 => {
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 },
20432420 },
20442421 }
2045 try call.finishReturn(isel);
20462422
20472423 try call.prepareCallee(isel);
20482424 try isel.global_relocs.append(gpa, .{
2049 .global = switch (bits) {
2425 .name = switch (bits) {
20502426 else => unreachable,
20512427 16 => "__fmodh",
20522428 32 => "fmodf",
......@@ -2212,7 +2588,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
22122588
22132589 try call.prepareCallee(isel);
22142590 try isel.global_relocs.append(gpa, .{
2215 .global = switch (air_tag) {
2591 .name = switch (air_tag) {
22162592 else => unreachable,
22172593 .max => switch (bits) {
22182594 else => unreachable,
......@@ -2284,7 +2660,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
22842660 else => unreachable,
22852661 .add_with_overflow => .add,
22862662 .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 });
22882666 }
22892667 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
22902668 },
......@@ -2318,6 +2696,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
23182696 }
23192697 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
23202698 },
2699 .inferred_alloc, .inferred_alloc_comptime => unreachable,
23212700 .assembly => {
23222701 const ty_pl = air.data(air.inst_index).ty_pl;
23232702 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 {
30853464 assert(dst_int_info.bits == src_child_int_info.bits * src_len);
30863465 const src_child_size = src_ty.childType(zcu).abiSize(zcu);
30873466 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
30903469 try call.prepareReturn(isel);
30913470 try call.finishReturn(isel);
30923471
30933472 try call.prepareCallee(isel);
30943473 try isel.global_relocs.append(gpa, .{
3095 .global = "memcpy",
3474 .name = "memcpy",
30963475 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
30973476 });
30983477 try isel.emit(.bl(0));
......@@ -3112,14 +3491,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
31123491 assert(dst_child_int_info.bits * dst_len == src_int_info.bits);
31133492 const dst_child_size = dst_ty.childType(zcu).abiSize(zcu);
31143493 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
31173496 try call.prepareReturn(isel);
31183497 try call.finishReturn(isel);
31193498
31203499 try call.prepareCallee(isel);
31213500 try isel.global_relocs.append(gpa, .{
3122 .global = "memcpy",
3501 .name = "memcpy",
31233502 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
31243503 });
31253504 try isel.emit(.bl(0));
......@@ -3139,19 +3518,9 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
31393518 .block => {
31403519 const ty_pl = air.data(air.inst_index).ty_pl;
31413520 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
3142
3143 if (ty_pl.ty != .noreturn_type) {
3144 isel.blocks.putAssumeCapacityNoClobber(air.inst_index, .{
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 }
3521 try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
3522 isel.air.extra.items[extra.end..][0..extra.data.body_len],
3523 ));
31553524 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
31563525 },
31573526 .loop => {
......@@ -3175,11 +3544,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
31753544 }
31763545
31773546 // IT'S DOM TIME!!!
3178 for (isel.blocks.values(), 0..) |*block, dom_index| {
3547 for (isel.blocks.values(), 0..) |*dom_block, dom_index| {
31793548 if (@as(u1, @truncate(isel.dom.items[
31803549 loop.dom + dom_index / @bitSizeOf(DomInt)
31813550 ] >> @truncate(dom_index))) == 0) continue;
3182 var live_reg_it = block.live_registers.iterator();
3551 var live_reg_it = dom_block.live_registers.iterator();
31833552 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
31843553 _ => |live_vi| try live_vi.mat(isel),
31853554 .allocating => unreachable,
......@@ -3211,8 +3580,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
32113580 },
32123581 .br => {
32133582 const br = air.data(air.inst_index).br;
3214 const block = isel.blocks.getPtr(br.block_inst).?;
3215 try block.branch(isel);
3583 try isel.blocks.getPtr(br.block_inst).?.branch(isel);
32163584 if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand);
32173585 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
32183586 },
......@@ -3224,10 +3592,32 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
32243592 try isel.emit(.brk(0xf000));
32253593 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
32263594 },
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 },
32273611 .call => {
32283612 const pl_op = air.data(air.inst_index).pl_op;
32293613 const extra = isel.air.extraData(Air.Call, pl_op.payload);
32303614 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
32323622 try call.prepareReturn(isel);
32333623 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 {
32513641 .value, .constant => unreachable,
32523642 .address => |address_vi| {
32533643 maybe_ret_addr_vi = address_vi;
3254 _ = try def_ret_vi.value.defAddr(
3255 isel,
3256 isel.air.typeOfIndex(air.inst_index, ip),
3257 null,
3258 &call.caller_saved_regs,
3259 );
3644 _ = try def_ret_vi.value.defAddr(isel, isel.air.typeOfIndex(air.inst_index, ip), .{
3645 .expected_live_registers = &call.caller_saved_regs,
3646 });
32603647 },
32613648 }
32623649 }
......@@ -3294,41 +3681,50 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
32943681 ret_addr_vi.hint(isel).?,
32953682 );
32963683 var param_it: CallAbiIterator = .init;
3297 for (args) |arg| {
3298 const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;
3684 for (args, 0..) |arg, arg_index| {
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;
32993696 defer param_vi.deref(isel);
33003697 const arg_vi = try isel.use(arg);
3301 const passed_vi = switch (param_vi.parent(isel)) {
3302 .unallocated, .stack_slot => param_vi,
3303 .value, .constant => unreachable,
3304 .address => |address_vi| {
3305 try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?);
3306 continue;
3698 switch (param_vi.parent(isel)) {
3699 .unallocated => if (param_vi.hint(isel)) |param_ra| {
3700 try call.paramLiveOut(isel, arg_vi, param_ra);
3701 } else {
3702 var param_part_it = param_vi.parts(isel);
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 }
33073722 },
3308 };
3309 if (passed_vi.hint(isel)) |param_ra| {
3310 try call.paramLiveOut(isel, arg_vi, param_ra);
3311 } else {
3312 var param_part_it = passed_vi.parts(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 }
3723 .stack_slot => |stack_slot| try arg_vi.store(isel, param_ty, stack_slot.base, .{
3724 .offset = @intCast(stack_slot.offset),
3725 }),
3726 .value, .constant => unreachable,
3727 .address => |address_vi| try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?),
33323728 }
33333729 }
33343730 try call.finishParams(isel);
......@@ -3659,7 +4055,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
36594055
36604056 try call.prepareCallee(isel);
36614057 try isel.global_relocs.append(gpa, .{
3662 .global = switch (air_tag) {
4058 .name = switch (air_tag) {
36634059 else => unreachable,
36644060 .sqrt => switch (bits) {
36654061 else => unreachable,
......@@ -3751,7 +4147,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
37514147
37524148 try call.prepareCallee(isel);
37534149 try isel.global_relocs.append(gpa, .{
3754 .global = switch (air_tag) {
4150 .name = switch (air_tag) {
37554151 else => unreachable,
37564152 .sin => switch (bits) {
37574153 else => unreachable,
......@@ -4239,7 +4635,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
42394635
42404636 try call.prepareCallee(isel);
42414637 try isel.global_relocs.append(gpa, .{
4242 .global = switch (bits) {
4638 .name = switch (bits) {
42434639 else => unreachable,
42444640 16 => "__cmphf2",
42454641 32 => "__cmpsf2",
......@@ -4328,7 +4724,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
43284724 };
43294725 var cond_mat: ?Value.Materialize = null;
43304726 var cond_reg: Register = undefined;
4331 var temp_reg: Register = undefined;
43324727 var cases_it = switch_br.iterateCases();
43334728 while (cases_it.next()) |case| {
43344729 const next_label = isel.instructions.items.len;
......@@ -4342,11 +4737,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
43424737 if (cond_mat == null) {
43434738 var cond_vi = try isel.use(switch_br.operand);
43444739 cond_mat = try cond_vi.matReg(isel);
4345 const temp_ra = try isel.allocIntReg();
4346 cond_reg, temp_reg = switch (cond_int_info.bits) {
4740 cond_reg = switch (cond_int_info.bits) {
43474741 else => unreachable,
4348 1...32 => .{ cond_mat.?.ra.w(), temp_ra.w() },
4349 33...64 => .{ cond_mat.?.ra.x(), temp_ra.x() },
4742 1...32 => cond_mat.?.ra.w(),
4743 33...64 => cond_mat.?.ra.x(),
43504744 };
43514745 }
43524746 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 {
43874781 ) else high_bigint.toInt(i64) catch
43884782 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 };
43904794 const delta_int = high_int -% low_int;
4391 if (case_range_index > 0) {
4392 return isel.fail("case range", .{});
4393 } else if (case.items.len > 0) {
4394 return isel.fail("case range", .{});
4795 if (case_range_index | case.items.len > 0) {
4796 if (std.math.cast(u5, delta_int)) |pos_imm| try isel.emit(.ccmp(
4797 adjusted_reg,
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 }
43954822 } else {
4396 const adjusted_reg = switch (low_int) {
4397 0 => cond_reg,
4398 else => temp_reg,
4399 };
4400
44014823 if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs(
44024824 zero_reg,
44034825 adjusted_reg,
......@@ -4421,41 +4843,55 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
44214843 adjusted_reg,
44224844 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
44234845 )) else {
4424 try isel.movImmediate(temp_reg, @bitCast(delta_int));
4425 try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = temp_reg }));
4846 const imm_ra = try isel.allocIntReg();
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));
44264855 }
4856 }
44274857
4428 switch (low_int) {
4429 0 => {},
4430 else => {
4431 if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
4432 adjusted_reg,
4433 cond_reg,
4434 .{ .immediate = pos_imm },
4435 )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
4436 adjusted_reg,
4437 cond_reg,
4438 .{ .immediate = neg_imm },
4439 )) else if (if (@as(i12, @truncate(low_int)) == 0)
4440 std.math.cast(u12, low_int >> 12)
4441 else
4442 null) |pos_imm_lsr_12| try isel.emit(.sub(
4443 adjusted_reg,
4444 cond_reg,
4445 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4446 )) else if (if (@as(i12, @truncate(-low_int)) == 0)
4447 std.math.cast(u12, -low_int >> 12)
4448 else
4449 null) |neg_imm_lsr_12| try isel.emit(.add(
4450 adjusted_reg,
4451 cond_reg,
4452 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4453 )) else {
4454 try isel.movImmediate(temp_reg, @bitCast(low_int));
4455 try isel.emit(.subs(adjusted_reg, cond_reg, .{ .register = temp_reg }));
4456 }
4457 },
4458 }
4858 switch (low_int) {
4859 0 => {},
4860 else => {
4861 if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
4862 adjusted_reg,
4863 cond_reg,
4864 .{ .immediate = pos_imm },
4865 )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
4866 adjusted_reg,
4867 cond_reg,
4868 .{ .immediate = neg_imm },
4869 )) else if (if (@as(i12, @truncate(low_int)) == 0)
4870 std.math.cast(u12, low_int >> 12)
4871 else
4872 null) |pos_imm_lsr_12| try isel.emit(.sub(
4873 adjusted_reg,
4874 cond_reg,
4875 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4876 )) else if (if (@as(i12, @truncate(-low_int)) == 0)
4877 std.math.cast(u12, -low_int >> 12)
4878 else
4879 null) |neg_imm_lsr_12| try isel.emit(.add(
4880 adjusted_reg,
4881 cond_reg,
4882 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4883 )) else {
4884 const imm_ra = try isel.allocIntReg();
4885 defer isel.freeReg(imm_ra);
4886 const imm_reg = switch (cond_int_info.bits) {
4887 else => unreachable,
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 },
44594895 }
44604896 }
44614897 var case_item_index = case.items.len;
......@@ -4483,13 +4919,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
44834919 .{ .n = false, .z = true, .c = false, .v = false },
44844920 .ne,
44854921 )) 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 };
44874929 try isel.emit(.ccmp(
44884930 cond_reg,
4489 .{ .register = temp_reg },
4931 .{ .register = imm_reg },
44904932 .{ .n = false, .z = true, .c = false, .v = false },
44914933 .ne,
44924934 ));
4935 try isel.movImmediate(imm_reg, @bitCast(item_int));
44934936 }
44944937 } else {
44954938 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 {
45154958 cond_reg,
45164959 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
45174960 )) else {
4518 try isel.movImmediate(temp_reg, @bitCast(item_int));
4519 try isel.emit(.subs(zero_reg, cond_reg, .{ .register = temp_reg }));
4520 }
4961 const imm_ra = try isel.allocIntReg();
4962 defer isel.freeReg(imm_ra);
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 }
45214971 }
45224972 }
45234973 }
4524 if (cond_mat) |mat| {
4525 try mat.finish(isel);
4526 isel.freeReg(temp_reg.alias);
4527 }
4974 if (cond_mat) |mat| try mat.finish(isel);
45284975 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
45294976 },
45304977 .@"try", .try_cold => {
......@@ -4560,24 +5007,75 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
45605007 const error_set_part_vi = try error_set_part_it.only(isel);
45615008 const error_set_part_mat = try error_set_part_vi.?.matReg(isel);
45625009 try isel.emit(.cbz(
4563 switch (error_set_part_vi.?.size(isel)) {
4564 else => unreachable,
4565 1...4 => error_set_part_mat.ra.w(),
4566 5...8 => error_set_part_mat.ra.x(),
4567 },
5010 error_set_part_mat.ra.w(),
45685011 @intCast((isel.instructions.items.len + 1 - cont_label) << 2),
45695012 ));
45705013 try error_set_part_mat.finish(isel);
45715014
45725015 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
45735016 },
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
45755064 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
45765065 },
5066 .dbg_stmt => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
45775067 .dbg_empty_stmt => {
45785068 try isel.emit(.nop());
45795069 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
45805070 },
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 },
45815079 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {
45825080 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
45835081 },
......@@ -4655,37 +5153,34 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
46555153 if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef());
46565154 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
46575155 defer dst_vi.value.deref(isel);
4658 switch (dst_vi.value.size(isel)) {
4659 0 => unreachable,
4660 1...Value.max_parts => {
4661 const ptr_vi = try isel.use(ty_op.operand);
4662 const ptr_mat = try ptr_vi.matReg(isel);
4663 _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{
4664 .@"volatile" = ptr_info.flags.is_volatile,
4665 });
4666 try ptr_mat.finish(isel);
4667 },
4668 else => |size| {
4669 try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), null, comptime &.initFill(.free)) orelse break :unused;
5156 const size = dst_vi.value.size(isel);
5157 if (size <= Value.max_parts and ip.zigTypeTag(ptr_info.child) != .@"union") {
5158 const ptr_vi = try isel.use(ty_op.operand);
5159 const ptr_mat = try ptr_vi.matReg(isel);
5160 _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{
5161 .@"volatile" = ptr_info.flags.is_volatile,
5162 });
5163 try ptr_mat.finish(isel);
5164 } else {
5165 try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), .{}) orelse break :unused;
46705166
4671 try call.prepareReturn(isel);
4672 try call.finishReturn(isel);
5167 try call.prepareReturn(isel);
5168 try call.finishReturn(isel);
46735169
4674 try call.prepareCallee(isel);
4675 try isel.global_relocs.append(gpa, .{
4676 .global = "memcpy",
4677 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4678 });
4679 try isel.emit(.bl(0));
4680 try call.finishCallee(isel);
5170 try call.prepareCallee(isel);
5171 try isel.global_relocs.append(gpa, .{
5172 .name = "memcpy",
5173 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
5174 });
5175 try isel.emit(.bl(0));
5176 try call.finishCallee(isel);
46815177
4682 try call.prepareParams(isel);
4683 const ptr_vi = try isel.use(ty_op.operand);
4684 try isel.movImmediate(.x2, size);
4685 try call.paramLiveOut(isel, ptr_vi, .r1);
4686 try call.paramAddress(isel, dst_vi.value, .r0);
4687 try call.finishParams(isel);
4688 },
5178 try call.prepareParams(isel);
5179 const ptr_vi = try isel.use(ty_op.operand);
5180 try isel.movImmediate(.x2, size);
5181 try call.paramLiveOut(isel, ptr_vi, .r1);
5182 try call.paramAddress(isel, dst_vi.value, .r0);
5183 try call.finishParams(isel);
46895184 }
46905185 }
46915186
......@@ -4765,10 +5260,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
47655260 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
47665261 const ptr_info = ptr_ty.ptrInfo(zcu);
47675262 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)) {
4769 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4770 break :air_tag;
4771 };
5263 if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val))
5264 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
47725265
47735266 const src_vi = try isel.use(bin_op.rhs);
47745267 const size = src_vi.size(isel);
......@@ -4782,8 +5275,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
47825275 });
47835276 try ptr_mat.finish(isel);
47845277
4785 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4786 break :air_tag;
5278 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
47875279 },
47885280 else => {},
47895281 };
......@@ -4792,7 +5284,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
47925284
47935285 try call.prepareCallee(isel);
47945286 try isel.global_relocs.append(gpa, .{
4795 .global = "memcpy",
5287 .name = "memcpy",
47965288 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
47975289 });
47985290 try isel.emit(.bl(0));
......@@ -4855,7 +5347,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
48555347
48565348 try call.prepareCallee(isel);
48575349 try isel.global_relocs.append(gpa, .{
4858 .global = switch (dst_bits) {
5350 .name = switch (dst_bits) {
48595351 else => unreachable,
48605352 16 => switch (src_bits) {
48615353 else => unreachable,
......@@ -5009,6 +5501,108 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
50095501 }
50105502 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
50115503 },
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 },
50125606 .trunc => |air_tag| {
50135607 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
50145608 defer dst_vi.value.deref(isel);
......@@ -5096,14 +5690,6 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
50965690 }
50975691 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
50985692 },
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 },
51075693 .optional_payload => {
51085694 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: {
51095695 defer payload_vi.value.deref(isel);
......@@ -5122,6 +5708,37 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
51225708 }
51235709 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
51245710 },
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 },
51255742 .wrap_optional => {
51265743 if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: {
51275744 defer opt_vi.value.deref(isel);
......@@ -5179,6 +5796,93 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
51795796 }
51805797 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
51815798 },
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 },
51825886 .wrap_errunion_payload => {
51835887 if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {
51845888 defer error_union_vi.value.deref(isel);
......@@ -5220,26 +5924,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
52205924 const error_set_size = error_set_ty.abiSize(zcu);
52215925 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);
52235930 if (payload_size > 0) {
52245931 var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
52255932 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) {
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 });
5933 try payload_part_vi.?.defUndef(isel, payload_ty, .{});
52395934 }
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);
52435935 }
52445936 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
52455937 },
......@@ -5313,7 +6005,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
53136005 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
53146006 },
53156007 .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: {
53176009 defer field_vi.value.deref(isel);
53186010
53196011 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 {
53406032 });
53416033
53426034 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));
5344 while (try agg_part_it.next(isel)) |agg_part| {
5345 var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));
5346 const field_part_vi = try field_part_it.only(isel);
5347 if (field_part_vi.? == agg_part.vi) continue;
5348 var field_subpart_it = field_part_vi.?.parts(isel);
5349 const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|
5350 field_subpart_vi.get(isel).offset_from_parent
5351 else
5352 0;
5353 while (field_subpart_it.next()) |field_subpart_vi| {
5354 const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;
5355 const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);
5356 var agg_subpart_it = agg_part.vi.field(
5357 field_ty,
5358 agg_part.offset + field_subpart_offset - field_part_offset,
5359 field_subpart_size,
5360 );
5361 const agg_subpart_vi = try agg_subpart_it.only(isel);
5362 try agg_subpart_vi.?.liveOut(isel, field_subpart_ra);
5363 }
6035 switch (agg_ty.zigTypeTag(zcu)) {
6036 else => unreachable,
6037 .@"struct" => {
6038 var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8));
6039 while (try agg_part_it.next(isel)) |agg_part| {
6040 var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));
6041 const field_part_vi = try field_part_it.only(isel);
6042 if (field_part_vi.? == agg_part.vi) continue;
6043 var field_subpart_it = field_part_vi.?.parts(isel);
6044 const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|
6045 field_subpart_vi.get(isel).offset_from_parent
6046 else
6047 0;
6048 while (field_subpart_it.next()) |field_subpart_vi| {
6049 const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;
6050 const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);
6051 var agg_subpart_it = agg_part.vi.field(
6052 field_ty,
6053 agg_part.offset + field_subpart_offset - field_part_offset,
6054 field_subpart_size,
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 },
53646084 }
53656085 }
53666086 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
53676087 },
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 },
53686114 .slice => {
53696115 if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {
53706116 defer slice_vi.value.deref(isel);
......@@ -5781,7 +6527,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
57816527
57826528 try call.prepareCallee(isel);
57836529 try isel.global_relocs.append(gpa, .{
5784 .global = switch (dst_int_info.bits) {
6530 .name = switch (dst_int_info.bits) {
57856531 else => unreachable,
57866532 1...32 => switch (dst_int_info.signedness) {
57876533 .signed => switch (src_bits) {
......@@ -5921,7 +6667,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
59216667
59226668 try call.prepareCallee(isel);
59236669 try isel.global_relocs.append(gpa, .{
5924 .global = switch (src_int_info.bits) {
6670 .name = switch (src_int_info.bits) {
59256671 else => unreachable,
59266672 1...32 => switch (src_int_info.signedness) {
59276673 .signed => switch (dst_bits) {
......@@ -6004,14 +6750,20 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
60046750 }
60056751 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
60066752 },
6007 .memset => |air_tag| {
6753 .memset, .memset_safe => |air_tag| {
60086754 const bin_op = air.data(air.inst_index).bin_op;
60096755 const dst_ty = isel.air.typeOf(bin_op.lhs, ip);
60106756 const dst_info = dst_ty.ptrInfo(zcu);
60116757 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 };
60136764 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
60146765 break :fill_byte .{ .constant = fill_byte };
6766 }
60156767 switch (dst_ty.elemType2(zcu).abiSize(zcu)) {
60166768 0 => unreachable,
60176769 1 => break :fill_byte .{ .value = bin_op.rhs },
......@@ -6070,8 +6822,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
60706822 .c => unreachable,
60716823 }
60726824
6073 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6074 break :air_tag;
6825 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
60756826 },
60766827 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }),
60776828 }
......@@ -6082,7 +6833,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
60826833
60836834 try call.prepareCallee(isel);
60846835 try isel.global_relocs.append(gpa, .{
6085 .global = "memset",
6836 .name = "memset",
60866837 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
60876838 });
60886839 try isel.emit(.bl(0));
......@@ -6128,7 +6879,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
61286879
61296880 try call.prepareCallee(isel);
61306881 try isel.global_relocs.append(gpa, .{
6131 .global = @tagName(air_tag),
6882 .name = @tagName(air_tag),
61326883 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
61336884 });
61346885 try isel.emit(.bl(0));
......@@ -6217,6 +6968,72 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
62176968
62186969 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
62196970 },
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 },
62207037 .aggregate_init => {
62217038 if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| {
62227039 defer agg_vi.value.deref(isel);
......@@ -6295,23 +7112,52 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
62957112 }
62967113 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
62977114 },
6298 .union_init => {
6299 if (isel.live_values.fetchRemove(air.inst_index)) |un_vi| unused: {
6300 defer un_vi.value.deref(isel);
7115 .union_init => |air_tag| {
7116 if (isel.live_values.fetchRemove(air.inst_index)) |union_vi| unused: {
7117 defer union_vi.value.deref(isel);
63017118
63027119 const ty_pl = air.data(air.inst_index).ty_pl;
63037120 const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;
6304 const un_ty = ty_pl.ty.toType();
6305 if (un_ty.containerLayout(zcu) != .@"extern") return isel.fail("bad union init {f}", .{isel.fmtType(un_ty)});
6306
6307 try un_vi.value.defAddr(isel, un_ty, null, comptime &.initFill(.free)) orelse break :unused;
7121 const union_ty = ty_pl.ty.toType();
7122 const loaded_union = ip.loadUnionType(union_ty.toIntern());
7123 const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
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
63097155 try call.prepareReturn(isel);
63107156 try call.finishReturn(isel);
63117157
63127158 try call.prepareCallee(isel);
63137159 try isel.global_relocs.append(gpa, .{
6314 .global = "memcpy",
7160 .name = "memcpy",
63157161 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
63167162 });
63177163 try isel.emit(.bl(0));
......@@ -6321,7 +7167,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
63217167 const init_vi = try isel.use(extra.init);
63227168 try isel.movImmediate(.x2, init_vi.size(isel));
63237169 try call.paramAddress(isel, init_vi, .r1);
6324 try call.paramAddress(isel, un_vi.value, .r0);
7170 try call.paramAddress(isel, payload_vi.?, .r0);
63257171 try call.finishParams(isel);
63267172 }
63277173 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 {
64277273
64287274 try call.prepareCallee(isel);
64297275 try isel.global_relocs.append(gpa, .{
6430 .global = switch (bits) {
7276 .name = switch (bits) {
64317277 else => unreachable,
64327278 16 => "__fmah",
64337279 32 => "fmaf",
......@@ -6508,6 +7354,33 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
65087354 }
65097355 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
65107356 },
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 },
65117384 .runtime_nav_ptr => {
65127385 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
65137386 defer ptr_vi.value.deref(isel);
......@@ -6516,19 +7389,19 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
65167389 const ty_nav = air.data(air.inst_index).ty_nav;
65177390 if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
65187391 false => {
6519 try isel.nav_relocs.append(zcu.gpa, .{
7392 try isel.nav_relocs.append(gpa, .{
65207393 .nav = ty_nav.nav,
65217394 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
65227395 });
65237396 try isel.emit(.adr(ptr_ra.x(), 0));
65247397 },
65257398 true => {
6526 try isel.nav_relocs.append(zcu.gpa, .{
7399 try isel.nav_relocs.append(gpa, .{
65277400 .nav = ty_nav.nav,
65287401 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
65297402 });
65307403 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, .{
65327405 .nav = ty_nav.nav,
65337406 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
65347407 });
......@@ -6538,19 +7411,266 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
65387411 }
65397412 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
65407413 },
6541 .add_safe,
6542 .sub_safe,
6543 .mul_safe,
6544 .inferred_alloc,
6545 .inferred_alloc_comptime,
6546 .int_from_float_safe,
6547 .int_from_float_optimized_safe,
6548 .wasm_memory_size,
6549 .wasm_memory_grow,
6550 .work_item_id,
6551 .work_group_size,
6552 .work_group_id,
6553 => unreachable,
7414 .c_va_arg => {
7415 const maybe_arg_vi = isel.live_values.fetchRemove(air.inst_index);
7416 defer if (maybe_arg_vi) |arg_vi| arg_vi.value.deref(isel);
7417 const ty_op = air.data(air.inst_index).ty_op;
7418 const ty = ty_op.ty.toType();
7419 var param_it: CallAbiIterator = .init;
7420 const param_vi = try param_it.param(isel, ty);
7421 defer param_vi.?.deref(isel);
7422 const passed_vi = switch (param_vi.?.parent(isel)) {
7423 .unallocated => param_vi.?,
7424 .stack_slot, .value, .constant => unreachable,
7425 .address => |address_vi| address_vi,
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,
65547674 }
65557675 assert(air.body_index == 0);
65567676}
......@@ -6631,7 +7751,7 @@ pub fn verify(isel: *Select, check_values: bool) void {
66317751pub fn layout(
66327752 isel: *Select,
66337753 incoming: CallAbiIterator,
6634 have_va: bool,
7754 is_sysv_var_args: bool,
66357755 saved_gra_len: u7,
66367756 saved_vra_len: u7,
66377757 mod: *const Package.Module,
......@@ -6642,8 +7762,6 @@ pub fn layout(
66427762 wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)});
66437763
66447764 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
66487766 var saves_buf: [10 + 8 + 8 + 2 + 8]struct {
66497767 class: enum { integer, vector },
......@@ -6721,7 +7839,7 @@ pub fn layout(
67217839
67227840 // incoming vr arguments
67237841 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)) {
67257843 saves_size = std.mem.alignForward(u10, saves_size, 16);
67267844 saves_buf[saves_len] = .{
67277845 .class = .vector,
......@@ -6771,87 +7889,117 @@ pub fn layout(
67717889 saves_len += 1;
67727890 saves_size += 8;
67737891 deferred_gr = null;
7892 } else switch (@as(u1, @truncate(saved_gra_len))) {
7893 0 => {},
7894 1 => saves_size += 8,
67747895 }
67757896 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)) {
67777898 saves_size = std.mem.alignForward(u10, saves_size, 8);
67787899 saves_buf[saves_len] = .{
67797900 .class = .integer,
67807901 .needs_restore = false,
67817902 .register = save_ra.x(),
67827903 .offset = saves_size,
6783 .size = 8,
6784 };
6785 saves_len += 1;
6786 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 }
7904 .size = 8,
7905 };
7906 saves_len += 1;
7907 saves_size += 8;
68317908 }
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 }));
68337955 const scratch_reg: Register = if (isel.stack_align == .@"16")
68347956 .sp
6835 else if (stack_size == 0)
7957 else if (stack_size == 0 and frame_record_offset == 0)
68367958 .fp
68377959 else
6838 .x9;
6839 try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset }));
6840 if (stack_size_high > 0) try isel.emit(.sub(scratch_reg, .sp, .{
6841 .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },
6842 }));
6843 if (stack_size_low > 0) try isel.emit(.sub(
6844 scratch_reg,
6845 if (stack_size_high > 0) scratch_reg else .sp,
6846 .{ .immediate = stack_size_low },
6847 ));
6848 if (isel.stack_align != .@"16") {
6849 try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{
6850 .N = .doubleword,
6851 .immr = -%isel.stack_align.toLog2Units(),
6852 .imms = ~isel.stack_align.toLog2Units(),
6853 } }));
7960 .ip0;
7961 const stack_size_lo: u12 = @truncate(stack_size >> 0);
7962 const stack_size_hi: u12 = @truncate(stack_size >> 12);
7963 if (mod.stack_check) {
7964 if (stack_size_hi > 2) {
7965 try isel.movImmediate(.ip1, stack_size_hi);
7966 const loop_label = isel.instructions.items.len;
7967 try isel.emit(.sub(.sp, .sp, .{
7968 .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" },
7969 }));
7970 try isel.emit(.sub(.ip1, .ip1, .{ .immediate = 1 }));
7971 try isel.emit(.ldr(.xzr, .{ .base = .sp }));
7972 try isel.emit(.cbnz(.ip1, -@as(i21, @intCast(
7973 (isel.instructions.items.len - loop_label) << 2,
7974 ))));
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 }));
68547997 }
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 } }));
68558003 wip_mir_log.debug("", .{});
68568004 }
68578005
......@@ -6859,6 +8007,7 @@ pub fn layout(
68598007 if (isel.returns) {
68608008 try isel.emit(.ret(.lr));
68618009 var save_index: usize = 0;
8010 var first_offset: ?u10 = null;
68628011 while (save_index < saves.len) {
68638012 if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and
68648013 saves[save_index + 0].class == saves[save_index + 1].class and
......@@ -6867,46 +8016,51 @@ pub fn layout(
68678016 try isel.emit(.ldp(
68688017 saves[save_index + 0].register,
68698018 saves[save_index + 1].register,
6870 switch (saves[save_index + 0].offset) {
6871 0 => .{ .post_index = .{
6872 .base = .sp,
6873 .index = @intCast(saves_size),
6874 } },
6875 else => |offset| .{ .signed_offset = .{
8019 if (first_offset) |offset| .{ .signed_offset = .{
8020 .base = .sp,
8021 .offset = @intCast(saves[save_index + 0].offset - offset),
8022 } } else form: {
8023 first_offset = @intCast(saves[save_index + 0].offset);
8024 break :form .{ .post_index = .{
68768025 .base = .sp,
6877 .offset = @intCast(offset),
6878 } },
8026 .index = @intCast(saves_size - first_offset.?),
8027 } };
68798028 },
68808029 ));
68818030 save_index += 2;
68828031 } else if (saves[save_index].needs_restore) {
68838032 try isel.emit(.ldr(
68848033 saves[save_index].register,
6885 switch (saves[save_index].offset) {
6886 0 => .{ .post_index = .{
6887 .base = .sp,
6888 .index = @intCast(saves_size),
6889 } },
6890 else => |offset| .{ .unsigned_offset = .{
8034 if (first_offset) |offset| .{ .unsigned_offset = .{
8035 .base = .sp,
8036 .offset = saves[save_index + 0].offset - offset,
8037 } } else form: {
8038 const offset = saves[save_index + 0].offset;
8039 first_offset = offset;
8040 break :form .{ .post_index = .{
68918041 .base = .sp,
6892 .offset = @intCast(offset),
6893 } },
8042 .index = @intCast(saves_size - offset),
8043 } };
68948044 },
68958045 ));
68968046 save_index += 1;
68978047 } else save_index += 1;
68988048 }
6899 if (isel.stack_align != .@"16" or (stack_size_low > 0 and stack_size_high > 0)) {
6900 try isel.emit(switch (frame_record_offset) {
6901 0 => .add(.sp, .fp, .{ .immediate = 0 }),
6902 else => |offset| .sub(.sp, .fp, .{ .immediate = offset }),
6903 });
8049 const offset = stack_size + first_offset.?;
8050 const offset_lo: u12 = @truncate(offset >> 0);
8051 const offset_hi: u12 = @truncate(offset >> 12);
8052 if (isel.stack_align != .@"16" or (offset_lo > 0 and offset_hi > 0)) {
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) }));
69048058 } else {
6905 if (stack_size_high > 0) try isel.emit(.add(.sp, .sp, .{
6906 .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },
8059 if (offset_hi > 0) try isel.emit(.add(.sp, .sp, .{
8060 .shifted_immediate = .{ .immediate = offset_hi, .lsl = .@"12" },
69078061 }));
6908 if (stack_size_low > 0) try isel.emit(.add(.sp, .sp, .{
6909 .immediate = stack_size_low,
8062 if (offset_lo > 0) try isel.emit(.add(.sp, .sp, .{
8063 .immediate = offset_lo,
69108064 }));
69118065 }
69128066 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
69778131 return constant.fmtValue(isel.pt);
69788132}
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
69808154fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void {
69818155 wip_mir_log.debug(" | {f}", .{instruction});
69828156 try isel.instructions.append(isel.pt.zcu.gpa, instruction);
69838157}
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
69858171fn emitLiteral(isel: *Select, bytes: []const u8) !void {
69868172 const words: []align(1) const u32 = @ptrCast(bytes);
69878173 const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len);
......@@ -8000,9 +9186,18 @@ pub const Value = struct {
80009186 var dst_part_it = dst_vi.parts(isel);
80019187 if (dst_part_it.only()) |dst_part_vi| {
80029188 var src_part_it = src_vi.parts(isel);
8003 if (src_part_it.only()) |src_part_vi| {
8004 try src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return);
8005 } else while (src_part_it.next()) |src_part_vi| {
9189 if (src_part_it.only()) |src_part_vi| only: {
9190 const src_part_size = src_part_vi.size(isel);
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| {
80069201 const src_part_offset, const src_part_size = src_part_vi.position(isel);
80079202 var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size);
80089203 const dst_field_vi = try dst_field_it.only(isel);
......@@ -8028,6 +9223,32 @@ pub const Value = struct {
80289223 }
80299224 }
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 };
80319252 fn addOrSubtract(
80329253 res_vi: Value.Index,
80339254 isel: *Select,
......@@ -8035,19 +9256,21 @@ pub const Value = struct {
80359256 lhs_vi: Value.Index,
80369257 op: codegen.aarch64.encoding.Instruction.AddSubtractOp,
80379258 rhs_vi: Value.Index,
8038 opts: struct {
8039 wrap: bool,
8040 overflow_ra: Register.Alias = .zr,
8041 },
9259 opts: AddOrSubtractOptions,
80429260 ) !void {
8043 assert(opts.wrap or opts.overflow_ra == .zr);
80449261 const zcu = isel.pt.zcu;
80459262 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
80469263 const int_info = ty.intInfo(zcu);
80479264 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
80489265 var part_offset = res_vi.size(isel);
8049 var need_wrap = opts.wrap;
8050 var need_carry = opts.overflow_ra != .zr;
9266 var need_wrap = switch (opts.overflow) {
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 };
80519274 while (part_offset > 0) : (need_wrap = false) {
80529275 const part_size = @min(part_offset, 8);
80539276 part_offset -= part_size;
......@@ -8057,48 +9280,87 @@ pub const Value = struct {
80579280 const unwrapped_res_part_ra = unwrapped_res_part_ra: {
80589281 if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra;
80599282 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) {
80619284 .signed => .vs,
80629285 .unsigned => switch (op) {
80639286 .add => .cs,
80649287 .sub => .cc,
80659288 },
8066 })));
9289 });
80679290 break :unwrapped_res_part_ra wrapped_res_part_ra;
80689291 }
8069 const wrapped_part_ra, const unwrapped_part_ra = if (opts.overflow_ra != .zr) part_ra: {
8070 switch (op) {
8071 .add => {},
8072 .sub => switch (int_info.signedness) {
8073 .signed => {},
8074 .unsigned => {
8075 try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.cc)));
8076 break :part_ra .{ wrapped_res_part_ra, wrapped_res_part_ra };
8077 },
9292 need_carry = false;
9293 const wrapped_part_ra, const unwrapped_part_ra = part_ra: switch (opts.overflow) {
9294 .@"unreachable" => unreachable,
9295 .panic, .ra => switch (int_info.signedness) {
9296 .signed => {
9297 try opts.overflow.defCond(isel, .ne);
9298 const wrapped_part_ra = switch (wrapped_res_part_ra) {
9299 else => |res_part_ra| res_part_ra,
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 };
80789318 },
8079 }
8080 try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.ne)));
8081 const wrapped_part_ra = switch (wrapped_res_part_ra) {
8082 else => |res_part_ra| res_part_ra,
8083 .zr => try isel.allocIntReg(),
8084 };
8085 errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
8086 const unwrapped_part_ra = unwrapped_part_ra: {
8087 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
8088 else => |res_part_ra| isel.lockReg(res_part_ra),
8089 .zr => .empty,
8090 };
8091 defer wrapped_res_part_lock.unlock(isel);
8092 break :unwrapped_part_ra try isel.allocIntReg();
8093 };
8094 errdefer isel.freeReg(unwrapped_part_ra);
8095 switch (part_size) {
8096 else => unreachable,
8097 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })),
8098 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })),
8099 }
8100 break :part_ra .{ wrapped_part_ra, unwrapped_part_ra };
8101 } else .{ wrapped_res_part_ra, wrapped_res_part_ra };
9319 .unsigned => {
9320 const unwrapped_part_ra = unwrapped_part_ra: {
9321 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
9322 else => |res_part_ra| isel.lockReg(res_part_ra),
9323 .zr => .empty,
9324 };
9325 defer wrapped_res_part_lock.unlock(isel);
9326 break :unwrapped_part_ra try isel.allocIntReg();
9327 };
9328 errdefer isel.freeReg(unwrapped_part_ra);
9329 const bit: u6 = @truncate(int_info.bits);
9330 switch (opts.overflow) {
9331 .@"unreachable", .wrap => unreachable,
9332 .panic => |panic_id| {
9333 const skip_label = isel.instructions.items.len;
9334 try isel.emitPanic(panic_id);
9335 try isel.emit(.tbz(
9336 switch (bit) {
9337 0, 32 => unreachable,
9338 1...31 => unwrapped_part_ra.w(),
9339 33...63 => unwrapped_part_ra.x(),
9340 },
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 };
81029364 defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
81039365 errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra);
81049366 if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) {
......@@ -8409,9 +9671,12 @@ pub const Value = struct {
84099671 fn defAddr(
84109672 def_vi: Value.Index,
84119673 isel: *Select,
8412 def_ty: ZigType,
8413 wrap: ?std.builtin.Type.Int,
8414 expected_live_registers: *const LiveRegisters,
9674 root_ty: ZigType,
9675 opts: struct {
9676 root_vi: Value.Index = .free,
9677 wrap: ?std.builtin.Type.Int = null,
9678 expected_live_registers: *const LiveRegisters = &.initFill(.free),
9679 },
84159680 ) !?void {
84169681 if (!def_vi.isUsed(isel)) return null;
84179682 const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel);
......@@ -8420,11 +9685,12 @@ pub const Value = struct {
84209685 .stack_slot => |stack_slot| .{ stack_slot, false },
84219686 else => unreachable,
84229687 };
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,
84249690 .offset = @intCast(stack_slot.offset + offset_from_parent),
84259691 .split = false,
8426 .wrap = wrap,
8427 .expected_live_registers = expected_live_registers,
9692 .wrap = opts.wrap,
9693 .expected_live_registers = opts.expected_live_registers,
84289694 });
84299695 if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot });
84309696 }
......@@ -8454,12 +9720,12 @@ pub const Value = struct {
84549720 const part_mat = try part_vi.matReg(isel);
84559721 try isel.emit(if (part_vi.isVector(isel)) emit: {
84569722 assert(part_offset == 0 and part_size == vi_size);
8457 break :emit size: switch (vi_size) {
9723 break :emit switch (vi_size) {
84589724 else => unreachable,
84599725 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
84609726 .fmov(ra.h(), .{ .register = part_mat.ra.h() })
84619727 else
8462 continue :size 4,
9728 .dup(ra.h(), part_mat.ra.@"h[]"(0)),
84639729 4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }),
84649730 8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }),
84659731 16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }),
......@@ -8503,6 +9769,53 @@ pub const Value = struct {
85039769 }
85049770 }
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
85069819 pub fn liveIn(
85079820 vi: Value.Index,
85089821 isel: *Select,
......@@ -8532,21 +9845,30 @@ pub const Value = struct {
85329845 },
85339846 true => switch (vi.size(isel)) {
85349847 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)),
85369852 4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }),
85379853 8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }),
85389854 },
85399855 },
85409856 true => switch (src_ra.isVector()) {
8541 false => switch (vi.size(isel)) {
9857 false => size: switch (vi.size(isel)) {
85429858 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,
85449863 4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }),
85459864 8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }),
85469865 },
85479866 true => switch (vi.size(isel)) {
85489867 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)),
85509872 4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }),
85519873 8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }),
85529874 16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }),
......@@ -8574,41 +9896,15 @@ pub const Value = struct {
85749896 expected_live_registers: *const LiveRegisters,
85759897 ) !void {
85769898 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);
85789900 switch (parent_vi.parent(isel)) {
85799901 .unallocated => {},
8580 .stack_slot => |stack_slot| {
8581 const offset = stack_slot.offset + offset_from_parent;
8582 try isel.emit(switch (vi.size(isel)) {
8583 else => unreachable,
8584 1 => if (src_ra.isVector()) .str(src_ra.b(), .{ .unsigned_offset = .{
8585 .base = stack_slot.base.x(),
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 },
9902 .stack_slot => |stack_slot| if (stack_slot.base != Register.Alias.fp) try isel.storeReg(
9903 src_ra,
9904 vi.size(isel),
9905 stack_slot.base,
9906 @as(i65, stack_slot.offset) + offset_from_parent,
9907 ),
86129908 else => unreachable,
86139909 }
86149910 try vi.spillReg(isel, src_ra, 0, expected_live_registers);
......@@ -8629,9 +9925,12 @@ pub const Value = struct {
86299925 const part_size = part_vi.size(isel);
86309926 const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra;
86319927 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) {
86339929 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,
86359934 4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }),
86369935 8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }),
86379936 });
......@@ -8798,6 +10097,11 @@ pub const Value = struct {
879810097 return it.vi;
879910098 }
880010099
10100 pub fn peek(it: PartIterator) ?Value.Index {
10101 var it_mut = it;
10102 return it_mut.next();
10103 }
10104
880110105 pub fn only(it: PartIterator) ?Value.Index {
880210106 return if (it.remaining == 1) it.vi else null;
880310107 }
......@@ -8856,24 +10160,31 @@ pub const Value = struct {
885610160 _ = vi.addPart(isel, 8, 8);
885710161 } else unreachable,
885810162 },
8859 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu))
8860 continue :type_key ip.indexToKey(child_type)
8861 else switch (ZigType.fromInterned(child_type).abiSize(zcu)) {
8862 0...8, 16 => |child_size| if (offset == 0 and size == ty_size) {
8863 vi.setParts(isel, 2);
8864 _ = vi.addPart(isel, 0, child_size);
8865 _ = vi.addPart(isel, child_size, 1);
8866 } else unreachable,
8867 9...15 => |child_size| if (offset == 0 and size == ty_size) {
8868 vi.setParts(isel, 2);
8869 _ = vi.addPart(isel, 0, 8);
8870 _ = vi.addPart(isel, 8, ty_size - 8);
8871 } else if (offset == 8 and size == ty_size - 8) {
8872 vi.setParts(isel, 2);
8873 _ = vi.addPart(isel, 0, child_size - 8);
8874 _ = vi.addPart(isel, child_size - 8, 1);
8875 } else unreachable,
8876 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
10163 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu)) continue :type_key ip.indexToKey(child_type) else {
10164 const child_ty: ZigType = .fromInterned(child_type);
10165 const child_size = child_ty.abiSize(zcu);
10166 if (offset == 0 and size == child_size) {
10167 ty = child_ty;
10168 ty_size = child_size;
10169 continue :type_key ip.indexToKey(child_type);
10170 }
10171 switch (child_size) {
10172 0...8, 16 => if (offset == 0 and size == ty_size) {
10173 vi.setParts(isel, 2);
10174 _ = vi.addPart(isel, 0, child_size);
10175 _ = vi.addPart(isel, child_size, 1);
10176 } else unreachable,
10177 9...15 => if (offset == 0 and size == ty_size) {
10178 vi.setParts(isel, 2);
10179 _ = vi.addPart(isel, 0, 8);
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 }
887710188 },
887810189 .array_type => |array_type| {
887910190 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 {
902710338 } },
902810339 },
902910340 .struct_type => {
9030 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
903110341 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;
903210349 if (loaded_struct.field_types.len > Value.max_parts and
903310350 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
903410351 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
......@@ -9136,6 +10453,77 @@ pub const Value = struct {
913610453 if (part.is_vector) subpart_vi.setIsVector(isel);
913710454 }
913810455 },
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 },
913910527 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
914010528 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
914110529 .error_set_type,
......@@ -9187,7 +10575,10 @@ pub const Value = struct {
918710575 if (vi.register(isel)) |ra| {
918810576 if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) {
918910577 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)),
919110582 4 => .fmov(mat.ra.s(), .{ .register = ra.s() }),
919210583 8 => .fmov(mat.ra.d(), .{ .register = ra.d() }),
919310584 16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }),
......@@ -9347,11 +10738,12 @@ pub const Value = struct {
934710738 } },
934810739 .error_union => |error_union| {
934910740 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);
935010742 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
9351 if (!ip.isNoReturn(error_union_type.error_set_type) and
9352 offset == codegen.errUnionErrorOffset(payload_ty, zcu))
9353 {
9354 offset = 0;
10743 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
10744 const error_set_size = error_set_ty.abiSize(zcu);
10745 if (offset >= error_set_offset and offset + size <= error_set_offset + error_set_size) {
10746 offset -= error_set_offset;
935510747 continue :constant_key switch (error_union.val) {
935610748 .err_name => |err_name| .{ .err = .{
935710749 .ty = error_union_type.error_set_type,
......@@ -9363,15 +10755,18 @@ pub const Value = struct {
936310755 } },
936410756 };
936510757 }
9366 assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
9367 offset -= @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));
9368 switch (error_union.val) {
9369 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
9370 .payload => |payload| {
9371 constant = payload;
9372 constant_key = ip.indexToKey(payload);
9373 continue :constant_key constant_key;
9374 },
10758 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
10759 const payload_size = payload_ty.abiSize(zcu);
10760 if (offset >= payload_offset and offset + size <= payload_offset + payload_size) {
10761 offset -= payload_offset;
10762 switch (error_union.val) {
10763 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
10764 .payload => |payload| {
10765 constant = payload;
10766 constant_key = ip.indexToKey(payload);
10767 continue :constant_key constant_key;
10768 },
10769 }
937510770 }
937610771 },
937710772 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },
......@@ -9555,21 +10950,29 @@ pub const Value = struct {
955510950 var base_ptr = ip.indexToKey(base).ptr;
955610951 const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child;
955710952 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;
955910959 continue :constant_key .{ .ptr = base_ptr };
956010960 },
9561 .opt_payload => |base| continue :constant_key .{ .ptr = ip.indexToKey(base).ptr },
956210961 .field => |field| {
956310962 var base_ptr = ip.indexToKey(field.base).ptr;
956410963 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;
956610965 continue :constant_key .{ .ptr = base_ptr };
956710966 },
956810967 .comptime_alloc, .comptime_field, .arr_elem => unreachable,
956910968 };
957010969 },
957110970 .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 },
957310976 else => {
957410977 assert(offset == @divExact(isel.target.ptrBitWidth(), 8));
957510978 offset = 0;
......@@ -9900,7 +11303,17 @@ fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8
990011303fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {
990111304 const zcu = isel.pt.zcu;
990211305 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) {
990411317 .int_type,
990511318 .ptr_type,
990611319 .array_type,
......@@ -9922,6 +11335,37 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
992211335 .empty_enum_value,
992311336 .memoized_call,
992411337 => 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 },
992511369 .opt => |opt| {
992611370 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));
992711371 switch (opt.val) {
......@@ -9933,7 +11377,6 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
993311377 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);
993411378 },
993511379 }
9936 return true;
993711380 },
993811381 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
993911382 else => unreachable,
......@@ -9952,9 +11395,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
995211395 elem_offset += elem_size;
995311396 },
995411397 }
9955 return true;
995611398 },
9957 .vector_type => {},
11399 .vector_type => return false,
995811400 .struct_type => {
995911401 const loaded_struct = ip.loadStructType(aggregate.ty);
996011402 switch (loaded_struct.layout) {
......@@ -9977,9 +11419,8 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
997711419 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
997811420 field_offset += field_size;
997911421 }
9980 return true;
998111422 },
9982 .@"extern", .@"packed" => {},
11423 .@"extern", .@"packed" => return false,
998311424 }
998411425 },
998511426 .tuple_type => |tuple_type| {
......@@ -9996,15 +11437,10 @@ fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMem
999611437 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
999711438 field_offset += field_size;
999811439 }
9999 return true;
1000011440 },
1000111441 },
10002 else => {},
11442 else => return false,
1000311443 }
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 };
1000811444 return true;
1000911445}
1001011446
......@@ -10622,16 +12058,14 @@ pub const CallAbiIterator = struct {
1062212058 {
1062312059 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
1062412060 const offset = codegen.errUnionErrorOffset(payload_ty, zcu);
10625 const size = error_set_ty.abiSize(zcu);
10626 const end = offset % 8 + size;
12061 const end = offset % 8 + error_set_ty.abiSize(zcu);
1062712062 const part_index: usize = @intCast(offset / 8);
1062812063 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
1062912064 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
1063012065 }
1063112066 {
1063212067 const offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
10633 const size = payload_ty.abiSize(zcu);
10634 const end = offset % 8 + size;
12068 const end = offset % 8 + payload_ty.abiSize(zcu);
1063512069 const part_index: usize = @intCast(offset / 8);
1063612070 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
1063712071 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
......@@ -10675,8 +12109,14 @@ pub const CallAbiIterator = struct {
1067512109 => unreachable,
1067612110 },
1067712111 .struct_type => {
10678 const size = wip_vi.size(isel);
1067912112 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);
1068012120 if (size <= 16 * 4) homogeneous_aggregate: {
1068112121 const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate;
1068212122 const parts_len = @shrExact(size, fdt.log2Size());
......@@ -10761,6 +12201,40 @@ pub const CallAbiIterator = struct {
1076112201 else => it.indirect(isel, wip_vi),
1076212202 }
1076312203 },
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 },
1076412238 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
1076512239 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
1076612240 .error_set_type,
......@@ -10789,6 +12263,16 @@ pub const CallAbiIterator = struct {
1078912263 return wip_vi.ref(isel);
1079012264 }
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
1079212276 pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
1079312277 const wip_vi = try it.param(isel, ty) orelse return null;
1079412278 switch (wip_vi.parent(isel)) {
src/codegen/aarch64/encoding.zig+4161-635
......@@ -81,6 +81,14 @@ pub const Register = struct {
8181 .@"16b", .@"8b" => .byte,
8282 };
8383 }
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 }
8492 };
8593
8694 pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } };
......@@ -151,6 +159,7 @@ pub const Register = struct {
151159 pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } };
152160 pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } };
153161
162 pub const ip = x16;
154163 pub const ip0 = x16;
155164 pub const ip1 = x17;
156165 pub const fp = x29;
......@@ -774,6 +783,7 @@ pub const Register = struct {
774783
775784 ffr,
776785
786 pub const ip: Alias = .r16;
777787 pub const ip0: Alias = .r16;
778788 pub const ip1: Alias = .r17;
779789 pub const fp: Alias = .r29;
......@@ -6815,7 +6825,7 @@ pub const Instruction = packed union {
68156825 o0: AddSubtractOp = .add,
68166826 Rm: Register.Encoded,
68176827 op21: u2 = 0b01,
6818 U: bool = false,
6828 U: std.builtin.Signedness = .signed,
68196829 decoded24: u5 = 0b11011,
68206830 op54: u2 = 0b00,
68216831 sf: Register.IntegerSize = .doubleword,
......@@ -6829,7 +6839,7 @@ pub const Instruction = packed union {
68296839 o0: AddSubtractOp = .sub,
68306840 Rm: Register.Encoded,
68316841 op21: u2 = 0b01,
6832 U: bool = false,
6842 U: std.builtin.Signedness = .signed,
68336843 decoded24: u5 = 0b11011,
68346844 op54: u2 = 0b00,
68356845 sf: Register.IntegerSize = .doubleword,
......@@ -6843,7 +6853,7 @@ pub const Instruction = packed union {
68436853 o0: AddSubtractOp = .add,
68446854 Rm: Register.Encoded,
68456855 op21: u2 = 0b10,
6846 U: bool = false,
6856 U: std.builtin.Signedness = .signed,
68476857 decoded24: u5 = 0b11011,
68486858 op54: u2 = 0b00,
68496859 sf: Register.IntegerSize = .doubleword,
......@@ -6857,7 +6867,7 @@ pub const Instruction = packed union {
68576867 o0: AddSubtractOp = .add,
68586868 Rm: Register.Encoded,
68596869 op21: u2 = 0b01,
6860 U: bool = true,
6870 U: std.builtin.Signedness = .unsigned,
68616871 decoded24: u5 = 0b11011,
68626872 op54: u2 = 0b00,
68636873 sf: Register.IntegerSize = .doubleword,
......@@ -6871,7 +6881,7 @@ pub const Instruction = packed union {
68716881 o0: AddSubtractOp = .sub,
68726882 Rm: Register.Encoded,
68736883 op21: u2 = 0b01,
6874 U: bool = true,
6884 U: std.builtin.Signedness = .unsigned,
68756885 decoded24: u5 = 0b11011,
68766886 op54: u2 = 0b00,
68776887 sf: Register.IntegerSize = .doubleword,
......@@ -6885,7 +6895,7 @@ pub const Instruction = packed union {
68856895 o0: AddSubtractOp = .add,
68866896 Rm: Register.Encoded,
68876897 op21: u2 = 0b10,
6888 U: bool = true,
6898 U: std.builtin.Signedness = .unsigned,
68896899 decoded24: u5 = 0b11011,
68906900 op54: u2 = 0b00,
68916901 sf: Register.IntegerSize = .doubleword,
......@@ -7007,8 +7017,12 @@ pub const Instruction = packed union {
70077017 /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD
70087018 pub const DataProcessingVector = packed union {
70097019 group: @This().Group,
7020 simd_scalar_copy: SimdScalarCopy,
7021 simd_scalar_two_register_miscellaneous_fp16: SimdScalarTwoRegisterMiscellaneousFp16,
7022 simd_scalar_two_register_miscellaneous: SimdScalarTwoRegisterMiscellaneous,
70107023 simd_scalar_pairwise: SimdScalarPairwise,
70117024 simd_copy: SimdCopy,
7025 simd_two_register_miscellaneous_fp16: SimdTwoRegisterMiscellaneousFp16,
70127026 simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous,
70137027 simd_across_lanes: SimdAcrossLanes,
70147028 simd_three_same: SimdThreeSame,
......@@ -7018,6 +7032,7 @@ pub const Instruction = packed union {
70187032 float_compare: FloatCompare,
70197033 float_immediate: FloatImmediate,
70207034 float_data_processing_two_source: FloatDataProcessingTwoSource,
7035 float_conditional_select: FloatConditionalSelect,
70217036 float_data_processing_three_source: FloatDataProcessingThreeSource,
70227037
70237038 /// 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 {
70307045 op0: u4,
70317046 };
70327047
7033 /// Advanced SIMD scalar pairwise
7034 pub const SimdScalarPairwise = 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 {
7048 /// Advanced SIMD scalar copy
7049 pub const SimdScalarCopy = packed union {
70667050 group: @This().Group,
7067 smov: Smov,
7068 umov: Umov,
7051 dup: Dup,
70697052
70707053 pub const Group = packed struct {
70717054 Rd: Register.Encoded,
......@@ -7074,227 +7057,2423 @@ pub const Instruction = packed union {
70747057 imm4: u4,
70757058 decoded15: u1 = 0b0,
70767059 imm5: u5,
7077 decoded21: u8 = 0b01110000,
7060 decoded21: u8 = 0b11110000,
70787061 op: u1,
7079 Q: Register.IntegerSize,
7080 decoded31: u1 = 0b0,
7062 decoded30: u2 = 0b01,
70817063 };
70827064
7083 /// C7.2.279 SMOV
7084 pub const Smov = packed struct {
7065 /// C7.2.39 DUP (element)
7066 pub const Dup = packed struct {
70857067 Rd: Register.Encoded,
70867068 Rn: Register.Encoded,
70877069 decoded10: u1 = 0b1,
7088 decoded11: u1 = 0b1,
7089 decoded12: u1 = 0b0,
7090 decoded13: u2 = 0b01,
7070 imm4: u4 = 0b0000,
70917071 decoded15: u1 = 0b0,
70927072 imm5: u5,
7093 decoded21: u8 = 0b01110000,
7094 decoded29: u1 = 0b0,
7095 Q: Register.IntegerSize,
7096 decoded31: u1 = 0b0,
7073 decoded21: u8 = 0b11110000,
7074 op: u1 = 0b0,
7075 decoded30: u2 = 0b01,
70977076 };
70987077
7099 /// C7.2.371 UMOV
7100 pub const Umov = packed struct {
7101 Rd: Register.Encoded,
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,
7078 pub const Decoded = union(enum) {
7079 unallocated,
7080 dup: Dup,
71137081 };
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 }
71147091 };
71157092
7116 /// Advanced SIMD two-register miscellaneous
7117 pub const SimdTwoRegisterMiscellaneous = packed union {
7093 /// Advanced SIMD scalar two-register miscellaneous FP16
7094 pub const SimdScalarTwoRegisterMiscellaneousFp16 = packed union {
71187095 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
71217117 pub const Group = packed struct {
71227118 Rd: Register.Encoded,
71237119 Rn: Register.Encoded,
71247120 decoded10: u2 = 0b10,
71257121 opcode: u5,
7126 decoded17: u5 = 0b10000,
7127 size: Size,
7128 decoded24: u5 = 0b01110,
7129 U: u1,
7130 Q: Q,
7131 decoded31: u1 = 0b0,
7122 decoded17: u6 = 0b111100,
7123 a: u1,
7124 decoded24: u5 = 0b11110,
7125 U: std.builtin.Signedness,
7126 decoded30: u2 = 0b01,
71327127 };
71337128
7134 /// C7.2.38 CNT
7135 pub const Cnt = packed struct {
7129 /// C7.2.80 FCVTNS (vector)
7130 pub const Fcvtns = packed struct {
71367131 Rd: Register.Encoded,
71377132 Rn: Register.Encoded,
71387133 decoded10: u2 = 0b10,
7139 opcode: u5 = 0b00101,
7140 decoded17: u5 = 0b10000,
7141 size: Size,
7142 decoded24: u5 = 0b01110,
7143 U: u1 = 0b0,
7144 Q: Q,
7145 decoded31: u1 = 0b0,
7134 opcode: u5 = 0b11010,
7135 decoded17: u6 = 0b111100,
7136 o2: u1 = 0b0,
7137 decoded24: u5 = 0b11110,
7138 U: std.builtin.Signedness = .signed,
7139 decoded30: u2 = 0b01,
71467140 };
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 {
71557144 Rd: Register.Encoded,
71567145 Rn: Register.Encoded,
71577146 decoded10: u2 = 0b10,
7158 opcode: u5,
7159 decoded17: u5 = 0b11000,
7160 size: Size,
7161 decoded24: u5 = 0b01110,
7162 U: u1,
7163 Q: Q,
7164 decoded31: u1 = 0b0,
7147 opcode: u5 = 0b11011,
7148 decoded17: u6 = 0b111100,
7149 o2: u1 = 0b0,
7150 decoded24: u5 = 0b11110,
7151 U: std.builtin.Signedness = .signed,
7152 decoded30: u2 = 0b01,
71657153 };
71667154
7167 /// C7.2.6 ADDV
7168 pub const Addv = packed struct {
7155 /// C7.2.70 FCVTAS (vector)
7156 pub const Fcvtas = packed struct {
71697157 Rd: Register.Encoded,
71707158 Rn: Register.Encoded,
71717159 decoded10: u2 = 0b10,
7172 opcode: u5 = 0b11011,
7173 decoded17: u5 = 0b11000,
7174 size: Size,
7175 decoded24: u5 = 0b01110,
7176 U: u1 = 0b0,
7177 Q: Q,
7178 decoded31: u1 = 0b0,
7160 opcode: u5 = 0b11100,
7161 decoded17: u6 = 0b111100,
7162 o2: u1 = 0b0,
7163 decoded24: u5 = 0b11110,
7164 U: std.builtin.Signedness = .signed,
7165 decoded30: u2 = 0b01,
71797166 };
7180 };
71817167
7182 /// Advanced SIMD three same
7183 pub const SimdThreeSame = packed union {
7184 group: @This().Group,
7185 addp: Addp,
7186 @"and": And,
7187 bic: Bic,
7188 orr: Orr,
7189 orn: Orn,
7190 eor: Eor,
7168 /// C7.2.234 SCVTF (vector, integer)
7169 pub const Scvtf = packed struct {
7170 Rd: Register.Encoded,
7171 Rn: Register.Encoded,
7172 decoded10: u2 = 0b10,
7173 opcode: u5 = 0b11101,
7174 decoded17: u6 = 0b111100,
7175 o2: u1 = 0b0,
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 {
71937183 Rd: Register.Encoded,
71947184 Rn: Register.Encoded,
7195 decoded10: u1 = 0b1,
7196 opcode: u5,
7197 Rm: Register.Encoded,
7198 decoded21: u1 = 0b1,
7199 size: Size,
7200 decoded24: u5 = 0b01110,
7201 U: u1,
7202 Q: Q,
7203 decoded31: u1 = 0b0,
7185 decoded10: u2 = 0b10,
7186 opcode: u5 = 0b01100,
7187 decoded17: u6 = 0b111100,
7188 o2: u1 = 0b1,
7189 decoded24: u5 = 0b11110,
7190 U: std.builtin.Signedness = .signed,
7191 decoded30: u2 = 0b01,
72047192 };
72057193
7206 /// C7.2.5 ADDP (vector)
7207 pub const Addp = packed struct {
7194 /// C7.2.57 FCMEQ (zero)
7195 pub const Fcmeq = packed struct {
72087196 Rd: Register.Encoded,
72097197 Rn: Register.Encoded,
7210 decoded10: u1 = 0b1,
7211 opcode: u5 = 0b10111,
7212 Rm: Register.Encoded,
7213 decoded21: u1 = 0b1,
7214 size: Size,
7215 decoded24: u5 = 0b01110,
7216 U: u1 = 0b0,
7217 Q: Q,
7218 decoded31: u1 = 0b0,
7198 decoded10: u2 = 0b10,
7199 opcode: u5 = 0b01101,
7200 decoded17: u6 = 0b111100,
7201 o2: u1 = 0b1,
7202 decoded24: u5 = 0b11110,
7203 U: std.builtin.Signedness = .signed,
7204 decoded30: u2 = 0b01,
72197205 };
72207206
7221 /// C7.2.11 AND (vector)
7222 pub const And = packed struct {
7207 /// C7.2.65 FCMLT (zero)
7208 pub const Fcmlt = packed struct {
72237209 Rd: Register.Encoded,
72247210 Rn: Register.Encoded,
7225 decoded10: u1 = 0b1,
7226 opcode: u5 = 0b00011,
7227 Rm: Register.Encoded,
7228 decoded21: u1 = 0b1,
7229 size: Size = .byte,
7230 decoded24: u5 = 0b01110,
7231 U: u1 = 0b0,
7232 Q: Q,
7233 decoded31: u1 = 0b0,
7211 decoded10: u2 = 0b10,
7212 opcode: u5 = 0b01110,
7213 decoded17: u6 = 0b111100,
7214 o2: u1 = 0b1,
7215 decoded24: u5 = 0b11110,
7216 U: std.builtin.Signedness = .signed,
7217 decoded30: u2 = 0b01,
72347218 };
72357219
7236 /// C7.2.21 BIC (vector, register)
7237 pub const Bic = packed struct {
7220 /// C7.2.84 FCVTPS (vector)
7221 pub const Fcvtps = packed struct {
72387222 Rd: Register.Encoded,
72397223 Rn: Register.Encoded,
7240 decoded10: u1 = 0b1,
7241 opcode: u5 = 0b00011,
7242 Rm: Register.Encoded,
7243 decoded21: u1 = 0b1,
7244 size: Size = .half,
7245 decoded24: u5 = 0b01110,
7246 U: u1 = 0b0,
7247 Q: Q,
7248 decoded31: u1 = 0b0,
7224 decoded10: u2 = 0b10,
7225 opcode: u5 = 0b11010,
7226 decoded17: u6 = 0b111100,
7227 o2: u1 = 0b1,
7228 decoded24: u5 = 0b11110,
7229 U: std.builtin.Signedness = .signed,
7230 decoded30: u2 = 0b01,
72497231 };
72507232
7251 /// C7.2.213 ORR (vector, register)
7252 pub const Orr = packed struct {
7233 /// C7.2.90 FCVTZS (vector, integer)
7234 pub const Fcvtzs = packed struct {
72537235 Rd: Register.Encoded,
72547236 Rn: Register.Encoded,
7255 decoded10: u1 = 0b1,
7256 opcode: u5 = 0b00011,
7257 Rm: Register.Encoded,
7258 decoded21: u1 = 0b1,
7259 size: Size = .single,
7260 decoded24: u5 = 0b01110,
7261 U: u1 = 0b0,
7262 Q: Q,
7263 decoded31: u1 = 0b0,
7237 decoded10: u2 = 0b10,
7238 opcode: u5 = 0b11011,
7239 decoded17: u6 = 0b111100,
7240 o2: u1 = 0b1,
7241 decoded24: u5 = 0b11110,
7242 U: std.builtin.Signedness = .signed,
7243 decoded30: u2 = 0b01,
72647244 };
72657245
7266 /// C7.2.211 ORN (vector)
7267 pub const Orn = packed struct {
7246 /// C7.2.144 FRECPE
7247 pub const Frecpe = packed struct {
72687248 Rd: Register.Encoded,
72697249 Rn: Register.Encoded,
7270 decoded10: u1 = 0b1,
7271 opcode: u5 = 0b00011,
7272 Rm: Register.Encoded,
7273 decoded21: u1 = 0b1,
7274 size: Size = .double,
7275 decoded24: u5 = 0b01110,
7276 U: u1 = 0b0,
7277 Q: Q,
7278 decoded31: u1 = 0b0,
7250 decoded10: u2 = 0b10,
7251 opcode: u5 = 0b11101,
7252 decoded17: u6 = 0b111100,
7253 o2: u1 = 0b1,
7254 decoded24: u5 = 0b11110,
7255 U: std.builtin.Signedness = .signed,
7256 decoded30: u2 = 0b01,
72797257 };
72807258
7281 /// C7.2.41 EOR (vector)
7282 pub const Eor = packed struct {
7259 /// C7.2.146 FRECPX
7260 pub const Frecpx = packed struct {
72837261 Rd: Register.Encoded,
72847262 Rn: Register.Encoded,
7285 decoded10: u1 = 0b1,
7286 opcode: u5 = 0b00011,
7287 Rm: Register.Encoded,
7288 decoded21: u1 = 0b1,
7289 size: Size = .byte,
7290 decoded24: u5 = 0b01110,
7291 U: u1 = 0b1,
7292 Q: Q,
7293 decoded31: u1 = 0b0,
7263 decoded10: u2 = 0b10,
7264 opcode: u5 = 0b11111,
7265 decoded17: u6 = 0b111100,
7266 o2: u1 = 0b1,
7267 decoded24: u5 = 0b11110,
7268 U: std.builtin.Signedness = .signed,
7269 decoded30: u2 = 0b01,
72947270 };
7295 };
72967271
7297 /// Advanced SIMD modified immediate
7272 /// 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
72989477 pub const SimdModifiedImmediate = packed union {
72999478 group: @This().Group,
73009479 movi: Movi,
......@@ -8152,6 +10331,58 @@ pub const Instruction = packed union {
815210331 };
815310332 };
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
815510386 /// Floating-point data-processing (3 source)
815610387 pub const FloatDataProcessingThreeSource = packed union {
815710388 group: @This().Group,
......@@ -8240,11 +10471,6 @@ pub const Instruction = packed union {
824010471 };
824110472 };
824210473
8243 pub const Q = enum(u1) {
8244 double = 0b0,
8245 quad = 0b1,
8246 };
8247
824810474 pub const Size = enum(u2) {
824910475 byte = 0b00,
825010476 half = 0b01,
......@@ -8260,22 +10486,66 @@ pub const Instruction = packed union {
826010486 };
826110487 }
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 {
826410541 return switch (vs) {
8265 .byte => .byte,
8266 .half => .half,
10542 else => unreachable,
826710543 .single => .single,
826810544 .double => .double,
10545 .half => .half,
826910546 };
827010547 }
827110548 };
8272
8273 pub const Ftype = enum(u2) {
8274 single = 0b00,
8275 double = 0b01,
8276 quad = 0b10,
8277 half = 0b11,
8278 };
827910549 };
828010550
828110551 pub const AddSubtractOp = enum(u1) {
......@@ -8318,6 +10588,33 @@ pub const Instruction = packed union {
831810588 };
831910589 }
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 }
832110618 /// C6.2.1 ADC
832210619 pub fn adc(d: Register, n: Register, m: Register) Instruction {
832310620 const sf = d.format.integer;
......@@ -8865,6 +11162,45 @@ pub const Instruction = packed union {
886511162 } },
886611163 }
886711164 }
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 }
886811204 /// C6.2.34 BL
886911205 pub fn bl(label: i28) Instruction {
887011206 return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
......@@ -8997,6 +11333,151 @@ pub const Instruction = packed union {
899711333 },
899811334 } } };
899911335 }
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 }
900011481 /// C7.2.38 CNT
900111482 pub fn cnt(d: Register, n: Register) Instruction {
900211483 const arrangement = d.format.vector;
......@@ -9092,6 +11573,57 @@ pub const Instruction = packed union {
909211573 },
909311574 } } };
909411575 }
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 }
909511627 /// C6.2.118 EON (shifted register)
909611628 pub fn eon(d: Register, n: Register, form: union(enum) {
909711629 register: Register,
......@@ -9204,46 +11736,317 @@ pub const Instruction = packed union {
920411736 .word => @as(u5, @intCast(lsb)),
920511737 .doubleword => @as(u6, @intCast(lsb)),
920611738 },
9207 .Rm = m.alias.encode(.{}),
9208 .N = sf,
9209 .sf = sf,
11739 .Rm = m.alias.encode(.{}),
11740 .N = 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 },
921011946 },
9211 } } };
11947 }
921211948 }
9213 /// C7.2.46 FABS (scalar)
9214 pub fn fabs(d: Register, n: Register) Instruction {
9215 const ftype = d.format.scalar;
9216 assert(n.format.scalar == ftype);
9217 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9218 .fabs = .{
9219 .Rd = d.alias.encode(.{ .V = true }),
9220 .Rn = n.alias.encode(.{ .V = true }),
9221 .ftype = switch (ftype) {
11949 /// C7.2.64 FCMLE (zero)
11950 pub fn fcmle(d: Register, n: Register, form: union(enum) { zero }) Instruction {
11951 switch (form) {
11952 .zero => switch (d.format) {
11953 else => unreachable,
11954 .scalar => |ftype| switch (n.format) {
922211955 else => unreachable,
9223 .single => .single,
9224 .double => .double,
9225 .half => .half,
11956 .scalar => |n_scalar| {
11957 assert(n_scalar == ftype);
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 }
922611996 },
922711997 },
9228 } } };
11998 }
922911999 }
9230 /// C7.2.50 FADD (scalar)
9231 pub fn fadd(d: Register, n: Register, m: Register) Instruction {
9232 const ftype = d.format.scalar;
9233 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9234 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9235 .fadd = .{
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) {
12000 /// C7.2.65 FCMLT (zero)
12001 pub fn fcmlt(d: Register, n: Register, form: union(enum) { zero }) Instruction {
12002 switch (form) {
12003 .zero => switch (d.format) {
12004 else => unreachable,
12005 .scalar => |ftype| switch (n.format) {
924012006 else => unreachable,
9241 .single => .single,
9242 .double => .double,
9243 .half => .half,
12007 .scalar => |n_scalar| {
12008 assert(n_scalar == ftype);
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 }
924412047 },
924512048 },
9246 } } };
12049 }
924712050 }
924812051 /// C7.2.66 FCMP
924912052 pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction {
......@@ -9256,12 +12059,7 @@ pub const Instruction = packed union {
925612059 .opc0 = .register,
925712060 .Rn = n.alias.encode(.{ .V = true }),
925812061 .Rm = m.alias.encode(.{ .V = true }),
9259 .ftype = switch (ftype) {
9260 else => unreachable,
9261 .single => .single,
9262 .double => .double,
9263 .half => .half,
9264 },
12062 .ftype = .fromVectorSize(ftype),
926512063 },
926612064 } } };
926712065 },
......@@ -9270,12 +12068,7 @@ pub const Instruction = packed union {
927012068 .opc0 = .register,
927112069 .Rn = n.alias.encode(.{ .V = true }),
927212070 .Rm = @enumFromInt(0b00000),
9273 .ftype = switch (ftype) {
9274 else => unreachable,
9275 .single => .single,
9276 .double => .double,
9277 .half => .half,
9278 },
12071 .ftype = .fromVectorSize(ftype),
927912072 },
928012073 } } },
928112074 }
......@@ -9291,12 +12084,7 @@ pub const Instruction = packed union {
929112084 .opc0 = .zero,
929212085 .Rn = n.alias.encode(.{ .V = true }),
929312086 .Rm = m.alias.encode(.{ .V = true }),
9294 .ftype = switch (ftype) {
9295 else => unreachable,
9296 .single => .single,
9297 .double => .double,
9298 .half => .half,
9299 },
12087 .ftype = .fromVectorSize(ftype),
930012088 },
930112089 } } };
930212090 },
......@@ -9305,16 +12093,25 @@ pub const Instruction = packed union {
930512093 .opc0 = .zero,
930612094 .Rn = n.alias.encode(.{ .V = true }),
930712095 .Rm = @enumFromInt(0b00000),
9308 .ftype = switch (ftype) {
9309 else => unreachable,
9310 .single => .single,
9311 .double => .double,
9312 .half => .half,
9313 },
12096 .ftype = .fromVectorSize(ftype),
931412097 },
931512098 } } },
931612099 }
931712100 }
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 }
931812115 /// C7.2.69 FCVT
931912116 pub fn fcvt(d: Register, n: Register) Instruction {
932012117 assert(d.format.scalar != n.format.scalar);
......@@ -9328,174 +12125,589 @@ pub const Instruction = packed union {
932812125 .double => .double,
932912126 .half => .half,
933012127 },
9331 .ftype = switch (n.format.scalar) {
9332 else => unreachable,
9333 .single => .single,
9334 .double => .double,
9335 .half => .half,
9336 },
12128 .ftype = .fromVectorSize(n.format.scalar),
933712129 },
933812130 } } };
933912131 }
12132 /// C7.2.70 FCVTAS (vector)
934012133 /// C7.2.71 FCVTAS (scalar)
934112134 pub fn fcvtas(d: Register, n: Register) Instruction {
9342 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9343 .fcvtas = .{
9344 .Rd = d.alias.encode(.{}),
9345 .Rn = n.alias.encode(.{ .V = true }),
9346 .ftype = switch (n.format.scalar) {
9347 else => unreachable,
9348 .single => .single,
9349 .double => .double,
9350 .half => .half,
12135 switch (d.format) {
12136 else => unreachable,
12137 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12138 .fcvtas = .{
12139 .Rd = d.alias.encode(.{}),
12140 .Rn = n.alias.encode(.{ .V = true }),
12141 .ftype = .fromVectorSize(n.format.scalar),
12142 .sf = sf,
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 }
935112165 },
9352 .sf = d.format.integer,
935312166 },
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 }
935512189 }
12190 /// C7.2.72 FCVTAU (vector)
935612191 /// C7.2.73 FCVTAU (scalar)
935712192 pub fn fcvtau(d: Register, n: Register) Instruction {
9358 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9359 .fcvtau = .{
9360 .Rd = d.alias.encode(.{}),
9361 .Rn = n.alias.encode(.{ .V = true }),
9362 .ftype = switch (n.format.scalar) {
9363 else => unreachable,
9364 .single => .single,
9365 .double => .double,
9366 .half => .half,
12193 switch (d.format) {
12194 else => unreachable,
12195 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12196 .fcvtau = .{
12197 .Rd = d.alias.encode(.{}),
12198 .Rn = n.alias.encode(.{ .V = true }),
12199 .ftype = .fromVectorSize(n.format.scalar),
12200 .sf = sf,
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 }
936712223 },
9368 .sf = d.format.integer,
936912224 },
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 }
937112247 }
12248 /// C7.2.75 FCVTMS (vector)
937212249 /// C7.2.76 FCVTMS (scalar)
937312250 pub fn fcvtms(d: Register, n: Register) Instruction {
9374 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9375 .fcvtms = .{
9376 .Rd = d.alias.encode(.{}),
9377 .Rn = n.alias.encode(.{ .V = true }),
9378 .ftype = switch (n.format.scalar) {
9379 else => unreachable,
9380 .single => .single,
9381 .double => .double,
9382 .half => .half,
12251 switch (d.format) {
12252 else => unreachable,
12253 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12254 .fcvtms = .{
12255 .Rd = d.alias.encode(.{}),
12256 .Rn = n.alias.encode(.{ .V = true }),
12257 .ftype = .fromVectorSize(n.format.scalar),
12258 .sf = sf,
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 }
938312281 },
9384 .sf = d.format.integer,
938512282 },
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 }
938712305 }
12306 /// C7.2.77 FCVTMU (vector)
938812307 /// C7.2.78 FCVTMU (scalar)
938912308 pub fn fcvtmu(d: Register, n: Register) Instruction {
9390 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9391 .fcvtmu = .{
9392 .Rd = d.alias.encode(.{}),
9393 .Rn = n.alias.encode(.{ .V = true }),
9394 .ftype = switch (n.format.scalar) {
9395 else => unreachable,
9396 .single => .single,
9397 .double => .double,
9398 .half => .half,
12309 switch (d.format) {
12310 else => unreachable,
12311 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12312 .fcvtmu = .{
12313 .Rd = d.alias.encode(.{}),
12314 .Rn = n.alias.encode(.{ .V = true }),
12315 .ftype = .fromVectorSize(n.format.scalar),
12316 .sf = sf,
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 }
939912339 },
9400 .sf = d.format.integer,
940112340 },
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 }
940312363 }
12364 /// C7.2.80 FCVTNS (vector)
940412365 /// C7.2.81 FCVTNS (scalar)
940512366 pub fn fcvtns(d: Register, n: Register) Instruction {
9406 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9407 .fcvtns = .{
9408 .Rd = d.alias.encode(.{}),
9409 .Rn = n.alias.encode(.{ .V = true }),
9410 .ftype = switch (n.format.scalar) {
9411 else => unreachable,
9412 .single => .single,
9413 .double => .double,
9414 .half => .half,
12367 switch (d.format) {
12368 else => unreachable,
12369 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12370 .fcvtns = .{
12371 .Rd = d.alias.encode(.{}),
12372 .Rn = n.alias.encode(.{ .V = true }),
12373 .ftype = .fromVectorSize(n.format.scalar),
12374 .sf = sf,
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 }
941512397 },
9416 .sf = d.format.integer,
941712398 },
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 }
941912421 }
12422 /// C7.2.82 FCVTNU (vector)
942012423 /// C7.2.83 FCVTNU (scalar)
942112424 pub fn fcvtnu(d: Register, n: Register) Instruction {
9422 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9423 .fcvtnu = .{
9424 .Rd = d.alias.encode(.{}),
9425 .Rn = n.alias.encode(.{ .V = true }),
9426 .ftype = switch (n.format.scalar) {
9427 else => unreachable,
9428 .single => .single,
9429 .double => .double,
9430 .half => .half,
12425 switch (d.format) {
12426 else => unreachable,
12427 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12428 .fcvtnu = .{
12429 .Rd = d.alias.encode(.{}),
12430 .Rn = n.alias.encode(.{ .V = true }),
12431 .ftype = .fromVectorSize(n.format.scalar),
12432 .sf = sf,
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 }
943112455 },
9432 .sf = d.format.integer,
943312456 },
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 }
943512479 }
12480 /// C7.2.84 FCVTPS (vector)
943612481 /// C7.2.85 FCVTPS (scalar)
943712482 pub fn fcvtps(d: Register, n: Register) Instruction {
9438 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9439 .fcvtps = .{
9440 .Rd = d.alias.encode(.{}),
9441 .Rn = n.alias.encode(.{ .V = true }),
9442 .ftype = switch (n.format.scalar) {
9443 else => unreachable,
9444 .single => .single,
9445 .double => .double,
9446 .half => .half,
12483 switch (d.format) {
12484 else => unreachable,
12485 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12486 .fcvtps = .{
12487 .Rd = d.alias.encode(.{}),
12488 .Rn = n.alias.encode(.{ .V = true }),
12489 .ftype = .fromVectorSize(n.format.scalar),
12490 .sf = sf,
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 }
944712513 },
9448 .sf = d.format.integer,
944912514 },
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 }
945112537 }
12538 /// C7.2.86 FCVTPU (vector)
945212539 /// C7.2.87 FCVTPU (scalar)
945312540 pub fn fcvtpu(d: Register, n: Register) Instruction {
9454 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9455 .fcvtpu = .{
9456 .Rd = d.alias.encode(.{}),
9457 .Rn = n.alias.encode(.{ .V = true }),
9458 .ftype = switch (n.format.scalar) {
9459 else => unreachable,
9460 .single => .single,
9461 .double => .double,
9462 .half => .half,
12541 switch (d.format) {
12542 else => unreachable,
12543 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12544 .fcvtpu = .{
12545 .Rd = d.alias.encode(.{}),
12546 .Rn = n.alias.encode(.{ .V = true }),
12547 .ftype = .fromVectorSize(n.format.scalar),
12548 .sf = sf,
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 }
946312571 },
9464 .sf = d.format.integer,
946512572 },
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 }
946712595 }
12596 /// C7.2.90 FCVTZS (vector, integer)
946812597 /// C7.2.92 FCVTZS (scalar, integer)
946912598 pub fn fcvtzs(d: Register, n: Register) Instruction {
9470 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9471 .fcvtzs = .{
9472 .Rd = d.alias.encode(.{}),
9473 .Rn = n.alias.encode(.{ .V = true }),
9474 .ftype = switch (n.format.scalar) {
9475 else => unreachable,
9476 .single => .single,
9477 .double => .double,
9478 .half => .half,
12599 switch (d.format) {
12600 else => unreachable,
12601 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12602 .fcvtzs = .{
12603 .Rd = d.alias.encode(.{}),
12604 .Rn = n.alias.encode(.{ .V = true }),
12605 .ftype = .fromVectorSize(n.format.scalar),
12606 .sf = sf,
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 }
947912629 },
9480 .sf = d.format.integer,
948112630 },
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 }
948312653 }
12654 /// C7.2.94 FCVTZU (vector, integer)
948412655 /// C7.2.96 FCVTZU (scalar, integer)
948512656 pub fn fcvtzu(d: Register, n: Register) Instruction {
9486 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9487 .fcvtzu = .{
9488 .Rd = d.alias.encode(.{}),
9489 .Rn = n.alias.encode(.{ .V = true }),
9490 .ftype = switch (n.format.scalar) {
9491 else => unreachable,
9492 .single => .single,
9493 .double => .double,
9494 .half => .half,
12657 switch (d.format) {
12658 else => unreachable,
12659 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
12660 .fcvtzu = .{
12661 .Rd = d.alias.encode(.{}),
12662 .Rn = n.alias.encode(.{ .V = true }),
12663 .ftype = .fromVectorSize(n.format.scalar),
12664 .sf = sf,
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 }
949512687 },
9496 .sf = d.format.integer,
949712688 },
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 }
949912711 }
950012712 /// C7.2.98 FDIV (scalar)
950112713 pub fn fdiv(d: Register, n: Register, m: Register) Instruction {
......@@ -9506,12 +12718,7 @@ pub const Instruction = packed union {
950612718 .Rd = d.alias.encode(.{ .V = true }),
950712719 .Rn = n.alias.encode(.{ .V = true }),
950812720 .Rm = m.alias.encode(.{ .V = true }),
9509 .ftype = switch (ftype) {
9510 else => unreachable,
9511 .single => .single,
9512 .double => .double,
9513 .half => .half,
9514 },
12721 .ftype = .fromVectorSize(ftype),
951512722 },
951612723 } } };
951712724 }
......@@ -9536,12 +12743,7 @@ pub const Instruction = packed union {
953612743 .Rn = n.alias.encode(.{ .V = true }),
953712744 .Rm = m.alias.encode(.{ .V = true }),
953812745 .Ra = a.alias.encode(.{ .V = true }),
9539 .ftype = switch (ftype) {
9540 else => unreachable,
9541 .single => .single,
9542 .double => .double,
9543 .half => .half,
9544 },
12746 .ftype = .fromVectorSize(ftype),
954512747 },
954612748 } } };
954712749 }
......@@ -9554,12 +12756,7 @@ pub const Instruction = packed union {
955412756 .Rd = d.alias.encode(.{ .V = true }),
955512757 .Rn = n.alias.encode(.{ .V = true }),
955612758 .Rm = m.alias.encode(.{ .V = true }),
9557 .ftype = switch (ftype) {
9558 else => unreachable,
9559 .single => .single,
9560 .double => .double,
9561 .half => .half,
9562 },
12759 .ftype = .fromVectorSize(ftype),
956312760 },
956412761 } } };
956512762 }
......@@ -9569,15 +12766,10 @@ pub const Instruction = packed union {
956912766 assert(n.format.scalar == ftype and m.format.scalar == ftype);
957012767 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
957112768 .fmaxnm = .{
9572 .Rd = d.alias.encode(.{ .V = true }),
9573 .Rn = n.alias.encode(.{ .V = true }),
9574 .Rm = m.alias.encode(.{ .V = true }),
9575 .ftype = switch (ftype) {
9576 else => unreachable,
9577 .single => .single,
9578 .double => .double,
9579 .half => .half,
9580 },
12769 .Rd = d.alias.encode(.{ .V = true }),
12770 .Rn = n.alias.encode(.{ .V = true }),
12771 .Rm = m.alias.encode(.{ .V = true }),
12772 .ftype = .fromVectorSize(ftype),
958112773 },
958212774 } } };
958312775 }
......@@ -9590,12 +12782,7 @@ pub const Instruction = packed union {
959012782 .Rd = d.alias.encode(.{ .V = true }),
959112783 .Rn = n.alias.encode(.{ .V = true }),
959212784 .Rm = m.alias.encode(.{ .V = true }),
9593 .ftype = switch (ftype) {
9594 else => unreachable,
9595 .single => .single,
9596 .double => .double,
9597 .half => .half,
9598 },
12785 .ftype = .fromVectorSize(ftype),
959912786 },
960012787 } } };
960112788 }
......@@ -9608,12 +12795,7 @@ pub const Instruction = packed union {
960812795 .Rd = d.alias.encode(.{ .V = true }),
960912796 .Rn = n.alias.encode(.{ .V = true }),
961012797 .Rm = m.alias.encode(.{ .V = true }),
9611 .ftype = switch (ftype) {
9612 else => unreachable,
9613 .single => .single,
9614 .double => .double,
9615 .half => .half,
9616 },
12798 .ftype = .fromVectorSize(ftype),
961712799 },
961812800 } } };
961912801 }
......@@ -9640,12 +12822,7 @@ pub const Instruction = packed union {
964012822 .fmov = .{
964112823 .Rd = d.alias.encode(.{ .V = true }),
964212824 .imm8 = imm,
9643 .ftype = switch (ftype) {
9644 else => unreachable,
9645 .single => .single,
9646 .double => .double,
9647 .half => .half,
9648 },
12825 .ftype = .fromVectorSize(ftype),
964912826 },
965012827 } } },
965112828 .vector => |arrangement| {
......@@ -9678,12 +12855,7 @@ pub const Instruction = packed union {
967812855 .Rn = n.alias.encode(.{ .V = true }),
967912856 .opcode = .float_to_integer,
968012857 .rmode = .@"0",
9681 .ftype = switch (ftype) {
9682 else => unreachable,
9683 .single => .single,
9684 .double => .double,
9685 .half => .half,
9686 },
12858 .ftype = .fromVectorSize(ftype),
968712859 .sf = sf,
968812860 },
968912861 } } };
......@@ -9721,12 +12893,7 @@ pub const Instruction = packed union {
972112893 .Rn = n.alias.encode(.{}),
972212894 .opcode = .integer_to_float,
972312895 .rmode = .@"0",
9724 .ftype = switch (ftype) {
9725 else => unreachable,
9726 .single => .single,
9727 .double => .double,
9728 .half => .half,
9729 },
12896 .ftype = .fromVectorSize(ftype),
973012897 .sf = sf,
973112898 },
973212899 } } };
......@@ -9737,12 +12904,7 @@ pub const Instruction = packed union {
973712904 .fmov = .{
973812905 .Rd = d.alias.encode(.{ .V = true }),
973912906 .Rn = n.alias.encode(.{ .V = true }),
9740 .ftype = switch (ftype) {
9741 else => unreachable,
9742 .single => .single,
9743 .double => .double,
9744 .half => .half,
9745 },
12907 .ftype = .fromVectorSize(ftype),
974612908 },
974712909 } } };
974812910 },
......@@ -9779,12 +12941,7 @@ pub const Instruction = packed union {
977912941 .Rn = n.alias.encode(.{ .V = true }),
978012942 .Rm = m.alias.encode(.{ .V = true }),
978112943 .Ra = a.alias.encode(.{ .V = true }),
9782 .ftype = switch (ftype) {
9783 else => unreachable,
9784 .single => .single,
9785 .double => .double,
9786 .half => .half,
9787 },
12944 .ftype = .fromVectorSize(ftype),
978812945 },
978912946 } } };
979012947 }
......@@ -9797,31 +12954,47 @@ pub const Instruction = packed union {
979712954 .Rd = d.alias.encode(.{ .V = true }),
979812955 .Rn = n.alias.encode(.{ .V = true }),
979912956 .Rm = m.alias.encode(.{ .V = true }),
9800 .ftype = switch (ftype) {
9801 else => unreachable,
9802 .single => .single,
9803 .double => .double,
9804 .half => .half,
9805 },
12957 .ftype = .fromVectorSize(ftype),
980612958 },
980712959 } } };
980812960 }
12961 /// C7.2.139 FNEG (vector)
980912962 /// C7.2.140 FNEG (scalar)
981012963 pub fn fneg(d: Register, n: Register) Instruction {
9811 const ftype = d.format.scalar;
9812 assert(n.format.scalar == ftype);
9813 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9814 .fneg = .{
9815 .Rd = d.alias.encode(.{ .V = true }),
9816 .Rn = n.alias.encode(.{ .V = true }),
9817 .ftype = switch (ftype) {
12964 switch (d.format) {
12965 else => unreachable,
12966 .vector => |arrangement| {
12967 assert(n.format.vector == arrangement);
12968 switch (arrangement.elemSize()) {
981812969 else => unreachable,
9819 .single => .single,
9820 .double => .double,
9821 .half => .half,
9822 },
12970 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
12971 .fneg = .{
12972 .Rd = d.alias.encode(.{ .V = true }),
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 }
982312986 },
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 }
982512998 }
982612999 /// C7.2.141 FNMADD
982713000 pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
......@@ -9833,12 +13006,7 @@ pub const Instruction = packed union {
983313006 .Rn = n.alias.encode(.{ .V = true }),
983413007 .Rm = m.alias.encode(.{ .V = true }),
983513008 .Ra = a.alias.encode(.{ .V = true }),
9836 .ftype = switch (ftype) {
9837 else => unreachable,
9838 .single => .single,
9839 .double => .double,
9840 .half => .half,
9841 },
13009 .ftype = .fromVectorSize(ftype),
984213010 },
984313011 } } };
984413012 }
......@@ -9852,12 +13020,7 @@ pub const Instruction = packed union {
985213020 .Rn = n.alias.encode(.{ .V = true }),
985313021 .Rm = m.alias.encode(.{ .V = true }),
985413022 .Ra = a.alias.encode(.{ .V = true }),
9855 .ftype = switch (ftype) {
9856 else => unreachable,
9857 .single => .single,
9858 .double => .double,
9859 .half => .half,
9860 },
13023 .ftype = .fromVectorSize(ftype),
986113024 },
986213025 } } };
986313026 }
......@@ -9870,150 +13033,313 @@ pub const Instruction = packed union {
987013033 .Rd = d.alias.encode(.{ .V = true }),
987113034 .Rn = n.alias.encode(.{ .V = true }),
987213035 .Rm = m.alias.encode(.{ .V = true }),
9873 .ftype = switch (ftype) {
9874 else => unreachable,
9875 .single => .single,
9876 .double => .double,
9877 .half => .half,
9878 },
13036 .ftype = .fromVectorSize(ftype),
987913037 },
988013038 } } };
988113039 }
13040 /// C7.2.155 FRINTA (vector)
988213041 /// C7.2.156 FRINTA (scalar)
988313042 pub fn frinta(d: Register, n: Register) Instruction {
9884 const ftype = d.format.scalar;
9885 assert(n.format.scalar == ftype);
9886 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9887 .frinta = .{
9888 .Rd = d.alias.encode(.{ .V = true }),
9889 .Rn = n.alias.encode(.{ .V = true }),
9890 .ftype = switch (ftype) {
13043 switch (d.format) {
13044 else => unreachable,
13045 .vector => |arrangement| {
13046 assert(arrangement != .@"1d" and n.format.vector == arrangement);
13047 switch (arrangement.elemSize()) {
989113048 else => unreachable,
9892 .single => .single,
9893 .double => .double,
9894 .half => .half,
9895 },
13049 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13050 .frinta = .{
13051 .Rd = d.alias.encode(.{ .V = true }),
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 }
989613065 },
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 }
989813077 }
13078 /// C7.2.157 FRINTI (vector)
989913079 /// C7.2.158 FRINTI (scalar)
990013080 pub fn frinti(d: Register, n: Register) Instruction {
9901 const ftype = d.format.scalar;
9902 assert(n.format.scalar == ftype);
9903 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9904 .frinti = .{
9905 .Rd = d.alias.encode(.{ .V = true }),
9906 .Rn = n.alias.encode(.{ .V = true }),
9907 .ftype = switch (ftype) {
13081 switch (d.format) {
13082 else => unreachable,
13083 .vector => |arrangement| {
13084 assert(arrangement != .@"1d" and n.format.vector == arrangement);
13085 switch (arrangement.elemSize()) {
990813086 else => unreachable,
9909 .single => .single,
9910 .double => .double,
9911 .half => .half,
9912 },
13087 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13088 .frinti = .{
13089 .Rd = d.alias.encode(.{ .V = true }),
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 }
991313103 },
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 }
991513115 }
13116 /// C7.2.159 FRINTM (vector)
991613117 /// C7.2.160 FRINTM (scalar)
991713118 pub fn frintm(d: Register, n: Register) Instruction {
9918 const ftype = d.format.scalar;
9919 assert(n.format.scalar == ftype);
9920 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9921 .frintm = .{
9922 .Rd = d.alias.encode(.{ .V = true }),
9923 .Rn = n.alias.encode(.{ .V = true }),
9924 .ftype = switch (ftype) {
13119 switch (d.format) {
13120 else => unreachable,
13121 .vector => |arrangement| {
13122 assert(arrangement != .@"1d" and n.format.vector == arrangement);
13123 switch (arrangement.elemSize()) {
992513124 else => unreachable,
9926 .single => .single,
9927 .double => .double,
9928 .half => .half,
9929 },
13125 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13126 .frintm = .{
13127 .Rd = d.alias.encode(.{ .V = true }),
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 }
993013141 },
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 }
993213153 }
13154 /// C7.2.161 FRINTN (vector)
993313155 /// C7.2.162 FRINTN (scalar)
993413156 pub fn frintn(d: Register, n: Register) Instruction {
9935 const ftype = d.format.scalar;
9936 assert(n.format.scalar == ftype);
9937 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9938 .frintn = .{
9939 .Rd = d.alias.encode(.{ .V = true }),
9940 .Rn = n.alias.encode(.{ .V = true }),
9941 .ftype = switch (ftype) {
13157 switch (d.format) {
13158 else => unreachable,
13159 .vector => |arrangement| {
13160 assert(arrangement != .@"1d" and n.format.vector == arrangement);
13161 switch (arrangement.elemSize()) {
994213162 else => unreachable,
9943 .single => .single,
9944 .double => .double,
9945 .half => .half,
9946 },
13163 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13164 .frintn = .{
13165 .Rd = d.alias.encode(.{ .V = true }),
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 }
994713179 },
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 }
994913191 }
13192 /// C7.2.163 FRINTP (vector)
995013193 /// C7.2.164 FRINTP (scalar)
995113194 pub fn frintp(d: Register, n: Register) Instruction {
9952 const ftype = d.format.scalar;
9953 assert(n.format.scalar == ftype);
9954 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9955 .frintp = .{
9956 .Rd = d.alias.encode(.{ .V = true }),
9957 .Rn = n.alias.encode(.{ .V = true }),
9958 .ftype = switch (ftype) {
13195 switch (d.format) {
13196 else => unreachable,
13197 .vector => |arrangement| {
13198 assert(arrangement != .@"1d" and n.format.vector == arrangement);
13199 switch (arrangement.elemSize()) {
995913200 else => unreachable,
9960 .single => .single,
9961 .double => .double,
9962 .half => .half,
9963 },
13201 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13202 .frintp = .{
13203 .Rd = d.alias.encode(.{ .V = true }),
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 }
996413217 },
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 }
996613229 }
13230 /// C7.2.165 FRINTX (vector)
996713231 /// C7.2.166 FRINTX (scalar)
996813232 pub fn frintx(d: Register, n: Register) Instruction {
9969 const ftype = d.format.scalar;
9970 assert(n.format.scalar == ftype);
9971 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9972 .frintx = .{
9973 .Rd = d.alias.encode(.{ .V = true }),
9974 .Rn = n.alias.encode(.{ .V = true }),
9975 .ftype = switch (ftype) {
13233 switch (d.format) {
13234 else => unreachable,
13235 .vector => |arrangement| {
13236 assert(arrangement != .@"1d" and n.format.vector == arrangement);
13237 switch (arrangement.elemSize()) {
997613238 else => unreachable,
9977 .single => .single,
9978 .double => .double,
9979 .half => .half,
9980 },
13239 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13240 .frintx = .{
13241 .Rd = d.alias.encode(.{ .V = true }),
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 }
998113255 },
9982 } } };
9983 }
9984 /// C7.2.168 FRINTZ (scalar)
9985 pub fn frintz(d: Register, n: Register) Instruction {
9986 const ftype = d.format.scalar;
9987 assert(n.format.scalar == ftype);
9988 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9989 .frintz = .{
9990 .Rd = d.alias.encode(.{ .V = true }),
9991 .Rn = n.alias.encode(.{ .V = true }),
9992 .ftype = switch (ftype) {
13256 .scalar => |ftype| {
13257 assert(n.format.scalar == ftype);
13258 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
13259 .frintx = .{
13260 .Rd = d.alias.encode(.{ .V = true }),
13261 .Rn = n.alias.encode(.{ .V = true }),
13262 .ftype = .fromVectorSize(ftype),
13263 },
13264 } } };
13265 },
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()) {
999313276 else => unreachable,
9994 .single => .single,
9995 .double => .double,
9996 .half => .half,
9997 },
13277 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13278 .frintz = .{
13279 .Rd = d.alias.encode(.{ .V = true }),
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 }
999813293 },
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 }
1000013305 }
13306 /// C7.2.171 FSQRT (vector)
1000113307 /// C7.2.172 FSQRT (scalar)
1000213308 pub fn fsqrt(d: Register, n: Register) Instruction {
10003 const ftype = d.format.scalar;
10004 assert(n.format.scalar == ftype);
10005 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
10006 .fsqrt = .{
10007 .Rd = d.alias.encode(.{ .V = true }),
10008 .Rn = n.alias.encode(.{ .V = true }),
10009 .ftype = switch (ftype) {
13309 switch (d.format) {
13310 else => unreachable,
13311 .vector => |arrangement| {
13312 assert(n.format.vector == arrangement);
13313 switch (arrangement.elemSize()) {
1001013314 else => unreachable,
10011 .single => .single,
10012 .double => .double,
10013 .half => .half,
10014 },
13315 .half => return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous_fp16 = .{
13316 .fsqrt = .{
13317 .Rd = d.alias.encode(.{ .V = true }),
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 }
1001513331 },
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 }
1001713343 }
1001813344 /// C7.2.174 FSUB (scalar)
1001913345 pub fn fsub(d: Register, n: Register, m: Register) Instruction {
......@@ -10024,12 +13350,7 @@ pub const Instruction = packed union {
1002413350 .Rd = d.alias.encode(.{ .V = true }),
1002513351 .Rn = n.alias.encode(.{ .V = true }),
1002613352 .Rm = m.alias.encode(.{ .V = true }),
10027 .ftype = switch (ftype) {
10028 else => unreachable,
10029 .single => .single,
10030 .double => .double,
10031 .half => .half,
10032 },
13353 .ftype = .fromVectorSize(ftype),
1003313354 },
1003413355 } } };
1003513356 }
......@@ -10087,26 +13408,26 @@ pub const Instruction = packed union {
1008713408 },
1008813409 } } } };
1008913410 },
10090 .signed_offset => |signed_offset| {
10091 assert(signed_offset.base.format.integer == .doubleword);
10092 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
13411 .pre_index => |pre_index| {
13412 assert(pre_index.base.format.integer == .doubleword);
13413 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
1009313414 .ldp = .{
1009413415 .Rt = t1.alias.encode(.{}),
10095 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
13416 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
1009613417 .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))),
1009813419 .sf = sf,
1009913420 },
1010013421 } } } };
1010113422 },
10102 .pre_index => |pre_index| {
10103 assert(pre_index.base.format.integer == .doubleword);
10104 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
13423 .signed_offset => |signed_offset| {
13424 assert(signed_offset.base.format.integer == .doubleword);
13425 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
1010513426 .ldp = .{
1010613427 .Rt = t1.alias.encode(.{}),
10107 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
13428 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
1010813429 .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))),
1011013431 .sf = sf,
1011113432 },
1011213433 } } } };
......@@ -11019,12 +14340,52 @@ pub const Instruction = packed union {
1101914340 },
1102014341 } } };
1102114342 }
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 }
1102214370 /// C6.2.238 NOP
1102314371 pub fn nop() Instruction {
1102414372 return .{ .branch_exception_generating_system = .{ .hints = .{
1102514373 .nop = .{},
1102614374 } } };
1102714375 }
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 }
1102814389 /// C6.2.239 ORN (shifted register)
1102914390 /// C7.2.211 ORN (vector)
1103014391 pub fn orn(d: Register, n: Register, form: union(enum) {
......@@ -11341,21 +14702,63 @@ pub const Instruction = packed union {
1134114702 },
1134214703 } } };
1134314704 }
14705 /// C7.2.234 SCVTF (vector, integer)
1134414706 /// C7.2.236 SCVTF (scalar, integer)
1134514707 pub fn scvtf(d: Register, n: Register) Instruction {
11346 return .{ .data_processing_vector = .{ .convert_float_integer = .{
11347 .scvtf = .{
11348 .Rd = d.alias.encode(.{ .V = true }),
11349 .Rn = n.alias.encode(.{}),
11350 .ftype = switch (d.format.scalar) {
11351 else => unreachable,
11352 .single => .single,
11353 .double => .double,
11354 .half => .half,
14708 switch (d.format) {
14709 else => unreachable,
14710 .scalar => |ftype| switch (n.format) {
14711 else => unreachable,
14712 .scalar => |elem_size| {
14713 assert(ftype == elem_size);
14714 switch (ftype) {
14715 else => unreachable,
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 }
1135514730 },
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 } } },
1135714739 },
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 }
1135914762 }
1136014763 /// C6.2.270 SDIV
1136114764 pub fn sdiv(d: Register, n: Register, m: Register) Instruction {
......@@ -11446,6 +14849,60 @@ pub const Instruction = packed union {
1144614849 },
1144714850 } } };
1144814851 }
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 }
1144914906 /// C6.2.321 STP
1145014907 /// C7.2.330 STP (SIMD&FP)
1145114908 pub fn stp(t1: Register, t2: Register, form: union(enum) {
......@@ -11471,26 +14928,26 @@ pub const Instruction = packed union {
1147114928 },
1147214929 } } } };
1147314930 },
11474 .signed_offset => |signed_offset| {
11475 assert(signed_offset.base.format.integer == .doubleword);
11476 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
14931 .pre_index => |pre_index| {
14932 assert(pre_index.base.format.integer == .doubleword);
14933 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
1147714934 .stp = .{
1147814935 .Rt = t1.alias.encode(.{}),
11479 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
14936 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
1148014937 .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))),
1148214939 .sf = sf,
1148314940 },
1148414941 } } } };
1148514942 },
11486 .pre_index => |pre_index| {
11487 assert(pre_index.base.format.integer == .doubleword);
11488 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
14943 .signed_offset => |signed_offset| {
14944 assert(signed_offset.base.format.integer == .doubleword);
14945 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
1148914946 .stp = .{
1149014947 .Rt = t1.alias.encode(.{}),
11491 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
14948 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
1149214949 .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))),
1149414951 .sf = sf,
1149514952 },
1149614953 } } } };
......@@ -11940,6 +15397,33 @@ pub const Instruction = packed union {
1194015397 } },
1194115398 }
1194215399 }
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 }
1194315427 /// C6.2.365 SVC
1194415428 pub fn svc(imm: u16) Instruction {
1194515429 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
......@@ -12019,21 +15503,63 @@ pub const Instruction = packed union {
1201915503 },
1202015504 } } };
1202115505 }
15506 /// C7.2.353 UCVTF (vector, integer)
1202215507 /// C7.2.355 UCVTF (scalar, integer)
1202315508 pub fn ucvtf(d: Register, n: Register) Instruction {
12024 return .{ .data_processing_vector = .{ .convert_float_integer = .{
12025 .ucvtf = .{
12026 .Rd = d.alias.encode(.{ .V = true }),
12027 .Rn = n.alias.encode(.{}),
12028 .ftype = switch (d.format.scalar) {
12029 else => unreachable,
12030 .single => .single,
12031 .double => .double,
12032 .half => .half,
15509 switch (d.format) {
15510 else => unreachable,
15511 .scalar => |ftype| switch (n.format) {
15512 else => unreachable,
15513 .scalar => |elem_size| {
15514 assert(ftype == elem_size);
15515 switch (ftype) {
15516 else => unreachable,
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 }
1203315531 },
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 } } },
1203515540 },
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 }
1203715563 }
1203815564 /// C6.2.387 UDF
1203915565 pub fn udf(imm: u16) Instruction {
......@@ -12147,7 +15673,7 @@ pub const Instruction = packed union {
1214715673 }
1214815674
1214915675 comptime {
12150 @setEvalBranchQuota(68_000);
15676 @setEvalBranchQuota(110_000);
1215115677 verify(@typeName(Instruction), Instruction);
1215215678 }
1215315679 fn verify(name: []const u8, Type: type) void {
src/codegen/aarch64/instructions.zon+190
......@@ -213,6 +213,63 @@
213213 },
214214 .encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
215215 },
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 },
216273 // C6.2.35 BLR
217274 .{
218275 .pattern = "BLR <Xn>",
......@@ -681,6 +738,82 @@
681738 },
682739 .encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
683740 },
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 },
684817 // C6.2.220 MOV (to/from SP)
685818 .{
686819 .pattern = "MOV WSP, <Wn|WSP>",
......@@ -964,6 +1097,63 @@
9641097 },
9651098 .encode = .{ .ret, .Xn },
9661099 },
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 },
9671157 // C6.2.268 SBFM
9681158 .{
9691159 .pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>",
src/codegen/llvm.zig+3-1
......@@ -4339,9 +4339,11 @@ pub const Object = struct {
43394339 /// types to work around a LLVM deficiency when targeting ARM/AArch64.
43404340 fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {
43414341 const zcu = pt.zcu;
4342 const ip = &zcu.intern_pool;
43424343 const int_ty = switch (ty.zigTypeTag(zcu)) {
43434344 .int => ty,
43444345 .@"enum" => ty.intTagType(zcu),
4346 .@"struct" => Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),
43454347 .float => {
43464348 if (!is_rmw_xchg) return .none;
43474349 return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));
......@@ -11424,7 +11426,7 @@ pub const FuncGen = struct {
1142411426
1142511427 if (workaround_disable_truncate) {
1142611428 // 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.
1142811430 return try fg.wip.load(access_kind, payload_llvm_ty, payload_ptr, payload_alignment, "");
1142911431 }
1143011432
src/link/Dwarf.zig+11-28
......@@ -142,8 +142,8 @@ const DebugInfo = struct {
142142 &abbrev_code_buf,
143143 debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off,
144144 ) != abbrev_code_buf.len) return error.InputOutput;
145 var abbrev_code_br: std.io.Reader = .fixed(&abbrev_code_buf);
146 return @enumFromInt(abbrev_code_br.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable);
145 var abbrev_code_reader: std.Io.Reader = .fixed(&abbrev_code_buf);
146 return @enumFromInt(abbrev_code_reader.takeLeb128(@typeInfo(AbbrevCode).@"enum".tag_type) catch unreachable);
147147 }
148148
149149 const trailer_bytes = 1 + 1;
......@@ -2094,7 +2094,7 @@ pub const WipNav = struct {
20942094 .generic_decl_const,
20952095 .generic_decl_func,
20962096 => true,
2097 else => unreachable,
2097 else => |t| std.debug.panic("bad decl abbrev code: {t}", .{t}),
20982098 };
20992099 if (parent_type.getCaptures(zcu).len == 0) {
21002100 if (was_generic_decl) try dwarf.freeCommonEntry(wip_nav.unit, decl_gop.value_ptr.*);
......@@ -6104,33 +6104,16 @@ fn sectionOffsetBytes(dwarf: *Dwarf) u32 {
61046104}
61056105
61066106fn uleb128Bytes(value: anytype) u32 {
6107 return leb128Bytes(switch (@typeInfo(@TypeOf(value))) {
6108 .comptime_int => @as(std.math.IntFittingRange(0, @abs(value)), value),
6109 .int => |value_info| switch (value_info.signedness) {
6110 .signed => @as(@Type(.{ .int = .{ .signedness = .unsigned, .bits = value_info.bits -| 1 } }), @intCast(value)),
6111 .unsigned => value,
6112 },
6113 else => comptime unreachable,
6114 });
6107 var trash_buffer: [64]u8 = undefined;
6108 var d: std.Io.Writer.Discarding = .init(&trash_buffer);
6109 d.writer.writeUleb128(value) catch unreachable;
6110 return @intCast(d.count + d.writer.end);
61156111}
61166112fn sleb128Bytes(value: anytype) u32 {
6117 return leb128Bytes(switch (@typeInfo(@TypeOf(value))) {
6118 .comptime_int => @as(std.math.IntFittingRange(@min(value, -1), @max(0, value)), value),
6119 .int => |value_info| switch (value_info.signedness) {
6120 .signed => value,
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);
6113 var trash_buffer: [64]u8 = undefined;
6114 var d: std.Io.Writer.Discarding = .init(&trash_buffer);
6115 d.writer.writeSleb128(value) catch unreachable;
6116 return @intCast(d.count + d.writer.end);
61346117}
61356118
61366119/// 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
11981198 const chdr = (try r.takeStruct(elf.Elf64_Chdr)).*;
11991199 switch (chdr.ch_type) {
12001200 .ZLIB => {
1201 var bw: Writer = .fixed(try gpa.alloc(u8, std.math.cast(usize, chdr.ch_size) orelse return error.Overflow));
1202 errdefer gpa.free(bw.buffer);
1203 try std.compress.zlib.decompress(&r, &bw);
1204 if (bw.end != bw.buffer.len) return error.InputOutput;
1205 return bw.buffer;
1201 var stream: std.Io.Reader = .fixed(data[@sizeOf(elf.Elf64_Chdr)..]);
1202 var zlib_stream: std.compress.flate.Decompress = .init(&stream, .zlib, &.{});
1203 const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow;
1204 var aw: std.Io.Writer.Allocating = .init(gpa);
1205 try aw.ensureUnusedCapacity(size);
1206 defer aw.deinit();
1207 _ = try zlib_stream.reader.streamRemaining(&aw.writer);
1208 return aw.toOwnedSlice();
12061209 },
12071210 else => @panic("TODO unhandled compression scheme"),
12081211 }
src/main.zig+7-2
......@@ -361,7 +361,12 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
361361 dev.check(.env_command);
362362 verifyLibcxxCorrectlyLinked();
363363 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 );
365370 return stdout_writer.interface.flush();
366371 } else if (mem.eql(u8, cmd, "reduce")) {
367372 return jitCmd(gpa, arena, cmd_args, .{
......@@ -4639,7 +4644,7 @@ const usage_init =
46394644 \\ directory.
46404645 \\
46414646 \\Options:
4642 \\ -s, --strip Generate files without comments
4647 \\ -m, --minimal Use minimal init template
46434648 \\ -h, --help Print this help and exit
46444649 \\
46454650 \\
src/print_env.zig+33-11
......@@ -1,21 +1,43 @@
11const std = @import("std");
2const builtin = @import("builtin");
23const build_options = @import("build_options");
3const introspect = @import("introspect.zig");
4const Compilation = @import("Compilation.zig");
45const Allocator = std.mem.Allocator;
6const EnvVar = std.zig.EnvVar;
57const fatal = std.process.fatal;
68
7pub fn cmdEnv(arena: Allocator, out: *std.Io.Writer) !void {
8 const cwd_path = try introspect.getResolvedCwd(arena);
9 const self_exe_path = try std.fs.selfExePathAlloc(arena);
10
11 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, cwd_path, self_exe_path) catch |err| {
12 fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});
9pub fn cmdEnv(
10 arena: Allocator,
11 out: *std.Io.Writer,
12 args: []const []const u8,
13 wasi_preopens: switch (builtin.target.os.tag) {
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 },
1326 };
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
2042 const host = try std.zig.system.resolveTargetQuery(.{});
2143 const triple = try host.zigTriple(arena);
......@@ -24,7 +46,7 @@ pub fn cmdEnv(arena: Allocator, out: *std.Io.Writer) !void {
2446 var root = try serializer.beginStruct(.{});
2547
2648 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, .{});
2850 try root.field("std_dir", zig_std_dir, .{});
2951 try root.field("global_cache_dir", global_cache_dir, .{});
3052 try root.field("version", build_options.version, .{});
src/target.zig+12-6
......@@ -236,7 +236,7 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
236236pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
237237 if (target.cpu.arch.isSpirV()) return true;
238238 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) {
240240 // Self-hosted linker needs work: https://github.com/ziglang/zig/issues/24341
241241 return false;
242242 }
......@@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
248248 return false;
249249}
250250
251pub fn supportsStackProbing(target: *const std.Target) bool {
252 return target.os.tag != .windows and target.os.tag != .uefi and
253 (target.cpu.arch == .x86 or target.cpu.arch == .x86_64);
251pub fn supportsStackProbing(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
252 return switch (backend) {
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 };
254258}
255259
256260pub 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
347351 }
348352}
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 {
351355 switch (target.os.tag) {
352356 .plan9 => return false,
353357 else => {},
......@@ -369,7 +373,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime
369373 };
370374}
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 {
373377 switch (target.cpu.arch) {
374378 .spirv32, .spirv64 => return false,
375379 // 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
378382 }
379383 return switch (zigBackend(target, use_llvm)) {
380384 .stage2_llvm => true,
385 .stage2_wasm => false,
381386 .stage2_x86_64 => switch (target.ofmt) {
382387 .elf, .macho => true,
383388 else => have_llvm,
......@@ -856,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile
856861pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {
857862 return switch (feature) {
858863 .panic_fn => switch (backend) {
864 .stage2_aarch64,
859865 .stage2_c,
860866 .stage2_llvm,
861867 .stage2_x86_64,
test/behavior/array.zig+13-3
......@@ -395,7 +395,6 @@ test "array literal as argument to function" {
395395}
396396
397397test "double nested array to const slice cast in array literal" {
398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
400399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
401400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -541,7 +540,6 @@ test "sentinel element count towards the ABI size calculation" {
541540}
542541
543542test "zero-sized array with recursive type definition" {
544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
545543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
546544 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
547545
......@@ -650,7 +648,6 @@ test "runtime initialized sentinel-terminated array literal" {
650648}
651649
652650test "array of array agregate init" {
653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
654651 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
655652 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"
11001097 // We can't check the value, but it's zero-bit, so the type matching is good enough.
11011098 comptime assert(@TypeOf(loaded) == @TypeOf(.{}));
11021099}
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 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
54
65const supports_128_bit_atomics = switch (builtin.cpu.arch) {
76 // TODO: Ideally this could be sync'd with the logic in Sema.
......@@ -364,25 +363,32 @@ test "atomics with different types" {
364363 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365364 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
366365 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
366 if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // #24282
367367
368368 try testAtomicsWithType(bool, true, false);
369369
370370 try testAtomicsWithType(u1, 0, 1);
371 try testAtomicsWithType(i4, 0, 1);
372 try testAtomicsWithType(u5, 0, 1);
373 try testAtomicsWithType(i15, 0, 1);
374 try testAtomicsWithType(u24, 0, 1);
371 try testAtomicsWithType(i4, 2, 1);
372 try testAtomicsWithType(u5, 2, 1);
373 try testAtomicsWithType(i15, 2, 1);
374 try testAtomicsWithType(u24, 2, 1);
375375
376376 try testAtomicsWithType(u0, 0, 0);
377377 try testAtomicsWithType(i0, 0, 0);
378378
379379 try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);
380 try testAtomicsWithType(enum(u19) { x = 1234, y = 5678 }, .x, .y);
380381
381382 try testAtomicsWithPackedStruct(
382383 packed struct { x: u7, y: u24, z: bool },
383384 .{ .x = 1, .y = 2, .z = true },
384385 .{ .x = 3, .y = 4, .z = false },
385386 );
387 try testAtomicsWithPackedStruct(
388 packed struct { x: u19, y: bool },
389 .{ .x = 1, .y = true },
390 .{ .x = 3, .y = false },
391 );
386392}
387393
388394fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
test/behavior/bit_shifting.zig-2
......@@ -170,8 +170,6 @@ test "Saturating Shift Left" {
170170
171171 const S = struct {
172172 fn shlSat(x: anytype, y: std.math.Log2Int(@TypeOf(x))) @TypeOf(x) {
173 // workaround https://github.com/ziglang/zig/issues/23033
174 @setRuntimeSafety(false);
175173 return x <<| y;
176174 }
177175
test/behavior/cast_int.zig+1
......@@ -217,6 +217,7 @@ test "load non byte-sized value in struct" {
217217test "load non byte-sized value in union" {
218218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
219219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
220 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
220221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
221222 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" {
3333}
3434
3535test "call decl literal with optional" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3736 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3938 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -74,7 +73,6 @@ test "call decl literal" {
7473}
7574
7675test "call decl literal with error union" {
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7876 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
7977
8078 const S = struct {
test/behavior/defer.zig-2
......@@ -107,7 +107,6 @@ test "mixing normal and error defers" {
107107}
108108
109109test "errdefer with payload" {
110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
111110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
113112 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -129,7 +128,6 @@ test "errdefer with payload" {
129128}
130129
131130test "reference to errdefer payload" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
133131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
134132 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135133 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" {
926926const Bar = enum { A, B, C, D };
927927
928928test "enum literal casting to error union with payload enum" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
931930
932931 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" {
145145}
146146
147147test "fn returning empty error set can be passed as fn returning any error" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149
150148 entry();
151149 comptime entry();
152150}
153151
154152test "fn returning empty error set can be passed as fn returning any error - pointer" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
157154
158155 entryPtr();
......@@ -404,7 +401,6 @@ fn intLiteral(str: []const u8) !?i64 {
404401}
405402
406403test "nested error union function call in optional unwrap" {
407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
408404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
409405 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" {
482478}
483479
484480test "nested catch" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
486481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
487482
488483 const S = struct {
......@@ -590,7 +585,6 @@ test "error union comptime caching" {
590585}
591586
592587test "@errorName" {
593 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
594588 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
595589 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
596590 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -605,7 +599,6 @@ fn gimmeItBroke() anyerror {
605599}
606600
607601test "@errorName sentinel length matches slice length" {
608 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
609602 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
610603 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
611604 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -700,7 +693,6 @@ test "coerce error set to the current inferred error set" {
700693}
701694
702695test "error union payload is properly aligned" {
703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
704696 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705697 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
706698 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -759,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {
759751}
760752
761753test "pointer to error union payload" {
762 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
763754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
764755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
765756 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -847,7 +838,6 @@ test "alignment of wrapping an error union payload" {
847838}
848839
849840test "compare error union and error set" {
850 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
851841 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
852842
853843 var a: anyerror = error.Foo;
......@@ -883,7 +873,6 @@ test "catch within a function that calls no errorable functions" {
883873}
884874
885875test "error from comptime string" {
886 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
887876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
888877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
889878 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -946,7 +935,6 @@ test "optional error set function parameter" {
946935}
947936
948937test "returning an error union containing a type with no runtime bits" {
949 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
950938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
951939 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
952940
......@@ -1038,8 +1026,6 @@ test "errorCast to adhoc inferred error set" {
10381026}
10391027
10401028test "@errorCast from error set to error union" {
1041 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1042
10431029 const S = struct {
10441030 fn doTheTest(set: error{ A, B }) error{A}!i32 {
10451031 return @errorCast(set);
......@@ -1050,8 +1036,6 @@ test "@errorCast from error set to error union" {
10501036}
10511037
10521038test "@errorCast from error union to error union" {
1053 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1054
10551039 const S = struct {
10561040 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {
10571041 return @errorCast(set);
test/behavior/field_parent_ptr.zig+6-5
......@@ -2,7 +2,6 @@ const expect = @import("std").testing.expect;
22const builtin = @import("builtin");
33
44test "@fieldParentPtr struct" {
5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
87
......@@ -587,11 +586,12 @@ test "@fieldParentPtr extern struct last zero-bit field" {
587586}
588587
589588test "@fieldParentPtr unaligned packed struct" {
590 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
589 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
591590 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
592591 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
593592 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
594593 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595595
596596 const C = packed struct {
597597 a: bool = true,
......@@ -726,11 +726,12 @@ test "@fieldParentPtr unaligned packed struct" {
726726}
727727
728728test "@fieldParentPtr aligned packed struct" {
729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
729 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
730730 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
731731 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
732732 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
733733 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
734 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
734735
735736 const C = packed struct {
736737 a: f32 = 3.14,
......@@ -868,6 +869,7 @@ test "@fieldParentPtr nested packed struct" {
868869 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
869870 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
870871 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
872 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
871873
872874 {
873875 const C = packed struct {
......@@ -1342,7 +1344,6 @@ test "@fieldParentPtr packed struct last zero-bit field" {
13421344}
13431345
13441346test "@fieldParentPtr tagged union" {
1345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13461347 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13471348 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13481349
......@@ -1479,7 +1480,6 @@ test "@fieldParentPtr tagged union" {
14791480}
14801481
14811482test "@fieldParentPtr untagged union" {
1482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14831483 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14841484 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14851485
......@@ -1616,6 +1616,7 @@ test "@fieldParentPtr untagged union" {
16161616}
16171617
16181618test "@fieldParentPtr extern union" {
1619 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
16191620 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16201621 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16211622
test/behavior/inline_switch.zig-2
......@@ -43,7 +43,6 @@ test "inline switch enums" {
4343
4444const U = union(E) { a: void, b: u2, c: u3, d: u4 };
4545test "inline switch unions" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4746 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4847 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4948
......@@ -105,7 +104,6 @@ test "inline else enum" {
105104}
106105
107106test "inline else int with gaps" {
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
110108 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 {
168168}
169169
170170test "@ctz 128-bit integers" {
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
172171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
174173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -463,7 +462,6 @@ test "binary not big int <= 128 bits" {
463462}
464463
465464test "division" {
466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
467465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
468466 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
469467 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -527,6 +525,8 @@ fn testIntDivision() !void {
527525 try expect(rem(i32, 10, 12) == 10);
528526 try expect(rem(i32, -14, 12) == -2);
529527 try expect(rem(i32, -2, 12) == -2);
528 try expect(rem(i32, 118, -12) == 10);
529 try expect(rem(i32, -14, -12) == -2);
530530 try expect(rem(i16, -118, 12) == -10);
531531
532532 try expect(divTrunc(i20, 20, -5) == -4);
......@@ -1819,7 +1819,6 @@ test "runtime int comparison to inf is comptime-known" {
18191819}
18201820
18211821test "float divide by zero" {
1822 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18231822 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18241823 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18251824 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" {
319319}
320320
321321test "coerce an anon struct literal to optional struct" {
322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
323322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
324323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
325324 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -391,7 +390,6 @@ test "0-bit child type coerced to optional" {
391390}
392391
393392test "array of optional unaligned types" {
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
395393 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397395 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -447,7 +445,6 @@ test "optional pointer to zero bit optional payload" {
447445}
448446
449447test "optional pointer to zero bit error union payload" {
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
451448 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
452449 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453450 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" {
13221322}
13231323
13241324test "packed struct with signed field" {
1325 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13251326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13261327
13271328 var s: packed struct {
test/behavior/pointers.zig-1
......@@ -246,7 +246,6 @@ test "implicit casting between C pointer and optional non-C pointer" {
246246}
247247
248248test "implicit cast error unions with non-optional to optional pointer" {
249 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
250249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
251250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
252251 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" {
552552 try comptime S.doTheTest(void, &{});
553553 try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
554554}
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 {
66}
77
88test "return address" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1211 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" {
628628 comptime assert(@TypeOf(ptr[1..][0..2]) == *[2]u8);
629629 comptime assert(@TypeOf(ptr[1..][0..4]) == *[4]u8);
630630 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
635632 var ptr_z: [*:0]u8 = &array;
636633 comptime assert(@TypeOf(ptr_z[1..][0..2]) == *[2]u8);
......@@ -710,7 +707,6 @@ test "slice pointer-to-array zero length" {
710707}
711708
712709test "type coercion of pointer to anon struct literal to pointer to slice" {
713 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
714710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
715711 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
716712 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" {
797797}
798798
799799test "non-packed struct with u128 entry in union" {
800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
801800 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802801 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
803802 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -956,7 +955,6 @@ test "tuple element initialized with fn call" {
956955}
957956
958957test "struct with union field" {
959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
960958 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
961959 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
962960 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1026,7 +1024,6 @@ test "packed struct with undefined initializers" {
10261024}
10271025
10281026test "for loop over pointers to struct, getting field from struct pointer" {
1029 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10301027 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10311028 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10321029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1093,7 +1090,6 @@ test "anon init through error unions and optionals" {
10931090}
10941091
10951092test "anon init through optional" {
1096 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10971093 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10981094 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10991095 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1113,7 +1109,6 @@ test "anon init through optional" {
11131109}
11141110
11151111test "anon init through error union" {
1116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11171112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11181113 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11191114 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1398,7 +1393,6 @@ test "struct has only one reference" {
13981393}
13991394
14001395test "no dependency loop on pointer to optional struct" {
1401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14021396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14031397 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 {
1212};
1313
1414test "struct contains slice of itself" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1817
......@@ -53,7 +52,6 @@ test "struct contains slice of itself" {
5352}
5453
5554test "struct contains aligned slice of itself" {
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5856 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;
88const maxInt = std.math.maxInt;
99
1010test "switch with numbers" {
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1413
......@@ -300,7 +299,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
300299}
301300
302301test "switch on enum using pointer capture" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
304302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
305303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306304
......@@ -361,7 +359,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
361359}
362360
363361test "switch on union with some prongs capturing" {
364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
365362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
366363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
367364
......@@ -469,7 +466,6 @@ test "switch on integer with else capturing expr" {
469466}
470467
471468test "else prong of switch on error set excludes other cases" {
472 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
473469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
474470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475471 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -505,7 +501,6 @@ test "else prong of switch on error set excludes other cases" {
505501}
506502
507503test "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;
509504 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
510505 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
511506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -736,7 +731,6 @@ test "switch on error set with single else" {
736731}
737732
738733test "switch capture copies its payload" {
739 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
740734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
741735 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
742736 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -931,7 +925,6 @@ test "nested break ignores switch conditions and breaks instead" {
931925}
932926
933927test "peer type resolution on switch captures ignores unused payload bits" {
934 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
935928 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
936929 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
937930
......@@ -976,8 +969,6 @@ test "switch prong captures range" {
976969}
977970
978971test "prong with inline call to unreachable" {
979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
980
981972 const U = union(enum) {
982973 void: void,
983974 bool: bool,
......@@ -1072,3 +1063,13 @@ test "switch on a signed value smaller than the smallest prong value" {
10721063 else => {},
10731064 }
10741065}
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;
66const builtin = @import("builtin");
77
88test "switch on error union catch capture" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1110 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 {
2121}
2222
2323test "switch prong returns error enum" {
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2726 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" {
4747}
4848
4949test "`try`ing an if/else expression" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5150 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5251 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5352 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/union.zig-39
......@@ -12,7 +12,6 @@ const FooWithFloats = union {
1212};
1313
1414test "basic unions with floats" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1716 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1817 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -29,7 +28,6 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {
2928}
3029
3130test "init union with runtime value - floats" {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3533 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -41,7 +39,6 @@ test "init union with runtime value - floats" {
4139}
4240
4341test "basic unions" {
44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4643 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4744 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -60,7 +57,6 @@ const Foo = union {
6057};
6158
6259test "init union with runtime value" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6662 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -101,7 +97,6 @@ const FooExtern = extern union {
10197};
10298
10399test "basic extern unions" {
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
105100 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
106101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107102
......@@ -160,7 +155,6 @@ test "unions embedded in aggregate types" {
160155}
161156
162157test "constant tagged union with payload" {
163 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
165159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
166160
......@@ -263,7 +257,6 @@ fn testComparison() !void {
263257}
264258
265259test "comparison between union and enum literal" {
266 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
267260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
268261 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
269262 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -279,7 +272,6 @@ const TheUnion = union(TheTag) {
279272 C: i32,
280273};
281274test "cast union to tag type of union" {
282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
283275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
284276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285277
......@@ -300,7 +292,6 @@ test "union field access gives the enum values" {
300292}
301293
302294test "cast tag type of union to union" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
304295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
305296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306297
......@@ -316,7 +307,6 @@ const Value2 = union(Letter2) {
316307};
317308
318309test "implicit cast union to its tag type" {
319 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
320310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
321311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
322312
......@@ -337,7 +327,6 @@ pub const PackThis = union(enum) {
337327};
338328
339329test "constant packed union" {
340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
341330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -483,7 +472,6 @@ pub const FooUnion = union(enum) {
483472var glbl_array: [2]FooUnion = undefined;
484473
485474test "initialize global array of union" {
486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
487475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
488476 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
489477 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -495,7 +483,6 @@ test "initialize global array of union" {
495483}
496484
497485test "update the tag value for zero-sized unions" {
498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
499486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
500487 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
734721}
735722
736723test "@intFromEnum works on unions" {
737 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
738724 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
739725 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
740726
......@@ -817,7 +803,6 @@ test "return union init with void payload" {
817803}
818804
819805test "@unionInit stored to a const" {
820 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
821806 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
822807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
823808 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -848,7 +833,6 @@ test "@unionInit stored to a const" {
848833}
849834
850835test "@unionInit can modify a union type" {
851 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
852836 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
853837 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
854838
......@@ -871,7 +855,6 @@ test "@unionInit can modify a union type" {
871855}
872856
873857test "@unionInit can modify a pointer value" {
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
875858 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
876859 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" {
926909}
927910
928911test "anonymous union literal syntax" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
930912 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
931913 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
932914 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -990,7 +972,6 @@ test "function call result coerces from tagged union to the tag" {
990972}
991973
992974test "switching on non exhaustive union" {
993 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
994975 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
995976 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
996977
......@@ -1096,7 +1077,6 @@ test "union enum type gets a separate scope" {
10961077}
10971078
10981079test "global variable struct contains union initialized to non-most-aligned field" {
1099 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11001080 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11011081 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11021082 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
11231103}
11241104
11251105test "union with no result loc initiated with a runtime value" {
1126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11271106 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11281107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11291108 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1141,7 +1120,6 @@ test "union with no result loc initiated with a runtime value" {
11411120}
11421121
11431122test "union with a large struct field" {
1144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11451123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11461124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11471125 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1176,7 +1154,6 @@ test "comptime equality of extern unions with same tag" {
11761154}
11771155
11781156test "union tag is set when initiated as a temporary value at runtime" {
1179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11801157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11811158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11821159 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1216,7 +1193,6 @@ test "extern union most-aligned field is smaller" {
12161193}
12171194
12181195test "return an extern union from C calling convention" {
1219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12201196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12211197 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12221198 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1248,7 +1224,6 @@ test "return an extern union from C calling convention" {
12481224}
12491225
12501226test "noreturn field in union" {
1251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12521227 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12531228 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12541229
......@@ -1299,7 +1274,6 @@ test "noreturn field in union" {
12991274}
13001275
13011276test "@unionInit uses tag value instead of field index" {
1302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13031277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13041278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13051279 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1408,7 +1382,6 @@ test "union int tag type is properly managed" {
14081382}
14091383
14101384test "no dependency loop when function pointer in union returns the union" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14121385 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14131386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14141387 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" {
14301403}
14311404
14321405test "union reassignment can use previous value" {
1433 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14341406 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14351407 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14361408
......@@ -1481,8 +1453,6 @@ test "reinterpreting enum value inside packed union" {
14811453}
14821454
14831455test "access the tag of a global tagged union" {
1484 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1485
14861456 const U = union(enum) {
14871457 a,
14881458 b: u8,
......@@ -1634,7 +1604,6 @@ test "union with 128 bit integer" {
16341604}
16351605
16361606test "memset extern union" {
1637 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16381607 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16391608
16401609 const U = extern union {
......@@ -1956,7 +1925,6 @@ test "packed union initialized via reintepreted struct field initializer" {
19561925}
19571926
19581927test "store of comptime reinterpreted memory to extern union" {
1959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19601928 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19611929
19621930 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
......@@ -2063,7 +2031,6 @@ test "circular dependency through pointer field of a union" {
20632031}
20642032
20652033test "pass nested union with rls" {
2066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20672034 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20682035 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20692036
......@@ -2085,7 +2052,6 @@ test "pass nested union with rls" {
20852052}
20862053
20872054test "runtime union init, most-aligned field != largest" {
2088 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20892055 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20902056 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20912057 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2111,7 +2077,6 @@ test "runtime union init, most-aligned field != largest" {
21112077}
21122078
21132079test "copied union field doesn't alias source" {
2114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21152080 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21162081 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21172082 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2255,7 +2220,6 @@ test "matching captures causes union equivalence" {
22552220}
22562221
22572222test "signed enum tag with negative value" {
2258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
22592223 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22602224 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
22612225 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2312,7 +2276,6 @@ test "extern union @FieldType" {
23122276}
23132277
23142278test "assign global tagged union" {
2315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23162279 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
23172280
23182281 const U = union(enum) {
......@@ -2334,8 +2297,6 @@ test "assign global tagged union" {
23342297}
23352298
23362299test "set mutable union by switching on same union" {
2337 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2338
23392300 const U = union(enum) {
23402301 foo,
23412302 bar: usize,
test/behavior/union_with_members.zig-1
......@@ -17,7 +17,6 @@ const ET = union(enum) {
1717};
1818
1919test "enum with members" {
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/var_args.zig-4
......@@ -92,7 +92,6 @@ fn doNothingWithFirstArg(args: anytype) void {
9292}
9393
9494test "simple variadic function" {
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9695 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9796 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9897 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -154,7 +153,6 @@ test "simple variadic function" {
154153}
155154
156155test "coerce reference to var arg" {
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
160158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -234,7 +232,6 @@ test "variadic functions" {
234232}
235233
236234test "copy VaList" {
237 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
238235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
239236 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
240237 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -269,7 +266,6 @@ test "copy VaList" {
269266}
270267
271268test "unused VaList arg" {
272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
273269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
274270 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
275271 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" {
174174}
175175
176176test "while with error union condition" {
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
178177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
180179 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -306,7 +305,6 @@ test "while optional 2 break statements and an else" {
306305}
307306
308307test "while error 2 break statements and an else" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
310308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311309 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312310
......@@ -344,7 +342,6 @@ test "else continue outer while" {
344342}
345343
346344test "try terminating an infinite loop" {
347 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
348345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
349346 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 {
54735473 // workaround https://github.com/ziglang/zig/issues/23139
54745474 return lhs <<| @min(@abs(rhs), splat(ChangeScalar(Type, u64), imax(u64)));
54755475 }
5476 // workaround https://github.com/ziglang/zig/issues/23033
5477 @setRuntimeSafety(false);
54785476 return lhs <<| @abs(rhs);
54795477}
54805478test shlSaturate {
test/cases/array_in_anon_struct.zig+1-1
......@@ -19,4 +19,4 @@ pub fn main() !void {
1919
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
55
66const NormalStruct = struct { x: u32 };
77export fn normalStruct() void {
8 var x: NormalStruct = 0;
8 var x: NormalStruct = .{ .x = 0 };
99 _ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);
1010}
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
1223// error
1324// backend=stage2
1425// target=native
1526//
1627// :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'
1829// :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 {}
77// target=aarch64-linux-none
88//
99// :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'
11// :1:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'
10// :2:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'
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 {
1313// error
1414//
1515// :6:12: error: expected error union type, found 'u8'
16// :6:12: note: consider omitting 'try'
1617// :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 {
2525
2626// error
2727// backend=stage2
28// target=native
28// target=x86_64-linux
2929//
3030// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'
3131// :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 {
1010
1111// error
1212// backend=stage2
13// target=native
13// target=x86_64-linux
1414//
1515// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
1616// :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 {
1515
1616// error
1717// backend=stage2
18// target=native
18// target=x86_64-linux
1919//
2020// :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 {
4343// error
4444//
4545// :5:23: error: expected error union type, found 'comptime_int'
46// :5:23: note: consider omitting 'try'
4647// :10:23: error: expected error union type, found '@TypeOf(.{})'
48// :10:23: note: consider omitting 'try'
4749// :15:23: error: expected error union type, found 'tmp.S'
4850// :1:11: note: struct declared here
51// :15:23: note: consider omitting 'try'
4952// :20:27: error: expected error union type, found 'tmp.S'
5053// :1:11: note: struct declared here
54// :20:27: note: consider omitting 'try'
5155// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
56// :25:23: note: consider omitting 'try'
5257// :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 {
66
77// error
88// backend=stage2
9// target=native
9// target=x86_64-linux
1010//
1111// :2:23: error: expected error union type, found 'bool'
test/cases/pic_freestanding.zig+1-1
......@@ -1,7 +1,7 @@
11const builtin = @import("builtin");
22const std = @import("std");
33
4fn _start() callconv(.naked) void {}
4pub fn _start() callconv(.naked) void {}
55
66comptime {
77 @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 {
2222}
2323// run
2424// backend=stage2,llvm
25// target=native
25// 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 {}
2323
2424// run
2525// backend=stage2,llvm
26// target=native
26// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - exhaustive.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1717fn baz(_: i8) void {}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717fn baz(_: u8) void {}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717fn baz(_: u8) void {}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/@ptrFromInt with misaligned address.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2323
2424// run
2525// backend=stage2,llvm
26// target=native
26// target=x86_64-linux
test/cases/safety/@tagName on corrupted union value.zig +1-1
......@@ -24,4 +24,4 @@ pub fn main() !void {
2424
2525// run
2626// backend=stage2,llvm
27// target=native
27// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch vector.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2424}
2525// run
2626// backend=stage2,llvm
27// target=native
27// target=x86_64-linux
test/cases/safety/calling panic.zig +1-1
......@@ -13,4 +13,4 @@ pub fn main() !void {
1313}
1414// run
1515// backend=stage2,llvm
16// target=native
16// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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) {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux
test/cases/safety/exact division failure.zig +1-1
......@@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch.zig+1-1
......@@ -22,4 +22,4 @@ pub fn main() !void {
2222}
2323// run
2424// backend=stage2,llvm
25// target=native
25// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch_three.zig+1-1
......@@ -21,4 +21,4 @@ pub fn main() !void {
2121}
2222// run
2323// backend=stage2,llvm
24// target=native
24// target=x86_64-linux,aarch64-linux
test/cases/safety/ignored expression integer overflow.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux
test/cases/safety/integer addition overflow.zig +1-1
......@@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/integer negation overflow.zig +1-1
......@@ -18,4 +18,4 @@ fn neg(a: i16) i16 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_alias.zig+1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_len_mismatch.zig+1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/memmove_len_mismatch.zig+1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_bytes.zig+1-1
......@@ -15,4 +15,4 @@ pub fn main() !void {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_large.zig+1-1
......@@ -15,4 +15,4 @@ pub fn main() !void {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_bytes.zig+1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_large.zig+1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux
test/cases/safety/noreturn returned.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() void {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// target=x86_64-linux,aarch64-linux
test/cases/safety/optional_empty_error_set.zig+1-1
......@@ -19,4 +19,4 @@ fn foo() !void {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1818fn baz(_: i32) void {}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer slice sentinel mismatch.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1919
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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 {
1919
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/signed-unsigned vector cast.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// 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 {
1515}
1616// run
1717// backend=stage2,llvm
18// target=native
18// target=x86_64-linux,aarch64-linux
test/cases/safety/slice sentinel mismatch - floats.zig +1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux
test/cases/safety/slice sentinel mismatch - optional pointers.zig +1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717
1818// run
1919// backend=stage2,llvm
20// target=native
20// target=x86_64-linux,aarch64-linux
test/cases/safety/slice slice sentinel mismatch.zig +1-1
......@@ -16,4 +16,4 @@ pub fn main() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2121
2222// run
2323// backend=stage2,llvm
24// target=native
24// 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 {
2020
2121// run
2222// backend=stage2,llvm
23// target=native
23// 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 {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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");
2424
2525// run
2626// backend=stage2,llvm
27// target=x86_64-linux
27// 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");
2424
2525// run
2626// backend=stage2,llvm
27// target=x86_64-linux
27// 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");
2424
2525// run
2626// backend=stage2,llvm
27// target=x86_64-linux
27// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/slicing null C pointer.zig +1-1
......@@ -17,4 +17,4 @@ pub fn main() !void {
1717}
1818// run
1919// backend=stage2,llvm
20// target=native
20// 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 {
2121}
2222// run
2323// backend=stage2,llvm
24// target=native
24// 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 {
2626}
2727// run
2828// backend=stage2,llvm
29// target=native
29// target=x86_64-linux
test/cases/safety/switch else on corrupt enum value.zig +1-1
......@@ -20,4 +20,4 @@ pub fn main() !void {
2020}
2121// run
2222// backend=stage2,llvm
23// target=native
23// target=x86_64-linux
test/cases/safety/switch on corrupted enum value.zig +1-1
......@@ -24,4 +24,4 @@ pub fn main() !void {
2424
2525// run
2626// backend=stage2,llvm
27// target=native
27// 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 {
2424
2525// run
2626// backend=stage2,llvm
27// target=native
27// target=x86_64-linux
test/cases/safety/truncating vector cast.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux
test/cases/safety/unreachable.zig+1-1
......@@ -12,4 +12,4 @@ pub fn main() !void {
1212}
1313// run
1414// backend=stage2,llvm
15// target=native
15// 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 {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/unsigned-signed vector cast.zig +1-1
......@@ -18,4 +18,4 @@ pub fn main() !void {
1818
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux
test/cases/safety/unwrap error switch.zig +1-1
......@@ -18,4 +18,4 @@ fn bar() !void {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// target=x86_64-linux,aarch64-linux
test/cases/safety/unwrap error.zig +1-1
......@@ -16,4 +16,4 @@ fn bar() !void {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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 {
1818}
1919// run
2020// backend=stage2,llvm
21// target=native
21// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// 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) {
1919}
2020// run
2121// backend=stage2,llvm
22// target=native
22// target=x86_64-linux
test/cases/safety/zero casted to error.zig +1-1
......@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
1616}
1717// run
1818// backend=stage2,llvm
19// target=native
19// 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 {
2323
2424// run
2525// backend=stage2,llvm
26// target=native
26// target=x86_64-linux
test/incremental/change_panic_handler-1
......@@ -1,4 +1,3 @@
1#target=x86_64-linux-selfhosted
21#target=x86_64-linux-cbe
32#target=x86_64-windows-cbe
43#update=initial version
test/incremental/change_panic_handler_explicit-1
......@@ -1,4 +1,3 @@
1#target=x86_64-linux-selfhosted
21#target=x86_64-linux-cbe
32#target=x86_64-windows-cbe
43#update=initial version
test/incremental/type_becomes_comptime_only-1
......@@ -1,4 +1,3 @@
1#target=x86_64-linux-selfhosted
21#target=x86_64-linux-cbe
32#target=x86_64-windows-cbe
43#target=wasm32-wasi-selfhosted
test/link/build.zig.zon+2-1
......@@ -1,5 +1,6 @@
11.{
2 .name = "link_test_cases",
2 .name = .link_test_cases,
3 .fingerprint = 0x404f657576fec9f2,
34 .version = "0.0.0",
45 .dependencies = .{
56 .bss = .{
test/link/elf.zig+369-369
......@@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step {
210210 \\}
211211 ,
212212 });
213 exe.addObject(obj);
214 exe.linkLibC();
213 exe.root_module.addObject(obj);
214 exe.root_module.link_libc = true;
215215
216216 const run = addRunArtifact(exe);
217217 run.expectExitCode(0);
......@@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
235235 \\
236236 ,
237237 });
238 main_o.linkLibC();
238 main_o.root_module.link_libc = true;
239239
240240 const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });
241241 addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});
......@@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
253253 const exe = addExecutable(b, opts, .{
254254 .name = "test",
255255 });
256 exe.addObject(main_o);
257 exe.linkSystemLibrary2("foo", .{ .needed = true });
258 exe.addLibraryPath(libfoo.getEmittedBinDirectory());
259 exe.addRPath(libfoo.getEmittedBinDirectory());
260 exe.linkSystemLibrary2("bar", .{ .needed = true });
261 exe.addLibraryPath(libbar.getEmittedBinDirectory());
262 exe.addRPath(libbar.getEmittedBinDirectory());
263 exe.linkSystemLibrary2("baz", .{ .needed = true });
264 exe.addLibraryPath(libbaz.getEmittedBinDirectory());
265 exe.addRPath(libbaz.getEmittedBinDirectory());
266 exe.linkLibC();
256 exe.root_module.addObject(main_o);
257 exe.root_module.linkSystemLibrary("foo", .{ .needed = true });
258 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
259 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
260 exe.root_module.linkSystemLibrary("bar", .{ .needed = true });
261 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
262 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
263 exe.root_module.linkSystemLibrary("baz", .{ .needed = true });
264 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
265 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
266 exe.root_module.link_libc = true;
267267
268268 const run = addRunArtifact(exe);
269269 run.expectStdOutEqual("42\n");
......@@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
281281 const exe = addExecutable(b, opts, .{
282282 .name = "test",
283283 });
284 exe.addObject(main_o);
285 exe.linkSystemLibrary2("foo", .{ .needed = false });
286 exe.addLibraryPath(libfoo.getEmittedBinDirectory());
287 exe.addRPath(libfoo.getEmittedBinDirectory());
288 exe.linkSystemLibrary2("bar", .{ .needed = false });
289 exe.addLibraryPath(libbar.getEmittedBinDirectory());
290 exe.addRPath(libbar.getEmittedBinDirectory());
291 exe.linkSystemLibrary2("baz", .{ .needed = false });
292 exe.addLibraryPath(libbaz.getEmittedBinDirectory());
293 exe.addRPath(libbaz.getEmittedBinDirectory());
294 exe.linkLibC();
284 exe.root_module.addObject(main_o);
285 exe.root_module.linkSystemLibrary("foo", .{ .needed = false });
286 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
287 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
288 exe.root_module.linkSystemLibrary("bar", .{ .needed = false });
289 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
290 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
291 exe.root_module.linkSystemLibrary("baz", .{ .needed = false });
292 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
293 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
294 exe.root_module.link_libc = true;
295295
296296 const run = addRunArtifact(exe);
297297 run.expectStdOutEqual("42\n");
......@@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
351351 ,
352352 .pic = false,
353353 });
354 main_o.linkLibC();
354 main_o.root_module.link_libc = true;
355355
356356 const exe = addExecutable(b, opts, .{
357357 .name = "main",
358358 });
359 exe.addObject(main_o);
360 exe.addObject(b_o);
361 exe.linkLibrary(dso);
362 exe.linkLibC();
359 exe.root_module.addObject(main_o);
360 exe.root_module.addObject(b_o);
361 exe.root_module.linkLibrary(dso);
362 exe.root_module.link_libc = true;
363363 exe.pie = false;
364364
365365 const run = addRunArtifact(exe);
......@@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
384384 \\}
385385 ,
386386 });
387 a_o.linkLibCpp();
387 a_o.root_module.link_libcpp = true;
388388
389389 const main_o = addObject(b, opts, .{
390390 .name = "main",
......@@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
401401 \\}
402402 ,
403403 });
404 main_o.linkLibCpp();
404 main_o.root_module.link_libcpp = true;
405405
406406 {
407407 const exe = addExecutable(b, opts, .{ .name = "main1" });
408 exe.addObject(a_o);
409 exe.addObject(main_o);
410 exe.linkLibCpp();
408 exe.root_module.addObject(a_o);
409 exe.root_module.addObject(main_o);
410 exe.root_module.link_libcpp = true;
411411
412412 const run = addRunArtifact(exe);
413413 run.expectStdOutEqual(
......@@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
420420
421421 {
422422 const exe = addExecutable(b, opts, .{ .name = "main2" });
423 exe.addObject(main_o);
424 exe.addObject(a_o);
425 exe.linkLibCpp();
423 exe.root_module.addObject(main_o);
424 exe.root_module.addObject(a_o);
425 exe.root_module.link_libcpp = true;
426426
427427 const run = addRunArtifact(exe);
428428 run.expectStdOutEqual(
......@@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
435435
436436 {
437437 const c_o = addObject(b, opts, .{ .name = "c" });
438 c_o.addObject(main_o);
439 c_o.addObject(a_o);
438 c_o.root_module.addObject(main_o);
439 c_o.root_module.addObject(a_o);
440440
441441 const exe = addExecutable(b, opts, .{ .name = "main3" });
442 exe.addObject(c_o);
443 exe.linkLibCpp();
442 exe.root_module.addObject(c_o);
443 exe.root_module.link_libcpp = true;
444444
445445 const run = addRunArtifact(exe);
446446 run.expectStdOutEqual(
......@@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
453453
454454 {
455455 const d_o = addObject(b, opts, .{ .name = "d" });
456 d_o.addObject(a_o);
457 d_o.addObject(main_o);
456 d_o.root_module.addObject(a_o);
457 d_o.root_module.addObject(main_o);
458458
459459 const exe = addExecutable(b, opts, .{ .name = "main4" });
460 exe.addObject(d_o);
461 exe.linkLibCpp();
460 exe.root_module.addObject(d_o);
461 exe.root_module.link_libcpp = true;
462462
463463 const run = addRunArtifact(exe);
464464 run.expectStdOutEqual(
......@@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step {
522522 \\ printf("%d %d %d\n", foo, bar, baz);
523523 \\}
524524 , &.{"-fcommon"});
525 exe.linkLibC();
525 exe.root_module.link_libc = true;
526526
527527 const run = addRunArtifact(exe);
528528 run.expectStdOutEqual("0 5 42\n");
......@@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
549549 ,
550550 .c_source_flags = &.{"-fcommon"},
551551 });
552 a_o.linkLibC();
552 a_o.root_module.link_libc = true;
553553
554554 const b_o = addObject(b, opts, .{
555555 .name = "b",
......@@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
575575 });
576576
577577 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
578 lib.addObject(b_o);
579 lib.addObject(c_o);
580 lib.addObject(d_o);
578 lib.root_module.addObject(b_o);
579 lib.root_module.addObject(c_o);
580 lib.root_module.addObject(d_o);
581581
582582 const exe = addExecutable(b, opts, .{
583583 .name = "test",
584584 });
585 exe.addObject(a_o);
586 exe.linkLibrary(lib);
587 exe.linkLibC();
585 exe.root_module.addObject(a_o);
586 exe.root_module.linkLibrary(lib);
587 exe.root_module.link_libc = true;
588588
589589 const run = addRunArtifact(exe);
590590 run.expectStdOutEqual("5 0 0 -1\n");
......@@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
603603 });
604604
605605 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
606 lib.addObject(b_o);
607 lib.addObject(e_o);
606 lib.root_module.addObject(b_o);
607 lib.root_module.addObject(e_o);
608608
609609 const exe = addExecutable(b, opts, .{
610610 .name = "test",
611611 });
612 exe.addObject(a_o);
613 exe.linkLibrary(lib);
614 exe.linkLibC();
612 exe.root_module.addObject(a_o);
613 exe.root_module.linkLibrary(lib);
614 exe.root_module.link_libc = true;
615615
616616 const run = addRunArtifact(exe);
617617 run.expectStdOutEqual("5 0 7 2\n");
......@@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step {
641641 \\}
642642 ,
643643 });
644 exe.linkLibrary(dso);
645 exe.linkLibC();
644 exe.root_module.linkLibrary(dso);
645 exe.root_module.link_libc = true;
646646
647647 const run = addRunArtifact(exe);
648648 run.expectStdOutEqual("3 5\n");
......@@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step {
679679 \\extern int bar;
680680 \\int *get_bar() { return &bar; }
681681 , &.{});
682 exe.linkLibrary(dso);
683 exe.linkLibC();
682 exe.root_module.linkLibrary(dso);
683 exe.root_module.link_libc = true;
684684 exe.pie = false;
685685
686686 const run = addRunArtifact(exe);
......@@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
712712 ,
713713 .pic = false,
714714 });
715 obj.linkLibC();
715 obj.root_module.link_libc = true;
716716
717717 const exp_stdout = "5\n";
718718
719719 {
720720 const exe = addExecutable(b, opts, .{ .name = "main" });
721 exe.addObject(obj);
722 exe.linkLibrary(a_so);
723 exe.linkLibC();
721 exe.root_module.addObject(obj);
722 exe.root_module.linkLibrary(a_so);
723 exe.root_module.link_libc = true;
724724 exe.pie = false;
725725
726726 const run = addRunArtifact(exe);
......@@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
737737
738738 {
739739 const exe = addExecutable(b, opts, .{ .name = "main" });
740 exe.addObject(obj);
741 exe.linkLibrary(b_so);
742 exe.linkLibC();
740 exe.root_module.addObject(obj);
741 exe.root_module.linkLibrary(b_so);
742 exe.root_module.link_libc = true;
743743 exe.pie = false;
744744
745745 const run = addRunArtifact(exe);
......@@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
756756
757757 {
758758 const exe = addExecutable(b, opts, .{ .name = "main" });
759 exe.addObject(obj);
760 exe.linkLibrary(c_so);
761 exe.linkLibC();
759 exe.root_module.addObject(obj);
760 exe.root_module.linkLibrary(c_so);
761 exe.root_module.link_libc = true;
762762 exe.pie = false;
763763
764764 const run = addRunArtifact(exe);
......@@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
793793 \\ real_hello();
794794 \\}
795795 , &.{});
796 dso.linkLibC();
796 dso.root_module.link_libc = true;
797797
798798 const exe = addExecutable(b, opts, .{ .name = "test" });
799799 addCSourceBytes(exe,
......@@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
806806 \\ hello();
807807 \\}
808808 , &.{});
809 exe.linkLibrary(dso);
810 exe.linkLibC();
809 exe.root_module.linkLibrary(dso);
810 exe.root_module.link_libc = true;
811811
812812 const run = addRunArtifact(exe);
813813 run.expectStdOutEqual("Hello WORLD\n");
......@@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
825825 \\int bar = 5;
826826 \\int baz() { return foo; }
827827 , &.{});
828 dso.linkLibC();
828 dso.root_module.link_libc = true;
829829
830830 const obj = addObject(b, opts, .{
831831 .name = "obj",
......@@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
833833 });
834834
835835 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
836 lib.addObject(obj);
836 lib.root_module.addObject(obj);
837837
838838 const exe = addExecutable(b, opts, .{ .name = "test" });
839 exe.linkLibrary(dso);
840 exe.linkLibrary(lib);
839 exe.root_module.linkLibrary(dso);
840 exe.root_module.linkLibrary(lib);
841841 addCSourceBytes(exe,
842842 \\extern int bar;
843843 \\int main() {
844844 \\ return bar - 5;
845845 \\}
846846 , &.{});
847 exe.linkLibC();
847 exe.root_module.link_libc = true;
848848
849849 const run = addRunArtifact(exe);
850850 run.expectExitCode(0);
......@@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
871871 \\ std.debug.print("foo={d}\n", .{foo()});
872872 \\}
873873 });
874 a_o.linkLibC();
874 a_o.root_module.link_libc = true;
875875
876876 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes =
877877 \\#include <stdio.h>
......@@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
880880 \\ fprintf(stderr, "bar=%d\n", bar);
881881 \\}
882882 });
883 b_o.linkLibC();
883 b_o.root_module.link_libc = true;
884884
885885 const c_o = addObject(b, opts, .{ .name = "c" });
886 c_o.addObject(a_o);
887 c_o.addObject(b_o);
886 c_o.root_module.addObject(a_o);
887 c_o.root_module.addObject(b_o);
888888
889889 const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes =
890890 \\const std = @import("std");
......@@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
895895 \\ printBar();
896896 \\}
897897 });
898 exe.addObject(c_o);
899 exe.linkLibC();
898 exe.root_module.addObject(c_o);
899 exe.root_module.link_libc = true;
900900
901901 const run = addRunArtifact(exe);
902902 run.expectStdErrEqual(
......@@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {
944944 });
945945
946946 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
947 lib.addObject(obj1);
948 lib.addObject(obj2);
949 lib.addObject(obj3);
947 lib.root_module.addObject(obj1);
948 lib.root_module.addObject(obj2);
949 lib.root_module.addObject(obj3);
950950
951951 const check = lib.checkObject();
952952 check.checkInArchiveSymtab();
......@@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
996996 \\}
997997 ,
998998 });
999 lib.addObject(obj1);
999 lib.root_module.addObject(obj1);
10001000
10011001 const exe = addExecutable(b, opts, .{
10021002 .name = "test",
......@@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
10081008 \\}
10091009 ,
10101010 });
1011 exe.linkLibrary(lib);
1011 exe.root_module.linkLibrary(lib);
10121012
10131013 const run = addRunArtifact(exe);
10141014 run.expectStdErrEqual("44");
......@@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
10231023 const exe = addExecutable(b, opts, .{ .name = "test" });
10241024 addCSourceBytes(exe, "int main() { return 0; }", &.{});
10251025 addCSourceBytes(exe, "", &.{});
1026 exe.linkLibC();
1026 exe.root_module.link_libc = true;
10271027
10281028 const run = addRunArtifact(exe);
10291029 run.expectExitCode(0);
......@@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
10521052
10531053 {
10541054 const exe = addExecutable(b, opts, .{ .name = "main" });
1055 exe.addObject(a_o);
1056 exe.addObject(b_o);
1055 exe.root_module.addObject(a_o);
1056 exe.root_module.addObject(b_o);
10571057 exe.entry = .{ .symbol_name = "foo" };
10581058
10591059 const check = exe.checkObject();
......@@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
10681068 // cause an artifact collision taking the cached executable from the above
10691069 // step instead of generating a new one.
10701070 const exe = addExecutable(b, opts, .{ .name = "other" });
1071 exe.addObject(a_o);
1072 exe.addObject(b_o);
1071 exe.root_module.addObject(a_o);
1072 exe.root_module.addObject(b_o);
10731073 exe.entry = .{ .symbol_name = "bar" };
10741074
10751075 const check = exe.checkObject();
......@@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step {
11131113 \\ return baz;
11141114 \\}
11151115 , &.{});
1116 exe.addObject(obj);
1117 exe.linkLibrary(dso);
1116 exe.root_module.addObject(obj);
1117 exe.root_module.linkLibrary(dso);
11181118 exe.rdynamic = true;
11191119
11201120 const check = exe.checkObject();
......@@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {
11521152 \\ foo();
11531153 \\}
11541154 , &.{});
1155 exe.linkLibrary(dso);
1156 exe.linkLibC();
1155 exe.root_module.linkLibrary(dso);
1156 exe.root_module.link_libc = true;
11571157
11581158 const check = exe.checkObject();
11591159 check.checkInDynamicSymtab();
......@@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step {
11811181 \\ assert(fn == ptr);
11821182 \\}
11831183 , &.{});
1184 exe.linkLibrary(dso);
1184 exe.root_module.linkLibrary(dso);
11851185 exe.root_module.pic = false;
11861186 exe.pie = false;
11871187
......@@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step {
12161216 });
12171217 obj.link_function_sections = true;
12181218 obj.link_data_sections = true;
1219 obj.linkLibC();
1220 obj.linkLibCpp();
1219 obj.root_module.link_libc = true;
1220 obj.root_module.link_libcpp = true;
12211221
12221222 {
12231223 const exe = addExecutable(b, opts, .{ .name = "test" });
1224 exe.addObject(obj);
1224 exe.root_module.addObject(obj);
12251225 exe.link_gc_sections = false;
1226 exe.linkLibC();
1227 exe.linkLibCpp();
1226 exe.root_module.link_libc = true;
1227 exe.root_module.link_libcpp = true;
12281228
12291229 const run = addRunArtifact(exe);
12301230 run.expectStdOutEqual("1 2\n");
......@@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step {
12521252
12531253 {
12541254 const exe = addExecutable(b, opts, .{ .name = "test" });
1255 exe.addObject(obj);
1255 exe.root_module.addObject(obj);
12561256 exe.link_gc_sections = true;
1257 exe.linkLibC();
1258 exe.linkLibCpp();
1257 exe.root_module.link_libc = true;
1258 exe.root_module.link_libcpp = true;
12591259
12601260 const run = addRunArtifact(exe);
12611261 run.expectStdOutEqual("1 2\n");
......@@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
13211321 \\}
13221322 ,
13231323 });
1324 exe.addObject(obj);
1324 exe.root_module.addObject(obj);
13251325 exe.link_gc_sections = false;
13261326
13271327 const run = addRunArtifact(exe);
......@@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
13631363 \\}
13641364 ,
13651365 });
1366 exe.addObject(obj);
1366 exe.root_module.addObject(obj);
13671367 exe.link_gc_sections = true;
13681368
13691369 const run = addRunArtifact(exe);
......@@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step {
14271427 \\}
14281428 , &.{});
14291429 exe.root_module.pic = true;
1430 exe.linkLibC();
1430 exe.root_module.link_libc = true;
14311431
14321432 const run = addRunArtifact(exe);
14331433 run.expectExitCode(0);
......@@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {
14671467 \\ assert(foo == p);
14681468 \\}
14691469 , &.{});
1470 exe.linkLibrary(dso);
1471 exe.linkLibC();
1472 exe.linkSystemLibrary2("dl", .{});
1470 exe.root_module.linkLibrary(dso);
1471 exe.root_module.link_libc = true;
1472 exe.root_module.linkSystemLibrary("dl", .{});
14731473 exe.root_module.pic = false;
14741474 exe.pie = false;
14751475
......@@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
14981498 \\}
14991499 ,
15001500 });
1501 dso.linkLibC();
1501 dso.root_module.link_libc = true;
15021502
15031503 const exe = addExecutable(b, opts, .{
15041504 .name = "main",
......@@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
15091509 \\}
15101510 ,
15111511 });
1512 exe.linkLibrary(dso);
1512 exe.root_module.linkLibrary(dso);
15131513
15141514 const run = addRunArtifact(exe);
15151515 run.expectStdOutEqual("Hello world\n");
......@@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
15401540 {
15411541 const exe = addExecutable(b, opts, .{ .name = "main" });
15421542 addCSourceBytes(exe, main_c, &.{});
1543 exe.linkLibC();
1543 exe.root_module.link_libc = true;
15441544 exe.link_z_lazy = true;
15451545
15461546 const run = addRunArtifact(exe);
......@@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
15501550 {
15511551 const exe = addExecutable(b, opts, .{ .name = "other" });
15521552 addCSourceBytes(exe, main_c, &.{});
1553 exe.linkLibC();
1553 exe.root_module.link_libc = true;
15541554
15551555 const run = addRunArtifact(exe);
15561556 run.expectStdOutEqual("Hello world\n");
......@@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step {
15761576 \\ return real_foobar;
15771577 \\}
15781578 , &.{});
1579 dso.linkLibC();
1579 dso.root_module.link_libc = true;
15801580
15811581 const check = dso.checkObject();
15821582 check.checkInDynamicSymtab();
......@@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {
16131613 \\}
16141614 , &.{});
16151615 exe.root_module.pic = true;
1616 exe.linkLibC();
1616 exe.root_module.link_libc = true;
16171617
16181618 const run = addRunArtifact(exe);
16191619 run.expectStdOutEqual("3\n");
......@@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step {
16421642 \\}
16431643 , &.{"-fno-plt"});
16441644 exe.root_module.pic = true;
1645 exe.linkLibC();
1645 exe.root_module.link_libc = true;
16461646
16471647 const run = addRunArtifact(exe);
16481648 run.expectStdOutEqual("Hello world\n");
......@@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step {
16691669 \\ return 0;
16701670 \\}
16711671 , &.{});
1672 exe.linkLibC();
1672 exe.root_module.link_libc = true;
16731673 exe.linkage = .static;
16741674
16751675 const run = addRunArtifact(exe);
......@@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
17001700 exe.linkage = .static;
17011701 exe.root_module.pic = true;
17021702 exe.pie = true;
1703 exe.linkLibC();
1703 exe.root_module.link_libc = true;
17041704
17051705 const run = addRunArtifact(exe);
17061706 run.expectStdOutEqual("Hello world\n");
......@@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {
17331733 \\ return 0;
17341734 \\}
17351735 , &.{});
1736 exe.linkLibC();
1736 exe.root_module.link_libc = true;
17371737 exe.image_base = 0x8000000;
17381738
17391739 const run = addRunArtifact(exe);
......@@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
17791779 \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }
17801780 ,
17811781 });
1782 dso.linkLibC();
1782 dso.root_module.link_libc = true;
17831783
17841784 const main = addExecutable(b, opts, .{
17851785 .name = "main",
......@@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
17981798 .strip = true, // TODO temp hack
17991799 });
18001800 main.pie = true;
1801 main.linkLibrary(dso);
1801 main.root_module.linkLibrary(dso);
18021802
18031803 const run = addRunArtifact(main);
18041804 run.expectStdErrEqual(
......@@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
18321832 }, .{
18331833 .name = "a",
18341834 });
1835 lib.addObject(obj);
1835 lib.root_module.addObject(obj);
18361836
18371837 const main = addExecutable(b, opts, .{
18381838 .name = "main",
......@@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
18441844 ,
18451845 .strip = true, // TODO temp hack
18461846 });
1847 main.linkLibrary(lib);
1848 main.linkLibC();
1847 main.root_module.linkLibrary(lib);
1848 main.root_module.link_libc = true;
18491849
18501850 const run = addRunArtifact(main);
18511851 run.expectStdErrEqual("42\n");
......@@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18641864 \\__attribute__((constructor(10000))) void init4() { printf("1"); }
18651865 ,
18661866 });
1867 a_o.linkLibC();
1867 a_o.root_module.link_libc = true;
18681868
18691869 const b_o = addObject(b, opts, .{
18701870 .name = "b",
......@@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18731873 \\__attribute__((constructor(1000))) void init3() { printf("2"); }
18741874 ,
18751875 });
1876 b_o.linkLibC();
1876 b_o.root_module.link_libc = true;
18771877
18781878 const c_o = addObject(b, opts, .{
18791879 .name = "c",
......@@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18821882 \\__attribute__((constructor)) void init1() { printf("3"); }
18831883 ,
18841884 });
1885 c_o.linkLibC();
1885 c_o.root_module.link_libc = true;
18861886
18871887 const d_o = addObject(b, opts, .{
18881888 .name = "d",
......@@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
18911891 \\__attribute__((constructor)) void init2() { printf("4"); }
18921892 ,
18931893 });
1894 d_o.linkLibC();
1894 d_o.root_module.link_libc = true;
18951895
18961896 const e_o = addObject(b, opts, .{
18971897 .name = "e",
......@@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
19001900 \\__attribute__((destructor(10000))) void fini4() { printf("5"); }
19011901 ,
19021902 });
1903 e_o.linkLibC();
1903 e_o.root_module.link_libc = true;
19041904
19051905 const f_o = addObject(b, opts, .{
19061906 .name = "f",
......@@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
19091909 \\__attribute__((destructor(1000))) void fini3() { printf("6"); }
19101910 ,
19111911 });
1912 f_o.linkLibC();
1912 f_o.root_module.link_libc = true;
19131913
19141914 const g_o = addObject(b, opts, .{
19151915 .name = "g",
......@@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
19181918 \\__attribute__((destructor)) void fini1() { printf("7"); }
19191919 ,
19201920 });
1921 g_o.linkLibC();
1921 g_o.root_module.link_libc = true;
19221922
19231923 const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes =
19241924 \\#include <stdio.h>
19251925 \\__attribute__((destructor)) void fini2() { printf("8"); }
19261926 });
1927 h_o.linkLibC();
1927 h_o.root_module.link_libc = true;
19281928
19291929 const exe = addExecutable(b, opts, .{ .name = "main" });
19301930 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1931 exe.addObject(a_o);
1932 exe.addObject(b_o);
1933 exe.addObject(c_o);
1934 exe.addObject(d_o);
1935 exe.addObject(e_o);
1936 exe.addObject(f_o);
1937 exe.addObject(g_o);
1938 exe.addObject(h_o);
1931 exe.root_module.addObject(a_o);
1932 exe.root_module.addObject(b_o);
1933 exe.root_module.addObject(c_o);
1934 exe.root_module.addObject(d_o);
1935 exe.root_module.addObject(e_o);
1936 exe.root_module.addObject(f_o);
1937 exe.root_module.addObject(g_o);
1938 exe.root_module.addObject(h_o);
19391939
19401940 if (opts.target.result.isGnuLibC()) {
19411941 // 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 {
19701970 \\}
19711971 , &.{});
19721972 dso.link_function_sections = true;
1973 dso.linkLibC();
1973 dso.root_module.link_libc = true;
19741974
19751975 const check = dso.checkObject();
19761976 check.checkInSymtab();
......@@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
19861986 \\void greet();
19871987 \\int main() { greet(); }
19881988 , &.{});
1989 exe.linkLibrary(dso);
1990 exe.linkLibC();
1989 exe.root_module.linkLibrary(dso);
1990 exe.root_module.link_libc = true;
19911991
19921992 const run = addRunArtifact(exe);
19931993 run.expectStdOutEqual("Hello world");
......@@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {
20212021 \\}
20222022 , &.{});
20232023 exe.link_function_sections = true;
2024 exe.linkLibC();
2024 exe.root_module.link_libc = true;
20252025
20262026 const check = exe.checkObject();
20272027 check.checkInSymtab();
......@@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step {
20492049 \\ return arr[2000];
20502050 \\}
20512051 , &.{});
2052 exe.linkLibC();
2052 exe.root_module.link_libc = true;
20532053 // Disabled to work around the ELF linker crashing.
20542054 // Can be reproduced on a x86_64-linux host by commenting out the line below.
20552055 exe.root_module.sanitize_c = .off;
......@@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
20712071 });
20722072
20732073 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
2074 dso.addObject(obj);
2074 dso.root_module.addObject(obj);
20752075
20762076 const lib = addStaticLibrary(b, opts, .{ .name = "b" });
2077 lib.addObject(obj);
2077 lib.root_module.addObject(obj);
20782078
20792079 const main_o = addObject(b, opts, .{
20802080 .name = "main",
......@@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
20892089 // https://github.com/ziglang/zig/issues/17450
20902090 // {
20912091 // const exe = addExecutable(b, opts, .{ .name = "main1"});
2092 // exe.addObject(main_o);
2093 // exe.linkSystemLibrary2("a", .{});
2094 // exe.addLibraryPath(dso.getEmittedBinDirectory());
2095 // exe.addRPath(dso.getEmittedBinDirectory());
2096 // exe.linkSystemLibrary2("b", .{});
2097 // exe.addLibraryPath(lib.getEmittedBinDirectory());
2098 // exe.addRPath(lib.getEmittedBinDirectory());
2099 // exe.linkLibC();
2092 // exe.root_module.addObject(main_o);
2093 // exe.root_module.linkSystemLibrary("a", .{});
2094 // exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2095 // exe.root_module.addRPath(dso.getEmittedBinDirectory());
2096 // exe.root_module.linkSystemLibrary("b", .{});
2097 // exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2098 // exe.root_module.addRPath(lib.getEmittedBinDirectory());
2099 // exe.root_module.link_libc = true;
21002100
21012101 // const check = exe.checkObject();
21022102 // check.checkInDynamicSection();
......@@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
21062106
21072107 {
21082108 const exe = addExecutable(b, opts, .{ .name = "main2" });
2109 exe.addObject(main_o);
2110 exe.linkSystemLibrary2("b", .{});
2111 exe.addLibraryPath(lib.getEmittedBinDirectory());
2112 exe.addRPath(lib.getEmittedBinDirectory());
2113 exe.linkSystemLibrary2("a", .{});
2114 exe.addLibraryPath(dso.getEmittedBinDirectory());
2115 exe.addRPath(dso.getEmittedBinDirectory());
2116 exe.linkLibC();
2109 exe.root_module.addObject(main_o);
2110 exe.root_module.linkSystemLibrary("b", .{});
2111 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2112 exe.root_module.addRPath(lib.getEmittedBinDirectory());
2113 exe.root_module.linkSystemLibrary("a", .{});
2114 exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2115 exe.root_module.addRPath(dso.getEmittedBinDirectory());
2116 exe.root_module.link_libc = true;
21172117
21182118 const check = exe.checkObject();
21192119 check.checkInDynamicSection();
......@@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step {
21492149 \\ return bar() - baz();
21502150 \\}
21512151 , &.{});
2152 exe.linkSystemLibrary2("a", .{});
2153 exe.addLibraryPath(scripts.getDirectory());
2154 exe.addLibraryPath(scripts2.getDirectory());
2155 exe.addLibraryPath(bar.getEmittedBinDirectory());
2156 exe.addLibraryPath(baz.getEmittedBinDirectory());
2157 exe.addRPath(bar.getEmittedBinDirectory());
2158 exe.addRPath(baz.getEmittedBinDirectory());
2159 exe.linkLibC();
2152 exe.root_module.linkSystemLibrary("a", .{});
2153 exe.root_module.addLibraryPath(scripts.getDirectory());
2154 exe.root_module.addLibraryPath(scripts2.getDirectory());
2155 exe.root_module.addLibraryPath(bar.getEmittedBinDirectory());
2156 exe.root_module.addLibraryPath(baz.getEmittedBinDirectory());
2157 exe.root_module.addRPath(bar.getEmittedBinDirectory());
2158 exe.root_module.addRPath(baz.getEmittedBinDirectory());
2159 exe.root_module.link_libc = true;
21602160 exe.allow_so_scripts = true;
21612161
21622162 const run = addRunArtifact(exe);
......@@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
21742174
21752175 const exe = addExecutable(b, opts, .{ .name = "main" });
21762176 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2177 exe.linkSystemLibrary2("a", .{});
2178 exe.addLibraryPath(scripts.getDirectory());
2179 exe.linkLibC();
2177 exe.root_module.linkSystemLibrary("a", .{});
2178 exe.root_module.addLibraryPath(scripts.getDirectory());
2179 exe.root_module.link_libc = true;
21802180 exe.allow_so_scripts = true;
21812181
21822182 // TODO: A future enhancement could make this error message also mention
......@@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
22132213 \\}
22142214 ,
22152215 });
2216 exe.linkLibrary(so);
2217 exe.linkLibC();
2216 exe.root_module.linkLibrary(so);
2217 exe.root_module.link_libc = true;
22182218 exe.allow_so_scripts = true;
22192219
22202220 const run = addRunArtifact(exe);
......@@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {
22692269 \\ return foo;
22702270 \\}
22712271 , &.{});
2272 exe.addObject(obj);
2273 exe.linkLibC();
2272 exe.root_module.addObject(obj);
2273 exe.root_module.link_libc = true;
22742274
22752275 expectLinkErrors(exe, test_step, .{ .exact = &.{
22762276 "invalid ELF machine type: AARCH64",
......@@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step {
22912291 \\ return 0;
22922292 \\}
22932293 , &.{});
2294 exe.linkLibC();
2294 exe.root_module.link_libc = true;
22952295
22962296 const run = addRunArtifact(exe);
22972297 run.expectStdOutEqual("Hello World!\n");
......@@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {
23202320 \\ return 0;
23212321 \\}
23222322 , &.{});
2323 exe.linkLibC();
2324 exe.linkLibCpp();
2323 exe.root_module.link_libc = true;
2324 exe.root_module.link_libcpp = true;
23252325
23262326 const run = addRunArtifact(exe);
23272327 run.expectStdOutEqual("Hello World!\n");
......@@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step {
23642364 \\}
23652365 ,
23662366 });
2367 exe.addObject(obj);
2367 exe.root_module.addObject(obj);
23682368
23692369 const run = addRunArtifact(exe);
23702370 run.expectStdErrEqual("84\n");
......@@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
23892389 \\}
23902390 ,
23912391 });
2392 lib.addObject(obj);
2392 lib.root_module.addObject(obj);
23932393
23942394 const exe = addExecutable(b, opts, .{
23952395 .name = "testlib",
......@@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
24022402 \\}
24032403 ,
24042404 });
2405 exe.linkLibrary(lib);
2405 exe.root_module.linkLibrary(lib);
24062406
24072407 const run = addRunArtifact(exe);
24082408 run.expectStdErrEqual("0\n");
......@@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
24522452 \\char16_t *utf16_1 = u"foo";
24532453 \\char32_t *utf32_1 = U"foo";
24542454 , &.{"-O2"});
2455 obj1.linkLibC();
2455 obj1.root_module.link_libc = true;
24562456
24572457 const obj2 = addObject(b, opts, .{ .name = "b.o" });
24582458 addCSourceBytes(obj2,
......@@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
24812481 \\ assert((void*)wide1 != (void*)utf16_1);
24822482 \\}
24832483 , &.{"-O2"});
2484 obj2.linkLibC();
2484 obj2.root_module.link_libc = true;
24852485
24862486 const exe = addExecutable(b, opts, .{ .name = "main" });
2487 exe.addObject(obj1);
2488 exe.addObject(obj2);
2489 exe.linkLibC();
2487 exe.root_module.addObject(obj1);
2488 exe.root_module.addObject(obj2);
2489 exe.root_module.link_libc = true;
24902490
24912491 const run = addRunArtifact(exe);
24922492 run.expectExitCode(0);
......@@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25202520
25212521 {
25222522 const exe = addExecutable(b, opts, .{ .name = "main1" });
2523 exe.addObject(obj1);
2524 exe.addObject(obj2);
2523 exe.root_module.addObject(obj1);
2524 exe.root_module.addObject(obj2);
25252525
25262526 const run = addRunArtifact(exe);
25272527 run.expectExitCode(0);
......@@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25372537
25382538 {
25392539 const obj3 = addObject(b, opts, .{ .name = "c" });
2540 obj3.addObject(obj1);
2541 obj3.addObject(obj2);
2540 obj3.root_module.addObject(obj1);
2541 obj3.root_module.addObject(obj2);
25422542
25432543 const exe = addExecutable(b, opts, .{ .name = "main2" });
2544 exe.addObject(obj3);
2544 exe.root_module.addObject(obj3);
25452545
25462546 const run = addRunArtifact(exe);
25472547 run.expectExitCode(0);
......@@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
25642564 const exe = addExecutable(b, opts, .{ .name = "main" });
25652565 addCSourceBytes(exe, "int main() { return 0; }", &.{});
25662566 exe.link_eh_frame_hdr = false;
2567 exe.linkLibC();
2567 exe.root_module.link_libc = true;
25682568
25692569 const check = exe.checkObject();
25702570 check.checkInHeaders();
......@@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step {
25862586 \\ return 0;
25872587 \\}
25882588 , &.{});
2589 exe.linkLibC();
2589 exe.root_module.link_libc = true;
25902590 exe.root_module.pic = true;
25912591 exe.pie = true;
25922592
......@@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step {
26172617 \\ printf("Hello world\n");
26182618 \\}
26192619 , &.{});
2620 dso.linkLibC();
2620 dso.root_module.link_libc = true;
26212621
26222622 const exe = addExecutable(b, opts, .{ .name = "main" });
26232623 addCSourceBytes(exe,
......@@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step {
26262626 \\void foo() { ignore(hello); }
26272627 \\int main() { hello(); }
26282628 , &.{});
2629 exe.linkLibrary(dso);
2629 exe.root_module.linkLibrary(dso);
26302630 exe.root_module.pic = true;
2631 exe.linkLibC();
2631 exe.root_module.link_libc = true;
26322632
26332633 const run = addRunArtifact(exe);
26342634 run.expectStdOutEqual("Hello world\n");
......@@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
26472647 });
26482648
26492649 const exe = addExecutable(b, opts, .{ .name = "main1" });
2650 exe.addObject(obj);
2650 exe.root_module.addObject(obj);
26512651
26522652 const check = exe.checkObject();
26532653 check.checkInDynamicSection();
......@@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
26622662 \\__attribute__((section(".preinit_array")))
26632663 \\void *preinit[] = { preinit_fn };
26642664 , &.{});
2665 exe.linkLibC();
2665 exe.root_module.link_libc = true;
26662666
26672667 const check = exe.checkObject();
26682668 check.checkInDynamicSection();
......@@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step {
27102710 });
27112711
27122712 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
2713 lib.addObject(obj1);
2714 lib.addObject(obj2);
2715 lib.addObject(obj3);
2713 lib.root_module.addObject(obj1);
2714 lib.root_module.addObject(obj2);
2715 lib.root_module.addObject(obj3);
27162716
27172717 const obj5 = addObject(b, opts, .{
27182718 .name = "obj5",
27192719 });
2720 obj5.addObject(obj4);
2721 obj5.linkLibrary(lib);
2720 obj5.root_module.addObject(obj4);
2721 obj5.root_module.linkLibrary(lib);
27222722
27232723 const check = obj5.checkObject();
27242724 check.checkInSymtab();
......@@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27442744 \\}
27452745 ,
27462746 });
2747 obj1.linkLibCpp();
2747 obj1.root_module.link_libcpp = true;
27482748 const obj2 = addObject(b, opts, .{
27492749 .name = "obj2",
27502750 .cpp_source_bytes =
......@@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27542754 \\}
27552755 ,
27562756 });
2757 obj2.linkLibCpp();
2757 obj2.root_module.link_libcpp = true;
27582758 const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes =
27592759 \\#include <iostream>
27602760 \\#include <stdexcept>
......@@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27682768 \\ return 0;
27692769 \\}
27702770 });
2771 obj3.linkLibCpp();
2771 obj3.root_module.link_libcpp = true;
27722772
27732773 {
27742774 const obj = addObject(b, opts, .{ .name = "obj" });
2775 obj.addObject(obj1);
2776 obj.addObject(obj2);
2777 obj.linkLibCpp();
2775 obj.root_module.addObject(obj1);
2776 obj.root_module.addObject(obj2);
2777 obj.root_module.link_libcpp = true;
27782778
27792779 const exe = addExecutable(b, opts, .{ .name = "test1" });
2780 exe.addObject(obj3);
2781 exe.addObject(obj);
2782 exe.linkLibCpp();
2780 exe.root_module.addObject(obj3);
2781 exe.root_module.addObject(obj);
2782 exe.root_module.link_libcpp = true;
27832783
27842784 const run = addRunArtifact(exe);
27852785 run.expectStdOutEqual("exception=Oh no!");
......@@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
27882788 {
27892789 // Flipping the order should not influence the end result.
27902790 const obj = addObject(b, opts, .{ .name = "obj" });
2791 obj.addObject(obj2);
2792 obj.addObject(obj1);
2793 obj.linkLibCpp();
2791 obj.root_module.addObject(obj2);
2792 obj.root_module.addObject(obj1);
2793 obj.root_module.link_libcpp = true;
27942794
27952795 const exe = addExecutable(b, opts, .{ .name = "test2" });
2796 exe.addObject(obj3);
2797 exe.addObject(obj);
2798 exe.linkLibCpp();
2796 exe.root_module.addObject(obj3);
2797 exe.root_module.addObject(obj);
2798 exe.root_module.link_libcpp = true;
27992799
28002800 const run = addRunArtifact(exe);
28012801 run.expectStdOutEqual("exception=Oh no!");
......@@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
28172817 \\}
28182818 ,
28192819 });
2820 obj1.linkLibCpp();
2820 obj1.root_module.link_libcpp = true;
28212821 const obj2 = addObject(b, opts, .{
28222822 .name = "obj2",
28232823 .cpp_source_bytes =
......@@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
28272827 \\}
28282828 ,
28292829 });
2830 obj2.linkLibCpp();
2830 obj2.root_module.link_libcpp = true;
28312831 const obj3 = addObject(b, opts, .{
28322832 .name = "obj3",
28332833 .cpp_source_bytes =
......@@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
28442844 \\}
28452845 ,
28462846 });
2847 obj3.linkLibCpp();
2847 obj3.root_module.link_libcpp = true;
28482848
28492849 const obj = addObject(b, opts, .{ .name = "obj" });
2850 obj.addObject(obj1);
2851 obj.addObject(obj2);
2852 obj.addObject(obj3);
2853 obj.linkLibCpp();
2850 obj.root_module.addObject(obj1);
2851 obj.root_module.addObject(obj2);
2852 obj.root_module.addObject(obj3);
2853 obj.root_module.link_libcpp = true;
28542854
28552855 const exe = addExecutable(b, opts, .{ .name = "test2" });
2856 exe.addObject(obj);
2857 exe.linkLibCpp();
2856 exe.root_module.addObject(obj);
2857 exe.root_module.link_libcpp = true;
28582858
28592859 const run = addRunArtifact(exe);
28602860 run.expectStdOutEqual("exception=Oh no!");
......@@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {
28802880 });
28812881
28822882 const obj2 = addObject(b, opts, .{ .name = "b" });
2883 obj2.addObject(obj1);
2883 obj2.root_module.addObject(obj1);
28842884
28852885 const check = obj2.checkObject();
28862886 check.dumpSection(".rodata.str1.1");
......@@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
29052905 const obj2 = addObject(b, opts, .{
29062906 .name = "obj2",
29072907 });
2908 obj2.addObject(obj1);
2908 obj2.root_module.addObject(obj1);
29092909
29102910 const check1 = obj1.checkObject();
29112911 check1.checkInHeaders();
......@@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
29402940 ,
29412941 .pic = true,
29422942 });
2943 obj.linkLibC();
2943 obj.root_module.link_libc = true;
29442944
29452945 {
29462946 const exe = addExecutable(b, opts, .{ .name = "main1" });
2947 exe.addObject(obj);
2948 exe.linkLibrary(dso);
2947 exe.root_module.addObject(obj);
2948 exe.root_module.linkLibrary(dso);
29492949 exe.pie = true;
29502950
29512951 const run = addRunArtifact(exe);
......@@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
29652965 // https://github.com/ziglang/zig/issues/17430
29662966 // {
29672967 // const exe = addExecutable(b, opts, .{ .name = "main2"});
2968 // exe.addObject(obj);
2969 // exe.linkLibrary(dso);
2968 // exe.root_module.addObject(obj);
2969 // exe.root_module.linkLibrary(dso);
29702970 // exe.pie = false;
29712971
29722972 // const run = addRunArtifact(exe);
......@@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step {
29992999 \\}
30003000 ,
30013001 });
3002 obj.linkLibC();
3002 obj.root_module.link_libc = true;
30033003
30043004 {
30053005 const exe = addExecutable(b, opts, .{ .name = "main1" });
3006 exe.addObject(obj);
3006 exe.root_module.addObject(obj);
30073007 exe.root_module.strip = false;
3008 exe.linkLibC();
3008 exe.root_module.link_libc = true;
30093009
30103010 const check = exe.checkObject();
30113011 check.checkInHeaders();
......@@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step {
30163016
30173017 {
30183018 const exe = addExecutable(b, opts, .{ .name = "main2" });
3019 exe.addObject(obj);
3019 exe.root_module.addObject(obj);
30203020 exe.root_module.strip = true;
3021 exe.linkLibC();
3021 exe.root_module.link_libc = true;
30223022
30233023 const check = exe.checkObject();
30243024 check.checkInHeaders();
......@@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
30743074
30753075 {
30763076 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3077 dso.addObject(obj);
3077 dso.root_module.addObject(obj);
30783078 // dso.link_relax = true;
30793079
30803080 const check = dso.checkObject();
......@@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
30863086 // TODO add -Wl,--no-relax
30873087 // {
30883088 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3089 // dso.addObject(obj);
3089 // dso.root_module.addObject(obj);
30903090 // dso.link_relax = false;
30913091
30923092 // const check = dso.checkObject();
......@@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step {
31283128 \\ return 0;
31293129 \\}
31303130 , &.{});
3131 exe.linkLibrary(dso);
3132 exe.linkLibC();
3131 exe.root_module.linkLibrary(dso);
3132 exe.root_module.link_libc = true;
31333133
31343134 const run = addRunArtifact(exe);
31353135 run.expectStdOutEqual("5 3 5 3 5 3\n");
......@@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
31593159 ,
31603160 .pic = true,
31613161 });
3162 main_o.linkLibC();
3162 main_o.root_module.link_libc = true;
31633163
31643164 const a_o = addObject(b, opts, .{
31653165 .name = "a",
......@@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
31843184 const exp_stdout = "1 2 3 4 5 6\n";
31853185
31863186 const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });
3187 dso1.addObject(a_o);
3187 dso1.root_module.addObject(a_o);
31883188
31893189 const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });
3190 dso2.addObject(b_o);
3190 dso2.root_module.addObject(b_o);
31913191 // dso2.link_relax = false; // TODO
31923192
31933193 {
31943194 const exe = addExecutable(b, opts, .{ .name = "main1" });
3195 exe.addObject(main_o);
3196 exe.linkLibrary(dso1);
3197 exe.linkLibrary(dso2);
3195 exe.root_module.addObject(main_o);
3196 exe.root_module.linkLibrary(dso1);
3197 exe.root_module.linkLibrary(dso2);
31983198
31993199 const run = addRunArtifact(exe);
32003200 run.expectStdOutEqual(exp_stdout);
......@@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32033203
32043204 {
32053205 const exe = addExecutable(b, opts, .{ .name = "main2" });
3206 exe.addObject(main_o);
3206 exe.root_module.addObject(main_o);
32073207 // exe.link_relax = false; // TODO
3208 exe.linkLibrary(dso1);
3209 exe.linkLibrary(dso2);
3208 exe.root_module.linkLibrary(dso1);
3209 exe.root_module.linkLibrary(dso2);
32103210
32113211 const run = addRunArtifact(exe);
32123212 run.expectStdOutEqual(exp_stdout);
......@@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32163216 // https://github.com/ziglang/zig/issues/17430 ??
32173217 // {
32183218 // const exe = addExecutable(b, opts, .{ .name = "main3"});
3219 // exe.addObject(main_o);
3220 // exe.linkLibrary(dso1);
3221 // exe.linkLibrary(dso2);
3219 // exe.root_module.addObject(main_o);
3220 // exe.root_module.linkLibrary(dso1);
3221 // exe.root_module.linkLibrary(dso2);
32223222 // exe.linkage = .static;
32233223
32243224 // const run = addRunArtifact(exe);
......@@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32283228
32293229 // {
32303230 // const exe = addExecutable(b, opts, .{ .name = "main4"});
3231 // exe.addObject(main_o);
3231 // exe.root_module.addObject(main_o);
32323232 // // exe.link_relax = false; // TODO
3233 // exe.linkLibrary(dso1);
3234 // exe.linkLibrary(dso2);
3233 // exe.root_module.linkLibrary(dso1);
3234 // exe.root_module.linkLibrary(dso2);
32353235 // exe.linkage = .static;
32363236
32373237 // const run = addRunArtifact(exe);
......@@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32653265 .c_source_flags = &.{"-fno-plt"},
32663266 .pic = true,
32673267 });
3268 obj.linkLibC();
3268 obj.root_module.link_libc = true;
32693269
32703270 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });
32713271 addCSourceBytes(a_so,
......@@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32843284
32853285 {
32863286 const exe = addExecutable(b, opts, .{ .name = "main1" });
3287 exe.addObject(obj);
3288 exe.linkLibrary(a_so);
3289 exe.linkLibrary(b_so);
3290 exe.linkLibC();
3287 exe.root_module.addObject(obj);
3288 exe.root_module.linkLibrary(a_so);
3289 exe.root_module.linkLibrary(b_so);
3290 exe.root_module.link_libc = true;
32913291
32923292 const run = addRunArtifact(exe);
32933293 run.expectStdOutEqual("1 2 3 4 5 6\n");
......@@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32963296
32973297 {
32983298 const exe = addExecutable(b, opts, .{ .name = "main2" });
3299 exe.addObject(obj);
3300 exe.linkLibrary(a_so);
3301 exe.linkLibrary(b_so);
3302 exe.linkLibC();
3299 exe.root_module.addObject(obj);
3300 exe.root_module.linkLibrary(a_so);
3301 exe.root_module.linkLibrary(b_so);
3302 exe.root_module.link_libc = true;
33033303 // exe.link_relax = false; // TODO
33043304
33053305 const run = addRunArtifact(exe);
......@@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33293329 ,
33303330 .pic = true,
33313331 });
3332 a_o.linkLibC();
3332 a_o.root_module.link_libc = true;
33333333
33343334 const b_o = addObject(b, opts, .{
33353335 .name = "b",
......@@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33423342
33433343 {
33443344 const dso = addSharedLibrary(b, opts, .{ .name = "a1" });
3345 dso.addObject(a_o);
3345 dso.root_module.addObject(a_o);
33463346
33473347 const exe = addExecutable(b, opts, .{ .name = "main1" });
3348 exe.addObject(b_o);
3349 exe.linkLibrary(dso);
3350 exe.linkLibC();
3348 exe.root_module.addObject(b_o);
3349 exe.root_module.linkLibrary(dso);
3350 exe.root_module.link_libc = true;
33513351
33523352 const run = addRunArtifact(exe);
33533353 run.expectStdOutEqual("1 2 3\n");
......@@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33563356
33573357 {
33583358 const dso = addSharedLibrary(b, opts, .{ .name = "a2" });
3359 dso.addObject(a_o);
3359 dso.root_module.addObject(a_o);
33603360 // dso.link_relax = false; // TODO
33613361
33623362 const exe = addExecutable(b, opts, .{ .name = "main2" });
3363 exe.addObject(b_o);
3364 exe.linkLibrary(dso);
3365 exe.linkLibC();
3363 exe.root_module.addObject(b_o);
3364 exe.root_module.linkLibrary(dso);
3365 exe.root_module.link_libc = true;
33663366
33673367 const run = addRunArtifact(exe);
33683368 run.expectStdOutEqual("1 2 3\n");
......@@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33713371
33723372 // {
33733373 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3374 // dso.addObject(a_o);
3374 // dso.root_module.addObject(a_o);
33753375 // dso.link_z_nodlopen = true;
33763376
33773377 // const exe = addExecutable(b, opts, .{ .name = "main"});
3378 // exe.addObject(b_o);
3379 // exe.linkLibrary(dso);
3378 // exe.root_module.addObject(b_o);
3379 // exe.root_module.linkLibrary(dso);
33803380
33813381 // const run = addRunArtifact(exe);
33823382 // run.expectStdOutEqual("1 2 3\n");
......@@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33853385
33863386 // {
33873387 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3388 // dso.addObject(a_o);
3388 // dso.root_module.addObject(a_o);
33893389 // dso.link_relax = false;
33903390 // dso.link_z_nodlopen = true;
33913391
33923392 // const exe = addExecutable(b, opts, .{ .name = "main"});
3393 // exe.addObject(b_o);
3394 // exe.linkLibrary(dso);
3393 // exe.root_module.addObject(b_o);
3394 // exe.root_module.linkLibrary(dso);
33953395
33963396 // const run = addRunArtifact(exe);
33973397 // run.expectStdOutEqual("1 2 3\n");
......@@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34173417 \\ printf("%d %d ", foo, bar);
34183418 \\}
34193419 , &.{});
3420 dso.linkLibC();
3420 dso.root_module.link_libc = true;
34213421
34223422 const main_o = addObject(b, opts, .{
34233423 .name = "main",
......@@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34353435 \\}
34363436 ,
34373437 });
3438 main_o.linkLibC();
3438 main_o.root_module.link_libc = true;
34393439
34403440 const exp_stdout = "0 0 3 5 7\n";
34413441
34423442 {
34433443 const exe = addExecutable(b, opts, .{ .name = "main1" });
3444 exe.addObject(main_o);
3445 exe.linkLibrary(dso);
3446 exe.linkLibC();
3444 exe.root_module.addObject(main_o);
3445 exe.root_module.linkLibrary(dso);
3446 exe.root_module.link_libc = true;
34473447
34483448 const run = addRunArtifact(exe);
34493449 run.expectStdOutEqual(exp_stdout);
......@@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34523452
34533453 {
34543454 const exe = addExecutable(b, opts, .{ .name = "main2" });
3455 exe.addObject(main_o);
3456 exe.linkLibrary(dso);
3457 exe.linkLibC();
3455 exe.root_module.addObject(main_o);
3456 exe.root_module.linkLibrary(dso);
3457 exe.root_module.link_libc = true;
34583458 // exe.link_relax = false; // TODO
34593459
34603460 const run = addRunArtifact(exe);
......@@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
35003500 ,
35013501 .pic = true,
35023502 });
3503 c_o.linkLibC();
3503 c_o.root_module.link_libc = true;
35043504
35053505 {
35063506 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3507 dso.addObject(a_o);
3508 dso.addObject(b_o);
3507 dso.root_module.addObject(a_o);
3508 dso.root_module.addObject(b_o);
35093509
35103510 const exe = addExecutable(b, opts, .{ .name = "main" });
3511 exe.addObject(c_o);
3512 exe.linkLibrary(dso);
3513 exe.linkLibC();
3511 exe.root_module.addObject(c_o);
3512 exe.root_module.linkLibrary(dso);
3513 exe.root_module.link_libc = true;
35143514
35153515 const run = addRunArtifact(exe);
35163516 run.expectStdOutEqual("42 1 2 3\n");
......@@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
35193519
35203520 {
35213521 const exe = addExecutable(b, opts, .{ .name = "main" });
3522 exe.addObject(a_o);
3523 exe.addObject(b_o);
3524 exe.addObject(c_o);
3525 exe.linkLibC();
3522 exe.root_module.addObject(a_o);
3523 exe.root_module.addObject(b_o);
3524 exe.root_module.addObject(c_o);
3525 exe.root_module.link_libc = true;
35263526
35273527 const run = addRunArtifact(exe);
35283528 run.expectStdOutEqual("42 1 2 3\n");
......@@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step {
35553555 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);
35563556 \\}
35573557 , &.{});
3558 exe.linkLibC();
3558 exe.root_module.link_libc = true;
35593559 // Disabled to work around the ELF linker crashing.
35603560 // Can be reproduced on a x86_64-linux host by commenting out the line below.
35613561 exe.root_module.sanitize_c = .off;
......@@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {
35803580 \\}
35813581 , &.{});
35823582 exe.root_module.pic = true;
3583 exe.linkLibC();
3583 exe.root_module.link_libc = true;
35843584
35853585 const run = addRunArtifact(exe);
35863586 run.expectStdOutEqual("1 2 3 0 5\n");
......@@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36093609 .c_source_flags = &.{"-ftls-model=local-dynamic"},
36103610 .pic = true,
36113611 });
3612 main_o.linkLibC();
3612 main_o.root_module.link_libc = true;
36133613
36143614 const a_o = addObject(b, opts, .{
36153615 .name = "a",
......@@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36223622
36233623 {
36243624 const exe = addExecutable(b, opts, .{ .name = "main1" });
3625 exe.addObject(main_o);
3626 exe.addObject(a_o);
3627 exe.linkLibC();
3625 exe.root_module.addObject(main_o);
3626 exe.root_module.addObject(a_o);
3627 exe.root_module.link_libc = true;
36283628
36293629 const run = addRunArtifact(exe);
36303630 run.expectStdOutEqual(exp_stdout);
......@@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36333633
36343634 {
36353635 const exe = addExecutable(b, opts, .{ .name = "main2" });
3636 exe.addObject(main_o);
3637 exe.addObject(a_o);
3638 exe.linkLibC();
3636 exe.root_module.addObject(main_o);
3637 exe.root_module.addObject(a_o);
3638 exe.root_module.link_libc = true;
36393639 // exe.link_relax = false; // TODO
36403640
36413641 const run = addRunArtifact(exe);
......@@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step {
36683668 \\ return 0;
36693669 \\}
36703670 , &.{});
3671 exe.linkLibrary(dso);
3672 exe.linkLibC();
3671 exe.root_module.linkLibrary(dso);
3672 exe.root_module.link_libc = true;
36733673
36743674 const run = addRunArtifact(exe);
36753675 run.expectStdOutEqual("1 2\n");
......@@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
36993699 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },
37003700 .pic = true,
37013701 });
3702 a_o.linkLibC();
3702 a_o.root_module.link_libc = true;
37033703
37043704 const b_o = addObject(b, opts, .{
37053705 .name = "b",
......@@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37103710
37113711 {
37123712 const exe = addExecutable(b, opts, .{ .name = "main1" });
3713 exe.addObject(a_o);
3714 exe.addObject(b_o);
3715 exe.linkLibC();
3713 exe.root_module.addObject(a_o);
3714 exe.root_module.addObject(b_o);
3715 exe.root_module.link_libc = true;
37163716
37173717 const run = addRunArtifact(exe);
37183718 run.expectStdOutEqual("3 5 3 5\n");
......@@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37213721
37223722 {
37233723 const exe = addExecutable(b, opts, .{ .name = "main2" });
3724 exe.addObject(a_o);
3725 exe.addObject(b_o);
3726 exe.linkLibC();
3724 exe.root_module.addObject(a_o);
3725 exe.root_module.addObject(b_o);
3726 exe.root_module.link_libc = true;
37273727 // exe.link_relax = false; // TODO
37283728
37293729 const run = addRunArtifact(exe);
......@@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step {
37563756 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;
37573757 , &.{});
37583758 exe.root_module.pic = false;
3759 exe.linkLibC();
3759 exe.root_module.link_libc = true;
37603760
37613761 const run = addRunArtifact(exe);
37623762 run.expectStdOutEqual("3 5 3 5\n");
......@@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
37843784 \\ return NULL;
37853785 \\}
37863786 , &.{});
3787 dso.linkLibC();
3787 dso.root_module.link_libc = true;
37883788
37893789 const exe = addExecutable(b, opts, .{ .name = "main" });
37903790 addCSourceBytes(exe,
......@@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
38113811 \\ pthread_join(thread, NULL);
38123812 \\}
38133813 , &.{});
3814 exe.addRPath(dso.getEmittedBinDirectory());
3815 exe.linkLibC();
3814 exe.root_module.addRPath(dso.getEmittedBinDirectory());
3815 exe.root_module.link_libc = true;
38163816 exe.root_module.pic = true;
38173817
38183818 const run = addRunArtifact(exe);
......@@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step {
38423842 ,
38433843 .pic = true,
38443844 });
3845 obj.linkLibC();
3845 obj.root_module.link_libc = true;
38463846
38473847 const exe = addExecutable(b, opts, .{ .name = "main" });
38483848 addCSourceBytes(exe,
38493849 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;
38503850 , &.{});
3851 exe.addObject(obj);
3852 exe.linkLibC();
3851 exe.root_module.addObject(obj);
3852 exe.root_module.link_libc = true;
38533853
38543854 const run = addRunArtifact(exe);
38553855 run.expectStdOutEqual("3 5 3 5\n");
......@@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
38893889 ,
38903890 .pic = true,
38913891 });
3892 c_o.linkLibC();
3892 c_o.root_module.link_libc = true;
38933893
38943894 {
38953895 const exe = addExecutable(b, opts, .{ .name = "main" });
3896 exe.addObject(a_o);
3897 exe.addObject(b_o);
3898 exe.addObject(c_o);
3899 exe.linkLibC();
3896 exe.root_module.addObject(a_o);
3897 exe.root_module.addObject(b_o);
3898 exe.root_module.addObject(c_o);
3899 exe.root_module.link_libc = true;
39003900
39013901 const run = addRunArtifact(exe);
39023902 run.expectStdOutEqual("42\n");
......@@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
39053905
39063906 {
39073907 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3908 dso.addObject(a_o);
3909 dso.addObject(b_o);
3908 dso.root_module.addObject(a_o);
3909 dso.root_module.addObject(b_o);
39103910
39113911 const exe = addExecutable(b, opts, .{ .name = "main" });
3912 exe.addObject(c_o);
3913 exe.linkLibrary(dso);
3914 exe.linkLibC();
3912 exe.root_module.addObject(c_o);
3913 exe.root_module.linkLibrary(dso);
3914 exe.root_module.link_libc = true;
39153915
39163916 const run = addRunArtifact(exe);
39173917 run.expectStdOutEqual("42\n");
......@@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step {
39393939 \\ return 0;
39403940 \\}
39413941 , &.{});
3942 exe.linkLibC();
3942 exe.root_module.link_libc = true;
39433943
39443944 const run = addRunArtifact(exe);
39453945 run.expectStdOutEqual(
......@@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {
39693969 \\ return foo;
39703970 \\}
39713971 , &.{});
3972 exe.linkLibrary(dylib);
3973 exe.linkLibC();
3972 exe.root_module.linkLibrary(dylib);
3973 exe.root_module.link_libc = true;
39743974
39753975 expectLinkErrors(exe, test_step, .{
39763976 .contains = "error: failed to parse shared library: BadMagic",
......@@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
39933993 ,
39943994 .c_source_flags = &.{"-ffunction-sections"},
39953995 });
3996 obj1.linkLibC();
3996 obj1.root_module.link_libc = true;
39973997
39983998 const obj2 = addObject(b, opts, .{
39993999 .name = "b",
......@@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
40074007 ,
40084008 .c_source_flags = &.{"-ffunction-sections"},
40094009 });
4010 obj2.linkLibC();
4010 obj2.root_module.link_libc = true;
40114011
40124012 const exe = addExecutable(b, opts, .{ .name = "main" });
4013 exe.addObject(obj1);
4014 exe.addObject(obj2);
4015 exe.linkLibC();
4013 exe.root_module.addObject(obj1);
4014 exe.root_module.addObject(obj2);
4015 exe.root_module.link_libc = true;
40164016
40174017 expectLinkErrors(exe, test_step, .{ .exact = &.{
40184018 "error: undefined symbol: foo",
......@@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
40374037 ,
40384038 .pic = true,
40394039 });
4040 obj.linkLibC();
4040 obj.root_module.link_libc = true;
40414041
40424042 {
40434043 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4044 dso.addObject(obj);
4045 dso.linkLibC();
4044 dso.root_module.addObject(obj);
4045 dso.root_module.link_libc = true;
40464046
40474047 const check = dso.checkObject();
40484048 check.checkInDynamicSymtab();
......@@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
40524052
40534053 {
40544054 const exe = addExecutable(b, opts, .{ .name = "main" });
4055 exe.addObject(obj);
4056 exe.linkLibC();
4055 exe.root_module.addObject(obj);
4056 exe.root_module.link_libc = true;
40574057
40584058 const check = exe.checkObject();
40594059 check.checkInDynamicSymtab();
......@@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
40844084 \\int bar();
40854085 \\int main() { printf("bar=%d\n", bar()); }
40864086 , &.{});
4087 exe.linkLibrary(dso);
4088 exe.linkLibC();
4087 exe.root_module.linkLibrary(dso);
4088 exe.root_module.link_libc = true;
40894089
40904090 const run = addRunArtifact(exe);
40914091 run.expectStdOutEqual("bar=-1\n");
......@@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
41004100 \\int bar();
41014101 \\int main() { printf("bar=%d\n", bar()); }
41024102 , &.{});
4103 exe.linkLibrary(dso);
4104 exe.linkLibC();
4103 exe.root_module.linkLibrary(dso);
4104 exe.root_module.link_libc = true;
41054105
41064106 const run = addRunArtifact(exe);
41074107 run.expectStdOutEqual("bar=5\n");
......@@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41224122
41234123 {
41244124 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4125 dso.addObject(obj);
4125 dso.root_module.addObject(obj);
41264126
41274127 const check = dso.checkObject();
41284128 check.checkInDynamicSection();
......@@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41324132
41334133 {
41344134 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4135 dso.addObject(obj);
4135 dso.root_module.addObject(obj);
41364136 dso.link_z_lazy = true;
41374137
41384138 const check = dso.checkObject();
......@@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {
41504150 const exe = addExecutable(b, opts, .{ .name = "main" });
41514151 addCSourceBytes(exe, "int main() { return 0; }", &.{});
41524152 exe.stack_size = 0x800000;
4153 exe.linkLibC();
4153 exe.root_module.link_libc = true;
41544154
41554155 const check = exe.checkObject();
41564156 check.checkInHeaders();
......@@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step {
42024202 });
42034203
42044204 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4205 dso.addObject(a_o);
4206 dso.addObject(b_o);
4205 dso.root_module.addObject(a_o);
4206 dso.root_module.addObject(b_o);
42074207 dso.link_z_notext = true;
42084208
42094209 const exe = addExecutable(b, opts, .{ .name = "main" });
......@@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step {
42144214 \\ printf("%d\n", fnn());
42154215 \\}
42164216 , &.{});
4217 exe.linkLibrary(dso);
4218 exe.linkLibC();
4217 exe.root_module.linkLibrary(dso);
4218 exe.root_module.link_libc = true;
42194219
42204220 const run = addRunArtifact(exe);
42214221 run.expectStdOutEqual("3\n");
test/link/link.zig+3-3
......@@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run {
140140pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
141141 const b = comp.step.owner;
142142 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 });
144144}
145145
146146pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
147147 const b = comp.step.owner;
148148 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 });
150150}
151151
152152pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {
153153 const b = comp.step.owner;
154154 const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");
155155 const file = WriteFile.create(b).add("a.s", actual_bytes);
156 comp.addAssemblyFile(file);
156 comp.root_module.addAssemblyFile(file);
157157}
158158
159159pub 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 {
127127
128128 {
129129 const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });
130 exe.addObject(obj);
130 exe.root_module.addObject(obj);
131131 exe.link_gc_sections = false;
132132
133133 const check = exe.checkObject();
......@@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
156156
157157 {
158158 const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });
159 exe.addObject(obj);
159 exe.root_module.addObject(obj);
160160 exe.link_gc_sections = true;
161161
162162 const check = exe.checkObject();
......@@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
206206 \\ strong();
207207 \\}
208208 });
209 exe.addObject(obj);
209 exe.root_module.addObject(obj);
210210
211211 expectLinkErrors(exe, test_step, .{ .exact = &.{
212212 "error: duplicate symbol definition: _strong",
......@@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
235235
236236 {
237237 const exe = addExecutable(b, opts, .{ .name = "main1" });
238 exe.addObject(main_o);
238 exe.root_module.addObject(main_o);
239239 exe.root_module.linkFramework("Cocoa", .{});
240240
241241 const check = exe.checkObject();
......@@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
254254
255255 {
256256 const exe = addExecutable(b, opts, .{ .name = "main2" });
257 exe.addObject(main_o);
257 exe.root_module.addObject(main_o);
258258 exe.root_module.linkFramework("Cocoa", .{});
259259 exe.dead_strip_dylibs = true;
260260
......@@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
350350 \\ printf("Hello world!");
351351 \\}
352352 });
353 exe.addObject(empty);
353 exe.root_module.addObject(empty);
354354
355355 const run = addRunArtifact(exe);
356356 run.expectStdOutEqual("Hello world!");
......@@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step {
451451 \\ return 0;
452452 \\}
453453 , &.{});
454 exe.linkLibrary(dylib);
454 exe.root_module.linkLibrary(dylib);
455455 exe.entry = .{ .symbol_name = "_bootstrap" };
456456 exe.forceUndefinedSymbol("_my_main");
457457
......@@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
604604 });
605605
606606 const lib = addSharedLibrary(b, opts, .{ .name = "a" });
607 lib.addObject(obj1);
607 lib.root_module.addObject(obj1);
608608
609609 {
610610 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
613613 const check = exe.checkObject();
614614 check.checkInHeaders();
......@@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
642642 }
643643
644644 const exe = addExecutable(b, opts, .{ .name = "main2" });
645 exe.linkLibrary(lib);
646 exe.addObject(obj);
645 exe.root_module.linkLibrary(lib);
646 exe.root_module.addObject(obj);
647647
648648 const check = exe.checkObject();
649649 check.checkInHeaders();
......@@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
665665 \\_main:
666666 \\ ret
667667 });
668 exe.linkLibrary(lib);
668 exe.root_module.linkLibrary(lib);
669669
670670 const check = exe.checkObject();
671671 check.checkInHeaders();
......@@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
910910 \\}
911911 ,
912912 });
913 lib.addObject(obj);
913 lib.root_module.addObject(obj);
914914
915915 const exe = addExecutable(b, opts, .{
916916 .name = "testlib",
......@@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
923923 \\}
924924 ,
925925 });
926 exe.linkLibrary(lib);
926 exe.root_module.linkLibrary(lib);
927927
928928 const run = addRunArtifact(exe);
929929 run.expectStdErrEqual("0\n");
......@@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {
10511051
10521052 {
10531053 const exe = addExecutable(b, opts, .{ .name = "main1" });
1054 exe.addObject(a_o);
1055 exe.addObject(b_o);
1056 exe.addObject(main_o);
1054 exe.root_module.addObject(a_o);
1055 exe.root_module.addObject(b_o);
1056 exe.root_module.addObject(main_o);
10571057 runWithChecks(test_step, exe);
10581058 }
10591059
10601060 {
10611061 const exe = addExecutable(b, opts, .{ .name = "main2" });
1062 exe.addObject(b_o);
1063 exe.addObject(a_o);
1064 exe.addObject(main_o);
1062 exe.root_module.addObject(b_o);
1063 exe.root_module.addObject(a_o);
1064 exe.root_module.addObject(main_o);
10651065 runWithChecks(test_step, exe);
10661066 }
10671067
10681068 {
10691069 const c_o = addObject(b, opts, .{ .name = "c" });
1070 c_o.addObject(a_o);
1071 c_o.addObject(b_o);
1072 c_o.addObject(main_o);
1070 c_o.root_module.addObject(a_o);
1071 c_o.root_module.addObject(b_o);
1072 c_o.root_module.addObject(main_o);
10731073
10741074 const exe = addExecutable(b, opts, .{ .name = "main3" });
1075 exe.addObject(c_o);
1075 exe.root_module.addObject(c_o);
10761076 runWithChecks(test_step, exe);
10771077 }
10781078
......@@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {
11671167
11681168 {
11691169 const exe = addExecutable(b, opts, .{ .name = "main1" });
1170 exe.addObject(a_o);
1171 exe.addObject(b_o);
1172 exe.addObject(main_o);
1170 exe.root_module.addObject(a_o);
1171 exe.root_module.addObject(b_o);
1172 exe.root_module.addObject(main_o);
11731173 runWithChecks(test_step, exe);
11741174 }
11751175
11761176 {
11771177 const exe = addExecutable(b, opts, .{ .name = "main2" });
1178 exe.addObject(b_o);
1179 exe.addObject(a_o);
1180 exe.addObject(main_o);
1178 exe.root_module.addObject(b_o);
1179 exe.root_module.addObject(a_o);
1180 exe.root_module.addObject(main_o);
11811181 runWithChecks(test_step, exe);
11821182 }
11831183
11841184 {
11851185 const c_o = addObject(b, opts, .{ .name = "c" });
1186 c_o.addObject(a_o);
1187 c_o.addObject(b_o);
1188 c_o.addObject(main_o);
1186 c_o.root_module.addObject(a_o);
1187 c_o.root_module.addObject(b_o);
1188 c_o.root_module.addObject(main_o);
11891189
11901190 const exe = addExecutable(b, opts, .{ .name = "main3" });
1191 exe.addObject(c_o);
1191 exe.root_module.addObject(c_o);
11921192 runWithChecks(test_step, exe);
11931193 }
11941194
......@@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {
12591259 });
12601260
12611261 const exe = addExecutable(b, opts, .{ .name = "main1" });
1262 exe.addObject(a_o);
1263 exe.addObject(b_o);
1264 exe.addObject(main_o);
1262 exe.root_module.addObject(a_o);
1263 exe.root_module.addObject(b_o);
1264 exe.root_module.addObject(main_o);
12651265
12661266 const check = exe.checkObject();
12671267 check.dumpSection("__TEXT,__const");
......@@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {
13351335
13361336 {
13371337 const exe = addExecutable(b, opts, .{ .name = "main1" });
1338 exe.addObject(a_o);
1339 exe.addObject(b_o);
1340 exe.addObject(main_o);
1338 exe.root_module.addObject(a_o);
1339 exe.root_module.addObject(b_o);
1340 exe.root_module.addObject(main_o);
13411341 runWithChecks(test_step, exe);
13421342 }
13431343
13441344 {
13451345 const exe = addExecutable(b, opts, .{ .name = "main2" });
1346 exe.addObject(b_o);
1347 exe.addObject(a_o);
1348 exe.addObject(main_o);
1346 exe.root_module.addObject(b_o);
1347 exe.root_module.addObject(a_o);
1348 exe.root_module.addObject(main_o);
13491349 runWithChecks(test_step, exe);
13501350 }
13511351
......@@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {
14141414
14151415 {
14161416 const exe = addExecutable(b, opts, .{ .name = "main1" });
1417 exe.addObject(main_o);
1418 exe.addObject(a_o);
1417 exe.root_module.addObject(main_o);
1418 exe.root_module.addObject(a_o);
14191419 exe.root_module.linkFramework("Foundation", .{});
14201420 runWithChecks(test_step, exe);
14211421 }
14221422
14231423 {
14241424 const exe = addExecutable(b, opts, .{ .name = "main2" });
1425 exe.addObject(a_o);
1426 exe.addObject(main_o);
1425 exe.root_module.addObject(a_o);
1426 exe.root_module.addObject(main_o);
14271427 exe.root_module.linkFramework("Foundation", .{});
14281428 runWithChecks(test_step, exe);
14291429 }
14301430
14311431 {
14321432 const b_o = addObject(b, opts, .{ .name = "b" });
1433 b_o.addObject(a_o);
1434 b_o.addObject(main_o);
1433 b_o.root_module.addObject(a_o);
1434 b_o.root_module.addObject(main_o);
14351435
14361436 const exe = addExecutable(b, opts, .{ .name = "main3" });
1437 exe.addObject(b_o);
1437 exe.root_module.addObject(b_o);
14381438 exe.root_module.linkFramework("Foundation", .{});
14391439 runWithChecks(test_step, exe);
14401440 }
......@@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
16101610 \\@end
16111611 });
16121612 foo_o.root_module.addIncludePath(foo_h.dirname());
1613 foo_o.linkLibCpp();
1613 foo_o.root_module.link_libcpp = true;
16141614
16151615 const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes =
16161616 \\#import "Foo.h"
......@@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
16281628 \\}
16291629 });
16301630 exe.root_module.addIncludePath(foo_h.dirname());
1631 exe.addObject(foo_o);
1632 exe.linkLibCpp();
1631 exe.root_module.addObject(foo_o);
1632 exe.root_module.link_libcpp = true;
16331633 exe.root_module.linkFramework("Foundation", .{});
16341634
16351635 const run = addRunArtifact(exe);
......@@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step {
16931693 \\ return bar() - foo();
16941694 \\}
16951695 });
1696 exe.linkLibrary(lib);
1696 exe.root_module.linkLibrary(lib);
16971697
16981698 const run = addRunArtifact(exe);
16991699 run.expectExitCode(0);
......@@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17111711 \\ throw std::runtime_error("Oh no!");
17121712 \\}
17131713 });
1714 a_o.linkLibCpp();
1714 a_o.root_module.link_libcpp = true;
17151715
17161716 const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes =
17171717 \\extern int try_me();
......@@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17331733 \\ return 0;
17341734 \\}
17351735 });
1736 main_o.linkLibCpp();
1736 main_o.root_module.link_libcpp = true;
17371737
17381738 const exp_stdout = "exception=Oh no!";
17391739
17401740 {
17411741 const c_o = addObject(b, opts, .{ .name = "c" });
1742 c_o.addObject(a_o);
1743 c_o.addObject(b_o);
1742 c_o.root_module.addObject(a_o);
1743 c_o.root_module.addObject(b_o);
17441744
17451745 const exe = addExecutable(b, opts, .{ .name = "main1" });
1746 exe.addObject(main_o);
1747 exe.addObject(c_o);
1748 exe.linkLibCpp();
1746 exe.root_module.addObject(main_o);
1747 exe.root_module.addObject(c_o);
1748 exe.root_module.link_libcpp = true;
17491749
17501750 const run = addRunArtifact(exe);
17511751 run.expectStdOutEqual(exp_stdout);
......@@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17541754
17551755 {
17561756 const d_o = addObject(b, opts, .{ .name = "d" });
1757 d_o.addObject(a_o);
1758 d_o.addObject(b_o);
1759 d_o.addObject(main_o);
1757 d_o.root_module.addObject(a_o);
1758 d_o.root_module.addObject(b_o);
1759 d_o.root_module.addObject(main_o);
17601760
17611761 const exe = addExecutable(b, opts, .{ .name = "main2" });
1762 exe.addObject(d_o);
1763 exe.linkLibCpp();
1762 exe.root_module.addObject(d_o);
1763 exe.root_module.link_libcpp = true;
17641764
17651765 const run = addRunArtifact(exe);
17661766 run.expectStdOutEqual(exp_stdout);
......@@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {
18051805 });
18061806
18071807 const c_o = addObject(b, opts, .{ .name = "c" });
1808 c_o.addObject(a_o);
1809 c_o.addObject(b_o);
1810 c_o.addObject(main_o);
1808 c_o.root_module.addObject(a_o);
1809 c_o.root_module.addObject(b_o);
1810 c_o.root_module.addObject(main_o);
18111811
18121812 const exe = addExecutable(b, opts, .{ .name = "main" });
1813 exe.addObject(c_o);
1813 exe.root_module.addObject(c_o);
18141814
18151815 const run = addRunArtifact(exe);
18161816 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
......@@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18331833 });
18341834
18351835 const liba = addStaticLibrary(b, opts, .{ .name = "a" });
1836 liba.addObject(obj);
1836 liba.root_module.addObject(obj);
18371837
18381838 const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
1839 dylib.addObject(obj);
1839 dylib.root_module.addObject(obj);
18401840
18411841 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes =
18421842 \\#include<stdio.h>
......@@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18501850
18511851 {
18521852 const exe = addExecutable(b, opts, .{ .name = "main" });
1853 exe.addObject(main_o);
1853 exe.root_module.addObject(main_o);
18541854 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });
18551855 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
18561856 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
......@@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18691869
18701870 {
18711871 const exe = addExecutable(b, opts, .{ .name = "main" });
1872 exe.addObject(main_o);
1872 exe.root_module.addObject(main_o);
18731873 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });
18741874 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
18751875 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
......@@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
19241924 });
19251925
19261926 const exe = addExecutable(b, opts, .{ .name = "test" });
1927 exe.addObject(obj1);
1928 exe.addObject(obj2);
1929 exe.addObject(main_o);
1927 exe.root_module.addObject(obj1);
1928 exe.root_module.addObject(obj2);
1929 exe.root_module.addObject(main_o);
19301930
19311931 const run = b.addRunArtifact(exe);
19321932 run.skip_foreign_checks = true;
......@@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
19511951 });
19521952
19531953 const exe = addExecutable(b, opts, .{ .name = "test" });
1954 exe.addObject(obj1);
1955 exe.addObject(obj3);
1956 exe.addObject(main_o);
1954 exe.root_module.addObject(obj1);
1955 exe.root_module.addObject(obj3);
1956 exe.root_module.addObject(main_o);
19571957
19581958 const run = b.addRunArtifact(exe);
19591959 run.skip_foreign_checks = true;
......@@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
20312031 });
20322032
20332033 const exe = addExecutable(b, opts, .{ .name = "main" });
2034 exe.addObject(obj1);
2035 exe.addObject(obj2);
2036 exe.addObject(main_o);
2034 exe.root_module.addObject(obj1);
2035 exe.root_module.addObject(obj2);
2036 exe.root_module.addObject(main_o);
20372037
20382038 const run = addRunArtifact(exe);
20392039 run.expectStdOutEqual("All your codebase are belong to us.\n");
......@@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
20542054 });
20552055
20562056 const exe = addExecutable(b, opts, .{ .name = "main2" });
2057 exe.addObject(obj1);
2058 exe.addObject(obj2);
2059 exe.addObject(main_o);
2057 exe.root_module.addObject(obj1);
2058 exe.root_module.addObject(obj2);
2059 exe.root_module.addObject(main_o);
20602060
20612061 const check = exe.checkObject();
20622062 check.checkInHeaders();
......@@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step {
21022102 });
21032103
21042104 const exe = addExecutable(b, opts, .{ .name = "main" });
2105 exe.addObject(a_o);
2106 exe.addObject(b_o);
2107 exe.addObject(main_o);
2105 exe.root_module.addObject(a_o);
2106 exe.root_module.addObject(b_o);
2107 exe.root_module.addObject(main_o);
21082108
21092109 const run = addRunArtifact(exe);
21102110 run.expectStdOutEqual("foo=42,bar=24");
......@@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
22992299 \\}
23002300 });
23012301 bar_o.root_module.addIncludePath(foo_h.dirname());
2302 bar_o.linkLibCpp();
2302 bar_o.root_module.link_libcpp = true;
23032303
23042304 const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes =
23052305 \\#include "foo.h"
......@@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
23092309 \\}
23102310 });
23112311 baz_o.root_module.addIncludePath(foo_h.dirname());
2312 baz_o.linkLibCpp();
2312 baz_o.root_module.link_libcpp = true;
23132313
23142314 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes =
23152315 \\extern int bar();
......@@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
23212321 \\}
23222322 });
23232323 main_o.root_module.addIncludePath(foo_h.dirname());
2324 main_o.linkLibCpp();
2324 main_o.root_module.link_libcpp = true;
23252325
23262326 const exe = addExecutable(b, opts, .{ .name = "main" });
2327 exe.addObject(bar_o);
2328 exe.addObject(baz_o);
2329 exe.addObject(main_o);
2330 exe.linkLibCpp();
2327 exe.root_module.addObject(bar_o);
2328 exe.root_module.addObject(baz_o);
2329 exe.root_module.addObject(main_o);
2330 exe.root_module.link_libcpp = true;
23312331
23322332 const run = addRunArtifact(exe);
23332333 run.expectExitCode(0);
......@@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24452445
24462446 {
24472447 const exe = addExecutable(b, opts, .{ .name = "main1" });
2448 exe.addObject(main_o);
2448 exe.root_module.addObject(main_o);
24492449 exe.root_module.linkSystemLibrary("a", .{});
24502450 exe.root_module.linkSystemLibrary("b", .{});
24512451 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
......@@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24742474
24752475 {
24762476 const exe = addExecutable(b, opts, .{ .name = "main2" });
2477 exe.addObject(main_o);
2477 exe.root_module.addObject(main_o);
24782478 exe.root_module.linkSystemLibrary("b", .{});
24792479 exe.root_module.linkSystemLibrary("a", .{});
24802480 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
......@@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
25102510 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" });
25112511
25122512 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2513 lib.addObject(obj);
2513 lib.root_module.addObject(obj);
25142514
25152515 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25162516
25172517 {
25182518 const exe = addExecutable(b, opts, .{ .name = "main3" });
2519 exe.addObject(main_o);
2520 exe.addObject(obj);
2519 exe.root_module.addObject(main_o);
2520 exe.root_module.addObject(obj);
25212521 exe.discard_local_symbols = true;
25222522
25232523 const run = addRunArtifact(exe);
......@@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
25322532
25332533 {
25342534 const exe = addExecutable(b, opts, .{ .name = "main4" });
2535 exe.addObject(main_o);
2536 exe.linkLibrary(lib);
2535 exe.root_module.addObject(main_o);
2536 exe.root_module.linkLibrary(lib);
25372537 exe.discard_local_symbols = true;
25382538
25392539 const run = addRunArtifact(exe);
......@@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25552555 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });
25562556
25572557 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2558 lib.addObject(obj);
2558 lib.root_module.addObject(obj);
25592559
25602560 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25612561
25622562 {
25632563 const exe = addExecutable(b, opts, .{ .name = "main1" });
2564 exe.addObject(main_o);
2565 exe.linkLibrary(lib);
2564 exe.root_module.addObject(main_o);
2565 exe.root_module.linkLibrary(lib);
25662566 exe.forceUndefinedSymbol("_foo");
25672567
25682568 const run = addRunArtifact(exe);
......@@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25772577
25782578 {
25792579 const exe = addExecutable(b, opts, .{ .name = "main2" });
2580 exe.addObject(main_o);
2581 exe.linkLibrary(lib);
2580 exe.root_module.addObject(main_o);
2581 exe.root_module.linkLibrary(lib);
25822582 exe.forceUndefinedSymbol("_foo");
25832583 exe.link_gc_sections = true;
25842584
......@@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25942594
25952595 {
25962596 const exe = addExecutable(b, opts, .{ .name = "main3" });
2597 exe.addObject(main_o);
2598 exe.addObject(obj);
2597 exe.root_module.addObject(main_o);
2598 exe.root_module.addObject(obj);
25992599
26002600 const run = addRunArtifact(exe);
26012601 run.expectExitCode(0);
......@@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
26092609
26102610 {
26112611 const exe = addExecutable(b, opts, .{ .name = "main4" });
2612 exe.addObject(main_o);
2613 exe.addObject(obj);
2612 exe.root_module.addObject(main_o);
2613 exe.root_module.addObject(obj);
26142614 exe.link_gc_sections = true;
26152615
26162616 const run = addRunArtifact(exe);
......@@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
26422642 \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()});
26432643 \\}
26442644 });
2645 exe.addObject(obj);
2645 exe.root_module.addObject(obj);
26462646
26472647 // TODO order should match across backends if possible
26482648 if (opts.use_llvm) {
......@@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
27642764 \\}
27652765 });
27662766 main_o.root_module.addIncludePath(all_h.dirname());
2767 main_o.linkLibCpp();
2767 main_o.root_module.link_libcpp = true;
27682768
27692769 const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes =
27702770 \\#include "all.h"
......@@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
27992799 \\}
28002800 });
28012801 simple_string_o.root_module.addIncludePath(all_h.dirname());
2802 simple_string_o.linkLibCpp();
2802 simple_string_o.root_module.link_libcpp = true;
28032803
28042804 const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes =
28052805 \\#include "all.h"
......@@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
28162816 \\}
28172817 });
28182818 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
28212821 const exp_stdout =
28222822 \\Constructed: a
......@@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
28282828 ;
28292829
28302830 const exe = addExecutable(b, opts, .{ .name = "main" });
2831 exe.addObject(main_o);
2832 exe.addObject(simple_string_o);
2833 exe.addObject(simple_string_owner_o);
2834 exe.linkLibCpp();
2831 exe.root_module.addObject(main_o);
2832 exe.root_module.addObject(simple_string_o);
2833 exe.root_module.addObject(simple_string_owner_o);
2834 exe.root_module.link_libcpp = true;
28352835
28362836 const run = addRunArtifact(exe);
28372837 run.expectStdOutEqual(exp_stdout);
......@@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
28962896 \\ return 0;
28972897 \\}
28982898 });
2899 exe.addObject(a_o);
2899 exe.root_module.addObject(a_o);
29002900
29012901 const run = addRunArtifact(exe);
29022902 run.expectStdOutEqual("4\n");
......@@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {
29482948 \\ return 0;
29492949 \\}
29502950 });
2951 exe.addObject(a_o);
2951 exe.root_module.addObject(a_o);
29522952
29532953 const run = addRunArtifact(exe);
29542954 run.expectStdOutEqual("4\n");
......@@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step {
30523052 \\ .quad 0
30533053 \\ .quad _weak_internal_tlv$tlv$init
30543054 });
3055 exe.linkLibrary(lib);
3055 exe.root_module.linkLibrary(lib);
30563056
30573057 {
30583058 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
1616 .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),
1717 }),
1818 });
19 exe.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
19 exe.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
2020 exe.use_llvm = false;
2121 exe.use_lld = false;
2222
test/src/Cases.zig+2-6
......@@ -436,7 +436,7 @@ fn addFromDirInner(
436436 const target = &resolved_target.result;
437437 for (backends) |backend| {
438438 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)
440440 {
441441 // Other backends don't support new liveness format
442442 continue;
......@@ -447,10 +447,6 @@ fn addFromDirInner(
447447 // Rosetta has issues with ZLD
448448 continue;
449449 }
450 if (backend == .stage2 and target.ofmt == .coff) {
451 // COFF linker has bitrotted
452 continue;
453 }
454450
455451 const next = ctx.cases.items.len;
456452 try ctx.cases.append(.{
......@@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps(
560556 .root_module = translate_c.createModule(),
561557 });
562558 run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
563 run_exe.linkLibC();
559 run_exe.root_module.link_libc = true;
564560 const run = b.addRunArtifact(run_exe);
565561 run.step.name = b.fmt("{s} run", .{annotated_case_name});
566562 run.expectStdOutEqual(output);
test/src/RunTranslatedC.zig+1-1
......@@ -89,7 +89,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
8989 .root_module = translate_c.createModule(),
9090 });
9191 exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
92 exe.linkLibC();
92 exe.root_module.link_libc = true;
9393 const run = b.addRunArtifact(exe);
9494 run.step.name = b.fmt("{s} run", .{annotated_case_name});
9595 if (!case.allow_warnings) {
test/standalone/build.zig.zon+4-1
......@@ -1,6 +1,6 @@
11.{
22 .name = .standalone_test_cases,
3 .fingerprint = 0xc0dbdf9c818957be,
3 .fingerprint = 0xc0dbdf9c3b92810b,
44 .version = "0.0.0",
55 .dependencies = .{
66 .simple = .{
......@@ -181,6 +181,9 @@
181181 .install_headers = .{
182182 .path = "install_headers",
183183 },
184 .dependency_options = .{
185 .path = "dependency_options",
186 },
184187 .dependencyFromBuildZig = .{
185188 .path = "dependencyFromBuildZig",
186189 },
test/standalone/c_embed_path/build.zig+3-3
......@@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void {
1313 .optimize = optimize,
1414 }),
1515 });
16 exe.addCSourceFile(.{
16 exe.root_module.addCSourceFile(.{
1717 .file = b.path("test.c"),
1818 .flags = &.{"-std=c23"},
1919 });
20 exe.linkLibC();
21 exe.addEmbedPath(b.path("data"));
20 exe.root_module.link_libc = true;
21 exe.root_module.addEmbedPath(b.path("data"));
2222
2323 const run_c_cmd = b.addRunArtifact(exe);
2424 run_c_cmd.expectExitCode(0);
test/standalone/dependencyFromBuildZig/build.zig.zon+2-1
......@@ -1,5 +1,6 @@
11.{
2 .name = "dependencyFromBuildZig",
2 .name = .dependencyFromBuildZig,
3 .fingerprint = 0xfd939a1eb8169080,
34 .version = "0.0.0",
45 .dependencies = .{
56 .other = .{
test/standalone/dependencyFromBuildZig/other/build.zig.zon+2-1
......@@ -1,5 +1,6 @@
11.{
2 .name = "other",
2 .name = .other,
3 .fingerprint = 0xd9583520a2405f6c,
34 .version = "0.0.0",
45 .dependencies = .{},
56 .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 {
3131 .target = b.graph.host,
3232 .optimize = optimize,
3333 }) });
34 test_exe.addObject(obj);
35 test_exe.linkLibrary(shared);
34 test_exe.root_module.addObject(obj);
35 test_exe.root_module.linkLibrary(shared);
3636
3737 test_step.dependOn(&b.addRunArtifact(test_exe).step);
3838}
test/standalone/issue_794/build.zig+1-1
......@@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {
88 .root_source_file = b.path("main.zig"),
99 .target = b.graph.host,
1010 }) });
11 test_artifact.addIncludePath(b.path("a_directory"));
11 test_artifact.root_module.addIncludePath(b.path("a_directory"));
1212
1313 // TODO: actually check the output
1414 _ = test_artifact.getEmittedBin();
test/standalone/stack_iterator/build.zig+1-1
......@@ -109,7 +109,7 @@ pub fn build(b: *std.Build) void {
109109 // .use_llvm = true,
110110 // });
111111
112 // exe.linkLibrary(c_shared_lib);
112 // exe.root_module.linkLibrary(c_shared_lib);
113113
114114 // const run_cmd = b.addRunArtifact(exe);
115115 // test_step.dependOn(&run_cmd.step);
test/tests.zig+2-2
......@@ -2371,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
23712371 } else "";
23722372 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
23762376 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, .{});
23782378 }
23792379
23802380 const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{